Replace config file with folder-based mapping
Mappings between local playlist folders and Kreativ-Tonies are now
expressed purely through the filesystem instead of a YAML config:
<root>/<household_id>/<freier_name> [id=<tonie_id>]/*.mp3
- internal/library: discovers tonie folders from this structure
(Discover/Filter), and scaffolds it automatically from the
TonieCloud account (Scaffold), leaving already-existing folders
(matched by tonie id) untouched
- internal/syncer: decoupled from the removed config package via a
plain Target{TonieID, Folder, Prune} struct
- cmd/toni-sync: new `init --root PATH` command to scaffold the
library; `sync [FILTER] --root PATH` now discovers targets from the
folder tree instead of a config file; removed the `config` command
group entirely
- Unit tests for folder discovery, filtering, and scaffolding
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mkTonieDir(t *testing.T, householdPath, dirName string) string {
|
||||
t.Helper()
|
||||
p := filepath.Join(householdPath, dirName)
|
||||
if err := os.MkdirAll(p, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func TestParseTonieDir(t *testing.T) {
|
||||
name, id, ok := ParseTonieDir("Peppa Wutz [id=ef01-5678]")
|
||||
if !ok || name != "Peppa Wutz" || id != "ef01-5678" {
|
||||
t.Fatalf("unexpected parse result: name=%q id=%q ok=%v", name, id, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTonieDirNoMatch(t *testing.T) {
|
||||
if _, _, ok := ParseTonieDir("just a folder"); ok {
|
||||
t.Fatal("expected no match for folder without [id=...] suffix")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirName(t *testing.T) {
|
||||
if got := DirName("Peppa/Wutz", "abc"); got != "Peppa-Wutz [id=abc]" {
|
||||
t.Fatalf("unexpected dir name: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscover(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
household := filepath.Join(root, "household-1")
|
||||
if err := os.MkdirAll(household, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mkTonieDir(t, household, "Peppa Wutz [id=tonie-1]")
|
||||
mkTonieDir(t, household, "not-a-tonie-folder")
|
||||
|
||||
// A second household with one tonie.
|
||||
household2 := filepath.Join(root, "household-2")
|
||||
mkTonieDir(t, household2, "Gute Nacht [id=tonie-2]")
|
||||
|
||||
tonies, err := Discover(root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(tonies) != 2 {
|
||||
t.Fatalf("expected 2 tonies, got %d: %+v", len(tonies), tonies)
|
||||
}
|
||||
|
||||
byID := map[string]Tonie{}
|
||||
for _, tn := range tonies {
|
||||
byID[tn.TonieID] = tn
|
||||
}
|
||||
|
||||
got, ok := byID["tonie-1"]
|
||||
if !ok || got.HouseholdID != "household-1" || got.Name != "Peppa Wutz" {
|
||||
t.Fatalf("unexpected tonie-1 entry: %+v", got)
|
||||
}
|
||||
got2, ok := byID["tonie-2"]
|
||||
if !ok || got2.HouseholdID != "household-2" || got2.Name != "Gute Nacht" {
|
||||
t.Fatalf("unexpected tonie-2 entry: %+v", got2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
tonies := []Tonie{
|
||||
{HouseholdID: "h1", TonieID: "t1", Name: "Peppa Wutz"},
|
||||
{HouseholdID: "h2", TonieID: "t2", Name: "Gute Nacht"},
|
||||
}
|
||||
|
||||
if got := Filter(tonies, ""); len(got) != 2 {
|
||||
t.Fatalf("empty filter should return all, got %d", len(got))
|
||||
}
|
||||
if got := Filter(tonies, "peppa"); len(got) != 1 || got[0].TonieID != "t1" {
|
||||
t.Fatalf("expected 1 match for 'peppa', got %+v", got)
|
||||
}
|
||||
if got := Filter(tonies, "h2"); len(got) != 1 || got[0].TonieID != "t2" {
|
||||
t.Fatalf("expected 1 match for 'h2', got %+v", got)
|
||||
}
|
||||
if got := Filter(tonies, "nomatch"); len(got) != 0 {
|
||||
t.Fatalf("expected no matches, got %+v", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user