This commit is contained in:
codey 2025-04-26 19:47:12 -04:00
parent 6c29c6fede
commit 58ba471b5e
10 changed files with 94 additions and 56 deletions

14
base.py
View File

@ -12,6 +12,7 @@ from lyric_search.sources import redis_cache
logger = logging.getLogger() logger = logging.getLogger()
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
app = FastAPI( app = FastAPI(
title="codey.lol API", title="codey.lol API",
@ -85,7 +86,9 @@ routes: dict = {
"lastfm": importlib.import_module("endpoints.lastfm").LastFM(app, util, constants), "lastfm": importlib.import_module("endpoints.lastfm").LastFM(app, util, constants),
"yt": importlib.import_module("endpoints.yt").YT(app, util, constants), "yt": importlib.import_module("endpoints.yt").YT(app, util, constants),
"karma": importlib.import_module("endpoints.karma").Karma(app, util, constants), "karma": importlib.import_module("endpoints.karma").Karma(app, util, constants),
"radio": importlib.import_module("endpoints.radio").Radio(app, util, constants), "radio": importlib.import_module("endpoints.radio").Radio(
app, util, constants, loop
),
"mgr": importlib.import_module("endpoints.mgr.mgr_test").Mgr(app, util, constants), "mgr": importlib.import_module("endpoints.mgr.mgr_test").Mgr(app, util, constants),
} }
@ -105,5 +108,14 @@ End Actionable Routes
Startup Startup
""" """
async def on_start():
uvicorn_access_logger = logging.getLogger("uvicorn.access")
uvicorn_access_logger.disabled = True
app.add_event_handler("startup", on_start)
redis = redis_cache.RedisCache() redis = redis_cache.RedisCache()
loop.create_task(redis.create_index()) loop.create_task(redis.create_index())

View File

@ -84,7 +84,9 @@ 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 = f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}" audit_message: str = (
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

@ -21,11 +21,12 @@ from fastapi.responses import RedirectResponse, JSONResponse
class Radio(FastAPI): class Radio(FastAPI):
"""Radio Endpoints""" """Radio Endpoints"""
def __init__(self, app: FastAPI, my_util, constants) -> None: def __init__(self, app: FastAPI, my_util, constants, loop) -> None:
self.app: FastAPI = app self.app: FastAPI = app
self.util = my_util self.util = my_util
self.constants = constants self.constants = constants
self.radio_util = radio_util.RadioUtil(self.constants) self.loop = loop
self.radio_util = radio_util.RadioUtil(self.constants, self.loop)
self.playlist_loaded: bool = False self.playlist_loaded: bool = False
self.endpoints: dict = { self.endpoints: dict = {
@ -57,10 +58,7 @@ class Radio(FastAPI):
async def on_start(self) -> None: async def on_start(self) -> None:
logging.info("radio: Initializing") logging.info("radio: Initializing")
with Pool() as pool: self.loop.run_in_executor(None, self.radio_util.load_playlist)
res = pool.apply_async(self.radio_util.load_playlist)
if res:
await self.radio_util._ls_skip()
async def radio_skip( async def radio_skip(
self, data: ValidRadioNextRequest, request: Request self, data: ValidRadioNextRequest, request: Request
@ -86,8 +84,8 @@ class Radio(FastAPI):
self.radio_util.active_playlist = self.radio_util.active_playlist[ self.radio_util.active_playlist = self.radio_util.active_playlist[
queue_item[0] : queue_item[0] :
] ]
if not self.radio_util.active_playlist: # if not self.radio_util.active_playlist:
await self.radio_util.load_playlist() # self.radio_util.load_playlist()
skip_result: bool = await self.radio_util._ls_skip() skip_result: bool = await self.radio_util._ls_skip()
status_code = 200 if skip_result else 500 status_code = 200 if skip_result else 500
return JSONResponse( return JSONResponse(
@ -154,12 +152,15 @@ class Radio(FastAPI):
"duration": item.get("duration"), "duration": item.get("duration"),
} }
) )
fallback_playlist_len: int = len(
self.radio_util.active_playlist
) # Used if search term is provided
out_json = { out_json = {
"draw": data.draw, "draw": data.draw,
"recordsTotal": len(queue_full), "recordsTotal": (
"recordsFiltered": ( len(queue_full) if not data.search else fallback_playlist_len
len(queue_full) if not data.search else len(queue_full) ),
), # todo: implement search "recordsFiltered": (len(queue_full)),
"items": queue_out, "items": queue_out,
} }
return JSONResponse(content=out_json) return JSONResponse(content=out_json)
@ -236,7 +237,7 @@ class Radio(FastAPI):
if not track_id: if not track_id:
track_id = self.radio_util.now_playing.get("id") track_id = self.radio_util.now_playing.get("id")
logging.debug("Seeking album art with trackId: %s", track_id) logging.debug("Seeking album art with trackId: %s", track_id)
album_art: Optional[bytes] = await self.radio_util.get_album_art( album_art: Optional[bytes] = self.radio_util.get_album_art(
track_id=track_id track_id=track_id
) )
if not album_art: if not album_art:
@ -312,7 +313,9 @@ class Radio(FastAPI):
if len(self.radio_util.active_playlist) > 1: if len(self.radio_util.active_playlist) > 1:
self.radio_util.active_playlist.append(next) # Push to end of playlist self.radio_util.active_playlist.append(next) # Push to end of playlist
else: else:
await self.radio_util.load_playlist() with Pool() as pool:
pool.apply_async(self.radio_util.load_playlist())
pool.close()
self.radio_util.now_playing = next self.radio_util.now_playing = next
next["start"] = time_started next["start"] = time_started
@ -323,9 +326,9 @@ class Radio(FastAPI):
logging.info("radio_get_next Exception: %s", str(e)) logging.info("radio_get_next Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
try: try:
album_art = await self.radio_util.get_album_art(track_id=next["id"]) album_art = self.radio_util.get_album_art(track_id=next["id"])
if not album_art: if not album_art:
await self.radio_util.cache_album_art(next["id"], next["file_path"]) self.radio_util.cache_album_art(next["id"], next["file_path"])
except Exception as e: except Exception as e:
logging.info("radio_get_next Exception: %s", str(e)) logging.info("radio_get_next Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
@ -364,7 +367,7 @@ class Radio(FastAPI):
}, },
) )
search: bool = await self.radio_util.search_playlist( search: bool = self.radio_util.search_playlist(
artistsong=artistsong, artist=artist, song=song artistsong=artistsong, artist=artist, song=song
) )
if data.alsoSkip: if data.alsoSkip:
@ -386,9 +389,7 @@ class Radio(FastAPI):
"errorText": "Invalid request.", "errorText": "Invalid request.",
}, },
) )
typeahead: Optional[list[str]] = await self.radio_util.trackdb_typeahead( typeahead: Optional[list[str]] = self.radio_util.trackdb_typeahead(data.query)
data.query
)
if not typeahead: if not typeahead:
return JSONResponse(content=[]) return JSONResponse(content=[])
return JSONResponse(content=typeahead) return JSONResponse(content=typeahead)

