reformat / resolves #32

This commit is contained in:
codey 2025-04-26 17:17:42 -04:00
parent 4c5d2b6943
commit 6c29c6fede
9 changed files with 74 additions and 52 deletions

View File

@ -292,6 +292,7 @@ class ValidRadioQueueRequest(BaseModel):
start: Optional[int] = 0 start: Optional[int] = 0
search: Optional[str] = None search: Optional[str] = None
class ValidRadioQueueShiftRequest(BaseModel): class ValidRadioQueueShiftRequest(BaseModel):
""" """
- **key**: API Key - **key**: API Key
@ -311,4 +312,4 @@ class ValidRadioQueueRemovalRequest(BaseModel):
""" """
key: str key: str
uuid: str uuid: str

View File

@ -84,9 +84,7 @@ class KarmaDB:
"INSERT INTO karma(keyword, score, last_change) VALUES(?, ?, ?)" "INSERT INTO karma(keyword, score, last_change) VALUES(?, ?, ?)"
) )
friendly_flag: str = "++" if not flag else "--" friendly_flag: str = "++" if not flag else "--"
audit_message: str = ( audit_message: str = f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}"
f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}"
)
audit_query: str = ( audit_query: str = (
"INSERT INTO karma_audit(impacted_keyword, comment) VALUES(?, ?)" "INSERT INTO karma_audit(impacted_keyword, comment) VALUES(?, ?)"
) )

View File

