mirror of
https://github.com/nathom/streamrip.git
synced 2025-06-03 16:48:44 -04:00
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:
parent
1aad9f0f65
commit
4c9baf9bb0
3 changed files with 22 additions and 2 deletions
|
@ -4,6 +4,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
from json import JSONDecodeError
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
@ -101,6 +102,17 @@ class TidalClient(Client):
|
||||||
|
|
||||||
item["albums"] = album_resp["items"]
|
item["albums"] = album_resp["items"]
|
||||||
item["albums"].extend(ep_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)
|
logger.debug(item)
|
||||||
return item
|
return item
|
||||||
|
@ -140,6 +152,9 @@ class TidalClient(Client):
|
||||||
manifest = json.loads(base64.b64decode(resp["manifest"]).decode("utf-8"))
|
manifest = json.loads(base64.b64decode(resp["manifest"]).decode("utf-8"))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise Exception(resp["userMessage"])
|
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)
|
logger.debug(manifest)
|
||||||
enc_key = manifest.get("keyId")
|
enc_key = manifest.get("keyId")
|
||||||
|
@ -306,7 +321,7 @@ class TidalClient(Client):
|
||||||
async with self.session.post(url, data=data, auth=auth) as resp:
|
async with self.session.post(url, data=data, auth=auth) as resp:
|
||||||
return await resp.json()
|
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.
|
"""Handle Tidal API requests.
|
||||||
|
|
||||||
:param path:
|
:param path:
|
||||||
|
@ -321,7 +336,7 @@ class TidalClient(Client):
|
||||||
params["limit"] = 100
|
params["limit"] = 100
|
||||||
|
|
||||||
async with self.rate_limiter:
|
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:
|
if resp.status == 404:
|
||||||
logger.warning("TIDAL: track not found", resp)
|
logger.warning("TIDAL: track not found", resp)
|
||||||
raise NonStreamableError("TIDAL: Track not found")
|
raise NonStreamableError("TIDAL: Track not found")
|
||||||
|
|
|
@ -183,6 +183,7 @@ class Container(Enum):
|
||||||
"discnumber",
|
"discnumber",
|
||||||
"composer",
|
"composer",
|
||||||
"isrc",
|
"isrc",
|
||||||
|
"lyrics",
|
||||||
}
|
}
|
||||||
if attr in in_trackmetadata:
|
if attr in in_trackmetadata:
|
||||||
if attr == "album":
|
if attr == "album":
|
||||||
|
|
|
@ -32,6 +32,7 @@ class TrackMetadata:
|
||||||
discnumber: int
|
discnumber: int
|
||||||
composer: str | None
|
composer: str | None
|
||||||
isrc: str | None = None
|
isrc: str | None = None
|
||||||
|
lyrics: str | None = ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_qobuz(cls, album: AlbumMetadata, resp: dict) -> TrackMetadata | None:
|
def from_qobuz(cls, album: AlbumMetadata, resp: dict) -> TrackMetadata | None:
|
||||||
|
@ -170,6 +171,8 @@ class TrackMetadata:
|
||||||
else:
|
else:
|
||||||
artist = track["artist"]["name"]
|
artist = track["artist"]["name"]
|
||||||
|
|
||||||
|
lyrics = track.get("lyrics", "")
|
||||||
|
|
||||||
quality_map: dict[str, int] = {
|
quality_map: dict[str, int] = {
|
||||||
"LOW": 0,
|
"LOW": 0,
|
||||||
"HIGH": 1,
|
"HIGH": 1,
|
||||||
|
@ -209,6 +212,7 @@ class TrackMetadata:
|
||||||
discnumber=discnumber,
|
discnumber=discnumber,
|
||||||
composer=None,
|
composer=None,
|
||||||
isrc=isrc,
|
isrc=isrc,
|
||||||
|
lyrics=lyrics
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue