Files
toni-sync/README.md
T
arnefandCopilot eb77c0ecbd Support m3u playlist files to define chapter order
The chapter order on the tonie is already fully API-controlled via
SortChaptersOfTonie/PATCH. This adds an explicit way to define that
order via an .m3u/.m3u8 file placed in the tonie folder, instead of
relying on alphabetical filenames:

- internal/syncer/playlist.go: finds a single playlist file in the
  tonie folder, parses its entries (ignoring blanks/#-comments), and
  reorders local tracks accordingly. Tracks not referenced by the
  playlist are appended afterwards so nothing is silently dropped;
  playlist entries without a matching local file are ignored.
  Multiple playlist files in the same folder is an error (ambiguous
  order).
- ListLocalTracks now prefers this playlist-defined order, falling
  back to alphabetical filename order when no playlist is present.
- Tests covering playlist ordering, unreferenced-track handling,
  missing entries, and the multiple-playlists error case.
- README documents the .m3u/.m3u8 convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-14 13:26:09 +02:00

169 lines
5.0 KiB
Markdown

# toni-sync
Ein CLI-Tool zur Verwaltung von Kreativ-Tonies: Es synchronisiert lokale
Audio-Ordner (z. B. exportierte Deezer-Playlists) automatisch zu den
passenden Kreativ-Tonies über die inoffizielle TonieCloud-API. Geschrieben
in Go, kompiliert zu einer einzigen statischen Binary - keine Laufzeit-
Abhängigkeiten (kein Python/pip nötig).
> **Hinweis:** toni-sync lädt selbst keine Musik von Deezer herunter. Das
> Herunterladen/Umgehen von DRM-geschützten Streams verstößt gegen die
> Nutzungsbedingungen von Deezer und ggf. gegen Urheberrecht. Lege deine
> bereits legal exportierten Audiodateien einfach in die passenden
> lokalen Ordner - toni-sync kümmert sich nur um den Abgleich mit der
> TonieCloud.
## Keine Config-Datei - die Ordnerstruktur *ist* die Konfiguration
Statt einer separaten Config-Datei wird das Mapping Playlist ↔ Kreativ-Tonie
direkt über die Ordnerstruktur abgebildet:
```
<root>/
<household_id>/
<freier_name> [id=<tonie_id>]/
01 - Track.mp3
02 - Track.mp3
```
- `<household_id>`: die Household-ID deines TonieCloud-Accounts
- `<freier_name> [id=<tonie_id>]`: frei wählbarer Name + Tonie-ID in eckigen
Klammern - der Name dient nur der Lesbarkeit, für das Mapping zählt allein
die ID
- Die alphabetische Dateireihenfolge innerhalb eines Tonie-Ordners bestimmt
die Kapitelreihenfolge auf dem Tonie
## Installation
Benötigt wird nur eine Go-Toolchain (>= 1.21) zum Bauen - danach ist das
Ergebnis eine einzelne Binary ohne weitere Abhängigkeiten:
```bash
go build -o toni-sync ./cmd/toni-sync
./toni-sync --help
```
Oder direkt installieren (landet in `$(go env GOPATH)/bin`):
```bash
go install ./cmd/toni-sync
```
## Anmeldedaten
toni-sync benötigt deine TonieCloud-Zugangsdaten (dieselben wie in der
Tonies-App). Sie werden **nicht** gespeichert, sondern bei jedem Aufruf
über Umgebungsvariablen oder interaktiven Prompt abgefragt:
```bash
export TONI_SYNC_USERNAME="you@example.com"
export TONI_SYNC_PASSWORD="********"
```
Alternativ: `--username`/`--password` Flags bei `tonies list`, `init` und `sync`.
## Nutzung
### 1. Library-Ordner automatisch anlegen
```bash
toni-sync init --root ~/Musik/tonies
```
Legt für jede Household und jeden Kreativ-Tonie deines Accounts den
passenden Ordner an, z. B.:
```
[created] /home/you/Musik/tonies/abcd-1234/Peppa Wutz [id=ef01-5678]
[created] /home/you/Musik/tonies/abcd-1234/Gute-Nacht-Geschichten [id=9876-4321]
Library ready at /home/you/Musik/tonies
```
Bereits vorhandene Ordner (anhand der Tonie-ID erkannt, auch bei geändertem
Namen) werden nicht angefasst - deine Audiodateien bleiben unberührt.
Alternativ manuell: einfach die Ordner nach obigem Schema selbst anlegen.
### 2. Root-Ordner festlegen
Der Library-Root wird wie folgt bestimmt (erste zutreffende Option):
1. `--root PATH` Flag
2. Umgebungsvariable `TONI_SYNC_ROOT`
3. aktuelles Arbeitsverzeichnis
### 3. Audiodateien einsortieren & synchronisieren
Lege deine (legal exportierten) Audiodateien in den passenden Tonie-Ordner.
Die Kapitelreihenfolge wird wie folgt bestimmt:
- **Mit Playlist:** Liegt genau eine `.m3u`/`.m3u8`-Datei im Tonie-Ordner,
bestimmt deren Zeilenreihenfolge die Kapitelreihenfolge (Kommentare/`#`-Zeilen
und Leerzeilen werden ignoriert, Pfade relativ zum Ordner). Dateien, die
lokal existieren aber nicht in der Playlist stehen, werden trotzdem
synchronisiert und ans Ende angehängt (nichts geht verloren). Einträge in
der Playlist ohne passende Datei werden ignoriert. Liegen mehrere Playlist-
Dateien im selben Ordner, bricht `sync` mit einem Fehler ab (Reihenfolge
wäre sonst mehrdeutig).
- **Ohne Playlist:** alphabetische Dateireihenfolge, z. B. `01 - Track.mp3`,
`02 - Track.mp3`, ...
Beispiel `playlist.m3u`:
```
#EXTM3U
02 - Second Track.mp3
01 - First Track.mp3
03 - Third Track.mp3
```
```bash
# alle gefundenen Tonies synchronisieren
toni-sync sync --root ~/Musik/tonies
# nur Tonies syncen, deren Household-ID/Tonie-ID/Name den Filter enthalten
toni-sync sync peppa --root ~/Musik/tonies
# nur anzeigen, was sich ändern würde
toni-sync sync --root ~/Musik/tonies --dry-run
```
`sync` lädt neue Dateien hoch, entfernt Kapitel, die lokal nicht mehr
existieren (abschaltbar via `--no-prune`), und sortiert die Kapitel passend
zur lokalen Reihenfolge (Playlist-Datei falls vorhanden, sonst alphabetisch).
### Household-/Tonie-IDs nachschlagen
Falls du die Struktur lieber manuell pflegen willst:
```bash
toni-sync tonies list
```
```
Household: Familie Müller [id=abcd-1234]
- Peppa Wutz [id=ef01-5678] (12 chapters, 3600s)
- Gute-Nacht-Geschichten [id=9876-4321] (0 chapters, 0s)
```
## Unterstützte Audioformate
`.mp3`, `.m4a`, `.aac`, `.ogg`, `.flac`, `.wav`
## Projektstruktur
```
cmd/toni-sync/ CLI-Einstiegspunkt (Cobra-Kommandos: tonies, init, sync)
internal/tonieapi/ Eigener, minimaler TonieCloud-API-Client
internal/library/ Erkennung & Scaffolding der Ordnerstruktur (Household/Tonie)
internal/syncer/ Diff-/Apply-Logik zwischen lokalem Ordner und Tonie
```
## Entwicklung / Tests
```bash
go build ./...
go vet ./...
go test ./...
```