mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-06-17 15:05:39 +02:00
unify folder naming with resolved audio profiles across providers
This commit is contained in:
@@ -64,22 +64,34 @@ type fakeVideoProvider struct {
|
||||
url string
|
||||
}
|
||||
|
||||
type fakeResolvedAlbumProvider struct {
|
||||
url string
|
||||
downloadable provider.Downloadable
|
||||
downloadableHits int
|
||||
}
|
||||
|
||||
type fakeFailProvider struct{}
|
||||
|
||||
func (f *fakeAlbumProvider) Source() string { return "qobuz" }
|
||||
func (f *fakePlaylistProvider) Source() string { return "qobuz" }
|
||||
func (f *fakeVideoProvider) Source() string { return "tidal" }
|
||||
func (f *fakeResolvedAlbumProvider) Source() string { return "qobuz" }
|
||||
func (f *fakeAlbumProvider) Login(context.Context) error { return nil }
|
||||
func (f *fakePlaylistProvider) Login(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
func (f *fakeVideoProvider) Login(context.Context) error { return nil }
|
||||
func (f *fakeAlbumProvider) LoggedIn() bool { return true }
|
||||
func (f *fakePlaylistProvider) LoggedIn() bool { return true }
|
||||
func (f *fakeVideoProvider) LoggedIn() bool { return true }
|
||||
func (f *fakeAlbumProvider) Close() error { return nil }
|
||||
func (f *fakePlaylistProvider) Close() error { return nil }
|
||||
func (f *fakeVideoProvider) Close() error { return nil }
|
||||
func (f *fakeResolvedAlbumProvider) Login(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
func (f *fakeAlbumProvider) LoggedIn() bool { return true }
|
||||
func (f *fakePlaylistProvider) LoggedIn() bool { return true }
|
||||
func (f *fakeVideoProvider) LoggedIn() bool { return true }
|
||||
func (f *fakeResolvedAlbumProvider) LoggedIn() bool { return true }
|
||||
func (f *fakeAlbumProvider) Close() error { return nil }
|
||||
func (f *fakePlaylistProvider) Close() error { return nil }
|
||||
func (f *fakeVideoProvider) Close() error { return nil }
|
||||
func (f *fakeResolvedAlbumProvider) Close() error { return nil }
|
||||
func (f *fakeAlbumProvider) Search(context.Context, string, string, int) ([]map[string]any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -89,6 +101,9 @@ func (f *fakePlaylistProvider) Search(context.Context, string, string, int) ([]m
|
||||
func (f *fakeVideoProvider) Search(context.Context, string, string, int) ([]map[string]any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakeResolvedAlbumProvider) Search(context.Context, string, string, int) ([]map[string]any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakeAlbumProvider) GetMetadata(_ context.Context, id string, mediaType string) (map[string]any, error) {
|
||||
if mediaType == "album" {
|
||||
return map[string]any{
|
||||
@@ -161,6 +176,22 @@ func (f *fakeVideoProvider) GetMetadata(_ context.Context, id string, mediaType
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakeResolvedAlbumProvider) GetMetadata(_ context.Context, id string, mediaType string) (map[string]any, error) {
|
||||
if mediaType == "album" {
|
||||
return map[string]any{
|
||||
"title": "Fallback Album",
|
||||
"release_date_original": "2020-01-01",
|
||||
"artist": map[string]any{"name": "Fallback Artist"},
|
||||
"tracks": map[string]any{"items": []any{map[string]any{"id": "t1"}}},
|
||||
}, nil
|
||||
}
|
||||
return map[string]any{
|
||||
"title": "Fallback Song",
|
||||
"track_number": float64(1),
|
||||
"performer": map[string]any{"name": "Fallback Artist"},
|
||||
"album": map[string]any{"title": "Fallback Album", "artist": map[string]any{"name": "Fallback Artist"}},
|
||||
}, nil
|
||||
}
|
||||
func (f *fakeProvider) GetDownloadable(context.Context, string, int) (*provider.Downloadable, error) {
|
||||
return &provider.Downloadable{URL: f.url, Extension: "flac", Source: "qobuz"}, nil
|
||||
}
|
||||
@@ -173,6 +204,14 @@ func (f *fakePlaylistProvider) GetDownloadable(context.Context, string, int) (*p
|
||||
func (f *fakeVideoProvider) GetDownloadable(context.Context, string, int) (*provider.Downloadable, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakeResolvedAlbumProvider) GetDownloadable(context.Context, string, int) (*provider.Downloadable, error) {
|
||||
f.downloadableHits++
|
||||
d := f.downloadable
|
||||
if d.URL == "" {
|
||||
d.URL = f.url
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
func (f *fakeVideoProvider) GetVideoDownloadable(context.Context, string) (*provider.Downloadable, error) {
|
||||
return &provider.Downloadable{URL: f.url, Extension: "mp4", Source: "tidal"}, nil
|
||||
}
|
||||
@@ -466,7 +505,7 @@ func TestTrackOutputPathFallsBackToDisc1(t *testing.T) {
|
||||
"performer": map[string]any{"name": "Dido"},
|
||||
"album": map[string]any{"id": "a", "title": "Greatest Hits", "artist": map[string]any{"name": "Dido"}},
|
||||
}
|
||||
path := m.trackOutputPath("tidal", "1", "Song", "flac", meta, filepath.Join(tmp, "Album"), 2)
|
||||
path := m.trackOutputPath("tidal", "1", "Song", "flac", nil, meta, filepath.Join(tmp, "Album"), 2)
|
||||
if !strings.Contains(path, string(filepath.Separator)+"Disc 1"+string(filepath.Separator)) {
|
||||
t.Fatalf("expected Disc 1 subdir in path, got %q", path)
|
||||
}
|
||||
@@ -657,12 +696,107 @@ func TestTrackOutputPathSinglesUsesAlbumID(t *testing.T) {
|
||||
"performer": map[string]any{"name": "Artist"},
|
||||
}
|
||||
|
||||
out := m.trackOutputPath("qobuz", "track-999", "Song", "flac", meta, "", 0)
|
||||
out := m.trackOutputPath("qobuz", "track-999", "Song", "flac", nil, meta, "", 0)
|
||||
if got, want := filepath.Dir(out), filepath.Join(tmp, "album-123"); got != want {
|
||||
t.Fatalf("trackOutputPath() dir=%q want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrackOutputPathSinglesUsesResolvedAudioProfile(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
d := config.DefaultConfigData()
|
||||
d.Downloads.Folder = tmp
|
||||
d.Downloads.SourceSubdirectories = false
|
||||
d.Filepaths.AddSinglesToFolder = true
|
||||
d.Filepaths.FolderFormat = "{container}-{bit_depth}-{sampling_rate}"
|
||||
d.Filepaths.TrackFormat = "{title}"
|
||||
d.Filepaths.RestrictCharacters = false
|
||||
|
||||
m := &Main{Config: &config.Config{File: d, Session: d}}
|
||||
meta := map[string]any{
|
||||
"album": map[string]any{
|
||||
"id": "album-123",
|
||||
"title": "Album",
|
||||
"artist": map[string]any{"name": "Artist"},
|
||||
},
|
||||
"performer": map[string]any{"name": "Artist"},
|
||||
}
|
||||
dl := &provider.Downloadable{Extension: "mp3", Audio: provider.AudioProfile{Container: "MP3", Codec: "MP3", Quality: "HIGH", BitDepth: 16, SamplingRate: "44.1", BitrateKbps: 320}}
|
||||
|
||||
out := m.trackOutputPath("qobuz", "track-999", "Song", "mp3", dl, meta, "", 0)
|
||||
if got, want := filepath.Dir(out), filepath.Join(tmp, "MP3-16-44.1"); got != want {
|
||||
t.Fatalf("trackOutputPath() dir=%q want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRipAlbumUsesResolvedAudioProfileForFolderName(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte("audio-bytes"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
d := config.DefaultConfigData()
|
||||
d.Downloads.Folder = tmp
|
||||
d.Downloads.SourceSubdirectories = false
|
||||
d.Downloads.Concurrency = false
|
||||
d.Filepaths.RestrictCharacters = false
|
||||
cfg := &config.Config{File: d, Session: d}
|
||||
|
||||
sqlite, err := store.NewSQLite(filepath.Join(tmp, "db.sqlite"))
|
||||
if err != nil {
|
||||
t.Fatalf("NewSQLite() error = %v", err)
|
||||
}
|
||||
defer func() { _ = sqlite.Close() }()
|
||||
|
||||
fake := &fakeResolvedAlbumProvider{
|
||||
url: ts.URL,
|
||||
downloadable: provider.Downloadable{
|
||||
URL: ts.URL,
|
||||
Extension: "mp3",
|
||||
Source: "qobuz",
|
||||
Audio: provider.AudioProfile{
|
||||
Container: "MP3",
|
||||
Codec: "MP3",
|
||||
Quality: "HIGH",
|
||||
BitDepth: 16,
|
||||
SamplingRate: "44.1",
|
||||
BitrateKbps: 320,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m := &Main{
|
||||
Config: cfg,
|
||||
Providers: map[string]provider.Client{
|
||||
"qobuz": fake,
|
||||
},
|
||||
Store: sqlite,
|
||||
DL: download.NewWithOptions(true, false),
|
||||
Tagger: noopTagger{},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if err = m.AddByID(ctx, "qobuz", "album", "a1"); err != nil {
|
||||
t.Fatalf("AddByID() error = %v", err)
|
||||
}
|
||||
if err = m.Resolve(ctx); err != nil {
|
||||
t.Fatalf("Resolve() error = %v", err)
|
||||
}
|
||||
if err = m.Rip(ctx); err != nil {
|
||||
t.Fatalf("Rip() error = %v", err)
|
||||
}
|
||||
|
||||
folder := filepath.Join(tmp, "Fallback Artist - Fallback Album (2020) [MP3] [16B-44.1kHz]")
|
||||
if _, err = os.Stat(filepath.Join(folder, "01. Fallback Artist - Fallback Song.mp3")); err != nil {
|
||||
t.Fatalf("missing track in resolved-quality folder: %v", err)
|
||||
}
|
||||
if fake.downloadableHits != 1 {
|
||||
t.Fatalf("GetDownloadable() calls=%d, want 1 (prefetched reuse)", fake.downloadableHits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildTagMetadataReplayGainFallbacks(t *testing.T) {
|
||||
meta := map[string]any{
|
||||
"replayGain": float64(-7.25),
|
||||
|
||||
Reference in New Issue
Block a user