44import logging
55import re
66import time
7+ from json import JSONDecodeError
78
89import aiohttp
910
@@ -101,6 +102,17 @@ async def get_metadata(self, item_id: str, media_type: str) -> dict:
101102
102103 item ["albums" ] = album_resp ["items" ]
103104 item ["albums" ].extend (ep_resp ["items" ])
105+ elif media_type == "track" :
106+ try :
107+ resp = await self ._api_request (f"tracks/{ str (item_id )} /lyrics" , base = "https://listen.tidal.com/v1" )
108+
109+ # Use unsynced lyrics for MP3, synced for others (FLAC, OPUS, etc)
110+ if self .global_config .session .conversion .enabled and self .global_config .session .conversion .codec .upper () == "MP3" :
111+ item ["lyrics" ] = resp .get ("lyrics" ) or ''
112+ else :
113+ item ["lyrics" ] = resp .get ("subtitles" ) or resp .get ("lyrics" ) or ''
114+ except TypeError as e :
115+ logger .warning (f"Failed to get lyrics for { item_id } : { e } " )
104116
105117 logger .debug (item )
106118 return item
@@ -140,6 +152,9 @@ async def get_downloadable(self, track_id: str, quality: int):
140152 manifest = json .loads (base64 .b64decode (resp ["manifest" ]).decode ("utf-8" ))
141153 except KeyError :
142154 raise Exception (resp ["userMessage" ])
155+ except JSONDecodeError :
156+ logger .warning (f"Failed to get manifest for { track_id } . Retrying with lower quality." )
157+ return await self .get_downloadable (track_id , quality - 1 )
143158
144159 logger .debug (manifest )
145160 enc_key = manifest .get ("keyId" )
@@ -306,7 +321,7 @@ async def _api_post(self, url, data, auth: aiohttp.BasicAuth | None = None) -> d
306321 async with self .session .post (url , data = data , auth = auth ) as resp :
307322 return await resp .json ()
308323
309- async def _api_request (self , path : str , params = None ) -> dict :
324+ async def _api_request (self , path : str , params = None , base : str = BASE ) -> dict :
310325 """Handle Tidal API requests.
311326
312327 :param path:
@@ -321,7 +336,7 @@ async def _api_request(self, path: str, params=None) -> dict:
321336 params ["limit" ] = 100
322337
323338 async with self .rate_limiter :
324- async with self .session .get (f"{ BASE } /{ path } " , params = params ) as resp :
339+ async with self .session .get (f"{ base } /{ path } " , params = params ) as resp :
325340 if resp .status == 404 :
326341 logger .warning ("TIDAL: track not found" , resp )
327342 raise NonStreamableError ("TIDAL: Track not found" )
0 commit comments