Implement WebSocket support for real-time radio updates and enhance LRC fetching logic
This commit is contained in:
@@ -4,6 +4,7 @@ import time
|
||||
import datetime
|
||||
import os
|
||||
import random
|
||||
import asyncio
|
||||
from uuid import uuid4 as uuid
|
||||
from typing import Union, Optional, Iterable
|
||||
from aiohttp import ClientSession, ClientTimeout
|
||||
@@ -478,10 +479,11 @@ class RadioUtil:
|
||||
playlist, len(self.active_playlist[playlist]),
|
||||
)
|
||||
|
||||
"""Loading Complete"""
|
||||
logging.info(f"Skipping: {playlist}")
|
||||
await self._ls_skip(playlist) # Request skip from LS to bring streams current
|
||||
|
||||
"""Loading Complete"""
|
||||
# Request skip from LS to bring streams current
|
||||
for playlist in self.playlists:
|
||||
logging.info("Skipping: %s", playlist)
|
||||
await self._ls_skip(playlist)
|
||||
self.playlists_loaded = True
|
||||
except Exception as e:
|
||||
logging.info("Playlist load failed: %s", str(e))
|
||||
|
@@ -22,12 +22,12 @@ class MetadataFetchError(Exception):
|
||||
# Suppress all logging output from this module and its children
|
||||
for name in [__name__, "utils.sr_wrapper"]:
|
||||
logger = logging.getLogger(name)
|
||||
logger.setLevel(logging.CRITICAL)
|
||||
logger.setLevel(logging.INFO) # Temporarily set to INFO for debugging LRC
|
||||
logger.propagate = False
|
||||
for handler in logger.handlers:
|
||||
handler.setLevel(logging.CRITICAL)
|
||||
handler.setLevel(logging.INFO)
|
||||
# Also set the root logger to CRITICAL as a last resort (may affect global logging)
|
||||
logging.getLogger().setLevel(logging.CRITICAL)
|
||||
# logging.getLogger().setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
load_dotenv()
|
||||
@@ -746,3 +746,55 @@ class SRUtil:
|
||||
except Exception as e:
|
||||
logging.critical("Error: %s", str(e))
|
||||
return False
|
||||
|
||||
async def get_lrc_by_track_id(self, track_id: int) -> Optional[str]:
|
||||
"""Get LRC lyrics by track ID."""
|
||||
logging.info(f"SR: Fetching metadata for track ID {track_id}")
|
||||
metadata = await self.get_metadata_by_track_id(track_id)
|
||||
lrc = metadata.get('lyrics') if metadata else None
|
||||
logging.info(f"SR: LRC {'found' if lrc else 'not found'}")
|
||||
return lrc
|
||||
|
||||
|
||||
|
||||
async def get_lrc_by_artist_song(
|
||||
self, artist: str, song: str, album: Optional[str] = None, duration: Optional[int] = None
|
||||
) -> Optional[str]:
|
||||
"""Get LRC lyrics by artist and song, optionally filtering by album and duration."""
|
||||
logging.info(f"SR: Searching tracks for {artist} - {song}")
|
||||
tracks = await self.get_tracks_by_artist_song(artist, song)
|
||||
logging.info(f"SR: Found {len(tracks) if tracks else 0} tracks")
|
||||
if not tracks:
|
||||
return None
|
||||
|
||||
# Filter by album if provided
|
||||
if album:
|
||||
tracks = [
|
||||
t for t in tracks
|
||||
if t.get('album', {}).get('title', '').lower() == album.lower()
|
||||
]
|
||||
|
||||
if not tracks:
|
||||
return None
|
||||
|
||||
# If duration provided, select the track with closest duration match
|
||||
if duration is not None:
|
||||
tracks_with_diff = [
|
||||
(t, abs(t.get('duration', 0) - duration)) for t in tracks
|
||||
]
|
||||
tracks_with_diff.sort(key=lambda x: x[1])
|
||||
best_track, min_diff = tracks_with_diff[0]
|
||||
logging.info(f"SR: Best match duration diff: {min_diff}s")
|
||||
# If the closest match is more than 5 seconds off, consider no match
|
||||
if min_diff > 5:
|
||||
logging.info("SR: Duration diff too large, no match")
|
||||
return None
|
||||
else:
|
||||
best_track = tracks[0]
|
||||
|
||||
track_id = best_track.get('id')
|
||||
logging.info(f"SR: Using track ID {track_id}")
|
||||
if not track_id:
|
||||
return None
|
||||
|
||||
return await self.get_lrc_by_track_id(track_id)
|
||||
|
Reference in New Issue
Block a user