@ -115,7 +115,7 @@ class LyricSearch(FastAPI):
if data.src.upper() not in self.acceptable_request_sources: if data.src.upper() not in self.acceptable_request_sources:
await self.notifier.send( await self.notifier.send(
f"ERROR @ {__file__.rsplit("/", maxsplit=1)[-1]}", f"ERROR @ {__file__.rsplit('/', maxsplit=1)[-1]}",
f"Unknown request source: {data.src}", f"Unknown request source: {data.src}",
) )
return JSONResponse( return JSONResponse(

View File

@ -97,8 +97,7 @@ class Radio(FastAPI):
}, },
) )
except Exception as e: except Exception as e:
logging.debug("radio_skip Exception: %s", logging.debug("radio_skip Exception: %s", str(e))
str(e))
traceback.print_exc() traceback.print_exc()
return JSONResponse( return JSONResponse(
status_code=500, status_code=500,
@ -122,16 +121,22 @@ class Radio(FastAPI):
return JSONResponse(content={"ok": True}) return JSONResponse(content={"ok": True})
async def radio_get_queue( async def radio_get_queue(
self, request: Request, data: ValidRadioQueueRequest, self,
request: Request,
data: ValidRadioQueueRequest,
) -> JSONResponse: ) -> JSONResponse:
""" """
Get current play queue (paged, 20 results per page) Get current play queue (paged, 20 results per page)
""" """
start: int = int(data.start) start: int = int(data.start)
end: int = start+20 end: int = start + 20
logging.info("queue request with start pos: %s & end pos: %s", search: Optional[str] = data.search
start, end) logging.info("queue request with start pos: %s & end pos: %s", start, end)
queue_full: list = self.radio_util.active_playlist
if not search:
queue_full: list = self.radio_util.active_playlist
else:
queue_full: list = self.radio_util.datatables_search(data.search)
queue: list = queue_full[start:end] queue: list = queue_full[start:end]
logging.info("queue length: %s", len(queue)) logging.info("queue length: %s", len(queue))
queue_out: list[dict] = [] queue_out: list[dict] = []
@ -152,7 +157,9 @@ class Radio(FastAPI):
out_json = { out_json = {
"draw": data.draw, "draw": data.draw,
"recordsTotal": len(queue_full), "recordsTotal": len(queue_full),
"recordsFiltered": len(queue_full) if not data.search else len(queue_full), # todo: implement search "recordsFiltered": (
len(queue_full) if not data.search else len(queue_full)
), # todo: implement search
"items": queue_out, "items": queue_out,
} }
return JSONResponse(content=out_json) return JSONResponse(content=out_json)
@ -239,8 +246,7 @@ class Radio(FastAPI):
) )
return Response(content=album_art, media_type="image/png") return Response(content=album_art, media_type="image/png")
except Exception as e: except Exception as e:
logging.debug("album_art_handler Exception: %s", logging.debug("album_art_handler Exception: %s", str(e))
str(e))
traceback.print_exc() traceback.print_exc()
return RedirectResponse( return RedirectResponse(
url="https://codey.lol/images/radio_art_default.jpg", status_code=302 url="https://codey.lol/images/radio_art_default.jpg", status_code=302

View File

@ -113,9 +113,7 @@ class Transcriptions(FastAPI):
db_path: Union[str, LiteralString] = os.path.join( db_path: Union[str, LiteralString] = os.path.join(
"/usr/local/share", "sqlite_dbs", "sp.db" "/usr/local/share", "sqlite_dbs", "sp.db"
) )
db_query: str = ( db_query: str = """SELECT ("S" || Season || "E" || Episode || " " || Title), Character, Line FROM SP_DAT WHERE ID = ?"""
"""SELECT ("S" || Season || "E" || Episode || " " || Title), Character, Line FROM SP_DAT WHERE ID = ?"""
)
case 1: case 1:
db_path = os.path.join("/usr/local/share", "sqlite_dbs", "futur.db") db_path = os.path.join("/usr/local/share", "sqlite_dbs", "futur.db")
db_query = """SELECT ("S" || EP_S || "E" || EP_EP || " " || EP_TITLE || "<br><em>Opener: " || EP_OPENER || "</em>"), EP_LINE_SPEAKER, EP_LINE FROM clean_dialog WHERE EP_ID = ? ORDER BY LINE_ID ASC""" db_query = """SELECT ("S" || EP_S || "E" || EP_EP || " " || EP_TITLE || "<br><em>Opener: " || EP_OPENER || "</em>"), EP_LINE_SPEAKER, EP_LINE FROM clean_dialog WHERE EP_ID = ? ORDER BY LINE_ID ASC"""

View File

@ -78,7 +78,7 @@ class Aggregate:
traceback.print_exc() traceback.print_exc()
logging.info("Could not increment redis failed counter: %s", str(e)) logging.info("Could not increment redis failed counter: %s", str(e))
self.notifier.send( self.notifier.send(
f"ERROR @ {__file__.rsplit("/", maxsplit=1)[-1]}", f"ERROR @ {__file__.rsplit('/', maxsplit=1)[-1]}",
f"Could not increment redis failed counter: {str(e)}", f"Could not increment redis failed counter: {str(e)}",
) )
return search_result return search_result

View File

@ -89,10 +89,8 @@ class Cache:
logging.debug( logging.debug(
"Checking whether %s is already stored", artistsong.replace("\n", " - ") "Checking whether %s is already stored", artistsong.replace("\n", " - ")
) )
check_query: str = ( check_query: str = 'SELECT id, artist, song FROM lyrics WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\
'SELECT id, artist, song FROM lyrics WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\
<= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 1' <= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 1'
)
artistsong_split = artistsong.split("\n", maxsplit=1) artistsong_split = artistsong.split("\n", maxsplit=1)
artist = artistsong_split[0].lower() artist = artistsong_split[0].lower()
song = artistsong_split[1].lower() song = artistsong_split[1].lower()
@ -132,7 +130,7 @@ class Cache:
f"cache::store >> {str(e)}", f"cache::store >> {str(e)}",
) )
await self.notifier.send( await self.notifier.send(
f"ERROR @ {__file__.rsplit("/", maxsplit=1)[-1]}", f"ERROR @ {__file__.rsplit('/', maxsplit=1)[-1]}",
f"cache::store >> `{str(e)}`", f"cache::store >> `{str(e)}`",
) )
@ -213,8 +211,10 @@ class Cache:
lyrics = regex.sub(r"(<br>|\n|\r\n)", " / ", lyr_result.lyrics.strip()) lyrics = regex.sub(r"(<br>|\n|\r\n)", " / ", lyr_result.lyrics.strip())
lyrics = regex.sub(r"\s{2,}", " ", lyrics) lyrics = regex.sub(r"\s{2,}", " ", lyrics)
insert_query = "INSERT INTO lyrics (src, date_retrieved, artist, song, artistsong, confidence, lyrics)\ insert_query = (
"INSERT INTO lyrics (src, date_retrieved, artist, song, artistsong, confidence, lyrics)\
VALUES(?, ?, ?, ?, ?, ?, ?)" VALUES(?, ?, ?, ?, ?, ?, ?)"
)
params = ( params = (
lyr_result.src, lyr_result.src,
time.time(), time.time(),
@ -258,10 +258,8 @@ class Cache:
if artist == "!" and song == "!": if artist == "!" and song == "!":
random_search = True random_search = True
search_query: str = ( search_query: str = "SELECT id, artist, song, lyrics, src, confidence\
"SELECT id, artist, song, lyrics, src, confidence\
FROM lyrics ORDER BY RANDOM() LIMIT 1" FROM lyrics ORDER BY RANDOM() LIMIT 1"
)
logging.info("Searching %s - %s on %s", artist, song, self.label) logging.info("Searching %s - %s on %s", artist, song, self.label)
@ -319,11 +317,9 @@ class Cache:
self.cache_pre_query self.cache_pre_query
) as _db_cursor: ) as _db_cursor:
if not random_search: if not random_search:
search_query: str = ( search_query: str = 'SELECT id, artist, song, lyrics, src, confidence FROM lyrics\
'SELECT id, artist, song, lyrics, src, confidence FROM lyrics\
WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\ WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\
<= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 10' <= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 10'
)
search_params: tuple = ( search_params: tuple = (
artist.strip(), artist.strip(),
song.strip(), song.strip(),

View File

@ -31,7 +31,6 @@ class LastFM:
] ]
async with ClientSession() as session: async with ClientSession() as session:
async with await session.get( async with await session.get(
self.api_base_url, self.api_base_url,
params=request_params, params=request_params,

View File

@ -11,9 +11,11 @@ from regex import Pattern
import sqlite3 import sqlite3
import gpt import gpt
import music_tag # type: ignore import music_tag # type: ignore
from rapidfuzz import fuzz
from endpoints.constructors import RadioException from endpoints.constructors import RadioException
double_space: Pattern = regex.compile(r"\s{2,}") double_space: Pattern = regex.compile(r"\s{2,}")
non_alnum: Pattern = regex.compile(r"[^a-zA-Z0-9]")
""" """
TODO: TODO:
@ -110,7 +112,36 @@ class RadioUtil:
out_result = [str(r["artistsong"]) for r in result] out_result = [str(r["artistsong"]) for r in result]
return out_result return out_result
async def search_playlist( def datatables_search(self, filter: str) -> Optional[list[dict]]:
"""DataTables Search
Args:
filter (str): The filter query to fuzzy match with
Returns:
list[str]: List of matching playlist items (if any are found)
"""
filter = filter.strip().lower()
matched: list[dict] = []
for item in self.active_playlist:
artist: str = item.get("artist", None)
song: str = item.get("song", None)
artistsong: str = item.get("artistsong", None)
album: str = item.get("album", None)
if not artist or not song or not artistsong:
continue
if non_alnum.sub("", filter) in non_alnum.sub("", artistsong).lower():
matched.append(item)
continue
if (
fuzz.ratio(filter, artist) >= 85
or fuzz.ratio(filter, song) >= 85
or fuzz.ratio(filter, album) >= 85
):
matched.append(item)
return matched
def search_playlist(
self, self,
artistsong: Optional[str] = None, artistsong: Optional[str] = None,
artist: Optional[str] = None, artist: Optional[str] = None,
@ -130,11 +161,9 @@ class RadioUtil:
if not artistsong and (not artist or not song): if not artistsong and (not artist or not song):
raise RadioException("No query provided") raise RadioException("No query provided")
try: try:
search_query: str = ( search_query: str = 'SELECT id, artist, song, (artist || " - " || song) AS artistsong, album, file_path, duration FROM tracks\
'SELECT id, artist, song, (artist || " - " || song) AS artistsong, album, file_path, duration FROM tracks\
WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\ WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\
<= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 1' <= 410 ORDER BY editdist3((lower(artist) || " " || lower(song)), ?) ASC LIMIT 1'
)
if artistsong: if artistsong:
artistsong_split: list = artistsong.split(" - ", maxsplit=1) artistsong_split: list = artistsong.split(" - ", maxsplit=1)
(search_artist, search_song) = tuple(artistsong_split) (search_artist, search_song) = tuple(artistsong_split)
@ -153,9 +182,7 @@ class RadioUtil:
for ext in self.sqlite_exts: for ext in self.sqlite_exts:
db_conn.load_extension(ext) db_conn.load_extension(ext)
db_conn.row_factory = sqlite3.Row db_conn.row_factory = sqlite3.Row
db_cursor = db_conn.execute( db_cursor = db_conn.execute(search_query, search_params)
search_query, search_params
)
result: Optional[sqlite3.Row | bool] = db_cursor.fetchone() result: Optional[sqlite3.Row | bool] = db_cursor.fetchone()
if not result or not isinstance(result, sqlite3.Row): if not result or not isinstance(result, sqlite3.Row):
return False return False
@ -178,7 +205,7 @@ class RadioUtil:
traceback.print_exc() traceback.print_exc()
return False return False
async def add_genre(self, artist: str, genre: str) -> bool: def add_genre(self, artist: str, genre: str) -> bool:
""" """
Add artist/genre pairing to DB Add artist/genre pairing to DB
Args: Args:
@ -213,7 +240,7 @@ class RadioUtil:
traceback.print_exc() traceback.print_exc()
return False return False
async def add_genres(self, pairs: list[dict[str, str]]) -> bool: def add_genres(self, pairs: list[dict[str, str]]) -> bool:
""" """
(BATCH) Add artist/genre pairings to DB (BATCH) Add artist/genre pairings to DB
Expects list of dicts comprised of artist name (key), genre (value) Expects list of dicts comprised of artist name (key), genre (value)
@ -228,9 +255,7 @@ class RadioUtil:
for pair in pairs: for pair in pairs:
try: try:
artist, genre = pair artist, genre = pair
query: str = ( query: str = "INSERT OR IGNORE INTO artist_genre (artist, genre) VALUES(?, ?)"
"INSERT OR IGNORE INTO artist_genre (artist, genre) VALUES(?, ?)"
)
params: tuple[str, str] = (artist, genre) params: tuple[str, str] = (artist, genre)
res = _db.execute(query, params) res = _db.execute(query, params)
if isinstance(res.lastrowid, int): if isinstance(res.lastrowid, int):
@ -411,11 +436,13 @@ class RadioUtil:
if isinstance(db_cursor.lastrowid, int): if isinstance(db_cursor.lastrowid, int):
db_conn.commit() db_conn.commit()
else: else:
logging.debug("No row inserted for track_id: %s w/ file_path: %s", track_id, logging.debug(
file_path) "No row inserted for track_id: %s w/ file_path: %s",
track_id,
file_path,
)
except Exception as e: except Exception as e:
logging.debug("cache_album_art Exception: %s", logging.debug("cache_album_art Exception: %s", str(e))
str(e))
traceback.print_exc() traceback.print_exc()
async def get_album_art(self, track_id: int) -> Optional[bytes]: async def get_album_art(self, track_id: int) -> Optional[bytes]:
@ -433,15 +460,12 @@ class RadioUtil:
query_params: tuple[int] = (track_id,) query_params: tuple[int] = (track_id,)
db_cursor = db_conn.execute(query, query_params) db_cursor = db_conn.execute(query, query_params)
result: Optional[Union[sqlite3.Row, bool]] = ( result: Optional[Union[sqlite3.Row, bool]] = db_cursor.fetchone()
db_cursor.fetchone()
)
if not result or not isinstance(result, sqlite3.Row): if not result or not isinstance(result, sqlite3.Row):
return None return None
return result["album_art"] return result["album_art"]
except Exception as e: except Exception as e:
logging.debug("get_album_art Exception: %s", logging.debug("get_album_art Exception: %s", str(e))
str(e))
traceback.print_exc() traceback.print_exc()
return None return None