diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9e1fec0c..cec6d1bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog
-## 0.6.8
+## 0.7.0
- added tls support in mqtt
- prepared support of TB2 (added new v3 tonies APIs)
@@ -9,19 +9,20 @@
- gui: removed switch enable rtnl on rtnl page, is now autoenabled
- gui: Added find all unused TAF Search in Library [https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/279](https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/279)
- gui: Prepared support for TB2
+- gui: Added Custom Tonies Editor with Image Manager for managing custom models [PR #283](https://github.com/toniebox-reverse-engineering/teddycloud_web/pull/283)
### Commits
-- [https://github.com/toniebox-reverse-engineering/teddycloud/compare/tc_v0.6.7...tc_v0.6.8](https://github.com/toniebox-reverse-engineering/teddycloud/compare/tc_v0.6.7...tc_v0.6.8)
-- [https://github.com/toniebox-reverse-engineering/teddycloud_web/compare/tcw_v0.6.7...tcw_v0.6.8](https://github.com/toniebox-reverse-engineering/teddycloud_web/compare/tcw_v0.6.7...tcw_v0.6.8)
+- [https://github.com/toniebox-reverse-engineering/teddycloud/compare/tc_v0.6.7...tc_v0.7.0](https://github.com/toniebox-reverse-engineering/teddycloud/compare/tc_v0.6.7...tc_v0.7.0)
+- [https://github.com/toniebox-reverse-engineering/teddycloud_web/compare/tcw_v0.6.7...tcw_v0.7.0](https://github.com/toniebox-reverse-engineering/teddycloud_web/compare/tcw_v0.6.7...tcw_v0.7.0)
### Discussion
-- [https://forum.revvox.de/t/release-notes-0-6-8/3235](https://forum.revvox.de/t/release-notes-0-6-8/3235)
+- [https://forum.revvox.de/t/release-notes-0-7-0/3235](https://forum.revvox.de/t/release-notes-0-7-0/3235)
### GitHub Release
-- [https://github.com/toniebox-reverse-engineering/teddycloud/releases/tag/tc_v0.6.8](https://github.com/toniebox-reverse-engineering/teddycloud/releases/tag/tc_v0.6.8)
+- [https://github.com/toniebox-reverse-engineering/teddycloud/releases/tag/tc_v0.7.0](https://github.com/toniebox-reverse-engineering/teddycloud/releases/tag/tc_v0.7.0)
## 0.6.7
diff --git a/package-lock.json b/package-lock.json
index 6fc23b07..468755a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "teddycloud-web",
- "version": "0.6.8",
+ "version": "0.7.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "teddycloud-web",
- "version": "0.6.8",
+ "version": "0.7.0",
"dependencies": {
"@ant-design/icons": "^6.1.0",
"@dnd-kit/core": "^6.3.1",
@@ -618,7 +618,6 @@
"cpu": [
"ppc64"
],
- "license": "MIT",
"optional": true,
"os": [
"aix"
@@ -634,7 +633,6 @@
"cpu": [
"arm"
],
- "license": "MIT",
"optional": true,
"os": [
"android"
@@ -650,7 +648,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"android"
@@ -666,7 +663,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"android"
@@ -682,7 +678,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -698,7 +693,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -714,7 +708,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -730,7 +723,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -746,7 +738,6 @@
"cpu": [
"arm"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -762,7 +753,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -778,7 +768,6 @@
"cpu": [
"ia32"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -794,7 +783,6 @@
"cpu": [
"loong64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -810,7 +798,6 @@
"cpu": [
"mips64el"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -826,7 +813,6 @@
"cpu": [
"ppc64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -842,7 +828,6 @@
"cpu": [
"riscv64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -858,7 +843,6 @@
"cpu": [
"s390x"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -874,7 +858,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -890,7 +873,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"netbsd"
@@ -906,7 +888,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"netbsd"
@@ -922,7 +903,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"openbsd"
@@ -938,7 +918,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"openbsd"
@@ -954,7 +933,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"openharmony"
@@ -970,7 +948,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"sunos"
@@ -986,7 +963,6 @@
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1002,7 +978,6 @@
"cpu": [
"ia32"
],
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1018,7 +993,6 @@
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1870,8 +1844,7 @@
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
- "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
- "license": "MIT"
+ "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="
},
"node_modules/@rollup/pluginutils": {
"version": "5.3.0",
@@ -2673,7 +2646,6 @@
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
"integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==",
- "license": "MIT",
"dependencies": {
"@babel/core": "^7.29.0",
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
@@ -3315,7 +3287,6 @@
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
"hasInstallScript": true,
- "license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@@ -3436,7 +3407,6 @@
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "license": "MIT",
"engines": {
"node": ">=12.0.0"
},
@@ -5057,7 +5027,6 @@
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
"integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
- "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -5567,7 +5536,6 @@
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
- "license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
@@ -5854,7 +5822,6 @@
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
- "license": "MIT",
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -5942,7 +5909,6 @@
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.1.1.tgz",
"integrity": "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==",
- "license": "MIT",
"dependencies": {
"debug": "^4.1.1",
"globrex": "^0.1.2",
diff --git a/package.json b/package.json
index f5ad96d6..c7923782 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "teddycloud-web",
- "version": "0.6.8",
+ "version": "0.7.0",
"private": true,
"homepage": "/web",
"dependencies": {
diff --git a/public/translations/de.json b/public/translations/de.json
index ac487a89..183c9c4b 100644
--- a/public/translations/de.json
+++ b/public/translations/de.json
@@ -10,6 +10,13 @@
"errorNoOggOpusSupportByApple": "Dein Browser unterstützt im Moment keine OGG/Opus (taf) Dateien. Nutzt du ein Apple Gerät, dann hilf uns, indem Sie ein Ticket bei Apple zur Behebung des Problems einreichen!",
"unknownSource": "Unbekannt"
},
+ "common": {
+ "cancel": "Abbrechen",
+ "clean": "unverändert",
+ "changed": "geändert*",
+ "deleted": "gelöscht*",
+ "new": "neu*"
+ },
"community": {
"attribution": {
"navigationTitle": "Lizenzhinweise",
@@ -566,7 +573,7 @@
"items": {
"01assignContent": "Inhalte und andere Eigenschaften jedem Tag zuweisen",
"02searchStreams": "Webradio-Streams suchen und jedem Tag zuweisen",
- "03defineMetaData": "Metadaten deiner benutzerdefinierten Tags definieren (PoC im WebFrontend)",
+ "03defineMetaData": "Metadaten deiner benutzerdefinierten Tags definieren (Custom Models Editor im WebFrontend)",
"04filterTonies": "Tonies/Tags filtern",
"05hideTonies": "Nicht verfügbare Tonies/Tags ausblenden",
"06showLastPlayed": "Zuletzt gespielte Tonies/Tags anzeigen"
@@ -636,9 +643,8 @@
"01firmwareUpdate": "Firmware-Update über TeddyCloud",
"03reportUnknownTonies": "Unbekannte Tonies melden",
"04completeTAPIntegration": "Abschluss der TAP-WebFrontend-Integration",
- "05completeCustomToniesIntegration": "Abschluss der Integration benutzerdefinierter Tonies im JSON-WebFront (\"Metadaten benutzerdefinierter Tags\")",
- "06moreStats": "Mehr Statistiken über deine gespielten Tonies/Tags",
- "07securityImprovements": "Sicherheitsverbesserungen wie Zugriffskontrolle (Tonieboxen und Benutzer)"
+ "05moreStats": "Mehr Statistiken über deine gespielten Tonies/Tags",
+ "06securityImprovements": "Sicherheitsverbesserungen wie Zugriffskontrolle (Tonieboxen und Benutzer)"
},
"navigationTitle": "Features",
"title": "Features TeddyCloud",
@@ -1802,6 +1808,85 @@
"track": "Track"
},
"addToniesCustomJsonEntry": "WIP: Modell anlegen",
+ "customToniesEditorJsonEntry": "Custom-Modelle",
+ "imageManager": {
+ "title": "Bilder auswählen & verwalten",
+ "okText": "Übernehmen",
+ "sourceCustom": "Custom",
+ "sourceOriginal": "Original",
+ "noOriginalImages": "Keine Original-Bilder gefunden"
+ },
+ "customEditor": {
+ "actions": {
+ "delete": "Löschen",
+ "deleteCount": "{{count}} Modell(e) löschen",
+ "discard": "Verwerfen",
+ "duplicate": "Duplizieren",
+ "edit": "Bearbeiten",
+ "newModel": "Neues Modell",
+ "preview": "Vorschau",
+ "restore": "Wiederherstellen",
+ "toggleChangesOnly": "Nur Änderungen"
+ },
+ "audio": {
+ "libraryLabel": "Custom-Audio (Bibliothek)",
+ "notInIndex": "Nicht im Custom-Audio-Index: {{audioId}}/{{hash}}",
+ "placeholder": "Custom-Audio aus der Bibliothek wählen"
+ },
+ "batch": {
+ "description": "Änderungen gelten für alle ausgewählten Modelle.",
+ "title": "Batch-Bearbeitung aktiv"
+ },
+ "coinHint": {
+ "description": "Optional – nur für Metadaten (Titel, Tracks). Custom Coins funktionieren auch ohne Modell. Nur Custom-Audio – offizielle IDs überschreiben echte Tonies. Verknüpft keine NFC-Tags mit Audio.",
+ "title": "Hinweis: Audio-Zuordnung"
+ },
+ "columns": {
+ "actions": "Aktionen",
+ "image": "Bild",
+ "status": "Status"
+ },
+ "errors": {
+ "emptyResult": "Mindestens ein Modell muss erhalten bleiben.",
+ "invalidSelectedIndex": "Ungültiger ausgewählter Index",
+ "releaseNumeric": "Release muss numerisch sein"
+ },
+ "filterPlaceholder": "Modelle filtern...",
+ "modelsTitle": "Modelle",
+ "noChangesBody": "Es gibt aktuell nichts zu speichern.",
+ "noChangesTitle": "Keine Änderungen erkannt",
+ "optionalColumns": "Zusatzspalten",
+ "picHint": "Bild aus custom_img oder von Original-Tonies wählen",
+ "preflight": {
+ "confirm": "Jetzt speichern",
+ "deletes": "Löschungen: {{count}}",
+ "description": "Bitte bestätige den Umfang dieses Speichervorgangs.",
+ "renames": "Umbenennungen: {{count}}",
+ "title": "Änderungen vor dem Speichern prüfen",
+ "upserts": "Aktualisierungen/Neuanlagen: {{count}}"
+ },
+ "previewTitle": "Bildvorschau",
+ "saveSuccessWithCount": "tonies.custom.json gespeichert ({{count}} Einträge). Sicherung und Neuladen wurden ausgelöst.",
+ "savedState": "Alle Änderungen gespeichert",
+ "sections": {
+ "audio": "Audio-Zuordnung",
+ "media": "Medien und Bilder",
+ "metadata": "Optionale Metadaten",
+ "tracks": "Tracks"
+ },
+ "selection": {
+ "description": "Das Bearbeitungsformular unten gilt immer für die aktuelle Auswahl.",
+ "multiple": "{{count}} Modelle ausgewählt",
+ "none": "Kein Modell ausgewählt",
+ "single": "Ausgewähltes Modell: {{model}}"
+ },
+ "tableMenu": "Tabellen-Menü",
+ "title": "Modell-Editor",
+ "unsaved": "{{count}} ungespeicherte Änderung(en)",
+ "validation": {
+ "title": "Bitte zuerst diese Probleme beheben"
+ }
+ },
"alternativeSource": "Der Toniefigur {{originalTonie}} ist der Inhalt {{assignedContent}} zugewiesen!",
"alternativeSourceUnknown": "Der Toniefigur {{originalTonie}} ist alternativer Inhalt zugewiesen!",
"cancel": "Abbrechen",
@@ -1822,6 +1907,7 @@
},
"currentPath": "Aktueller Pfad: ",
"editModal": {
+ "editSelectedCustomModel": "Modell weiter bearbeiten",
"model": "Modell",
"placeholderSearchForAModel": "Nach einem Modell suchen",
"placeholderSearchForARadioStream": "Suche nach einem Radiostream",
diff --git a/public/translations/en.json b/public/translations/en.json
index 4d6c2cb1..2bfbbe77 100644
--- a/public/translations/en.json
+++ b/public/translations/en.json
@@ -10,6 +10,13 @@
"errorNoOggOpusSupportByApple": "Your browser does not support OGG/Opus (taf) files at the moment. If you are using an Apple device, help us out by submitting a ticket to Apple for a fix!",
"unknownSource": "Unkown"
},
+ "common": {
+ "cancel": "Cancel",
+ "clean": "unchanged",
+ "changed": "changed*",
+ "deleted": "deleted*",
+ "new": "new*"
+ },
"community": {
"attribution": {
"navigationTitle": "Attribution",
@@ -566,7 +573,7 @@
"items": {
"01assignContent": "assign content and other properties to each tag",
"02searchStreams": "search and assign webradio streams to each tag",
- "03defineMetaData": "define meta data of your custom tags (PoC in WebFrontend)",
+ "03defineMetaData": "define meta data of your custom tags (Custom Models Editor in WebFrontend)",
"04filterTonies": "filter Tonies/Tags",
"05hideTonies": "hide unavailable Tonies/Tags",
"06showLastPlayed": "show last played Tonies/Tags"
@@ -636,9 +643,8 @@
"01firmwareUpdate": "Firmware update through TeddyCloud",
"03reportUnknownTonies": "Report unknown Tonies",
"04completeTAPIntegration": "Completion of TAP WebFrontend Integration",
- "05completeCustomToniesIntegration": "Completion of Custom Tonies Json WebFront Integration (\"Meta data of custom tags\")",
- "06moreStats": "More stats about your played Tonies/Tags",
- "07securityImprovements": "Security improvements like Access control (tonieboxes and user)"
+ "05moreStats": "More stats about your played Tonies/Tags",
+ "06securityImprovements": "Security improvements like Access control (tonieboxes and user)"
},
"navigationTitle": "Features",
"title": "Features TeddyCloud",
@@ -1802,6 +1808,85 @@
"track": "Track"
},
"addToniesCustomJsonEntry": "WIP: Add Model",
+ "customToniesEditorJsonEntry": "Custom models",
+ "imageManager": {
+ "title": "Select & manage images",
+ "okText": "Apply",
+ "sourceCustom": "Custom",
+ "sourceOriginal": "Original",
+ "noOriginalImages": "No original images found"
+ },
+ "customEditor": {
+ "actions": {
+ "delete": "Delete",
+ "deleteCount": "Delete {{count}} model(s)",
+ "discard": "Discard",
+ "duplicate": "Duplicate",
+ "edit": "Edit",
+ "newModel": "New model",
+ "preview": "Preview",
+ "restore": "Restore",
+ "toggleChangesOnly": "Changes only"
+ },
+ "audio": {
+ "libraryLabel": "Custom audio (library)",
+ "notInIndex": "Not in custom audio index: {{audioId}}/{{hash}}",
+ "placeholder": "Select custom audio from library"
+ },
+ "batch": {
+ "description": "Changes apply to all selected models.",
+ "title": "Batch editing active"
+ },
+ "coinHint": {
+ "description": "Optional – only for metadata (title, tracks). Custom coins work without a model. Use only custom audio – official IDs overwrite real Tonies. Does not link NFC tags to audio.",
+ "title": "Hint: Audio assignment"
+ },
+ "columns": {
+ "actions": "Actions",
+ "image": "Image",
+ "status": "Status"
+ },
+ "errors": {
+ "emptyResult": "At least one model must remain.",
+ "invalidSelectedIndex": "Invalid selected index",
+ "releaseNumeric": "Release must be numeric"
+ },
+ "filterPlaceholder": "Filter models...",
+ "modelsTitle": "Models",
+ "noChangesBody": "There is nothing to save at the moment.",
+ "noChangesTitle": "No changes detected",
+ "optionalColumns": "Optional columns",
+ "picHint": "Select image from custom_img or from original tonies",
+ "preflight": {
+ "confirm": "Save now",
+ "deletes": "Deletions: {{count}}",
+ "description": "Please confirm the scope of this save operation.",
+ "renames": "Renames: {{count}}",
+ "title": "Review changes before saving",
+ "upserts": "Updates/new entries: {{count}}"
+ },
+ "previewTitle": "Image preview",
+ "saveSuccessWithCount": "tonies.custom.json saved ({{count}} entries). Backup and reload triggered.",
+ "savedState": "All changes saved",
+ "sections": {
+ "audio": "Audio assignment",
+ "media": "Media and images",
+ "metadata": "Optional metadata",
+ "tracks": "Tracks"
+ },
+ "selection": {
+ "description": "The edit form below always applies to the current selection.",
+ "multiple": "{{count}} models selected",
+ "none": "No model selected",
+ "single": "Selected model: {{model}}"
+ },
+ "tableMenu": "Table menu",
+ "title": "Model editor",
+ "unsaved": "{{count}} unsaved change(s)",
+ "validation": {
+ "title": "Please fix these issues first"
+ }
+ },
"alternativeSource": "This Tonie {{originalTonie}} is assigned the content {{assignedContent}}!",
"alternativeSourceUnknown": "This Tonie {{originalTonie}} is assigned alternative content!",
"cancel": "Cancel",
@@ -1822,6 +1907,7 @@
},
"currentPath": "Current Path: ",
"editModal": {
+ "editSelectedCustomModel": "Continue editing model",
"model": "Model",
"placeholderSearchForAModel": "Search for a model",
"placeholderSearchForARadioStream": "Search for a radio stream",
diff --git a/public/translations/es.json b/public/translations/es.json
index fdddf47e..813a9e0f 100644
--- a/public/translations/es.json
+++ b/public/translations/es.json
@@ -10,6 +10,13 @@
"errorNoOggOpusSupportByApple": "Tu navegador no soporta archivos OGG/Opus (taf) en este momento. Si estás utilizando un dispositivo Apple, ¡ayúdanos enviando un ticket a Apple para solicitar una solución!",
"unknownSource": "Desconocido"
},
+ "common": {
+ "cancel": "Cancelar",
+ "clean": "sin cambios",
+ "changed": "modificado*",
+ "deleted": "eliminado*",
+ "new": "nuevo*"
+ },
"community": {
"attribution": {
"navigationTitle": "Atribuciones",
@@ -566,7 +573,7 @@
"items": {
"01assignContent": "asignar contenido y otras propiedades a cada etiqueta",
"02searchStreams": "buscar y asignar transmisiones de radio web a cada etiqueta",
- "03defineMetaData": "definir metadatos de tus etiquetas personalizadas (PoC en el frontend web)",
+ "03defineMetaData": "definir metadatos de tus etiquetas personalizadas (editor de modelos personalizados en el frontend web)",
"04filterTonies": "filtrar Tonies/Etiquetas",
"05hideTonies": "ocultar Tonies/Etiquetas no disponibles",
"06showLastPlayed": "mostrar últimos Tonies/Etiquetas reproducidos"
@@ -636,9 +643,8 @@
"01firmwareUpdate": "Actualización de firmware a través de TeddyCloud",
"03reportUnknownTonies": "Informar sobre Tonies desconocidos",
"04completeTAPIntegration": "Finalización de la integración TAP en el frontend web",
- "05completeCustomToniesIntegration": "Finalización de la integración del archivo Tonies Json personalizado en el frontend web (\"Metadatos de etiquetas personalizadas\")",
- "06moreStats": "Más estadísticas sobre tus Tonies/Etiquetas reproducidos",
- "07securityImprovements": "Mejoras en la seguridad, como control de acceso (tonieboxes y usuarios)"
+ "05moreStats": "Más estadísticas sobre tus Tonies/Etiquetas reproducidos",
+ "06securityImprovements": "Mejoras en la seguridad, como control de acceso (tonieboxes y usuarios)"
},
"navigationTitle": "Características",
"title": "Características de TeddyCloud",
@@ -1802,6 +1808,85 @@
"track": "Pista"
},
"addToniesCustomJsonEntry": "WIP: Agregar modelo",
+ "customToniesEditorJsonEntry": "Modelos personalizados",
+ "imageManager": {
+ "title": "Seleccionar y gestionar imágenes",
+ "okText": "Aplicar",
+ "sourceCustom": "Personalizado",
+ "sourceOriginal": "Original",
+ "noOriginalImages": "No se encontraron imágenes originales"
+ },
+ "customEditor": {
+ "actions": {
+ "delete": "Eliminar",
+ "deleteCount": "Eliminar {{count}} modelo(s)",
+ "discard": "Descartar",
+ "duplicate": "Duplicar",
+ "edit": "Editar",
+ "newModel": "Nuevo modelo",
+ "preview": "Vista previa",
+ "restore": "Restaurar",
+ "toggleChangesOnly": "Solo cambios"
+ },
+ "audio": {
+ "libraryLabel": "Audio personalizado (biblioteca)",
+ "notInIndex": "No en el índice de audio personalizado: {{audioId}}/{{hash}}",
+ "placeholder": "Seleccionar audio personalizado de la biblioteca"
+ },
+ "batch": {
+ "description": "Los cambios se aplican a todos los modelos seleccionados.",
+ "title": "Edición por lotes activa"
+ },
+ "coinHint": {
+ "description": "Opcional – solo para metadatos (título, pistas). Las monedas personalizadas funcionan sin modelo. Solo audio personalizado – los IDs oficiales sobrescriben Tonies reales. No vincula tags NFC con audio.",
+ "title": "Nota: Asignación de audio"
+ },
+ "columns": {
+ "actions": "Acciones",
+ "image": "Imagen",
+ "status": "Estado"
+ },
+ "errors": {
+ "emptyResult": "Debe permanecer al menos un modelo.",
+ "invalidSelectedIndex": "Índice seleccionado no válido",
+ "releaseNumeric": "Release debe ser numérico"
+ },
+ "filterPlaceholder": "Filtrar modelos...",
+ "modelsTitle": "Modelos",
+ "noChangesBody": "No hay nada que guardar en este momento.",
+ "noChangesTitle": "No se detectaron cambios",
+ "optionalColumns": "Columnas opcionales",
+ "picHint": "Seleccionar imagen de custom_img o de tonies originales",
+ "preflight": {
+ "confirm": "Guardar ahora",
+ "deletes": "Eliminaciones: {{count}}",
+ "description": "Por favor confirma el alcance de esta operación de guardado.",
+ "renames": "Renombrados: {{count}}",
+ "title": "Revisar cambios antes de guardar",
+ "upserts": "Actualizaciones/nuevas entradas: {{count}}"
+ },
+ "previewTitle": "Vista previa de imagen",
+ "saveSuccessWithCount": "tonies.custom.json guardado ({{count}} entradas). Copia de seguridad y recarga activadas.",
+ "savedState": "Todos los cambios guardados",
+ "sections": {
+ "audio": "Asignación de audio",
+ "media": "Medios e imágenes",
+ "metadata": "Metadatos opcionales",
+ "tracks": "Pistas"
+ },
+ "selection": {
+ "description": "El formulario de edición siguiente siempre se aplica a la selección actual.",
+ "multiple": "{{count}} modelos seleccionados",
+ "none": "Ningún modelo seleccionado",
+ "single": "Modelo seleccionado: {{model}}"
+ },
+ "tableMenu": "Menú de tabla",
+ "title": "Editor de modelos",
+ "unsaved": "{{count}} cambio(s) sin guardar",
+ "validation": {
+ "title": "Por favor corrige estos problemas primero"
+ }
+ },
"alternativeSource": "Este Tonie {{originalTonie}} tiene asignado el contenido {{assignedContent}}!",
"alternativeSourceUnknown": "¡Este Tonie {{originalTonie}} tiene asignado contenido alternativo!",
"cancel": "Cancelar",
@@ -1822,6 +1907,7 @@
},
"currentPath": "Ruta actual: ",
"editModal": {
+ "editSelectedCustomModel": "Continuar editando modelo",
"model": "Modelo",
"placeholderSearchForAModel": "Buscar un modelo",
"placeholderSearchForARadioStream": "Buscar una transmisión de radio",
diff --git a/public/translations/fr.json b/public/translations/fr.json
index ebbf446a..4eb98b3f 100644
--- a/public/translations/fr.json
+++ b/public/translations/fr.json
@@ -10,6 +10,13 @@
"errorNoOggOpusSupportByApple": "Votre navigateur ne prend pas en charge les fichiers OGG/Opus (taf) pour le moment. Si vous utilisez un appareil Apple, aidez-nous en soumettant un ticket à Apple pour demander une solution !",
"unknownSource": "Inconnu"
},
+ "common": {
+ "cancel": "Annuler",
+ "clean": "inchangé",
+ "changed": "modifié*",
+ "deleted": "supprimé*",
+ "new": "nouveau*"
+ },
"community": {
"attribution": {
"navigationTitle": "Attributions",
@@ -566,7 +573,7 @@
"items": {
"01assignContent": "attribuer du contenu et d'autres propriétés à chaque tag",
"02searchStreams": "rechercher et attribuer des flux de webradio à chaque tag",
- "03defineMetaData": "définir les métadonnées de vos tags personnalisés (PoC dans le WebFrontend)",
+ "03defineMetaData": "définir les métadonnées de vos tags personnalisés (éditeur de modèles personnalisés dans le WebFrontend)",
"04filterTonies": "filtrer les Tonies/Tags",
"05hideTonies": "masquer les Tonies/Tags non disponibles",
"06showLastPlayed": "afficher les derniers Tonies/Tags joués"
@@ -636,9 +643,8 @@
"01firmwareUpdate": "Mise à jour du firmware via TeddyCloud",
"03reportUnknownTonies": "Signaler les Tonies inconnus",
"04completeTAPIntegration": "Achèvement de l'intégration de TAP WebFrontend",
- "05completeCustomToniesIntegration": "Achèvement de l'intégration des Tonies personnalisés dans le WebFront JSON (\"Métadonnées des tags personnalisés\")",
- "06moreStats": "Plus de statistiques sur vos Tonies/Tags joués",
- "07securityImprovements": "Améliorations de la sécurité comme le contrôle d'accès (tonieboxes et utilisateur)"
+ "05moreStats": "Plus de statistiques sur vos Tonies/Tags joués",
+ "06securityImprovements": "Améliorations de la sécurité comme le contrôle d'accès (tonieboxes et utilisateur)"
},
"navigationTitle": "Fonctionnalités",
"title": "Fonctionnalités TeddyCloud",
@@ -1802,6 +1808,85 @@
"track": "Piste"
},
"addToniesCustomJsonEntry": "WIP: Ajouter un modèle",
+ "customToniesEditorJsonEntry": "Modèles personnalisés",
+ "imageManager": {
+ "title": "Sélectionner et gérer les images",
+ "okText": "Appliquer",
+ "sourceCustom": "Personnalisé",
+ "sourceOriginal": "Original",
+ "noOriginalImages": "Aucune image originale trouvée"
+ },
+ "customEditor": {
+ "actions": {
+ "delete": "Supprimer",
+ "deleteCount": "Supprimer {{count}} modèle(s)",
+ "discard": "Annuler",
+ "duplicate": "Dupliquer",
+ "edit": "Modifier",
+ "newModel": "Nouveau modèle",
+ "preview": "Aperçu",
+ "restore": "Restaurer",
+ "toggleChangesOnly": "Modifications uniquement"
+ },
+ "audio": {
+ "libraryLabel": "Audio personnalisé (bibliothèque)",
+ "notInIndex": "Pas dans l'index audio personnalisé : {{audioId}}/{{hash}}",
+ "placeholder": "Sélectionner l'audio personnalisé dans la bibliothèque"
+ },
+ "batch": {
+ "description": "Les modifications s'appliquent à tous les modèles sélectionnés.",
+ "title": "Édition par lot active"
+ },
+ "coinHint": {
+ "description": "Optionnel – uniquement pour les métadonnées (titre, pistes). Les pièces personnalisées fonctionnent sans modèle. Uniquement l'audio personnalisé – les IDs officiels écrasent les vrais Tonies. Ne lie pas les tags NFC à l'audio.",
+ "title": "Conseil : Assignation audio"
+ },
+ "columns": {
+ "actions": "Actions",
+ "image": "Image",
+ "status": "Statut"
+ },
+ "errors": {
+ "emptyResult": "Au moins un modèle doit rester.",
+ "invalidSelectedIndex": "Index sélectionné invalide",
+ "releaseNumeric": "Release doit être numérique"
+ },
+ "filterPlaceholder": "Filtrer les modèles...",
+ "modelsTitle": "Modèles",
+ "noChangesBody": "Il n'y a rien à enregistrer pour le moment.",
+ "noChangesTitle": "Aucune modification détectée",
+ "optionalColumns": "Colonnes optionnelles",
+ "picHint": "Sélectionner une image depuis custom_img ou les tonies originaux",
+ "preflight": {
+ "confirm": "Enregistrer maintenant",
+ "deletes": "Suppressions : {{count}}",
+ "description": "Veuillez confirmer la portée de cette opération d'enregistrement.",
+ "renames": "Renommages : {{count}}",
+ "title": "Vérifier les modifications avant l'enregistrement",
+ "upserts": "Mises à jour/nouvelles entrées : {{count}}"
+ },
+ "previewTitle": "Aperçu de l'image",
+ "saveSuccessWithCount": "tonies.custom.json enregistré ({{count}} entrées). Sauvegarde et rechargement déclenchés.",
+ "savedState": "Toutes les modifications enregistrées",
+ "sections": {
+ "audio": "Assignation audio",
+ "media": "Médias et images",
+ "metadata": "Métadonnées optionnelles",
+ "tracks": "Pistes"
+ },
+ "selection": {
+ "description": "Le formulaire d'édition ci-dessous s'applique toujours à la sélection actuelle.",
+ "multiple": "{{count}} modèles sélectionnés",
+ "none": "Aucun modèle sélectionné",
+ "single": "Modèle sélectionné : {{model}}"
+ },
+ "tableMenu": "Menu du tableau",
+ "title": "Éditeur de modèles",
+ "unsaved": "{{count}} modification(s) non enregistrée(s)",
+ "validation": {
+ "title": "Veuillez d'abord corriger ces problèmes"
+ }
+ },
"alternativeSource": "Cette Tonie {{originalTonie}} est assignée à un contenu {{assignedContent}} !",
"alternativeSourceUnknown": "Cette Tonie {{originalTonie}} est assignée à un contenu alternatif !",
"cancel": "Annuler",
@@ -1822,6 +1907,7 @@
},
"currentPath": "Chemin actuel : ",
"editModal": {
+ "editSelectedCustomModel": "Continuer l'édition du modèle",
"model": "Modèle",
"placeholderSearchForAModel": "Rechercher un modèle",
"placeholderSearchForARadioStream": "Rechercher un flux radio",
diff --git a/src/App.tsx b/src/App.tsx
index f6d6195e..b0364a1d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -51,6 +51,7 @@ import { TeddyAudioPlayerPage } from "./pages/tonies/TeddyAudioPlayerPage";
import { TeddyAudioPlaylistsPage } from "./pages/tonies/TeddyAudioPlaylistsPage";
import { TeddyStudioPage } from "./pages/tonies/TeddyStudioPage";
import { ToniesPage } from "./pages/tonies/ToniesPage";
+import { CustomTonieCreatorPage } from "./pages/tonies/CustomTonieCreatorPage";
import "./styles/matrix/matrix.css";
import { matrixAlgorithm } from "./styles/matrix/matrixAlgorithm";
@@ -176,6 +177,7 @@ function App() {