From: Marcel van der Veldt Date: Sun, 2 Nov 2025 15:53:30 +0000 (+0100) Subject: Fiox Apple Music - encryption key is session bound X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=dd1dd467673a2d656d956b5be55c4315aa8ebdb2;p=music-assistant-server.git Fiox Apple Music - encryption key is session bound --- diff --git a/music_assistant/providers/apple_music/__init__.py b/music_assistant/providers/apple_music/__init__.py index ac376c9d..4aeba7ef 100644 --- a/music_assistant/providers/apple_music/__init__.py +++ b/music_assistant/providers/apple_music/__init__.py @@ -59,6 +59,7 @@ from music_assistant_models.media_items import ( from music_assistant_models.streamdetails import StreamDetails from pywidevine import PSSH, Cdm, Device, DeviceTypes from pywidevine.license_protocol_pb2 import WidevinePsshData +from shortuuid import uuid from music_assistant.controllers.cache import use_cache from music_assistant.helpers.app_vars import app_var @@ -263,6 +264,7 @@ class AppleMusicProvider(MusicProvider): _storefront: str | None = None _decrypt_client_id: bytes | None = None _decrypt_private_key: bytes | None = None + _session_id: str | None = None # rate limiter needs to be specified on provider-level, # so make it an instance attribute throttler = ThrottlerManager(rate_limit=1, period=2, initial_backoff=15) @@ -272,6 +274,9 @@ class AppleMusicProvider(MusicProvider): self._music_user_token = self.config.get_value(CONF_MUSIC_USER_TOKEN) self._music_app_token = self.config.get_value(CONF_MUSIC_APP_TOKEN) self._storefront = await self._get_user_storefront() + # create random session id to use for decryption keys + # to invalidate cached keys on each provider initialization + self._session_id = str(uuid()) async with aiofiles.open( os.path.join(WIDEVINE_BASE_PATH, DECRYPT_CLIENT_ID_FILENAME), "rb" ) as _file: @@ -523,7 +528,7 @@ class AppleMusicProvider(MusicProvider): return StreamDetails( item_id=item_id, provider=self.lookup_key, - audio_format=AudioFormat(content_type=ContentType.MP4, codec_type=ContentType.AAC), + audio_format=AudioFormat(ccontent_type=ContentType.MP4, codec_type=ContentType.AAC), stream_type=StreamType.ENCRYPTED_HTTP, decryption_key=await self._get_decryption_key(license_url, key_id, uri, item_id), path=stream_url, @@ -937,7 +942,10 @@ class AppleMusicProvider(MusicProvider): ) -> str: """Get the decryption key for a song.""" if decryption_key := await self.mass.cache.get( - key=item_id, provider=self.instance_id, category=CACHE_CATEGORY_DECRYPT_KEY + key=item_id, + provider=self.instance_id, + category=CACHE_CATEGORY_DECRYPT_KEY, + checksum=self._session_id, ): self.logger.debug("Decryption key for %s found in cache.", item_id) return decryption_key @@ -963,9 +971,10 @@ class AppleMusicProvider(MusicProvider): self.mass.cache.set( key=item_id, data=decryption_key, - expiration=1800, + expiration=3600, provider=self.instance_id, category=CACHE_CATEGORY_DECRYPT_KEY, + checksum=self._session_id, ) ) return decryption_key