From: Marvin Schenkel Date: Sun, 28 May 2023 10:54:35 +0000 (+0200) Subject: Fix YoutubeMusic UnplayableMedia issue (#686) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=84bac5b4b2d50f065968da8d15056ee84bbce017;p=music-assistant-server.git Fix YoutubeMusic UnplayableMedia issue (#686) * Fix retry of expired timestamp. * Fix merge conflicts. --- diff --git a/music_assistant/server/providers/ytmusic/__init__.py b/music_assistant/server/providers/ytmusic/__init__.py index dfa94059..e5c9733a 100644 --- a/music_assistant/server/providers/ytmusic/__init__.py +++ b/music_assistant/server/providers/ytmusic/__init__.py @@ -469,7 +469,7 @@ class YoutubeMusicProvider(MusicProvider): return tracks return [] - async def get_stream_details(self, item_id: str) -> StreamDetails: + async def get_stream_details(self, item_id: str, retry=True) -> StreamDetails: """Return the content details for the given track when it will be streamed.""" data = { "playbackContext": { @@ -480,6 +480,14 @@ class YoutubeMusicProvider(MusicProvider): track_obj = await self._post_data("player", data=data) stream_format = await self._parse_stream_format(track_obj) url = await self._parse_stream_url(stream_format=stream_format, item_id=item_id) + if not await self._is_valid_deciphered_url(url=url): + if not retry: + raise UnplayableMediaError(f"Could not resolve a valid URL for item '{item_id}'.") + self.logger.debug( + "Invalid playback URL encountered. Retrying with new signature timestamp." + ) + self._signature_timestamp = await self._get_signature_timestamp() + return await self.get_stream_details(item_id=item_id, retry=False) stream_details = StreamDetails( provider=self.instance_id, item_id=item_id, @@ -744,27 +752,11 @@ class YoutubeMusicProvider(MusicProvider): ciphered_signature=cipher_parts["s"], item_id=item_id ) url = cipher_parts["url"] + "&sig=" + signature - if not await self._is_valid_deciphered_url(url=url): - raise UnplayableMediaError(f"Obtained invalid URL for item '{item_id}'.") - # Disable caching for now. - # Verify if URL is playable. If not, obtain a new cipher and try again. - # if not await self._is_valid_deciphered_url(url=url): - # if retry > 50: - # raise UnplayableMediaError( - # f"Cannot obtain a valid URL for item '{item_id}' after renewing - # cipher {retry} times." - # ) - # self.logger.debug("Cipher expired. Obtaining new Cipher.") - # self._cipher = None - # return await self._parse_stream_url( - # stream_format=stream_format, item_id=item_id, retry=retry + 1 - # ) elif stream_format.get("url"): # Non secured URL url = stream_format.get("url") else: - # TODO: Remove, this is for debugging purposes - self.logger.warning( + self.logger.debug( f"Something went wrong. No URL found for stream format {stream_format}" ) return url @@ -780,21 +772,16 @@ class YoutubeMusicProvider(MusicProvider): cipher = pytube.cipher.Cipher(js=ytm_js) return cipher - cipher = await asyncio.to_thread(_decipher) - return cipher.get_signature(ciphered_signature) - - # if not self._cipher: - # self.logger.debug("Grabbing a new cipher.") - # self._cipher = await asyncio.to_thread(_decipher) - # self.logger.debug(f"Cipher is {self._cipher}") - # return self._cipher.get_signature(ciphered_signature) + if not self._cipher: + self._cipher = await asyncio.to_thread(_decipher) + return self._cipher.get_signature(ciphered_signature) async def _is_valid_deciphered_url(self, url: str) -> bool: """Verify whether the URL has been deciphered using a valid cipher.""" async with self.mass.http_session.head(url) as response: - # TODO: Remove, this is for debugging purposes + # TODO: Remove after 403 issue has been verified as fixed if response.status != 200: - self.logger.warn(f"Deciphered URL HTTP status: {response.status}") + self.logger.debug(f"Deciphered URL HTTP status: {response.status}") return response.status != 403 def _get_item_mapping(self, media_type: MediaType, key: str, name: str) -> ItemMapping: diff --git a/music_assistant/server/providers/ytmusic/manifest.json b/music_assistant/server/providers/ytmusic/manifest.json index 44defd14..0bbe9174 100644 --- a/music_assistant/server/providers/ytmusic/manifest.json +++ b/music_assistant/server/providers/ytmusic/manifest.json @@ -4,7 +4,7 @@ "name": "YouTube Music", "description": "Support for the YouTube Music streaming provider in Music Assistant.", "codeowners": ["@MarvinSchenkel"], - "requirements": ["ytmusicapi==1.0.2", "git+https://github.com/pytube/pytube.git@refs/pull/1501/head"], + "requirements": ["ytmusicapi==1.0.0", "git+https://github.com/pytube/pytube.git@refs/pull/1501/head"], "documentation": "https://github.com/music-assistant/hass-music-assistant/discussions/606", "multi_instance": true } diff --git a/requirements_all.txt b/requirements_all.txt index 80a0acc7..92fb5a6f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -29,5 +29,5 @@ shortuuid==1.0.11 soco==0.29.1 unidecode==1.3.6 xmltodict==0.13.0 -ytmusicapi==1.0.2 +ytmusicapi==1.0.0 zeroconf==0.62.0