Date: Sun, 9 Feb 2025 12:33:10 +0100
Subject: [PATCH 07/13] gh-204 + gh-203 added tracklength to taf-header info
modal and display content as yaml
---
package-lock.json | 14 ++++--
package.json | 1 +
public/translations/de.json | 1 +
public/translations/en.json | 1 +
public/translations/es.json | 1 +
public/translations/fr.json | 1 +
src/components/utils/FileBrowser.tsx | 71 +++++++++++++++++++++-------
src/types/fileBrowserTypes.tsx | 1 +
8 files changed, 72 insertions(+), 19 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7d507630..92bba328 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -37,6 +37,7 @@
},
"devDependencies": {
"@babel/plugin-transform-private-property-in-object": "^7.25.9",
+ "@types/js-yaml": "^4.0.9",
"@types/react-syntax-highlighter": "^15.5.13",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3"
@@ -1808,6 +1809,13 @@
"pretty-format": "^29.0.0"
}
},
+ "node_modules/@types/js-yaml": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/node": {
"version": "22.8.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz",
@@ -4526,9 +4534,9 @@
}
},
"node_modules/vite": {
- "version": "5.4.10",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
- "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
+ "version": "5.4.14",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
+ "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
diff --git a/package.json b/package.json
index e10c0e8f..dcde49d8 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
},
"devDependencies": {
"@babel/plugin-transform-private-property-in-object": "^7.25.9",
+ "@types/js-yaml": "^4.0.9",
"@types/react-syntax-highlighter": "^15.5.13",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3"
diff --git a/public/translations/de.json b/public/translations/de.json
index 9f99410f..95f06d35 100644
--- a/public/translations/de.json
+++ b/public/translations/de.json
@@ -1441,6 +1441,7 @@
"title": "System Sounds"
},
"tafHeaderOf": "TAF-Header von ",
+ "tafHeaderInvalid": "Ungültige TAF",
"tap": {
"navigationTitle": "WIP: Audio Playlists",
"title": "WIP: Tonie Audio Playlists"
diff --git a/public/translations/en.json b/public/translations/en.json
index 7ad48196..476b3623 100644
--- a/public/translations/en.json
+++ b/public/translations/en.json
@@ -1441,6 +1441,7 @@
"title": "System Sounds"
},
"tafHeaderOf": "TAF-Header of ",
+ "tafHeaderInvalid": "Invalid TAF",
"tap": {
"navigationTitle": "WIP: Audio Playlists",
"title": "WIP: Tonie Audio Playlists"
diff --git a/public/translations/es.json b/public/translations/es.json
index 9b84205f..7da99d8e 100644
--- a/public/translations/es.json
+++ b/public/translations/es.json
@@ -1441,6 +1441,7 @@
"title": "Sonidos del sistema"
},
"tafHeaderOf": "TAF-Header de ",
+ "tafHeaderInvalid": "TAF no válido",
"tap": {
"navigationTitle": "WIP: Listas de reproducción de audio",
"title": "WIP: Listas de reproducción de audio de Tonie"
diff --git a/public/translations/fr.json b/public/translations/fr.json
index 9e65fc7f..14598f9a 100644
--- a/public/translations/fr.json
+++ b/public/translations/fr.json
@@ -1441,6 +1441,7 @@
"title": "Sons du système"
},
"tafHeaderOf": "En-tête TAF de ",
+ "tafHeaderInvalid": "TAF invalide",
"tap": {
"navigationTitle": "WIP: Listes de lecture audio",
"title": "WIP: Listes de lecture audio de Tonie"
diff --git a/src/components/utils/FileBrowser.tsx b/src/components/utils/FileBrowser.tsx
index 1385eb42..259c2acf 100644
--- a/src/components/utils/FileBrowser.tsx
+++ b/src/components/utils/FileBrowser.tsx
@@ -22,6 +22,7 @@ import {
Tag,
Flex,
} from "antd";
+import yaml from "js-yaml";
import {
CloseOutlined,
CloudServerOutlined,
@@ -135,7 +136,7 @@ export const FileBrowser: React.FC<{
const [isTafMetaEditorModalOpen, setIsTafMetaEditorModalOpen] = useState
(false);
const [tafMetaEditorKey, setTafMetaEditorKey] = useState(0);
- const [currentRecordTafHeader, setCurrentRecordTafHeader] = useState();
+ const [currentRecordYaml, setCurrentRecordYaml] = useState("");
const [isTafHeaderModalOpen, setIsTafHeaderModalOpen] = useState(false);
const [isUnchangedOrEmpty, setIsUnchangedOrEmpty] = useState(true);
@@ -397,6 +398,20 @@ export const FileBrowser: React.FC<{
/>
);
+ // other functions
+ const transformTafHeaderToYaml = (jsonData: RecordTafHeader) => {
+ const transformedData = [
+ {
+ "audio-id": jsonData.audioId,
+ hash: jsonData.sha1Hash,
+ size: jsonData.size,
+ tracks: jsonData.trackSeconds?.length,
+ confidence: 0,
+ },
+ ];
+ return yaml.dump(transformedData).trim();
+ };
+
// information model functions
const showInformationModal = (record: any) => {
if (!record.isDir && record.tonieInfo?.tracks) {
@@ -455,10 +470,13 @@ export const FileBrowser: React.FC<{
// taf header viewer functions
const showTafHeader = (file: string, recordTafHeader: RecordTafHeader) => {
- const currentRecordTafHeader: RecordTafHeader = recordTafHeader;
- const { trackSeconds, ...currentRecordTafHeaderCopy } = currentRecordTafHeader;
setFilterFieldAutoFocus(false);
- setCurrentRecordTafHeader(currentRecordTafHeaderCopy);
+
+ if (recordTafHeader.valid) {
+ setCurrentRecordYaml(transformTafHeaderToYaml(recordTafHeader));
+ } else {
+ setCurrentRecordYaml(t("tonies.tafHeaderInvalid"));
+ }
setCurrentFile(file);
setIsTafHeaderModalOpen(true);
};
@@ -480,8 +498,10 @@ export const FileBrowser: React.FC<{
onCancel={closeTafHeader}
width={700}
>
- {currentRecordTafHeader ? (
-
+ {currentRecordYaml ? (
+ <>
+
+ >
) : (
"Loading..."
)}
@@ -1955,12 +1975,20 @@ export const FileBrowser: React.FC<{
""
)}
-
-
-
{t("tonies.currentPath")}
- {generateBreadcrumbs(path, handleBreadcrumbClick)}
+
+
+
{t("tonies.currentPath")}
+ {generateBreadcrumbs(path, handleBreadcrumbClick)}
-
({files.filter(x => x.name != "..").length})
+
({files.filter((x) => x.name != "..").length})
selectedRowKeys.includes(item.name) && !item.isDir)
.length > 0 ? (
-
+
}
@@ -1995,7 +2028,12 @@ export const FileBrowser: React.FC<{
) : (
""
)}
-
+
}
@@ -2020,8 +2058,9 @@ export const FileBrowser: React.FC<{
);
+ actions.push(
+ downloading[record.name] ? (
+ }
+ />
+ ) : (
+
+ handleFileDownload(record)}
+ />
+
+ )
+ );
// migration to lib possible
if (special !== "library") {
actions.push(
diff --git a/src/components/utils/TonieInformationModal.tsx b/src/components/utils/TonieInformationModal.tsx
index a9e1ca85..e3dee571 100644
--- a/src/components/utils/TonieInformationModal.tsx
+++ b/src/components/utils/TonieInformationModal.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import { Modal, Typography, Button, Tooltip } from "antd";
-import { PlayCircleOutlined } from "@ant-design/icons";
+import { Modal, Typography, Button, Tooltip, Spin, theme } from "antd";
+import { DownloadOutlined, LoadingOutlined, PlayCircleOutlined } from "@ant-design/icons";
import { Record } from "../../types/fileBrowserTypes";
import { TonieCardProps } from "../../types/tonieTypes";
@@ -17,6 +17,7 @@ import { NotificationTypeEnum } from "../../types/teddyCloudNotificationTypes";
const api = new TeddyCloudApi(defaultAPIConfig());
const { Text } = Typography;
+const { useToken } = theme;
type TonieCardTAFRecord = TonieCardProps | Record;
@@ -42,6 +43,7 @@ const TonieInformationModal: React.FC = ({
onHide,
}) => {
const { t } = useTranslation();
+ const { token } = useToken();
const { playAudio } = useAudioContext();
const { addNotification } = useTeddyCloud();
@@ -52,6 +54,8 @@ const TonieInformationModal: React.FC = ({
const [sourcePic, setSourcePic] = useState("");
const [sourceTracks, setSourceTracks] = useState([]);
+ const [isDownloading, setIsDownloading] = useState(false);
+
useEffect(() => {
if (
showSourceInfo &&
@@ -82,6 +86,21 @@ const TonieInformationModal: React.FC = ({
);
};
+ const handleDownload = async (url: string, filename: string) => {
+ setIsDownloading(true);
+ const response = await fetch(url);
+ const blob = await response.blob();
+ const blobUrl = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = blobUrl;
+ link.download = filename;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(blobUrl);
+ setIsDownloading(false);
+ };
+
const toniePlayedOn =
lastRUIDs && "ruid" in tonieCardOrTAFRecord
? lastRUIDs
@@ -364,6 +383,42 @@ const TonieInformationModal: React.FC = ({
) : (
<>>
)}
+ {"exists" in tonieCardOrTAFRecord &&
+ tonieCardOrTAFRecord.exists &&
+ "audioUrl" in tonieCardOrTAFRecord ? (
+
+ handleDownload(
+ import.meta.env.VITE_APP_TEDDYCLOUD_API_URL +
+ tonieCardOrTAFRecord.audioUrl,
+ sourceTitle ? sourceTitle : modelTitle + ".ogg"
+ )
+ : undefined
+ }
+ >
+ {isDownloading ? (
+
+ }
+ />
+ ) : (
+
+ )}
+ {t("tonies.infoModal.download")}
+
+ ) : (
+ ""
+ )}
{confirmHideTonieModal}
diff --git a/src/pages/community/ChangelogPage.tsx b/src/pages/community/ChangelogPage.tsx
index 743e0641..1f0f55fa 100644
--- a/src/pages/community/ChangelogPage.tsx
+++ b/src/pages/community/ChangelogPage.tsx
@@ -29,6 +29,7 @@ export const ChangelogPage = () => {
"gui: show number of selected entries / total files in library/content view https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/199",
"gui: hide baudrate selection if not necessary https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/195",
"gui: added support previous set hostname in esp32 flash process https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/189",
+ "gui: added download possibility to taf files as *.ogg file within Tonie/tag Information modal and filebrowser https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/207",
"gui: Some refactoring",
],
commits: [
From bb5333b5619b07c559928e91f63f08fe927078dc Mon Sep 17 00:00:00 2001
From: henryk86 <166761451+henryk86@users.noreply.github.com>
Date: Sun, 2 Mar 2025 17:53:03 +0100
Subject: [PATCH 12/13] extended Changelog
---
src/pages/community/ChangelogPage.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/pages/community/ChangelogPage.tsx b/src/pages/community/ChangelogPage.tsx
index 1f0f55fa..29fffbfe 100644
--- a/src/pages/community/ChangelogPage.tsx
+++ b/src/pages/community/ChangelogPage.tsx
@@ -21,6 +21,7 @@ export const ChangelogPage = () => {
"Add field2/field6 of the toniebox settings with unknown functionality",
"Always set Toniebox settings, if cloud not enabled or had error",
"Save used domains sent via rtnl",
+ "Implemented tbs_tag_removed for CC3200 + ESP32 (new mqtt event, more details: https://github.com/toniebox-reverse-engineering/teddycloud/pull/309)",
"Disable keep-alive for boxine upstream https://github.com/toniebox-reverse-engineering/teddycloud/issues/310",
"Added hide flag to dirs https://github.com/toniebox-reverse-engineering/teddycloud/issues/234",
"gui: added track count to taf header viewer https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/203",
From d24276e8d0972477d988449c566879974795d02a Mon Sep 17 00:00:00 2001
From: SciLor
Date: Mon, 3 Mar 2025 18:54:08 +0000
Subject: [PATCH 13/13] make clear that c2.der is the source file
---
public/translations/de.json | 2 +-
public/translations/en.json | 2 +-
public/translations/es.json | 2 +-
public/translations/fr.json | 2 +-
src/pages/tonieboxes/boxsetup/cc3200/CC3200BoxFlashingPage.tsx | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/public/translations/de.json b/public/translations/de.json
index 86b72509..70156008 100644
--- a/public/translations/de.json
+++ b/public/translations/de.json
@@ -913,7 +913,7 @@
"dumpCertificatesLink": "Hier findest du die Anleitung zum Entnehmen von Zertifikaten",
"flashCAreplacement": "CA-Ersatz für TeddyCloud flashen",
"flashCAreplacementIntro": "Es wird empfohlen, das Ersatz-CA-Zertifikat nach /cert/c2.der zu flashen und den Hackiebox-NG-Bootloader mit dem altCA.305-Patch zu verwenden (weitere Details in den nächsten Schritten). Dadurch kannst du nahtlos zwischen dem Originalzertifikat und deinem Ersatzzertifikat wechseln.",
- "flashCAreplacementOutro": "Stelle sicher, dass du den richtigen Pfad zur Datei ca.der ausgewählt hast.",
+ "flashCAreplacementOutro": "Stelle sicher, dass du den richtigen Pfad zur Datei c2.der ausgewählt hast.",
"flashCAreplacementText": "Um die heruntergeladene c2.der-Datei (siehe oben) auf deine Toniebox zu schreiben, verwende den folgenden Befehl:",
"hint": "Es gibt derzeit keine direkte Unterstützung, um deine CC3200 Toniebox mit TeddyCloud zu flashen, aber hier findest du eine Schritt-für-Schritt-Anleitung:",
"hint2": "Bitte folge dann dem CC3200-Pfad:",
diff --git a/public/translations/en.json b/public/translations/en.json
index 38589f75..54e59552 100644
--- a/public/translations/en.json
+++ b/public/translations/en.json
@@ -913,7 +913,7 @@
"dumpCertificatesLink": "Find instructions for dumping certificates here",
"flashCAreplacement": "Flash CA replacement for TeddyCloud",
"flashCAreplacementIntro": "It is recommended to flash the replacement CA to /cert/c2.der and use the Hackiebox-NG bootloader with the altCA.305 patch (more details provided in the next steps). This setup enables you to switch seamlessly between the original certificate and your replacement certificate.",
- "flashCAreplacementOutro": "Ensure that you have selected the correct path to the ca.der file.",
+ "flashCAreplacementOutro": "Ensure that you have selected the correct path to the c2.der file.",
"flashCAreplacementText": "To write the downloaded c2.der file (refer to the steps above) to your Toniebox, use the following command:",
"hint": "There is currently no direct support of flashing your CC3200 Toniebox with TeddyCloud, but you will find a step by step guidance here:",
"hint2": "Please follow then the CC3200 path:",
diff --git a/public/translations/es.json b/public/translations/es.json
index 06bd816b..c82e969d 100644
--- a/public/translations/es.json
+++ b/public/translations/es.json
@@ -913,7 +913,7 @@
"dumpCertificatesLink": "Encuentra las instrucciones para extraer certificados aquí",
"flashCAreplacement": "Flashear reemplazo CA para TeddyCloud",
"flashCAreplacementIntro": "Se recomienda flashear el certificado CA de reemplazo en /cert/c2.der y usar el bootloader Hackiebox-NG con el parche altCA.305 (más detalles en los siguientes pasos). Esto te permitirá cambiar fácilmente entre el certificado original y tu certificado de reemplazo.",
- "flashCAreplacementOutro": "Asegúrate de haber seleccionado la ruta correcta al archivo ca.der.",
+ "flashCAreplacementOutro": "Asegúrate de haber seleccionado la ruta correcta al archivo c2.der.",
"flashCAreplacementText": "Para escribir el archivo c2.der descargado (consulta los pasos anteriores) en tu Toniebox, utiliza el siguiente comando:",
"hint": "Actualmente no hay soporte directo para flashear tu Toniebox CC3200 con TeddyCloud, pero encontrarás una guía paso a paso aquí:",
"hint2": "Sigue luego el camino para CC3200:",
diff --git a/public/translations/fr.json b/public/translations/fr.json
index 26374772..db71792a 100644
--- a/public/translations/fr.json
+++ b/public/translations/fr.json
@@ -913,7 +913,7 @@
"dumpCertificatesLink": "Trouve les instructions pour extraire les certificats ici",
"flashCAreplacement": "Flasher le remplacement CA pour TeddyCloud",
"flashCAreplacementIntro": "Il est recommandé de flasher le certificat CA de remplacement dans /cert/c2.der et d'utiliser le bootloader Hackiebox-NG avec le patch altCA.305 (plus de détails dans les étapes suivantes). Cela te permettra de basculer facilement entre le certificat original et ton certificat de remplacement.",
- "flashCAreplacementOutro": "Assure-toi d'avoir sélectionné le bon chemin vers le fichier ca.der.",
+ "flashCAreplacementOutro": "Assure-toi d'avoir sélectionné le bon chemin vers le fichier c2.der.",
"flashCAreplacementText": "Pour écrire le fichier c2.der téléchargé (voir les étapes ci-dessus) sur ta Toniebox, utilise la commande suivante :",
"hint": "Il n'y a actuellement pas de support direct pour flasher votre CC3200 Toniebox avec TeddyCloud, mais vous trouverez ici un guide étape par étape :",
"hint2": "Veuillez suivre ensuite le chemin CC3200 :",
diff --git a/src/pages/tonieboxes/boxsetup/cc3200/CC3200BoxFlashingPage.tsx b/src/pages/tonieboxes/boxsetup/cc3200/CC3200BoxFlashingPage.tsx
index 2dd0e0bc..16525454 100644
--- a/src/pages/tonieboxes/boxsetup/cc3200/CC3200BoxFlashingPage.tsx
+++ b/src/pages/tonieboxes/boxsetup/cc3200/CC3200BoxFlashingPage.tsx
@@ -468,7 +468,7 @@ export const CC3200BoxFlashingPage = () => {
{t("tonieboxes.cc3200BoxFlashing.flashCAreplacement")}
{t("tonieboxes.cc3200BoxFlashing.flashCAreplacementIntro")}
{t("tonieboxes.cc3200BoxFlashing.flashCAreplacementText")}
-
+
{t("tonieboxes.cc3200BoxFlashing.flashCAreplacementOutro")}
>
);