diff --git a/streamrip/client/deezer.py b/streamrip/client/deezer.py index 056463f9..1b6e4440 100644 --- a/streamrip/client/deezer.py +++ b/streamrip/client/deezer.py @@ -86,8 +86,38 @@ async def get_track(self, item_id: str) -> dict: album_metadata["track_total"] = len(album_tracks["data"]) item["album"] = album_metadata + if self.global_config.session.downloads.lyrics: + try: + lyrics_resp = await asyncio.to_thread( + self.client.gw.get_track_lyrics, item_id + ) + # Use unsynced lyrics for MP3, synced for others (FLAC, OPUS, etc) + conversion = self.global_config.session.conversion + if conversion.enabled and conversion.codec.upper() == "MP3": + item["lyrics"] = lyrics_resp.get("LYRICS_TEXT") or "" + else: + item["lyrics"] = self._format_synced_lyrics( + lyrics_resp.get("LYRICS_SYNC_JSON") + ) or (lyrics_resp.get("LYRICS_TEXT") or "") + except Exception as e: + logger.warning(f"Failed to get lyrics for {item_id}: {e}") + return item + @staticmethod + def _format_synced_lyrics(sync_json: list[dict] | None) -> str: + """Convert Deezer's LYRICS_SYNC_JSON into LRC-formatted text.""" + if not sync_json: + return "" + lines = [] + for entry in sync_json: + timestamp = entry.get("lrc_timestamp") + if timestamp: + lines.append(f"{timestamp}{entry.get('line', '')}") + else: + lines.append("") + return "\n".join(lines) + async def get_album(self, item_id: str) -> dict: album_metadata, album_tracks = await asyncio.gather( asyncio.to_thread(self.client.api.get_album, item_id), diff --git a/streamrip/client/tidal.py b/streamrip/client/tidal.py index 92455d20..bbe569b7 100644 --- a/streamrip/client/tidal.py +++ b/streamrip/client/tidal.py @@ -110,7 +110,7 @@ async def get_metadata(self, item_id: str, media_type: str) -> dict: item["albums"] = album_resp["items"] item["albums"].extend(ep_resp["items"]) - elif media_type == "track": + elif media_type == "track" and self.global_config.session.downloads.lyrics: try: resp = await self._api_request( f"tracks/{item_id!s}/lyrics", base="https://tidal.com/v1" diff --git a/streamrip/config.py b/streamrip/config.py index bafa5687..5ddaf4b8 100644 --- a/streamrip/config.py +++ b/streamrip/config.py @@ -203,6 +203,9 @@ class DownloadsConfig: # Verify SSL certificates for API connections # Set to false if you encounter SSL certificate verification errors (not recommended) verify_ssl: bool + # Download and embed lyrics (currently supported for Deezer and Tidal) + # Defaulted so configs written before this option don't fail to load + lyrics: bool = True @dataclass(slots=True) diff --git a/streamrip/config.toml b/streamrip/config.toml index 029115bd..6d1bc9e3 100644 --- a/streamrip/config.toml +++ b/streamrip/config.toml @@ -20,6 +20,8 @@ requests_per_minute = 60 # Verify SSL certificates for API connections # Set to false if you encounter SSL certificate verification errors (not recommended) verify_ssl = true +# Download and embed lyrics (currently supported for Deezer and Tidal) +lyrics = true [qobuz] # 1: 320kbps MP3, 2: 16/44.1, 3: 24/<=96, 4: 24/>=96 diff --git a/streamrip/metadata/track.py b/streamrip/metadata/track.py index bea7a9b0..88ee4719 100644 --- a/streamrip/metadata/track.py +++ b/streamrip/metadata/track.py @@ -99,6 +99,7 @@ def from_deezer(cls, album: AlbumMetadata, resp) -> TrackMetadata | None: tracknumber = typed(resp["track_position"], int) discnumber = typed(resp["disk_number"], int) composer = None + lyrics = resp.get("lyrics", "") info = TrackInfo( id=track_id, quality=album.info.quality, @@ -116,6 +117,7 @@ def from_deezer(cls, album: AlbumMetadata, resp) -> TrackMetadata | None: discnumber=discnumber, composer=composer, isrc=isrc, + lyrics=lyrics, ) @classmethod diff --git a/tests/test_config.py b/tests/test_config.py index 44742b95..5c916f3f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -164,6 +164,7 @@ def test_sample_config_data_fields(sample_config_data): max_connections=6, requests_per_minute=60, verify_ssl=True, + lyrics=True, ), qobuz=QobuzConfig( use_auth_token=False, diff --git a/tests/test_config.toml b/tests/test_config.toml index a33a1864..d0556b45 100644 --- a/tests/test_config.toml +++ b/tests/test_config.toml @@ -20,6 +20,8 @@ requests_per_minute = 60 # Verify SSL certificates for API connections # Set to false if you encounter SSL certificate verification errors (not recommended) verify_ssl = true +# Download and embed lyrics (currently supported for Deezer and Tidal) +lyrics = true [qobuz] # 1: 320kbps MP3, 2: 16/44.1, 3: 24/<=96, 4: 24/>=96