),
stream_type=StreamType.CUSTOM,
duration=int(song_data["DURATION"]),
- data={"url": url, "format": url_details["format"]},
+ # Due to track replacement, the track ID of the stream may be different from the ID
+ # that is stored. We need the proper track ID to decrypt the stream, so store it
+ # separately so we can use it later on.
+ data={"url": url, "format": url_details["format"], "track_id": song_data["SNG_ID"]},
size=int(song_data[f"FILESIZE_{url_details['format']}"]),
)
self, streamdetails: StreamDetails, seek_position: int = 0
) -> AsyncGenerator[bytes, None]:
"""Return the audio stream for the provider item."""
- blowfish_key = self.get_blowfish_key(streamdetails.item_id)
+ blowfish_key = self.get_blowfish_key(streamdetails.data["track_id"])
chunk_index = 0
timeout = ClientTimeout(total=0, connect=30, sock_read=600)
headers = {}
async def get_deezer_track_urls(self, track_id):
"""Get the URL for a given track id."""
dz_license = await self._get_license()
- song_data = await self.get_song_data(track_id)
- track_token = song_data["results"]["TRACK_TOKEN"]
+
+ song_results = await self.get_song_data(track_id)
+
+ song_data = song_results["results"]
+ # If the song has been replaced by a newer version, the old track will
+ # not play anymore. The data for the newer song is contained in a
+ # "FALLBACK" entry in the song data. So if that is available, use that
+ # instead so we get the right track token.
+ if "FALLBACK" in song_data:
+ song_data = song_data["FALLBACK"]
+
+ track_token = song_data["TRACK_TOKEN"]
url_data = {
"license_token": dz_license,
"media": [
msg = "Received an error from API"
raise DeezerGWError(msg, error)
- return result_json["data"][0]["media"][0], song_data["results"]
+ return result_json["data"][0]["media"][0], song_data
async def log_listen(
self, next_track: str | None = None, last_track: StreamDetails | None = None