From 1a4c44e33b1948f9c71789487d0a86be79ace1cc Mon Sep 17 00:00:00 2001 From: codey Date: Tue, 22 Apr 2025 09:18:15 -0400 Subject: [PATCH] restore album art functionality, cleanup needed --- endpoints/radio.py | 18 ++++------ utils/radio_util.py | 83 +++++++++++++++++++++++---------------------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/endpoints/radio.py b/endpoints/radio.py index 098499f..5f6c7b4 100644 --- a/endpoints/radio.py +++ b/endpoints/radio.py @@ -3,7 +3,6 @@ import traceback import time import random import asyncio -from utils import radio_util from .constructors import ( ValidRadioNextRequest, ValidRadioReshuffleRequest, @@ -11,8 +10,8 @@ from .constructors import ( ValidRadioQueueRemovalRequest, ValidRadioSongRequest, ValidRadioTypeaheadRequest, - RadioException, ) +from utils import radio_util from uuid import uuid4 as uuid from typing import Optional @@ -294,17 +293,14 @@ class Radio(FastAPI): try: background_tasks.add_task(self.radio_util.webhook_song_change, next) except Exception as e: + logging.info("radio_get_next Exception: %s", str(e)) traceback.print_exc() try: - if not await self.radio_util.get_album_art(file_path=next["file_path"]): - album_art = await self.radio_util.get_album_art( - file_path=next["file_path"] - ) - if album_art: - await self.radio_util.cache_album_art(next["id"], album_art) - else: - logging.debug("Could not read album art for %s", next["file_path"]) - except: + album_art = await self.radio_util.get_album_art(track_id=next["id"]) + if not album_art: + await self.radio_util.cache_album_art(next["id"], next["file_path"]) + except Exception as e: + logging.info("radio_get_next Exception: %s", str(e)) traceback.print_exc() return JSONResponse(content=next) diff --git a/utils/radio_util.py b/utils/radio_util.py index cb78c6f..c972261 100644 --- a/utils/radio_util.py +++ b/utils/radio_util.py @@ -10,6 +10,7 @@ import regex from regex import Pattern import aiosqlite as sqlite3 import gpt +import music_tag # type: ignore from endpoints.constructors import RadioException double_space: Pattern = regex.compile(r"\s{2,}") @@ -44,6 +45,9 @@ class RadioUtil: self.artist_genre_db_path: str = os.path.join( "/usr/local/share", "sqlite_dbs", "artist_genre_map.db" ) + self.album_art_db_path: str = os.path.join( + "/usr/local/share", "sqlite_dbs", "track_album_art.db" + ) self.active_playlist_name = "default" # not used self.active_playlist: list[dict] = [] self.now_playing: dict = { @@ -261,61 +265,58 @@ class RadioUtil: logging.info("Playlist load failed: %s", str(e)) traceback.print_exc() - async def cache_album_art(self, track_id: int, album_art: bytes) -> None: + async def cache_album_art(self, track_id: int, file_path: str) -> None: """ Cache Album Art to SQLite DB Args: track_id (int): Track ID to update - album_art (bytes): Album art data + file_path (str): Path to file, for artwork extraction Returns: None """ - return None # TODO: Album art is being reworked, temporarily return None - # try: - # async with sqlite3.connect(self.active_playlist_path, timeout=2) as db_conn: - # async with await db_conn.execute( - # "UPDATE tracks SET album_art = ? WHERE id = ?", - # ( - # album_art, - # track_id, - # ), - # ) as db_cursor: - # await db_conn.commit() - # except: - # traceback.print_exc() + try: + logging.info( + "cache_album_art: Attempting to store album art for track_id: %s", + track_id, + ) + tagger = music_tag.load_file(file_path) + album_art = tagger["artwork"].first.data + async with sqlite3.connect(self.album_art_db_path, timeout=2) as db_conn: + async with await db_conn.execute( + "INSERT OR IGNORE INTO album_art (track_id, album_art) VALUES(?, ?)", + ( + track_id, + album_art, + ), + ) as db_cursor: + await db_conn.commit() + except: + traceback.print_exc() - async def get_album_art( - self, track_id: Optional[int] = None, file_path: Optional[str] = None - ) -> Optional[bytes]: + async def get_album_art(self, track_id: int) -> Optional[bytes]: """ Get Album Art Args: - track_id (Optional[int]): Track ID to query (ignored if file_path is specified) - file_path (Optional[str]): file_path to query (ignored if track_id is specified) + track_id (int): Track ID to query Returns: - bytes + Optional[bytes] """ - return None # TODO: Album art is being reworked, temporarily return None - # try: - # async with sqlite3.connect(self.active_playlist_path, timeout=2) as db_conn: - # db_conn.row_factory = sqlite3.Row - # query: str = "SELECT album_art FROM tracks WHERE id = ?" - # query_params: tuple = (track_id,) + try: + async with sqlite3.connect(self.album_art_db_path, timeout=2) as db_conn: + db_conn.row_factory = sqlite3.Row + query: str = "SELECT album_art FROM album_art WHERE track_id = ?" + query_params: tuple = (track_id,) - # if file_path and not track_id: - # query = "SELECT album_art FROM tracks WHERE file_path = ?" - # query_params = (file_path,) - - # async with await db_conn.execute(query, query_params) as db_cursor: - # result: Optional[Union[sqlite3.Row, bool]] = ( - # await db_cursor.fetchone() - # ) - # if not result or not isinstance(result, sqlite3.Row): - # return None - # return result["album_art"] - # except: - # traceback.print_exc() - # return None + async with await db_conn.execute(query, query_params) as db_cursor: + result: Optional[Union[sqlite3.Row, bool]] = ( + await db_cursor.fetchone() + ) + if not result or not isinstance(result, sqlite3.Row): + return None + return result["album_art"] + except: + traceback.print_exc() + return None def get_queue_item_by_uuid(self, _uuid: str) -> Optional[tuple[int, dict]]: """