View File

@ -35,7 +35,7 @@ class RandMsg(FastAPI):
short = data.short short = data.short
if short: if short:
db_rand_selected: int = 9 db_rand_selected: int = 9
db_rand_selected = random.choice([0, 1, 3]) db_rand_selected = random.choice([3])
title_attr: str = "Unknown" title_attr: str = "Unknown"
match db_rand_selected: match db_rand_selected:

View File

@ -113,7 +113,9 @@ 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 = """SELECT ("S" || Season || "E" || Episode || " " || Title), Character, Line FROM SP_DAT WHERE ID = ?""" db_query: str = (
"""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

@ -89,8 +89,10 @@ 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 = 'SELECT id, artist, song FROM lyrics WHERE editdist3((lower(artist) || " " || lower(song)), (? || " " || ?))\ check_query: str = (
'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()
@ -211,10 +213,8 @@ 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_query = "INSERT INTO lyrics (src, date_retrieved, artist, song, artistsong, confidence, lyrics)\
"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(),
@ -233,8 +233,8 @@ class Cache:
await db_conn.commit() await db_conn.commit()
logging.info("Stored %s to SQLite!", artistsong.replace("\n", " - ")) logging.info("Stored %s to SQLite!", artistsong.replace("\n", " - "))
return _cursor.lastrowid return _cursor.lastrowid
except: except Exception as e:
logging.critical("Cache storage error!") logging.critical("Cache storage error: %s", str(e))
traceback.print_exc() traceback.print_exc()
async def search(self, artist: str, song: str, **kwargs) -> Optional[LyricsResult]: async def search(self, artist: str, song: str, **kwargs) -> Optional[LyricsResult]:
@ -258,8 +258,10 @@ class Cache:
if artist == "!" and song == "!": if artist == "!" and song == "!":
random_search = True random_search = True
search_query: str = "SELECT id, artist, song, lyrics, src, confidence\ search_query: str = (
"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)
@ -304,7 +306,8 @@ class Cache:
) )
await self.redis_cache.increment_found_count(self.label) await self.redis_cache.increment_found_count(self.label)
return matched return matched
except: except Exception as e:
logging.debug(str(e))
pass pass
"""SQLite: Fallback""" """SQLite: Fallback"""
@ -317,9 +320,11 @@ 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 = 'SELECT id, artist, song, lyrics, src, confidence FROM lyrics\ search_query: str = (
'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(),
@ -354,5 +359,6 @@ class Cache:
matched.time = time_diff matched.time = time_diff
await self.redis_cache.increment_found_count(self.label) await self.redis_cache.increment_found_count(self.label)
return matched return matched
except: except Exception as e:
logging.info("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()

View File

@ -1,5 +1,5 @@
from difflib import SequenceMatcher from difflib import SequenceMatcher
from typing import List, Optional, Union, Any from typing import List, Optional
import logging import logging
import regex import regex
from regex import Pattern from regex import Pattern

View File

@ -50,7 +50,8 @@ class LastFM:
.split("<a href")[0], .split("<a href")[0],
} }
return ret_obj return ret_obj
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return { return {
"err": "Failed", "err": "Failed",
@ -101,8 +102,9 @@ class LastFM:
"album": album, "album": album,
} }
return ret_obj return ret_obj
except: except Exception as e:
traceback.print_exc() traceback.print_exc()
logging.debug("Exception: %s", str(e))
return { return {
"err": "General Failure", "err": "General Failure",
} }
@ -132,8 +134,9 @@ class LastFM:
return ret_obj return ret_obj
except: except Exception as e:
traceback.print_exc() traceback.print_exc()
logging.debug("Exception: %s", str(e))
return { return {
"err": "General Failure", "err": "General Failure",
} }
@ -178,7 +181,8 @@ class LastFM:
and int(item.get("playcount")) >= 50 and int(item.get("playcount")) >= 50
] ]
return ret_obj return ret_obj
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return { return {
"err": "Failed", "err": "Failed",
@ -201,7 +205,8 @@ class LastFM:
return -1 return -1
artist_id: int = int(artist_search[0].get("id", 0)) artist_id: int = int(artist_search[0].get("id", 0))
return artist_id return artist_id
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return -1 return -1
@ -252,7 +257,8 @@ class LastFM:
"members": members, "members": members,
} }
return ret_obj return ret_obj
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return { return {
"err": "Failed", "err": "Failed",
@ -284,7 +290,8 @@ class LastFM:
"err": "Failed", "err": "Failed",
} }
return artist_info return artist_info
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return { return {
"err": "Failed", "err": "Failed",
@ -337,7 +344,8 @@ class LastFM:
} }
try: try:
track_key: list = data.get("tracks", None).get("track") track_key: list = data.get("tracks", None).get("track")
except: except Exception as e:
logging.debug("Exception: %s", str(e))
track_key = [] track_key = []
if isinstance(track_key, list): if isinstance(track_key, list):
ret_obj["tracks"] = [ ret_obj["tracks"] = [
@ -357,7 +365,8 @@ class LastFM:
} }
] ]
return ret_obj return ret_obj
except: except Exception as e:
logging.debug("Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
return { return {
"err": "Failed", "err": "Failed",

View File

@ -34,8 +34,9 @@ class RadioUtil:
Radio Utils Radio Utils
""" """
def __init__(self, constants) -> None: def __init__(self, constants, loop) -> None:
self.constants = constants self.constants = constants
self.loop = loop
self.gpt = gpt.GPT(self.constants) self.gpt = gpt.GPT(self.constants)
self.ls_uri: str = self.constants.LS_URI self.ls_uri: str = self.constants.LS_URI
self.sqlite_exts: list[str] = [ self.sqlite_exts: list[str] = [
@ -51,12 +52,12 @@ class RadioUtil:
"/usr/local/share", "sqlite_dbs", "track_album_art.db" "/usr/local/share", "sqlite_dbs", "track_album_art.db"
) )
self.playback_genres: list[str] = [ self.playback_genres: list[str] = [
# "post-hardcore", "post-hardcore",
# "post hardcore", "post hardcore",
# "metalcore", "metalcore",
# "deathcore", "deathcore",
# "edm", "edm",
# "electronic", "electronic",
] ]
self.active_playlist: list[dict] = [] self.active_playlist: list[dict] = []
self.playlist_loaded: bool = False self.playlist_loaded: bool = False
@ -161,9 +162,11 @@ 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 = 'SELECT id, artist, song, (artist || " - " || song) AS artistsong, album, file_path, duration FROM tracks\ search_query: str = (
'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)
@ -255,7 +258,9 @@ class RadioUtil:
for pair in pairs: for pair in pairs:
try: try:
artist, genre = pair artist, genre = pair
query: str = "INSERT OR IGNORE INTO artist_genre (artist, genre) VALUES(?, ?)" query: str = (
"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):
@ -405,11 +410,12 @@ class RadioUtil:
len(self.active_playlist), len(self.active_playlist),
) )
self.playlist_loaded = True self.playlist_loaded = True
self.loop.create_task(self._ls_skip())
except Exception as e: except Exception as e:
logging.info("Playlist load failed: %s", str(e)) logging.info("Playlist load failed: %s", str(e))
traceback.print_exc() traceback.print_exc()
async def cache_album_art(self, track_id: int, file_path: str) -> None: def cache_album_art(self, track_id: int, file_path: str) -> None:
""" """
Cache Album Art to SQLite DB Cache Album Art to SQLite DB
Args: Args:
@ -445,7 +451,7 @@ class RadioUtil:
logging.debug("cache_album_art Exception: %s", str(e)) logging.debug("cache_album_art Exception: %s", str(e))
traceback.print_exc() traceback.print_exc()
async def get_album_art(self, track_id: int) -> Optional[bytes]: def get_album_art(self, track_id: int) -> Optional[bytes]:
""" """
Get Album Art Get Album Art
Args: Args: