Fixes#368.
Reopening a Spotify playlist from "recent access" showed no tracks,
while the first view (right after pasting the URL) worked fine.
Root cause traced across two layers:
1. Go: ExtURLHandleResult (the parsed shape of an extension's handleUrl()
return value) never captured a top-level `id` for the handled
resource. Track/album/artist results carry their own id inside their
nested metadata, but a plain playlist result has no such object, so
its id was silently dropped everywhere from the goja parser through
to the JSON the Dart side receives.
2. Dart: TrackState had nowhere to put that id even if it existed
(only playlistName), so recording a "recent" playlist access stored
the playlist's *name* as if it were its id. Reopening it later fed
that name into PlaylistScreen's provider-guessing logic
(legacyProviderIdFromResourceId, which only recognizes legacy
"provider:id" prefixes), which naturally failed and fell through to
a hardcoded Deezer metadata fetch using a Spotify playlist's name as
the resource id - guaranteed to return nothing.
Fix, matching the "generic API, not per-provider checks" architecture
in CONTRIBUTING.md:
- go_backend/extension_provider_wrapper.go: add ExtURLHandleResult.ID.
- go_backend/extension_goja_convert.go: parse it from the handler's
return value.
- go_backend/exports_extensions.go: surface it in the JSON response.
- lib/providers/track_provider.dart: add TrackState.playlistId,
populated from the response's `id` field for playlist results.
- lib/screens/home_tab.dart: record the real playlist id (falling back
to the name only if a provider never supplies one) and pass both the
id and the already-known provider id forward to PlaylistScreen.
- lib/screens/playlist_screen.dart: PlaylistScreen gains a
metadataProviderId param that takes priority over guessing from the
id's shape.
- lib/screens/home_tab_recent.dart: pass the recent-access entry's
stored providerId through when reopening a playlist.
- lib/utils/provider_resource_ids.dart: extract the
known-id-vs-guessed-id preference into a small, directly testable
resolvePreferredMetadataProviderId helper.
Note: this fixes the common case (an extension already reported its
own id as the source provider for the URL it handled). If a provider
never supplies an id for its handleUrl() playlist result, playlistId
stays null and behavior is unchanged from before this fix - no
regression, just not a complete fix for that narrower case, since
that would require changes in extension-side JS code outside this
repo.
Tests:
- go_backend/extension_goja_convert_url_handle_test.go: the new ID
field round-trips from a handler's return value, and stays empty
when the handler doesn't supply one.
- test/provider_resource_ids_test.dart: resolvePreferredMetadataProviderId
prefers a known provider id, falls back to the legacy-prefix guess,
treats a blank known id as unknown, and returns null for the
unprefixed-id-with-no-known-provider case from #368 itself.
Verification: go build/vet/test and flutter analyze/test all green.