Added support for Tidal lyrics and fixed parsing error when preferred quality too high (#736)

* fixed json error when preferred quality not found for track

* added tidal lyrics support

* improve mp3 lyrics support

* handle error when there are no lyrics (404)

* change error to warning
This commit is contained in:
Mathieu Broillet 2024-12-07 07:41:47 +01:00 committed by GitHub
parent 1aad9f0f65
commit 4c9baf9bb0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 2 deletions

View file

@ -4,6 +4,7 @@ import json
import logging
import re
import time
from json import JSONDecodeError
import aiohttp
@ -101,6 +102,17 @@ class TidalClient(Client):
item["albums"] = album_resp["items"]
item["albums"].extend(ep_resp["items"])
elif media_type == "track":
try:
resp = await self._api_request(f"tracks/{str(item_id)}/lyrics", base="https://listen.tidal.com/v1")
# Use unsynced lyrics for MP3, synced for others (FLAC, OPUS, etc)
if self.global_config.session.conversion.enabled and self.global_config.session.conversion.codec.upper() == "MP3":
item["lyrics"] = resp.get("lyrics") or ''
else:
item["lyrics"] = resp.get("subtitles") or resp.get("lyrics") or ''
except TypeError as e:
logger.warning(f"Failed to get lyrics for {item_id}: {e}")
logger.debug(item)
return item
@ -140,6 +152,9 @@ class TidalClient(Client):
manifest = json.loads(base64.b64decode(resp["manifest"]).decode("utf-8"))
except KeyError:
raise Exception(resp["userMessage"])
except JSONDecodeError:
logger.warning(f"Failed to get manifest for {track_id}. Retrying with lower quality.")
return await self.get_downloadable(track_id, quality - 1)
logger.debug(manifest)
enc_key = manifest.get("keyId")
@ -306,7 +321,7 @@ class TidalClient(Client):
async with self.session.post(url, data=data, auth=auth) as resp:
return await resp.json()
async def _api_request(self, path: str, params=None) -> dict:
async def _api_request(self, path: str, params=None, base: str = BASE) -> dict:
"""Handle Tidal API requests.
:param path:
@ -321,7 +336,7 @@ class TidalClient(Client):
params["limit"] = 100
async with self.rate_limiter:
async with self.session.get(f"{BASE}/{path}", params=params) as resp:
async with self.session.get(f"{base}/{path}", params=params) as resp:
if resp.status == 404:
logger.warning("TIDAL: track not found", resp)
raise NonStreamableError("TIDAL: Track not found")

View file

@ -183,6 +183,7 @@ class Container(Enum):
"discnumber",
"composer",
"isrc",
"lyrics",
}
if attr in in_trackmetadata:
if attr == "album":

View file

@ -32,6 +32,7 @@ class TrackMetadata:
discnumber: int
composer: str | None
isrc: str | None = None
lyrics: str | None = ""
@classmethod
def from_qobuz(cls, album: AlbumMetadata, resp: dict) -> TrackMetadata | None:
@ -170,6 +171,8 @@ class TrackMetadata:
else:
artist = track["artist"]["name"]
lyrics = track.get("lyrics", "")
quality_map: dict[str, int] = {
"LOW": 0,
"HIGH": 1,
@ -209,6 +212,7 @@ class TrackMetadata:
discnumber=discnumber,
composer=None,
isrc=isrc,
lyrics=lyrics
)
@classmethod