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,80 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/arnef/toni-sync/internal/tonieapi"
|
||||
)
|
||||
|
||||
type fakeScaffoldClient struct {
|
||||
households []tonieapi.Household
|
||||
toniesByHouse map[string][]tonieapi.CreativeTonie
|
||||
}
|
||||
|
||||
func (f *fakeScaffoldClient) GetHouseholds() ([]tonieapi.Household, error) {
|
||||
return f.households, nil
|
||||
}
|
||||
|
||||
func (f *fakeScaffoldClient) GetCreativeTonies(householdID string) ([]tonieapi.CreativeTonie, error) {
|
||||
return f.toniesByHouse[householdID], nil
|
||||
}
|
||||
|
||||
func TestScaffoldCreatesFolders(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
client := &fakeScaffoldClient{
|
||||
households: []tonieapi.Household{{ID: "h1", Name: "Family"}},
|
||||
toniesByHouse: map[string][]tonieapi.CreativeTonie{
|
||||
"h1": {{ID: "t1", HouseholdID: "h1", Name: "Peppa Wutz"}},
|
||||
},
|
||||
}
|
||||
|
||||
results, err := Scaffold(client, root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(results) != 1 || !results[0].Created {
|
||||
t.Fatalf("expected 1 created result, got %+v", results)
|
||||
}
|
||||
|
||||
expected := filepath.Join(root, "h1", "Peppa Wutz [id=t1]")
|
||||
if info, err := os.Stat(expected); err != nil || !info.IsDir() {
|
||||
t.Fatalf("expected folder %s to exist: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaffoldLeavesExistingFolderUntouched(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
// Simulate an existing folder that was renamed locally but keeps the id suffix.
|
||||
existing := filepath.Join(root, "h1", "My Custom Name [id=t1]")
|
||||
if err := os.MkdirAll(existing, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Put a marker file inside to make sure Scaffold doesn't touch it.
|
||||
marker := filepath.Join(existing, "song.mp3")
|
||||
if err := os.WriteFile(marker, []byte("data"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client := &fakeScaffoldClient{
|
||||
households: []tonieapi.Household{{ID: "h1", Name: "Family"}},
|
||||
toniesByHouse: map[string][]tonieapi.CreativeTonie{
|
||||
"h1": {{ID: "t1", HouseholdID: "h1", Name: "Peppa Wutz (renamed in cloud)"}},
|
||||
},
|
||||
}
|
||||
|
||||
results, err := Scaffold(client, root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(results) != 1 || results[0].Created {
|
||||
t.Fatalf("expected existing folder to be reported as not created, got %+v", results)
|
||||
}
|
||||
if results[0].Folder != existing {
|
||||
t.Fatalf("expected folder %s, got %s", existing, results[0].Folder)
|
||||
}
|
||||
if _, err := os.Stat(marker); err != nil {
|
||||
t.Fatalf("expected local file to remain untouched: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user