diff --git a/go_backend/coverage_test_helpers_test.go b/go_backend/coverage_test_helpers_test.go index 5cac7bc1..c0160a87 100644 --- a/go_backend/coverage_test_helpers_test.go +++ b/go_backend/coverage_test_helpers_test.go @@ -63,11 +63,11 @@ function track(id) { isrc: "USRC17607839", itemType: "track", albumType: "album", - tidalId: "tidal-1", - qobuzId: "qobuz-1", - deezerId: "deezer-1", - spotifyId: "spotify:track:1", - externalLinks: { tidal: "https://tidal.example/1" }, + tidalId: "alternate-id-a", + qobuzId: "alternate-id-b", + deezerId: "alternate-id-c", + spotifyId: "source-track-1", + externalLinks: { provider: "https://provider.example/1" }, label: "Label", copyright: "Copyright", genre: "Pop", diff --git a/go_backend/cross_extension_share_test.go b/go_backend/cross_extension_share_test.go index ac936221..588de8a3 100644 --- a/go_backend/cross_extension_share_test.go +++ b/go_backend/cross_extension_share_test.go @@ -7,7 +7,7 @@ func TestCrossExtensionShareUsesAlbumCollectionItems(t *testing.T) { Manifest: &ExtensionManifest{ Capabilities: map[string]any{ "shareUrlTemplates": map[string]any{ - "album": "https://music.apple.com/us/album/{id}", + "album": "https://media.example/album/{id}", }, }, }, @@ -25,7 +25,7 @@ func TestCrossExtensionShareUsesAlbumCollectionItems(t *testing.T) { if best == nil { t.Fatal("expected album collection item to match") } - if url := resolveCollectionShareURL(ext, "album", best); url != "https://music.apple.com/us/album/1440783617" { + if url := resolveCollectionShareURL(ext, "album", best); url != "https://media.example/album/1440783617" { t.Fatalf("album share URL = %q", url) } } @@ -35,7 +35,7 @@ func TestCrossExtensionShareUsesArtistCollectionItems(t *testing.T) { Manifest: &ExtensionManifest{ Capabilities: map[string]any{ "shareUrlTemplates": map[string]any{ - "artist": "https://music.youtube.com/browse/{id}", + "artist": "https://media.example/artist/{id}", }, }, }, @@ -52,29 +52,29 @@ func TestCrossExtensionShareUsesArtistCollectionItems(t *testing.T) { if best == nil { t.Fatal("expected artist collection item to match") } - if url := resolveCollectionShareURL(ext, "artist", best); url != "https://music.youtube.com/browse/UCrPe3hLA51968GwxHSZ1llw" { + if url := resolveCollectionShareURL(ext, "artist", best); url != "https://media.example/artist/UCrPe3hLA51968GwxHSZ1llw" { t.Fatalf("artist share URL = %q", url) } } func TestCrossExtensionShareCacheKeyIsProviderOrderStable(t *testing.T) { - apple := &extensionProviderWrapper{ + providerA := &extensionProviderWrapper{ extension: &loadedExtension{ - ID: "apple", - SourceDir: "/extensions/apple", - Manifest: &ExtensionManifest{DisplayName: "Apple Music"}, + ID: "provider-a", + SourceDir: "/extensions/provider-a", + Manifest: &ExtensionManifest{DisplayName: "Provider A"}, }, } - qobuz := &extensionProviderWrapper{ + providerB := &extensionProviderWrapper{ extension: &loadedExtension{ - ID: "qobuz", - SourceDir: "/extensions/qobuz", - Manifest: &ExtensionManifest{DisplayName: "Qobuz"}, + ID: "provider-b", + SourceDir: "/extensions/provider-b", + Manifest: &ExtensionManifest{DisplayName: "Provider B"}, }, } - first := crossExtensionShareCacheKey("Nevermind", "Nirvana", "album", "spotify", []*extensionProviderWrapper{apple, qobuz}) - second := crossExtensionShareCacheKey("Nevermind", "Nirvana", "album", "spotify", []*extensionProviderWrapper{qobuz, apple}) + first := crossExtensionShareCacheKey("Nevermind", "Nirvana", "album", "metadata-source", []*extensionProviderWrapper{providerA, providerB}) + second := crossExtensionShareCacheKey("Nevermind", "Nirvana", "album", "metadata-source", []*extensionProviderWrapper{providerB, providerA}) if first != second { t.Fatalf("cache key should not depend on provider order:\n%s\n%s", first, second) } @@ -82,17 +82,17 @@ func TestCrossExtensionShareCacheKeyIsProviderOrderStable(t *testing.T) { func TestCrossExtensionShareCacheableSkipsTransientErrors(t *testing.T) { cacheable := []CrossExtensionShareResult{ - {ExtensionID: "apple", Found: true, URL: "https://music.apple.com/us/album/1"}, - {ExtensionID: "qobuz", Error: "album not found"}, - {ExtensionID: "tidal", Error: "no results"}, + {ExtensionID: "provider-a", Found: true, URL: "https://media.example/album/1"}, + {ExtensionID: "provider-b", Error: "album not found"}, + {ExtensionID: "provider-c", Error: "no results"}, } if !crossExtensionShareResultsCacheable(cacheable) { t.Fatal("expected found and deterministic not-found results to be cacheable") } transient := []CrossExtensionShareResult{ - {ExtensionID: "apple", Found: true, URL: "https://music.apple.com/us/album/1"}, - {ExtensionID: "qobuz", Error: "request failed: timeout"}, + {ExtensionID: "provider-a", Found: true, URL: "https://media.example/album/1"}, + {ExtensionID: "provider-b", Error: "request failed: timeout"}, } if crossExtensionShareResultsCacheable(transient) { t.Fatal("expected transient extension errors to skip cache") diff --git a/go_backend/download_comment_test.go b/go_backend/download_comment_test.go index 6b7232b1..53829eaf 100644 --- a/go_backend/download_comment_test.go +++ b/go_backend/download_comment_test.go @@ -3,15 +3,15 @@ package gobackend import "testing" func TestBuildDownloadedFileCommentKeepsSourceComment(t *testing.T) { - const source = "https://music.apple.com/us/album/example/123" - got := buildDownloadedFileComment(source, "https://music.amazon.com/albums/example") + const source = "https://source.example/album/example/123" + got := buildDownloadedFileComment(source, "https://provider.example/albums/example") if got != source { t.Fatalf("comment = %q, want %q", got, source) } } func TestBuildDownloadedFileCommentUsesProviderCommentWhenSourceIsEmpty(t *testing.T) { - const provider = "https://music.amazon.com/albums/example" + const provider = "https://provider.example/albums/example" got := buildDownloadedFileComment("", provider) if got != provider { t.Fatalf("comment = %q, want %q", got, provider) diff --git a/go_backend/download_preparation_cache_test.go b/go_backend/download_preparation_cache_test.go index c97d3b18..4ea0eac6 100644 --- a/go_backend/download_preparation_cache_test.go +++ b/go_backend/download_preparation_cache_test.go @@ -19,7 +19,7 @@ func TestPreparedDownloadRequestCache(t *testing.T) { ItemID: "item-1", Service: "provider-a", Source: "source-a", - SpotifyID: "spotify-1", + SpotifyID: "source-track-1", TrackName: "Track", ArtistName: "Artist", OutputDir: "/new/output", @@ -33,7 +33,7 @@ func TestPreparedDownloadRequestCache(t *testing.T) { prepared.ISRC = "USRC17607839" prepared.AlbumName = "Resolved Album" prepared.AlbumArtist = "Resolved Album Artist" - prepared.DeezerID = "deezer-1" + prepared.DeezerID = "alternate-track-1" prepared.Genre = "Pop" prepared.OutputDir = "/stale/output" prepared.OutputPath = "/stale/output/old.flac" @@ -73,7 +73,7 @@ func TestPreparedDownloadRequestCacheRejectsChangedTrackAndExpiry(t *testing.T) req := DownloadRequest{ ItemID: "item-2", Service: "provider-a", - SpotifyID: "spotify-2", + SpotifyID: "source-track-2", TrackName: "Track", ArtistName: "Artist", } @@ -81,7 +81,7 @@ func TestPreparedDownloadRequestCacheRejectsChangedTrackAndExpiry(t *testing.T) cachePreparedDownloadRequest(key, req) changed := req - changed.SpotifyID = "spotify-other" + changed.SpotifyID = "source-track-other" if _, _, ok := takePreparedDownloadRequest(downloadPreparationKey(changed), changed); ok { t.Fatal("changed track must not reuse another track's prepared metadata") } diff --git a/go_backend/exports_test.go b/go_backend/exports_test.go index 13424769..2fc80af0 100644 --- a/go_backend/exports_test.go +++ b/go_backend/exports_test.go @@ -51,7 +51,7 @@ func TestBuildDownloadSuccessResponsePrefersRequestedAlbumMetadata(t *testing.T) resp := buildDownloadSuccessResponse( req, result, - "tidal", + "download-provider", "ok", "/tmp/test.flac", false, @@ -186,7 +186,7 @@ func TestBuildDownloadSuccessResponseReturnsResolvedProviderFilename(t *testing. req := DownloadRequest{ TrackName: "Track", ArtistName: "Artist", - DownloadProvider: "soundcloud", + DownloadProvider: "download-provider", ProviderTrackID: "998877", FilenameFormat: "{artist} - {title} [{isrc}] [{provider}-{provider_id}]", OutputExt: ".flac", @@ -199,13 +199,13 @@ func TestBuildDownloadSuccessResponseReturnsResolvedProviderFilename(t *testing. resp := buildDownloadSuccessResponse( req, result, - "soundcloud", + "download-provider", "ok", "/proc/self/fd/10", false, ) - want := "Artist - Track [USABC1234567] [soundcloud-998877].m4a" + want := "Artist - Track [USABC1234567] [download-provider-998877].m4a" if resp.ResolvedFileName != want { t.Fatalf("resolved filename = %q, want %q", resp.ResolvedFileName, want) } @@ -229,7 +229,7 @@ func TestBuildDownloadSuccessResponseNormalizesDecryptionDescriptor(t *testing.T resp := buildDownloadSuccessResponse( req, result, - "amazon", + "download-provider", "ok", "/tmp/test.m4a", false, @@ -426,7 +426,7 @@ func TestEnrichExtraMetadataByISRCPrefersDeezerGenre(t *testing.T) { func TestApplyReEnrichTrackMetadataPreservesExistingReleaseDateWhenCandidateMissing(t *testing.T) { req := reEnrichRequest{ - SpotifyID: "spotify-track-id", + SpotifyID: "source-track-id", AlbumName: "Original Album", ReleaseDate: "2024-01-01", ISRC: "REQ123", @@ -541,7 +541,7 @@ func TestSelectBestReEnrichTrackPrefersCandidateWithReleaseDate(t *testing.T) { AlbumName: "Album Name", DurationMS: 180000, ReleaseDate: "", - ProviderID: "spotify", + ProviderID: "metadata-a", }, { ID: "second", @@ -550,7 +550,7 @@ func TestSelectBestReEnrichTrackPrefersCandidateWithReleaseDate(t *testing.T) { AlbumName: "Album Name", DurationMS: 180000, ReleaseDate: "2024-03-09", - ProviderID: "deezer", + ProviderID: "metadata-b", }, } @@ -582,7 +582,7 @@ func TestSelectBestReEnrichTrackRejectsMismatchedSearchResults(t *testing.T) { TrackNumber: 4, DiscNumber: 1, ISRC: "WRONG1234567", - ProviderID: "deezer", + ProviderID: "metadata-b", }, } @@ -606,7 +606,7 @@ func TestSelectBestReEnrichTrackAllowsExactISRCDespiteMetadataMismatch(t *testin Artists: "Different Artist", DurationMS: 180000, ISRC: "USRC17607839", - ProviderID: "deezer", + ProviderID: "metadata-b", }, } @@ -634,7 +634,7 @@ func TestSelectBestReEnrichTrackPlaceholderFallsBackToAlbum(t *testing.T) { Artists: "Harry Styles", AlbumName: "Harry Styles", DurationMS: 180000, - ProviderID: "deezer", + ProviderID: "metadata-b", }, } diff --git a/go_backend/extension_download_quality_test.go b/go_backend/extension_download_quality_test.go index ed34d402..45f4401b 100644 --- a/go_backend/extension_download_quality_test.go +++ b/go_backend/extension_download_quality_test.go @@ -12,8 +12,8 @@ func qualityTestManifest(name string, options ...QualityOption) *ExtensionManife } func TestExtensionQualityKeepsAudioKindAcrossProviders(t *testing.T) { - amazon := qualityTestManifest("source", QualityOption{ID: "best", Label: "FLAC Best Available"}, QualityOption{ID: "ac4", Label: "Dolby Atmos"}) - tidal := qualityTestManifest("target", + source := qualityTestManifest("source", QualityOption{ID: "best", Label: "FLAC Best Available"}, QualityOption{ID: "ac4", Label: "Dolby Atmos"}) + target := qualityTestManifest("target", QualityOption{ID: "DOLBY_ATMOS", Label: "Dolby Atmos", Description: "falls back to FLAC"}, QualityOption{ID: "HI_RES_LOSSLESS", Label: "HiRes FLAC"}, QualityOption{ID: "LOSSLESS", Label: "Lossless"}, @@ -25,13 +25,13 @@ func TestExtensionQualityKeepsAudioKindAcrossProviders(t *testing.T) { {"ac4", "DOLBY_ATMOS"}, {"DOLBY_ATMOS", "DOLBY_ATMOS"}, {"HIGH", "HIGH"}, } { t.Run(tc.requested, func(t *testing.T) { - got, err := resolveExtensionDownloadQuality(tc.requested, amazon, tidal) + got, err := resolveExtensionDownloadQuality(tc.requested, source, target) if err != nil || got != tc.want { t.Fatalf("quality=%q err=%v; want %q", got, err, tc.want) } }) } - if got, err := resolveExtensionDownloadQuality("best", amazon, amazon); err != nil || got != "best" { + if got, err := resolveExtensionDownloadQuality("best", source, source); err != nil || got != "best" { t.Fatalf("same provider selection changed: %s %v", got, err) } } diff --git a/go_backend/extension_fallback_metadata_test.go b/go_backend/extension_fallback_metadata_test.go index 60fb35f3..605eed4d 100644 --- a/go_backend/extension_fallback_metadata_test.go +++ b/go_backend/extension_fallback_metadata_test.go @@ -8,7 +8,7 @@ func TestOverlayExtensionReleaseMetadataFillsMissingRequestFields(t *testing.T) AlbumType: "album", Explicit: true, UPC: "4006381333931", - Comment: "https://music.apple.com/jp/album/1532211596", + Comment: "https://source.example/album/1532211596", } overlayExtensionReleaseMetadata(&req, track) @@ -29,7 +29,7 @@ func TestOverlayExtensionReleaseMetadataFillsMissingRequestFields(t *testing.T) response := buildDownloadSuccessResponse( req, DownloadResult{}, - "amazon", + "download-provider", "downloaded", "song.m4a", false, diff --git a/go_backend/extension_fallback_resume_test.go b/go_backend/extension_fallback_resume_test.go index 0d0588f3..4e557173 100644 --- a/go_backend/extension_fallback_resume_test.go +++ b/go_backend/extension_fallback_resume_test.go @@ -36,7 +36,7 @@ func TestVerifiedDownloadResumeTriesSelectedProviderBeforeMetadata(t *testing.T) ItemID: "resume-item", Service: downloadExt.ID, Source: metadataExt.ID, - SpotifyID: "spotify:track:1", + SpotifyID: "source-track-1", TrackName: "Original Song", ArtistName: "Artist", AlbumName: "Album", @@ -93,7 +93,7 @@ func TestVerifiedDownloadResumeReusesPreparedMetadata(t *testing.T) { ItemID: "prepared-item", Service: downloadExt.ID, Source: metadataExt.ID, - SpotifyID: "spotify:track:2", + SpotifyID: "source-track-2", TrackName: "Original Song", ArtistName: "Artist", AlbumName: "Album", diff --git a/go_backend/extension_health_misc_supplement_test.go b/go_backend/extension_health_misc_supplement_test.go index 366a65f1..6bcd0097 100644 --- a/go_backend/extension_health_misc_supplement_test.go +++ b/go_backend/extension_health_misc_supplement_test.go @@ -16,7 +16,7 @@ func TestExtensionHealthClassificationAndValidation(t *testing.T) { if status, _ := classifyExtensionHealthBody([]byte(`not-json`), ""); status != "online" { t.Fatalf("invalid JSON status = %q", status) } - if status, msg := classifyExtensionHealthBody([]byte(`{"services":{"tidal":{"status":401,"label":"Tidal","detail":"auth_required"}}}`), "tidal"); status != "degraded" || !strings.Contains(msg, "Tidal") { + if status, msg := classifyExtensionHealthBody([]byte(`{"services":{"provider":{"status":401,"label":"Provider","detail":"auth_required"}}}`), "provider"); status != "degraded" || !strings.Contains(msg, "Provider") { t.Fatalf("service status/message = %q/%q", status, msg) } if status, msg, ok := classifyExtensionHealthService(map[string]any{"services": map[string]any{}}, "missing"); !ok || status != "unknown" || !strings.Contains(msg, "missing") { diff --git a/go_backend/extension_provider_supplement_test.go b/go_backend/extension_provider_supplement_test.go index 16312250..23ddb569 100644 --- a/go_backend/extension_provider_supplement_test.go +++ b/go_backend/extension_provider_supplement_test.go @@ -68,7 +68,7 @@ func TestExtensionProviderWrapperFullSurface(t *testing.T) { if err != nil { t.Fatalf("SearchTracks: %v", err) } - if search.Total != 1 || search.Tracks[0].ProviderID != ext.ID || search.Tracks[0].ExternalLinks["tidal"] == "" { + if search.Total != 1 || search.Tracks[0].ProviderID != ext.ID || search.Tracks[0].ExternalLinks["provider"] == "" { t.Fatalf("search = %#v", search) } @@ -112,7 +112,7 @@ func TestExtensionProviderWrapperFullSurface(t *testing.T) { t.Fatalf("enriched = %#v", enriched) } - availability, err := provider.CheckAvailabilityForItemID("ISRC", "Song", "Artist", "spotify:1", "dz", "tidal", "qobuz", 0, "") + availability, err := provider.CheckAvailabilityForItemID("ISRC", "Song", "Artist", "source-id", "alternate-id-a", "alternate-id-b", "alternate-id-c", 0, "") if err != nil { t.Fatalf("CheckAvailabilityForItemID: %v", err) } @@ -172,15 +172,15 @@ func TestExtensionProviderWrapperFullSurface(t *testing.T) { func TestExtensionProviderAndManagerSelectionHelpers(t *testing.T) { manifest := &ExtensionManifest{Capabilities: map[string]any{ - "replacesBuiltInProviders": []any{" Deezer ", 7, ""}, + "replacesBuiltInProviders": []any{" Legacy-Provider ", 7, ""}, }} - if values := manifestCapabilityStringList(manifest, "replacesBuiltInProviders"); len(values) != 1 || values[0] != "deezer" { + if values := manifestCapabilityStringList(manifest, "replacesBuiltInProviders"); len(values) != 1 || values[0] != "legacy-provider" { t.Fatalf("capability list = %#v", values) } - if !extensionReplacesBuiltInProvider(&loadedExtension{Manifest: manifest}, "deezer") || extensionReplacesBuiltInProvider(nil, "deezer") { + if !extensionReplacesBuiltInProvider(&loadedExtension{Manifest: manifest}, "legacy-provider") || extensionReplacesBuiltInProvider(nil, "legacy-provider") { t.Fatal("extension replacement mismatch") } - if trimKnownProviderPrefix("Deezer:101", "deezer") != "101" || trimKnownProviderPrefix("101", "deezer") != "101" { + if trimKnownProviderPrefix("Legacy-Provider:101", "legacy-provider") != "101" || trimKnownProviderPrefix("101", "legacy-provider") != "101" { t.Fatal("trimKnownProviderPrefix mismatch") } if metadataTrackDedupKey(ExtTrackMetadata{ISRC: "usrc"}) != "isrc:USRC" || diff --git a/go_backend/extension_providers_test.go b/go_backend/extension_providers_test.go index 2fcdc8a7..32569909 100644 --- a/go_backend/extension_providers_test.go +++ b/go_backend/extension_providers_test.go @@ -133,10 +133,10 @@ func TestSetProviderPriorityKeepsExtensionNamedLikeRetiredDownloader(t *testing. func TestPrioritizeFallbackProvidersByHealthPrefersOnlineAndSkipsOffline(t *testing.T) { manager := getExtensionManager() - amazon := newTestLoadedExtension(t, ExtensionTypeDownloadProvider) - amazon.ID = "amazon" - amazon.Manifest.Name = "amazon" - amazon.Manifest.ServiceHealth = []ExtensionHealthCheck{{ + unavailable := newTestLoadedExtension(t, ExtensionTypeDownloadProvider) + unavailable.ID = "unavailable-provider" + unavailable.Manifest.Name = "unavailable-provider" + unavailable.Manifest.ServiceHealth = []ExtensionHealthCheck{{ ID: "main", URL: "://bad", Required: true, @@ -146,59 +146,59 @@ func TestPrioritizeFallbackProvidersByHealthPrefersOnlineAndSkipsOffline(t *test plain.ID = "plain" plain.Manifest.Name = "plain" - deezer := newTestLoadedExtension(t, ExtensionTypeDownloadProvider) - deezer.ID = "deezer" - deezer.Manifest.Name = "deezer" - deezer.Manifest.ServiceHealth = []ExtensionHealthCheck{{ + available := newTestLoadedExtension(t, ExtensionTypeDownloadProvider) + available.ID = "available-provider" + available.Manifest.Name = "available-provider" + available.Manifest.ServiceHealth = []ExtensionHealthCheck{{ ID: "main", URL: "https://example.test/health", }} manager.mu.Lock() - previousAmazon, hadAmazon := manager.extensions[amazon.ID] + previousUnavailable, hadUnavailable := manager.extensions[unavailable.ID] previousPlain, hadPlain := manager.extensions[plain.ID] - previousDeezer, hadDeezer := manager.extensions[deezer.ID] - manager.extensions[amazon.ID] = amazon + previousAvailable, hadAvailable := manager.extensions[available.ID] + manager.extensions[unavailable.ID] = unavailable manager.extensions[plain.ID] = plain - manager.extensions[deezer.ID] = deezer + manager.extensions[available.ID] = available manager.mu.Unlock() defer func() { manager.mu.Lock() - if hadAmazon { - manager.extensions[amazon.ID] = previousAmazon + if hadUnavailable { + manager.extensions[unavailable.ID] = previousUnavailable } else { - delete(manager.extensions, amazon.ID) + delete(manager.extensions, unavailable.ID) } if hadPlain { manager.extensions[plain.ID] = previousPlain } else { delete(manager.extensions, plain.ID) } - if hadDeezer { - manager.extensions[deezer.ID] = previousDeezer + if hadAvailable { + manager.extensions[available.ID] = previousAvailable } else { - delete(manager.extensions, deezer.ID) + delete(manager.extensions, available.ID) } manager.mu.Unlock() extensionHealthCacheMu.Lock() - delete(extensionHealthCache, amazon.ID) - delete(extensionHealthCache, deezer.ID) + delete(extensionHealthCache, unavailable.ID) + delete(extensionHealthCache, available.ID) extensionHealthCacheMu.Unlock() }() extensionHealthCacheMu.Lock() - extensionHealthCache[amazon.ID] = cachedExtensionHealthResult{ + extensionHealthCache[unavailable.ID] = cachedExtensionHealthResult{ result: ExtensionHealthResult{ - ExtensionID: amazon.ID, + ExtensionID: unavailable.ID, Status: "offline", CheckedAt: time.Now().UTC().Format(time.RFC3339), }, expiresAt: time.Now().Add(time.Minute), } - extensionHealthCache[deezer.ID] = cachedExtensionHealthResult{ + extensionHealthCache[available.ID] = cachedExtensionHealthResult{ result: ExtensionHealthResult{ - ExtensionID: deezer.ID, + ExtensionID: available.ID, Status: "online", CheckedAt: time.Now().UTC().Format(time.RFC3339), }, @@ -207,11 +207,11 @@ func TestPrioritizeFallbackProvidersByHealthPrefersOnlineAndSkipsOffline(t *test extensionHealthCacheMu.Unlock() got := prioritizeFallbackProvidersByHealth( - []string{"amazon", "plain", "deezer"}, + []string{"unavailable-provider", "plain", "available-provider"}, manager, "", ) - want := []string{"deezer", "plain"} + want := []string{"available-provider", "plain"} if len(got) != len(want) { t.Fatalf("unexpected provider order length: got %v want %v", got, want) } @@ -468,14 +468,14 @@ func TestShouldStopProviderFallback(t *testing.T) { } func TestMoveProviderToFrontPreservesExplicitSelection(t *testing.T) { - priority := []string{"qobuz-web", "amazon-web", "tidal-web"} - got := moveProviderToFront(priority, "AMAZON-WEB") - want := []string{"amazon-web", "qobuz-web", "tidal-web"} + priority := []string{"provider-a", "provider-b", "provider-c"} + got := moveProviderToFront(priority, "PROVIDER-B") + want := []string{"provider-b", "provider-a", "provider-c"} if !reflect.DeepEqual(got, want) { t.Fatalf("moveProviderToFront() = %#v, want %#v", got, want) } - if !reflect.DeepEqual(priority, []string{"qobuz-web", "amazon-web", "tidal-web"}) { + if !reflect.DeepEqual(priority, []string{"provider-a", "provider-b", "provider-c"}) { t.Fatalf("moveProviderToFront mutated input: %#v", priority) } } @@ -520,15 +520,15 @@ func TestDiscardRejectedExtensionOutputPreservesExistingLibraryHit(t *testing.T) } func TestBuildExtensionFallbackStoppedResponsePrefersAvailabilityReason(t *testing.T) { - resp := buildExtensionFallbackStoppedResponse("soundcloud", &ExtAvailabilityResult{ - Reason: "direct SoundCloud track ID", + resp := buildExtensionFallbackStoppedResponse("direct-provider", &ExtAvailabilityResult{ + Reason: "direct provider track ID", SkipFallback: true, }, errors.New("ignored")) - if resp.Service != "soundcloud" { + if resp.Service != "direct-provider" { t.Fatalf("service = %q", resp.Service) } - if resp.Error != "Fallback stopped by soundcloud: direct SoundCloud track ID" { + if resp.Error != "Fallback stopped by direct-provider: direct provider track ID" { t.Fatalf("unexpected error message: %q", resp.Error) } if resp.ErrorType != "extension_error" { @@ -537,11 +537,11 @@ func TestBuildExtensionFallbackStoppedResponsePrefersAvailabilityReason(t *testi } func TestBuildExtensionFallbackStoppedResponseFallsBackToError(t *testing.T) { - resp := buildExtensionFallbackStoppedResponse("soundcloud", &ExtAvailabilityResult{ + resp := buildExtensionFallbackStoppedResponse("direct-provider", &ExtAvailabilityResult{ SkipFallback: true, }, errors.New("lookup failed")) - if resp.Error != "Fallback stopped by soundcloud: lookup failed" { + if resp.Error != "Fallback stopped by direct-provider: lookup failed" { t.Fatalf("unexpected error message: %q", resp.Error) } } @@ -619,7 +619,7 @@ func TestParseExtensionSearchResultAcceptsObjectAndArrayShapes(t *testing.T) { album_name: "Album", duration_ms: 123000, cover_url: "https://img.test/cover.jpg", - external_links: { spotify: "spotify:track:1" }, + external_links: { provider: "https://provider.example/track/1" }, audio_quality: "LOSSLESS" }], total: 9 @@ -640,7 +640,7 @@ func TestParseExtensionSearchResultAcceptsObjectAndArrayShapes(t *testing.T) { track.AlbumName != "Album" || track.DurationMS != 123000 || track.CoverURL != "https://img.test/cover.jpg" || - track.ExternalLinks["spotify"] != "spotify:track:1" || + track.ExternalLinks["provider"] != "https://provider.example/track/1" || track.AudioQuality != "LOSSLESS" { t.Fatalf("unexpected parsed track: %+v", track) } @@ -846,16 +846,16 @@ func TestMatchesURLHostAnchored(t *testing.T) { manifest := &ExtensionManifest{ URLHandler: &URLHandlerConfig{ Enabled: true, - Patterns: []string{"spotify.com", "deezer.page.link", "spotify:"}, + Patterns: []string{"catalog.example", "short.example", "catalog:"}, }, } for _, urlStr := range []string{ - "https://open.spotify.com/track/abc", - "https://spotify.com/track/abc", - "HTTPS://OPEN.SPOTIFY.COM/track/ABC", - "https://deezer.page.link/xyz", - "spotify:track:abc123", + "https://open.catalog.example/track/abc", + "https://catalog.example/track/abc", + "HTTPS://OPEN.CATALOG.EXAMPLE/track/ABC", + "https://short.example/xyz", + "catalog:track:abc123", } { if !manifest.MatchesURL(urlStr) { t.Fatalf("expected match for %q", urlStr) @@ -864,10 +864,10 @@ func TestMatchesURLHostAnchored(t *testing.T) { for _, urlStr := range []string{ // The old substring matching accepted all of these. - "https://evil.example/?next=https://spotify.com/track/abc", - "https://notspotify.com/track/abc", - "https://spotify.com.evil.example/track/abc", - "https://example.com/spotify.com", + "https://evil.example/?next=https://catalog.example/track/abc", + "https://notcatalog.example/track/abc", + "https://catalog.example.evil.example/track/abc", + "https://example.com/catalog.example", "not a url at all", } { if manifest.MatchesURL(urlStr) { @@ -878,13 +878,13 @@ func TestMatchesURLHostAnchored(t *testing.T) { withPath := &ExtensionManifest{ URLHandler: &URLHandlerConfig{ Enabled: true, - Patterns: []string{"youtube.com/watch"}, + Patterns: []string{"video.example/watch"}, }, } - if !withPath.MatchesURL("https://www.youtube.com/watch?v=abc") { + if !withPath.MatchesURL("https://www.video.example/watch?v=abc") { t.Fatal("expected host+path prefix to match") } - if withPath.MatchesURL("https://www.youtube.com/playlist?list=abc") { + if withPath.MatchesURL("https://www.video.example/playlist?list=abc") { t.Fatal("expected different path to not match") } } diff --git a/go_backend/extension_runtime_supplement_test.go b/go_backend/extension_runtime_supplement_test.go index 6f01609c..1f804f90 100644 --- a/go_backend/extension_runtime_supplement_test.go +++ b/go_backend/extension_runtime_supplement_test.go @@ -1170,7 +1170,7 @@ func TestExtensionRuntimeUtilityAPIs(t *testing.T) { } func TestClassifySignedSessionExpiredAsVerification(t *testing.T) { - got := classifyDownloadErrorType("Failed to resolve Deezer download: signed session expired") + got := classifyDownloadErrorType("Failed to resolve provider download: signed session expired") if got != "verification_required" { t.Fatalf("expected verification_required, got %q", got) } diff --git a/go_backend/extension_signed_session_test.go b/go_backend/extension_signed_session_test.go index 294b6e46..495451d9 100644 --- a/go_backend/extension_signed_session_test.go +++ b/go_backend/extension_signed_session_test.go @@ -81,7 +81,7 @@ func TestSignedSessionConfigWithDefaults(t *testing.T) { t.Run("preserves values the manifest already set", func(t *testing.T) { custom := &SignedSessionConfig{ - Namespace: "tidal", + Namespace: "provider", BaseURL: "https://auth.example.com", AppVersion: "5.0", Platform: "mobile", @@ -89,7 +89,7 @@ func TestSignedSessionConfigWithDefaults(t *testing.T) { Endpoints: SignedSessionEndpoints{Exchange: "/custom/exchange"}, } got := signedSessionConfigWithDefaults(custom) - if got.Namespace != "tidal" || got.BaseURL != "https://auth.example.com" { + if got.Namespace != "provider" || got.BaseURL != "https://auth.example.com" { t.Errorf("namespace/baseUrl were overwritten: %+v", got) } if got.AppVersion != "5.0" || got.Platform != "mobile" || got.TimeWindowSeconds != 60 { @@ -360,7 +360,7 @@ func TestDownloadWithExtensionsPreflightsBeforeMetadataEnrichment(t *testing.T) // Metadata may originate from another extension, but the explicitly chosen // download provider owns the signed-session namespace and verification. - requestJSON := `{"source":"spotify-metadata","service":"preflight-download","item_id":"preflight-item","isrc":"USRC17607839"}` + requestJSON := `{"source":"source-metadata","service":"preflight-download","item_id":"preflight-item","isrc":"USRC17607839"}` responseJSON, err := DownloadWithExtensionsJSON(requestJSON) if err != nil { t.Fatalf("DownloadWithExtensionsJSON: %v", err) @@ -718,12 +718,12 @@ func TestSignedSessionProviderRetryDuration(t *testing.T) { } func TestNormalizeSignedSessionRecordScope(t *testing.T) { - config := SignedSessionConfig{Namespace: "Tidal", BaseURL: "https://a.example.com", AppVersion: "1.0", Platform: "mobile"} + config := SignedSessionConfig{Namespace: "Provider", BaseURL: "https://a.example.com", AppVersion: "1.0", Platform: "mobile"} t.Run("first save just stamps the scope", func(t *testing.T) { record := &signedSessionRecord{SessionID: "s1", SessionSecret: "secret"} normalizeSignedSessionRecordScope(config, record) - if record.Namespace != "tidal" || record.BaseURL != config.BaseURL { + if record.Namespace != "provider" || record.BaseURL != config.BaseURL { t.Errorf("scope not stamped: %+v", record) } if record.SessionID != "s1" || record.SessionSecret != "secret" { @@ -733,7 +733,7 @@ func TestNormalizeSignedSessionRecordScope(t *testing.T) { t.Run("same scope preserves the session", func(t *testing.T) { record := &signedSessionRecord{ - Namespace: "tidal", BaseURL: config.BaseURL, AppVersion: config.AppVersion, Platform: config.Platform, + Namespace: "provider", BaseURL: config.BaseURL, AppVersion: config.AppVersion, Platform: config.Platform, SessionID: "s1", SessionSecret: "secret", ExpiresAt: "later", } normalizeSignedSessionRecordScope(config, record) @@ -744,7 +744,7 @@ func TestNormalizeSignedSessionRecordScope(t *testing.T) { t.Run("changed scope wipes the session secret", func(t *testing.T) { record := &signedSessionRecord{ - Namespace: "tidal", BaseURL: "https://old.example.com", AppVersion: config.AppVersion, Platform: config.Platform, + Namespace: "provider", BaseURL: "https://old.example.com", AppVersion: config.AppVersion, Platform: config.Platform, SessionID: "s1", SessionSecret: "secret", ExpiresAt: "later", } normalizeSignedSessionRecordScope(config, record) @@ -791,10 +791,10 @@ func saveUsableSignedSession( } func TestSignedSessionFilePathDeterminism(t *testing.T) { - runtime := newSignedSessionTestRuntime(t, "tidal-ext", nil) + runtime := newSignedSessionTestRuntime(t, "provider-ext", nil) - configA := SignedSessionConfig{Namespace: "tidal", BaseURL: "https://a.example.com"} - configB := SignedSessionConfig{Namespace: "tidal", BaseURL: "https://b.example.com"} + configA := SignedSessionConfig{Namespace: "provider", BaseURL: "https://a.example.com"} + configB := SignedSessionConfig{Namespace: "provider", BaseURL: "https://b.example.com"} pathA1, err := runtime.signedSessionFilePath(configA) if err != nil { @@ -822,8 +822,8 @@ func TestSignedSessionFilePathDeterminism(t *testing.T) { } func TestLoadAndSaveSignedSessionRoundTrip(t *testing.T) { - runtime := newSignedSessionTestRuntime(t, "tidal-ext", nil) - config := SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", nil) + config := SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} record, err := runtime.loadSignedSession(config) if err != nil { @@ -868,8 +868,8 @@ func TestLoadAndSaveSignedSessionRoundTrip(t *testing.T) { } func TestSignedSessionStatusAndClear(t *testing.T) { - runtime := newSignedSessionTestRuntime(t, "tidal-ext", nil) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", nil) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} readStatus := func() map[string]any { v := runtime.signedSessionStatus(goja.FunctionCall{}) @@ -929,7 +929,7 @@ func TestDoSignedSessionRequestSignature(t *testing.T) { var capturedErr string transport := roundTripFunc(func(req *http.Request) (*http.Response, error) { - config := signedSessionConfigWithDefaults(&SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"}) + config := signedSessionConfigWithDefaults(&SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"}) prefix := config.HeaderPrefix ts := req.Header.Get(prefix + "Timestamp") @@ -982,8 +982,8 @@ func TestDoSignedSessionRequestSignature(t *testing.T) { }, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - config := signedSessionConfigWithDefaults(&SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"}) + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + config := signedSessionConfigWithDefaults(&SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"}) record := &signedSessionRecord{InstallID: "install-1", SessionID: sessionID, SessionSecret: sessionSecret} resp, body, _, err := runtime.doSignedSessionRequest(config, record, http.MethodPost, "/tracks/search", []byte(`{"q":"test"}`), nil) @@ -1017,8 +1017,8 @@ func TestSignedSessionFetchUnauthenticatedTriggersVerification(t *testing.T) { return nil, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} call := goja.FunctionCall{Arguments: []goja.Value{runtime.vm.ToValue("GET"), runtime.vm.ToValue("/tracks/search")}} result := runtime.signedSessionFetch(call).Export().(map[string]any) @@ -1056,8 +1056,8 @@ func TestSignedSessionFetchRevokesSessionOnCanonicalSessionInvalid(t *testing.T) } }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - config := SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + config := SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} runtime.manifest.SignedSession = &config resolved := signedSessionConfigWithDefaults(&config) @@ -1849,8 +1849,8 @@ func TestExchangeSignedSessionGrant(t *testing.T) { body, _ := json.Marshal(payload) return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(string(body))), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} if err := runtime.exchangeSignedSessionGrant("grant-token"); err != nil { t.Fatalf("unexpected error: %v", err) @@ -1876,8 +1876,8 @@ func TestExchangeSignedSessionGrant(t *testing.T) { transport := roundTripFunc(func(req *http.Request) (*http.Response, error) { return &http.Response{StatusCode: 400, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(`{}`)), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} if err := runtime.exchangeSignedSessionGrant("bad-grant"); err == nil { t.Fatal("expected an error for a non-2xx exchange response") @@ -1919,9 +1919,9 @@ func TestExchangeSignedSessionGrant(t *testing.T) { Request: req, }, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-rate-limit", transport) + runtime := newSignedSessionTestRuntime(t, "provider-rate-limit", transport) runtime.manifest.SignedSession = &SignedSessionConfig{ - Namespace: "tidal-rate-limit", + Namespace: "provider-rate-limit", BaseURL: "https://auth.example.com", } setPendingSignedSessionGrant(runtime.extensionID, "grant-preserved") @@ -1964,9 +1964,9 @@ func TestExchangeSignedSessionGrant(t *testing.T) { Request: req, }, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-rate-limit-exhausted", transport) + runtime := newSignedSessionTestRuntime(t, "provider-rate-limit-exhausted", transport) runtime.manifest.SignedSession = &SignedSessionConfig{ - Namespace: "tidal-rate-limit-exhausted", + Namespace: "provider-rate-limit-exhausted", BaseURL: "https://auth.example.com", } setPendingSignedSessionGrant(runtime.extensionID, "grant-retry-later") @@ -2025,9 +2025,9 @@ func TestRefreshSignedSession(t *testing.T) { body, _ := json.Marshal(payload) return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(string(body))), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) config := signedSessionConfigWithDefaults(&SignedSessionConfig{ - Namespace: "tidal", BaseURL: "https://auth.example.com", + Namespace: "provider", BaseURL: "https://auth.example.com", Endpoints: SignedSessionEndpoints{Refresh: "/session/refresh"}, }) record := &signedSessionRecord{InstallID: "install-1", SessionID: "sess-1", SessionSecret: "old-secret", ExpiresAt: "2030-01-01T00:00:00Z"} @@ -2055,9 +2055,9 @@ func TestRefreshSignedSession(t *testing.T) { transport := roundTripFunc(func(req *http.Request) (*http.Response, error) { return &http.Response{StatusCode: 500, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(`{}`)), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) config := signedSessionConfigWithDefaults(&SignedSessionConfig{ - Namespace: "tidal", BaseURL: "https://auth.example.com", + Namespace: "provider", BaseURL: "https://auth.example.com", Endpoints: SignedSessionEndpoints{Refresh: "/session/refresh"}, }) record := &signedSessionRecord{InstallID: "install-1", SessionID: "sess-1", SessionSecret: "old-secret"} @@ -2229,8 +2229,8 @@ func TestSignedSessionCompleteGrant(t *testing.T) { body, _ := json.Marshal(payload) return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(string(body))), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", transport) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext", transport) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} call := goja.FunctionCall{Arguments: []goja.Value{runtime.vm.ToValue("grant-from-arg")}} result := runtime.signedSessionCompleteGrant(call).Export().(map[string]any) @@ -2245,8 +2245,8 @@ func TestSignedSessionCompleteGrant(t *testing.T) { body, _ := json.Marshal(payload) return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(string(body))), Request: req}, nil }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext-pending", transport) - runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "tidal", BaseURL: "https://auth.example.com"} + runtime := newSignedSessionTestRuntime(t, "provider-ext-pending", transport) + runtime.manifest.SignedSession = &SignedSessionConfig{Namespace: "provider", BaseURL: "https://auth.example.com"} setPendingSignedSessionGrant(runtime.extensionID, "pending-grant") result := runtime.signedSessionCompleteGrant(goja.FunctionCall{}).Export().(map[string]any) @@ -2263,7 +2263,7 @@ func TestSignedSessionCompleteGrant(t *testing.T) { }) t.Run("no grant available reports failure", func(t *testing.T) { - runtime := newSignedSessionTestRuntime(t, "tidal-ext-none", nil) + runtime := newSignedSessionTestRuntime(t, "provider-ext-none", nil) result := runtime.signedSessionCompleteGrant(goja.FunctionCall{}).Export().(map[string]any) if result["success"] != false { t.Fatalf("expected failure without a grant, got %+v", result) @@ -2273,11 +2273,11 @@ func TestSignedSessionCompleteGrant(t *testing.T) { func TestBuildSignedSessionChallengeURL(t *testing.T) { config := signedSessionConfigWithDefaults(&SignedSessionConfig{ - Namespace: "tidal", + Namespace: "provider", BaseURL: "https://auth.example.com", CallbackURL: "spotiflac://session-grant", }) - runtime := newSignedSessionTestRuntime(t, "tidal-ext", nil) + runtime := newSignedSessionTestRuntime(t, "provider-ext", nil) got := runtime.buildSignedSessionChallengeURL(config, "chal-123", "state-123") diff --git a/go_backend/filename_test.go b/go_backend/filename_test.go index 26863bca..51ffaa68 100644 --- a/go_backend/filename_test.go +++ b/go_backend/filename_test.go @@ -123,13 +123,13 @@ func TestBuildDownloadFilename_ProvidesTraceabilityPlaceholders(t *testing.T) { TrackName: "Song Name", ArtistName: "Artist Name", ISRC: "USABC1234567", - DownloadProvider: "tidal-web", + DownloadProvider: "download-provider", ProviderTrackID: "123456789", FilenameFormat: "{artist} - {title} [{isrc}] [{provider}-{provider_id}]", OutputExt: ".flac", }) - expected := "Artist Name - Song Name [USABC1234567] [tidal-web-123456789].flac" + expected := "Artist Name - Song Name [USABC1234567] [download-provider-123456789].flac" if filename != expected { t.Fatalf("expected %q, got %q", expected, filename) } @@ -137,12 +137,12 @@ func TestBuildDownloadFilename_ProvidesTraceabilityPlaceholders(t *testing.T) { func TestBuildFilenameFromTemplate_TraceabilityAliases(t *testing.T) { metadata := map[string]any{ - "provider": "soundcloud", + "provider": "download-provider", "provider_id": "998877", } formatted := buildFilenameFromTemplate("{platform}-{id}", metadata) - if formatted != "soundcloud-998877" { + if formatted != "download-provider-998877" { t.Fatalf("unexpected alias filename: %q", formatted) } } @@ -150,14 +150,14 @@ func TestBuildFilenameFromTemplate_TraceabilityAliases(t *testing.T) { func TestBuildFilenameFromTemplate_CleansEmptyTraceabilityDecorations(t *testing.T) { metadata := map[string]any{ "title": "Song Name", - "provider": "tidal-web", + "provider": "download-provider", } formatted := buildFilenameFromTemplate( "{title} [{isrc}] [{provider}-{provider_id}]", metadata, ) - if formatted != "Song Name [tidal-web]" { + if formatted != "Song Name [download-provider]" { t.Fatalf("unexpected empty placeholder cleanup: %q", formatted) } } diff --git a/go_backend/lyrics_supplement_test.go b/go_backend/lyrics_supplement_test.go index f112f4f3..fcc3181a 100644 --- a/go_backend/lyrics_supplement_test.go +++ b/go_backend/lyrics_supplement_test.go @@ -79,8 +79,8 @@ func TestLyricsCacheParsingAndLRCLibClient(t *testing.T) { if ua := appUserAgent(); !strings.Contains(ua, "4.5.0") { t.Fatalf("user agent = %q", ua) } - SetLyricsProviderOrder([]string{"LRCLIB", "bad", "extension:Apple-Music", "netease", "extension:apple-music"}) - if providers := GetLyricsProviderOrder(); len(providers) != 3 || providers[0] != LyricsProviderLRCLIB || providers[1] != "extension:apple-music" { + SetLyricsProviderOrder([]string{"LRCLIB", "bad", "extension:Lyrics-Fixture", "netease", "extension:lyrics-fixture"}) + if providers := GetLyricsProviderOrder(); len(providers) != 3 || providers[0] != LyricsProviderLRCLIB || providers[1] != "extension:lyrics-fixture" { t.Fatalf("providers = %#v", providers) } SetLyricsProviderOrder(nil) @@ -332,7 +332,7 @@ func TestConcurrentLyricsProvidersReturnFastFallback(t *testing.T) { func TestResolveLyricsProviderOrderOnlyIncludesSelectedAvailableExtensions(t *testing.T) { availableExtensions := map[string]*extensionProviderWrapper{ - "extension:apple-music": nil, + "extension:lyrics-fixture": nil, "extension:future-provider": nil, } providers := resolveLyricsProviderOrder( diff --git a/go_backend/title_match_utils_test.go b/go_backend/title_match_utils_test.go index 0bf865da..a1910d1e 100644 --- a/go_backend/title_match_utils_test.go +++ b/go_backend/title_match_utils_test.go @@ -167,7 +167,7 @@ func TestTrackMatchesRequestRejectsDurationMismatchAcrossReleases(t *testing.T) func TestTitlesMatch_SeparatorVariants(t *testing.T) { if !titlesMatch("Doctor / Cops", "Doctor _ Cops") { - t.Fatal("expected tidal titlesMatch to accept / vs _ variant") + t.Fatal("expected titlesMatch to accept / vs _ variant") } } diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift index caebfebe..201956e3 100644 --- a/ios/RunnerTests/RunnerTests.swift +++ b/ios/RunnerTests/RunnerTests.swift @@ -47,14 +47,14 @@ class RunnerTests: XCTestCase { func testParsesOAuthCallback() { let route = ExtensionCallbackParser.parse( - URL(string: "spotiflac://callback?code=auth-code&state=spotify-web")! + URL(string: "spotiflac://callback?code=auth-code&state=metadata-provider")! ) XCTAssertEqual( route, ExtensionCallbackRoute( code: "auth-code", - state: "spotify-web", + state: "metadata-provider", isSessionGrant: false ) ) diff --git a/test/download_history_logic_test.dart b/test/download_history_logic_test.dart index ccb3518d..e734f5bd 100644 --- a/test/download_history_logic_test.dart +++ b/test/download_history_logic_test.dart @@ -15,7 +15,7 @@ DownloadHistoryItem _historyItem({ filePath: filePath, service: 'test', downloadedAt: downloadedAt, - spotifyId: 'spotify:track:same', + spotifyId: 'source-track-same', isrc: 'SAMEISRC', ); } @@ -84,7 +84,7 @@ void main() { totalCount: 2, ); - expect(state.getBySpotifyId('spotify:track:same')?.id, 'newest'); + expect(state.getBySpotifyId('source-track-same')?.id, 'newest'); expect(state.getByIsrc('SAMEISRC')?.id, 'newest'); expect( state.findByTrackAndArtist('Same Song', 'Same Artist')?.id, diff --git a/test/download_verification_retry_guard_test.dart b/test/download_verification_retry_guard_test.dart index 8d1d253a..a177c983 100644 --- a/test/download_verification_retry_guard_test.dart +++ b/test/download_verification_retry_guard_test.dart @@ -8,43 +8,43 @@ void main() { test('failed challenge attempts do not consume the granted retry', () { final guard = DownloadVerificationRetryGuard(); - guard.recordVerificationResult('item-1', 'tidal-web', granted: false); + guard.recordVerificationResult('item-1', 'provider-a', granted: false); - expect(guard.hasRetriedAfterGrant('item-1', 'tidal-web'), isFalse); + expect(guard.hasRetriedAfterGrant('item-1', 'provider-a'), isFalse); }); test('completed grants allow only one automatic retry per service', () { final guard = DownloadVerificationRetryGuard(); - guard.recordVerificationResult('item-1', ' TIDAL-WEB ', granted: true); + guard.recordVerificationResult('item-1', ' PROVIDER-A ', granted: true); - expect(guard.hasRetriedAfterGrant('item-1', 'tidal-web'), isTrue); - expect(guard.hasRetriedAfterGrant('item-1', 'qobuz-web'), isFalse); - expect(guard.hasRetriedAfterGrant('item-2', 'tidal-web'), isFalse); + expect(guard.hasRetriedAfterGrant('item-1', 'provider-a'), isTrue); + expect(guard.hasRetriedAfterGrant('item-1', 'provider-b'), isFalse); + expect(guard.hasRetriedAfterGrant('item-2', 'provider-a'), isFalse); }); test('manual retry clears every service marker for an item', () { final guard = DownloadVerificationRetryGuard() - ..recordVerificationResult('item-1', 'tidal-web', granted: true) - ..recordVerificationResult('item-1', 'qobuz-web', granted: true) - ..recordVerificationResult('item-2', 'tidal-web', granted: true); + ..recordVerificationResult('item-1', 'provider-a', granted: true) + ..recordVerificationResult('item-1', 'provider-b', granted: true) + ..recordVerificationResult('item-2', 'provider-a', granted: true); guard.clearItem('item-1'); - expect(guard.hasRetriedAfterGrant('item-1', 'tidal-web'), isFalse); - expect(guard.hasRetriedAfterGrant('item-1', 'qobuz-web'), isFalse); - expect(guard.hasRetriedAfterGrant('item-2', 'tidal-web'), isTrue); + expect(guard.hasRetriedAfterGrant('item-1', 'provider-a'), isFalse); + expect(guard.hasRetriedAfterGrant('item-1', 'provider-b'), isFalse); + expect(guard.hasRetriedAfterGrant('item-2', 'provider-a'), isTrue); }); test('queue cleanup retains markers only for remaining items', () { final guard = DownloadVerificationRetryGuard() - ..recordVerificationResult('removed', 'tidal-web', granted: true) - ..recordVerificationResult('remaining', 'tidal-web', granted: true); + ..recordVerificationResult('removed', 'provider-a', granted: true) + ..recordVerificationResult('remaining', 'provider-a', granted: true); guard.retainItems({'remaining'}); - expect(guard.hasRetriedAfterGrant('removed', 'tidal-web'), isFalse); - expect(guard.hasRetriedAfterGrant('remaining', 'tidal-web'), isTrue); + expect(guard.hasRetriedAfterGrant('removed', 'provider-a'), isFalse); + expect(guard.hasRetriedAfterGrant('remaining', 'provider-a'), isTrue); }); }); @@ -58,7 +58,7 @@ void main() { final result = coordinator.waitForGrant( itemId: 'item-1', - service: 'tidal-web', + service: 'provider-a', startFlow: (cancellationSignal) async { flowStarted.complete(); await cancellationSignal; @@ -81,7 +81,7 @@ void main() { final first = coordinator.waitForGrant( itemId: 'item-1', - service: 'tidal-web', + service: 'provider-a', startFlow: (cancellationSignal) async { starts++; await cancellationSignal; @@ -93,7 +93,7 @@ void main() { final second = coordinator.waitForGrant( itemId: 'item-2', - service: 'tidal-web', + service: 'provider-a', startFlow: (_) async { starts++; return true; @@ -122,12 +122,12 @@ void main() { final first = coordinator.waitForGrant( itemId: 'item-1', - service: ' TIDAL-WEB ', + service: ' PROVIDER-A ', startFlow: startFlow, ); final second = coordinator.waitForGrant( itemId: 'item-2', - service: 'tidal-web', + service: 'provider-a', startFlow: startFlow, ); diff --git a/test/models_and_utils_test.dart b/test/models_and_utils_test.dart index b35bee92..dfe39a80 100644 --- a/test/models_and_utils_test.dart +++ b/test/models_and_utils_test.dart @@ -680,7 +680,7 @@ void main() { test('round-trips json with service availability', () { final track = Track.fromJson({ - 'id': 'spotify:track:1', + 'id': 'source-track-1', 'name': 'Song', 'artistName': 'Artist', 'albumName': 'Album', @@ -691,7 +691,7 @@ void main() { expect(track.availability?.tidal, isTrue); expect(track.availability?.qobuz, isFalse); expect(track.availability?.deezerId, '31337'); - expect(track.toJson()['id'], 'spotify:track:1'); + expect(track.toJson()['id'], 'source-track-1'); expect(track.availability!.toJson()['deezer'], isTrue); }); }); @@ -710,7 +710,7 @@ void main() { final item = DownloadItem( id: 'download-1', track: sampleTrack(), - service: 'tidal', + service: 'provider-a', createdAt: createdAt, ); @@ -745,7 +745,7 @@ void main() { final base = DownloadItem( id: 'download-1', track: sampleTrack(), - service: 'qobuz', + service: 'provider-b', createdAt: DateTime.utc(2026), filePath: '/music/stale.flac', error: 'raw backend failure', @@ -790,7 +790,7 @@ void main() { 'albumName': 'Album', 'duration': 1000, }, - 'service': 'deezer', + 'service': 'provider-a', 'status': 'failed', 'errorType': 'network', 'createdAt': '2026-05-04T10:00:00.000Z', @@ -811,7 +811,7 @@ void main() { final item = DownloadItem( id: 'download-active', track: sampleTrack(), - service: 'tidal', + service: 'provider-a', createdAt: DateTime.utc(2026), status: DownloadStatus.finalizing, progress: 0.97, @@ -937,7 +937,7 @@ void main() { ); final updated = settings.copyWith( - defaultService: 'tidal', + defaultService: 'provider-a', embedReplayGain: true, embeddedCoverMaxDimension: 1000, lyricsProviders: ['apple_music'], @@ -950,7 +950,7 @@ void main() { clearHomeFeedProvider: true, ); - expect(updated.defaultService, 'tidal'); + expect(updated.defaultService, 'provider-a'); expect(updated.embedReplayGain, isTrue); expect(updated.embeddedCoverMaxDimension, 1000); expect(updated.lyricsProviders, ['apple_music']); @@ -969,7 +969,7 @@ void main() { test('round-trips json including recently added settings', () { const settings = AppSettings( - defaultService: 'qobuz', + defaultService: 'provider-b', storageMode: 'saf', downloadTreeUri: 'content://tree/music', downloadFallbackExtensionIds: ['ext.a', 'ext.b'], @@ -996,7 +996,7 @@ void main() { final decoded = AppSettings.fromJson(settings.toJson()); - expect(decoded.defaultService, 'qobuz'); + expect(decoded.defaultService, 'provider-b'); expect(decoded.storageMode, 'saf'); expect(decoded.downloadTreeUri, 'content://tree/music'); expect(decoded.downloadFallbackExtensionIds, ['ext.a', 'ext.b']); @@ -1053,10 +1053,10 @@ void main() { test('serializes all backend field names', () { const payload = DownloadRequestPayload( isrc: 'ISRC123', - service: 'tidal', - downloadProvider: 'tidal-web', + service: 'source-provider', + downloadProvider: 'download-provider', providerTrackId: '123456789', - spotifyId: 'spotify:track:1', + spotifyId: 'source-track-1', trackName: 'Song', artistName: 'Artist', albumName: 'Album', @@ -1092,9 +1092,9 @@ void main() { explicit: true, albumType: 'compilation', upc: '0012345678901', - tidalId: 'tidal-1', - qobuzId: 'qobuz-1', - deezerId: 'deezer-1', + tidalId: 'alternate-id-a', + qobuzId: 'alternate-id-b', + deezerId: 'alternate-id-c', lyricsMode: 'sidecar', useExtensions: true, useFallback: true, @@ -1114,10 +1114,10 @@ void main() { expect(payload.toJson(), { 'contract_version': DownloadRequestPayload.nativeWorkerContractVersion, 'isrc': 'ISRC123', - 'service': 'tidal', - 'download_provider': 'tidal-web', + 'service': 'source-provider', + 'download_provider': 'download-provider', 'provider_track_id': '123456789', - 'spotify_id': 'spotify:track:1', + 'spotify_id': 'source-track-1', 'track_name': 'Song', 'artist_name': 'Artist', 'album_name': 'Album', @@ -1153,9 +1153,9 @@ void main() { 'explicit': true, 'album_type': 'compilation', 'upc': '0012345678901', - 'tidal_id': 'tidal-1', - 'qobuz_id': 'qobuz-1', - 'deezer_id': 'deezer-1', + 'tidal_id': 'alternate-id-a', + 'qobuz_id': 'alternate-id-b', + 'deezer_id': 'alternate-id-c', 'lyrics_mode': 'sidecar', 'use_extensions': true, 'use_fallback': true, @@ -1283,7 +1283,7 @@ void main() { 'albumType': 'album', 'explicit': true, 'upc': '4006381333931', - 'comment': 'https://listen.tidal.com/album/1', + 'comment': 'https://media.example/album/1', 'format': 'flac', }); @@ -1302,7 +1302,7 @@ void main() { expect(normalized['album_type'], 'album'); expect(normalized['explicit'], isTrue); expect(normalized['upc'], '4006381333931'); - expect(normalized['comment'], 'https://listen.tidal.com/album/1'); + expect(normalized['comment'], 'https://media.example/album/1'); expect(normalized['audio_codec'], 'flac'); }); diff --git a/test/platform_bridge_session_grant_test.dart b/test/platform_bridge_session_grant_test.dart index 9023ee10..1051cc6d 100644 --- a/test/platform_bridge_session_grant_test.dart +++ b/test/platform_bridge_session_grant_test.dart @@ -31,11 +31,11 @@ void main() { addTearDown(subscription.cancel); final first = PlatformBridge.completeExtensionSessionGrant( - ' qobuz-web ', + ' provider-a ', 'grant-value', ); final second = PlatformBridge.completeExtensionSessionGrant( - 'QOBUZ-WEB', + 'PROVIDER-A', 'grant-value', ); @@ -48,7 +48,7 @@ void main() { expect(callCount, 1); expect(events, hasLength(1)); - expect(events.single.extensionId, 'qobuz-web'); + expect(events.single.extensionId, 'provider-a'); expect(events.single.success, isTrue); }); } diff --git a/test/provider_resource_ids_test.dart b/test/provider_resource_ids_test.dart index 2177a29f..e906b769 100644 --- a/test/provider_resource_ids_test.dart +++ b/test/provider_resource_ids_test.dart @@ -45,10 +45,10 @@ void main() { test('prefers a known provider id over guessing from the resource id', () { expect( resolvePreferredMetadataProviderId( - 'apple-music-ext', + 'sample-provider', '37i9dQZF1DXcBWIGoYBM5M', ), - 'apple-music-ext', + 'sample-provider', ); }); diff --git a/test/track_metadata_header_contrast_test.dart b/test/track_metadata_header_contrast_test.dart index da499386..b6c69238 100644 --- a/test/track_metadata_header_contrast_test.dart +++ b/test/track_metadata_header_contrast_test.dart @@ -20,7 +20,7 @@ void main() { artistName: 'Artist', albumName: 'Album', filePath: r'Z:\missing\track.flac', - service: 'tidal-web', + service: 'provider-a', downloadedAt: DateTime(2026), duration: 250, bitDepth: 16, @@ -45,7 +45,7 @@ void main() { expect(headerMeta, findsOneWidget); expect(find.byType(ExplicitBadge), findsNWidgets(2)); expect(find.text('Explicit'), findsNothing); - for (final label in const ['16-bit/44.1kHz', '4:10', 'Tidal-web']) { + for (final label in const ['16-bit/44.1kHz', '4:10', 'Provider-a']) { final text = tester.widget( find.descendant(of: headerMeta, matching: find.text(label)), );