brim-borium/spotify_sdk

Support for track relinking

Closed this issue · 1 comments

The plugin currently doesn't support Spotify track relinking. This is a process by which Spotify automatically relinks a track which is not available in the user's current market, to the instance of that track which is available in the market (only happens if one track is released multiple times). This means that sometimes when playing a Spotify track by URI, the player can end up playing the same track under a different URI.
Each relinked track gets a linked_from field. We should implement that field into the plugin and subsequently into each platform implementation.

I'm having a relinking challenge here too. Sometimes I do play(uri) and the resulting event comes in with different track URI.

So I took a stab at this but couldn't get it working. EDIT: it is working! I'll work on a PR soon.

It doesn't help that track linking isn't documented on the Web Playback State docs:

https://developer.spotify.com/documentation/web-playback-sdk/reference/#object-web-playback-state

Here is what I tried...

diff --git a/lib/models/track.dart b/lib/models/track.dart
index 8ca65e0..8a55af9 100644
--- a/lib/models/track.dart
+++ b/lib/models/track.dart
@@ -15,7 +15,8 @@ class Track {
     this.duration,
     this.imageUri,
     this.name,
-    this.uri, {
+    this.uri,
+    this.linkedFromUri, {
     required this.isEpisode,
     required this.isPodcast,
   });
@@ -33,6 +34,8 @@ class Track {
   final bool isPodcast;
   final String name;
   final String uri;
+  @JsonKey(name: 'linked_from_uri')
+  final String? linkedFromUri;
 
   factory Track.fromJson(Map<String, dynamic> json) => _$TrackFromJson(json);
 
diff --git a/lib/models/track.g.dart b/lib/models/track.g.dart
index e07e1b8..c57adac 100644
--- a/lib/models/track.g.dart
+++ b/lib/models/track.g.dart
@@ -17,6 +17,7 @@ Track _$TrackFromJson(Map<String, dynamic> json) {
     ImageUri.fromJson(json['image_id'] as Map<String, dynamic>),
     json['name'] as String,
     json['uri'] as String,
+    json['linked_from_uri'] as String?,
     isEpisode: json['is_episode'] as bool,
     isPodcast: json['is_podcast'] as bool,
   );
@@ -32,4 +33,5 @@ Map<String, dynamic> _$TrackToJson(Track instance) => <String, dynamic>{
       'is_podcast': instance.isPodcast,
       'name': instance.name,
       'uri': instance.uri,
+      'linked_from_uri': instance.linkedFromUri,
     };
diff --git a/lib/spotify_sdk_web.dart b/lib/spotify_sdk_web.dart
index 62ab01c..ce78349 100644
--- a/lib/spotify_sdk_web.dart
+++ b/lib/spotify_sdk_web.dart
@@ -771,6 +771,7 @@ class SpotifySdkPlugin {
               ImageUri(albumRaw.images[0].url),
               trackRaw.name,
               trackRaw.uri,
+              trackRaw.linked_from?.uri,
               isEpisode: trackRaw.type == 'episode',
               isPodcast: trackRaw.type == 'episode',
             )
@@ -1027,6 +1028,8 @@ class WebPlaybackTrack {
   external WebPlaybackAlbum get album;
   // ignore: public_member_api_docs
   external List<WebPlaybackArtist> get artists;
+  // ignore: public_member_api_docs
+  external WebLinkedFrom? get linked_from;
 
   // ignore: public_member_api_docs
   external factory WebPlaybackTrack(
@@ -1039,7 +1042,8 @@ class WebPlaybackTrack {
       // ignore: non_constant_identifier_names
       bool? is_playable,
       WebPlaybackAlbum? album,
-      List<WebPlaybackArtist>? artists});
+      List<WebPlaybackArtist>? artists,
+      WebLinkedFrom? linked_from});
 }
 
 /// Spotify playback album object
@@ -1058,6 +1062,19 @@ class WebPlaybackAlbum {
       {String? uri, String? name, List<WebPlaybackAlbumImage>? images});
 }
 
+/// Spotify playback album object
+@JS()
+@anonymous
+class WebLinkedFrom {
+  // ignore: public_member_api_docs
+  external String get uri;
+  // ignore: public_member_api_docs
+  external String get id;
+
+  // ignore: public_member_api_docs
+  external factory WebLinkedFrom({String? uri, String? id});
+}
+
 /// Spotify artist object
 @JS()
 @anonymous