[Deezer] Quality of life and refactor (#682)
authorJonathan <jonathan@bangert.dk>
Fri, 26 May 2023 22:21:50 +0000 (00:21 +0200)
committerGitHub <noreply@github.com>
Fri, 26 May 2023 22:21:50 +0000 (00:21 +0200)
* Bump deezer-python to 5.12.0

* Add fd to ffmpeg whitelisted protocols

* Add documentation

* Refactor, throttler limit, artist toptracks limit, no eval

* provider name based on username

* Revert "Bump deezer-python to 5.12.0"

This reverts commit a95449d3885daf91f71d49650250a953125a20b3.

---------

Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
music_assistant/server/helpers/audio.py
music_assistant/server/providers/deezer/__init__.py
music_assistant/server/providers/deezer/gw_client.py
music_assistant/server/providers/deezer/helpers.py
music_assistant/server/providers/deezer/manifest.json

index 8b80f3063ee703671ecb62cfa1e44e12c5077288..c83be685d046b751f44d4ed1e2e4f1bac8790e10 100644 (file)
@@ -757,7 +757,7 @@ async def _get_ffmpeg_args(
         "warning" if LOGGER.isEnabledFor(logging.DEBUG) else "quiet",
         "-ignore_unknown",
         "-protocol_whitelist",
-        "file,http,https,tcp,tls,crypto,pipe",  # support nested protocols (e.g. within playlist)
+        "file,http,https,tcp,tls,crypto,pipe,fd",  # support nested protocols (e.g. within playlist)
     ]
     # collect input args
     input_args = []
index fa9efe0167dea3e395e566528cfa4d7eed9f0cb5..bd1da036abf669f6a19a26b1c5aeae9ff8d362fc 100644 (file)
@@ -119,7 +119,7 @@ async def get_config_entries(
     )
 
 
-class DeezerProvider(MusicProvider):
+class DeezerProvider(MusicProvider):  # pylint: disable=W0223
     """Deezer provider support."""
 
     client: DeezerClient
@@ -127,9 +127,16 @@ class DeezerProvider(MusicProvider):
     creds: Credential
     _throttler: Throttler
 
+    @property
+    def name(self) -> str:
+        """Return (custom) friendly name for this provider instance."""
+        if client := getattr(self, "client", None):
+            return f"Deezer - {client.user.name}"
+        return super().name
+
     async def handle_setup(self) -> None:
         """Set up the Deezer provider."""
-        self._throttler = Throttler(rate_limit=4, period=1)
+        self._throttler = Throttler(rate_limit=50, period=5)
         self.creds = Credential(
             app_id=DEEZER_APP_ID,
             app_secret=DEEZER_APP_SECRET,
@@ -272,7 +279,7 @@ class DeezerProvider(MusicProvider):
     async def get_artist_toptracks(self, prov_artist_id: str) -> list[Track]:
         """Get top 25 tracks of an artist."""
         artist = await self.client.get_artist(artist_id=int(prov_artist_id))
-        top_tracks = (await self.client.get_artist_top(artist=artist))[:25]
+        top_tracks = await self.client.get_artist_top(artist=artist, limit=25)
         return [
             self.parse_track(track=track, user_country=self.gw_client.user_country)
             for track in top_tracks
@@ -342,7 +349,7 @@ class DeezerProvider(MusicProvider):
     async def add_playlist_tracks(self, prov_playlist_id: str, prov_track_ids: list[str]):
         """Add tra ck(s) to playlist."""
         await self.client.add_playlist_tracks(
-            playlist_id=prov_playlist_id, tracks=[eval(i) for i in prov_track_ids]
+            playlist_id=prov_playlist_id, tracks=[int(i) for i in prov_track_ids]
         )
 
     async def remove_playlist_tracks(
index 97e69896aedadee1c17769af50544821ddc70a0d..90edf0684f5af585a042956d3d6bc0a67ea0d29d 100644 (file)
@@ -20,8 +20,6 @@ GW_LIGHT_URL = "https://www.deezer.com/ajax/gw-light.php"
 class DeezerGWError(BaseException):
     """Exception type for GWClient related exceptions."""
 
-    pass
-
 
 class GWClient:
     """The GWClient class can be used to perform actions not being of the official API."""
@@ -100,12 +98,12 @@ class GWClient:
         csrf_token = self._gw_csrf_token if use_csrf_token else "null"
         if params is None:
             params = {}
-        p = {"api_version": "1.0", "api_token": csrf_token, "input": "3", "method": method}
-        p.update(params)
+        parameters = {"api_version": "1.0", "api_token": csrf_token, "input": "3", "method": method}
+        parameters |= params
         result = await self.session.request(
             http_method,
             GW_LIGHT_URL,
-            params=p,
+            params=parameters,
             timeout=30,
             json=args,
             headers={"User-Agent": USER_AGENT_HEADER},
index 01b96356b215e95a7e0a18e0bb2f2b3efef8c399..c858f76bc878209942a4ee2fae4656969722b73a 100644 (file)
@@ -278,11 +278,11 @@ class DeezerClient:
 
         return await asyncio.to_thread(_get_albums_by_artist)
 
-    async def get_artist_top(self, artist: deezer.Artist) -> deezer.PaginatedList:
+    async def get_artist_top(self, artist: deezer.Artist, limit: int = 25) -> deezer.PaginatedList:
         """Get top tracks by an artist."""
 
         def _get_artist_top():
-            return artist.get_top()
+            return artist.get_top()[:limit]
 
         return await asyncio.to_thread(_get_artist_top)
 
index 6cd8318c6bccef8f07f5410294d6c2d05b24b521..0084ef1abfcd4111ea85985856a39bd653d72af0 100644 (file)
@@ -4,6 +4,7 @@
   "name": "Deezer",
   "description": "Support for the Deezer streaming provider in Music Assistant.",
   "codeowners": ["@Un10ck3d",  "@micha91"],
+  "documentation": "https://github.com/orgs/music-assistant/discussions/1245",
   "requirements": ["deezer-python==5.12.0", "pycryptodome==3.18.0"],
   "multi_instance": true
 }