mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-06-17 15:05:39 +02:00
harden deezer auth and lyrics tagging behavior
This commit is contained in:
@@ -510,6 +510,10 @@ func (m *Main) Rip(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID string, albumMeta map[string]any) error {
|
||||
if err := m.requireSourceDownloadAuth(source); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
albumTitle := titleFromMetadata(albumMeta, albumID)
|
||||
albumArtist := nestedString(albumMeta, "artist", "name")
|
||||
if albumArtist == "" {
|
||||
@@ -620,11 +624,19 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
}
|
||||
|
||||
func (m *Main) ripPlaylist(ctx context.Context, p provider.Client, source, playlistID string, playlistMeta map[string]any) error {
|
||||
if err := m.requireSourceDownloadAuth(source); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := titleFromMetadata(playlistMeta, playlistID)
|
||||
if n := stringFromAny(playlistMeta["name"]); n != "" {
|
||||
name = n
|
||||
}
|
||||
folder := filepath.Join(m.Config.Session.Downloads.Folder, naming.CleanName(name, naming.Config{
|
||||
base := m.Config.Session.Downloads.Folder
|
||||
if m.Config.Session.Downloads.SourceSubdirectories {
|
||||
base = filepath.Join(base, strings.Title(source))
|
||||
}
|
||||
folder := filepath.Join(base, naming.CleanName(name, naming.Config{
|
||||
RestrictCharacters: m.Config.Session.Filepaths.RestrictCharacters,
|
||||
TruncateTo: m.Config.Session.Filepaths.TruncateTo,
|
||||
}))
|
||||
@@ -765,6 +777,18 @@ func (m *Main) ripPlaylistMixed(ctx context.Context, playlistID, name string, re
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Main) requireSourceDownloadAuth(source string) error {
|
||||
if source == "deezer" {
|
||||
hasARL := strings.TrimSpace(m.Config.Session.Deezer.ARL) != ""
|
||||
hasCreds := strings.TrimSpace(m.Config.Session.Deezer.Email) != "" && strings.TrimSpace(m.Config.Session.Deezer.Password) != ""
|
||||
hasRefresh := strings.TrimSpace(m.Config.Session.Deezer.RefreshToken) != ""
|
||||
if !hasARL && !hasCreds && !hasRefresh {
|
||||
return fmt.Errorf("deezer native download requires deezer.arl, deezer.email+deezer.password, or deezer.refresh_token")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Main) ripTrack(ctx context.Context, p provider.Client, source, id, fallbackTitle string, opts ripTrackOptions) error {
|
||||
alreadyDownloaded, err := m.Store.IsDownloaded(ctx, source, id)
|
||||
if err == nil && alreadyDownloaded {
|
||||
@@ -1217,6 +1241,9 @@ func buildTagMetadata(trackMeta map[string]any, title, source, trackID string, o
|
||||
comment := stringFromAny(trackMeta["comment"])
|
||||
description := stringFromAny(trackMeta["description"])
|
||||
lyrics := stringFromAny(trackMeta["lyrics"])
|
||||
if lrc := stringFromAny(trackMeta["lyrics_synced"]); lrc != "" {
|
||||
lyrics = lrc
|
||||
}
|
||||
trackGain := replaygainGainFromAny(trackMeta["replaygain_track_gain"])
|
||||
if trackGain == "" {
|
||||
trackGain = replaygainGainFromAny(trackMeta["replayGain"])
|
||||
|
||||
@@ -464,6 +464,77 @@ func TestPlaylistRipPipeline(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaylistRipUsesSourceSubdirectory(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.Concurrency = false
|
||||
d.Downloads.SourceSubdirectories = true
|
||||
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() }()
|
||||
|
||||
m := &Main{
|
||||
Config: cfg,
|
||||
Providers: map[string]provider.Client{
|
||||
"qobuz": &fakePlaylistProvider{url: ts.URL},
|
||||
},
|
||||
Store: sqlite,
|
||||
DL: download.NewWithOptions(true, false),
|
||||
Tagger: noopTagger{},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if err = m.AddByID(ctx, "qobuz", "playlist", "pl1"); 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, "Qobuz", "Road Trip")
|
||||
if _, err = os.Stat(filepath.Join(folder, "01. Artist - Track One.flac")); err != nil {
|
||||
t.Fatalf("missing first playlist track in source subdir: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRipPlaylistRequiresDeezerARL(t *testing.T) {
|
||||
d := config.DefaultConfigData()
|
||||
m := &Main{Config: &config.Config{File: d, Session: d}}
|
||||
|
||||
err := m.ripPlaylist(context.Background(), nil, "deezer", "pl1", map[string]any{
|
||||
"name": "Road Trip",
|
||||
"tracks": map[string]any{"items": []any{map[string]any{"id": "p1"}}},
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "deezer") {
|
||||
t.Fatalf("expected deezer arl error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRipAlbumRequiresDeezerARL(t *testing.T) {
|
||||
d := config.DefaultConfigData()
|
||||
m := &Main{Config: &config.Config{File: d, Session: d}}
|
||||
|
||||
err := m.ripAlbum(context.Background(), nil, "deezer", "alb1", map[string]any{})
|
||||
if err == nil || !strings.Contains(err.Error(), "deezer") {
|
||||
t.Fatalf("expected deezer arl error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyQobuzArtistFiltersRepeats(t *testing.T) {
|
||||
albums := []collectionAlbum{
|
||||
{ID: "a1", Title: "Album X", BitDepth: 16, Sampling: 44.1, Explicit: false},
|
||||
|
||||
Reference in New Issue
Block a user