cleanup
This commit is contained in:
parent
00af36703a
commit
60416c493f
26
base.py
26
base.py
@ -25,8 +25,6 @@ app = FastAPI(title="codey.lol API",
|
|||||||
|
|
||||||
constants = importlib.import_module("constants").Constants()
|
constants = importlib.import_module("constants").Constants()
|
||||||
util = importlib.import_module("util").Utilities(app, constants)
|
util = importlib.import_module("util").Utilities(app, constants)
|
||||||
glob_state = importlib.import_module("state").State(app, util, constants)
|
|
||||||
|
|
||||||
|
|
||||||
origins = [
|
origins = [
|
||||||
"https://codey.lol",
|
"https://codey.lol",
|
||||||
@ -83,23 +81,23 @@ End Blacklisted Routes
|
|||||||
Actionable Routes
|
Actionable Routes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
randmsg_endpoint = importlib.import_module("endpoints.rand_msg").RandMsg(app, util, constants, glob_state)
|
randmsg_endpoint = importlib.import_module("endpoints.rand_msg").RandMsg(app, util, constants)
|
||||||
transcription_endpoints = importlib.import_module("endpoints.transcriptions").Transcriptions(app, util, constants, glob_state)
|
transcription_endpoints = importlib.import_module("endpoints.transcriptions").Transcriptions(app, util, constants)
|
||||||
ai_endpoints = importlib.import_module("endpoints.ai").AI(app, util, constants, glob_state)
|
ai_endpoints = importlib.import_module("endpoints.ai").AI(app, util, constants)
|
||||||
# Below also provides: /lyric_cache_list/ (in addition to /lyric_search/)
|
# Below also provides: /lyric_cache_list/ (in addition to /lyric_search/)
|
||||||
lyric_search_endpoint = importlib.import_module("endpoints.lyric_search").LyricSearch(app, util, constants, glob_state)
|
lyric_search_endpoint = importlib.import_module("endpoints.lyric_search").LyricSearch(app, util, constants)
|
||||||
# Below provides numerous LastFM-fed endpoints
|
# Below provides numerous LastFM-fed endpoints
|
||||||
lastfm_endpoints = importlib.import_module("endpoints.lastfm").LastFM(app, util, constants, glob_state)
|
lastfm_endpoints = importlib.import_module("endpoints.lastfm").LastFM(app, util, constants)
|
||||||
# Below: YT endpoint(s)
|
# Below: YT endpoint(s)
|
||||||
yt_endpoints = importlib.import_module("endpoints.yt").YT(app, util, constants, glob_state)
|
yt_endpoints = importlib.import_module("endpoints.yt").YT(app, util, constants)
|
||||||
# Below: XC endpoint(s)
|
# Below: XC endpoint(s)
|
||||||
xc_endpoints = importlib.import_module("endpoints.xc").XC(app, util, constants, glob_state)
|
xc_endpoints = importlib.import_module("endpoints.xc").XC(app, util, constants)
|
||||||
# Below: Karma endpoint(s)
|
# Below: Karma endpoint(s)
|
||||||
karma_endpoints = importlib.import_module("endpoints.karma").Karma(app, util, constants, glob_state)
|
karma_endpoints = importlib.import_module("endpoints.karma").Karma(app, util, constants)
|
||||||
# Below: Radio endpoint(s) - in development, sporadically loaded as needed
|
# Below: Radio endpoint(s) - in development, sporadically loaded as needed
|
||||||
radio_endpoints = importlib.import_module("endpoints.radio").Radio(app, util, constants, glob_state)
|
radio_endpoints = importlib.import_module("endpoints.radio").Radio(app, util, constants)
|
||||||
# Below: Misc endpoints
|
# Below: Misc endpoints
|
||||||
misc_endpoints = importlib.import_module("endpoints.misc").Misc(app, util, constants, glob_state, radio_endpoints)
|
misc_endpoints = importlib.import_module("endpoints.misc").Misc(app, util, constants, radio_endpoints)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
End Actionable Routes
|
End Actionable Routes
|
||||||
@ -109,6 +107,6 @@ End Actionable Routes
|
|||||||
"""
|
"""
|
||||||
Startup
|
Startup
|
||||||
"""
|
"""
|
||||||
redis_cache = redis_cache.RedisCache()
|
redis = redis_cache.RedisCache()
|
||||||
asyncio.get_event_loop().create_task(
|
asyncio.get_event_loop().create_task(
|
||||||
redis_cache.create_index())
|
redis.create_index())
|
@ -4,19 +4,20 @@
|
|||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
import regex
|
import regex
|
||||||
|
from regex import Pattern
|
||||||
|
from typing import Union
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
|
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
|
||||||
from .constructors import ValidHookSongRequest, ValidAISongRequest
|
from .constructors import ValidHookSongRequest, ValidAISongRequest
|
||||||
|
|
||||||
class AI(FastAPI):
|
class AI(FastAPI):
|
||||||
"""AI Endpoints"""
|
"""AI Endpoints"""
|
||||||
def __init__(self, app: FastAPI, my_util, constants, glob_state): # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, my_util, constants): # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = my_util
|
self.util = my_util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
self.url_clean_regex: Pattern = regex.compile(r'^\/ai\/(openai|base)\/')
|
||||||
self.url_clean_regex = regex.compile(r'^\/ai\/(openai|base)\/')
|
self.endpoints: dict = {
|
||||||
self.endpoints = {
|
|
||||||
"ai/openai": self.ai_openai_handler,
|
"ai/openai": self.ai_openai_handler,
|
||||||
"ai/base": self.ai_handler,
|
"ai/base": self.ai_handler,
|
||||||
"ai/song": self.ai_song_handler,
|
"ai/song": self.ai_song_handler,
|
||||||
@ -29,16 +30,20 @@ class AI(FastAPI):
|
|||||||
include_in_schema=False)
|
include_in_schema=False)
|
||||||
|
|
||||||
|
|
||||||
async def respond_via_webhook(self, data: ValidHookSongRequest, originalRequest: Request):
|
async def respond_via_webhook(self, data: ValidHookSongRequest, originalRequest: Request) -> bool:
|
||||||
"""Respond via Webhook"""
|
"""Respond via Webhook"""
|
||||||
try:
|
try:
|
||||||
logging.debug("Request received: %s", data)
|
logging.debug("Request received: %s", data)
|
||||||
data2 = data.copy()
|
data2 = data.copy()
|
||||||
del data2.hook
|
del data2.hook
|
||||||
|
|
||||||
|
if not data.hook:
|
||||||
|
return False
|
||||||
|
|
||||||
response = await self.ai_song_handler(data2, originalRequest)
|
response = await self.ai_song_handler(data2, originalRequest)
|
||||||
if not response.get('resp'):
|
if not response.get('resp'):
|
||||||
logging.critical("NO RESP!")
|
logging.critical("NO RESP!")
|
||||||
return
|
return False
|
||||||
response = response.get('resp')
|
response = response.get('resp')
|
||||||
hook_data = {
|
hook_data = {
|
||||||
'username': 'Claude',
|
'username': 'Claude',
|
||||||
@ -82,7 +87,6 @@ class AI(FastAPI):
|
|||||||
json=await request.json(),
|
json=await request.json(),
|
||||||
headers=local_llm_headers,
|
headers=local_llm_headers,
|
||||||
timeout=ClientTimeout(connect=15, sock_read=30)) as out_request:
|
timeout=ClientTimeout(connect=15, sock_read=30)) as out_request:
|
||||||
await self.glob_state.increment_counter('ai_requests')
|
|
||||||
response = await out_request.json()
|
response = await out_request.json()
|
||||||
return response
|
return response
|
||||||
except Exception as e: # pylint: disable=broad-exception-caught
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
@ -117,7 +121,6 @@ class AI(FastAPI):
|
|||||||
json=await request.json(),
|
json=await request.json(),
|
||||||
headers=local_llm_headers,
|
headers=local_llm_headers,
|
||||||
timeout=ClientTimeout(connect=15, sock_read=30)) as out_request:
|
timeout=ClientTimeout(connect=15, sock_read=30)) as out_request:
|
||||||
await self.glob_state.increment_counter('ai_requests')
|
|
||||||
response = await out_request.json()
|
response = await out_request.json()
|
||||||
return response
|
return response
|
||||||
except Exception as e: # pylint: disable=broad-exception-caught
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
@ -134,7 +137,7 @@ class AI(FastAPI):
|
|||||||
'success': True,
|
'success': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def ai_song_handler(self, data: ValidAISongRequest, request: Request):
|
async def ai_song_handler(self, data: Union[ValidAISongRequest, ValidHookSongRequest], request: Request):
|
||||||
"""
|
"""
|
||||||
/ai/song
|
/ai/song
|
||||||
AI (Song Info) Request [Public]
|
AI (Song Info) Request [Public]
|
||||||
@ -165,9 +168,8 @@ class AI(FastAPI):
|
|||||||
async with await session.post('https://api.anthropic.com/v1/messages',
|
async with await session.post('https://api.anthropic.com/v1/messages',
|
||||||
json=request_data,
|
json=request_data,
|
||||||
headers=local_llm_headers,
|
headers=local_llm_headers,
|
||||||
timeout=ClientTimeout(connect=15, sock_read=30)) as request:
|
timeout=ClientTimeout(connect=15, sock_read=30)) as aiohttp_request:
|
||||||
await self.glob_state.increment_counter('claude_ai_requests')
|
response = await aiohttp_request.json()
|
||||||
response = await request.json()
|
|
||||||
logging.debug("Response: %s",
|
logging.debug("Response: %s",
|
||||||
response)
|
response)
|
||||||
if response.get('type') == 'error':
|
if response.get('type') == 'error':
|
||||||
|
@ -14,7 +14,7 @@ from .constructors import ValidTopKarmaRequest, ValidKarmaRetrievalRequest,\
|
|||||||
|
|
||||||
class KarmaDB:
|
class KarmaDB:
|
||||||
"""Karma DB Util"""
|
"""Karma DB Util"""
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.db_path: LiteralString = os.path.join("/", "usr", "local", "share",
|
self.db_path: LiteralString = os.path.join("/", "usr", "local", "share",
|
||||||
"sqlite_dbs", "karma.db")
|
"sqlite_dbs", "karma.db")
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class KarmaDB:
|
|||||||
'errorText': f'No records for {keyword}',
|
'errorText': f'No records for {keyword}',
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_top(self, n: Optional[int] = 10) -> list[tuple]:
|
async def get_top(self, n: Optional[int] = 10) -> Optional[list[tuple]]:
|
||||||
"""Get Top n=10 Karma Entries
|
"""Get Top n=10 Karma Entries
|
||||||
Args:
|
Args:
|
||||||
n (Optional[int]) = 10: The number of top results to return
|
n (Optional[int]) = 10: The number of top results to return
|
||||||
@ -49,7 +49,7 @@ class KarmaDB:
|
|||||||
return await db_cursor.fetchall()
|
return await db_cursor.fetchall()
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return
|
return None
|
||||||
|
|
||||||
async def update_karma(self, granter: str, keyword: str, flag: int) -> Optional[bool]:
|
async def update_karma(self, granter: str, keyword: str, flag: int) -> Optional[bool]:
|
||||||
"""Update Karma for Keyword
|
"""Update Karma for Keyword
|
||||||
@ -62,7 +62,7 @@ class KarmaDB:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not flag in [0, 1]:
|
if not flag in [0, 1]:
|
||||||
return
|
return None
|
||||||
|
|
||||||
modifier: str = "score + 1" if not flag else "score - 1"
|
modifier: str = "score + 1" if not flag else "score - 1"
|
||||||
query: str = f"UPDATE karma SET score = {modifier}, last_change = ? WHERE keyword LIKE ?"
|
query: str = f"UPDATE karma SET score = {modifier}, last_change = ? WHERE keyword LIKE ?"
|
||||||
@ -90,13 +90,14 @@ class KarmaDB:
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
class Karma(FastAPI):
|
class Karma(FastAPI):
|
||||||
"""Karma Endpoints"""
|
"""Karma Endpoints"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state): # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants): # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
self.db = KarmaDB()
|
self.db = KarmaDB()
|
||||||
|
|
||||||
self.endpoints: dict = {
|
self.endpoints: dict = {
|
||||||
@ -117,12 +118,17 @@ class Karma(FastAPI):
|
|||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
|
|
||||||
n: int = 10
|
n: int = 10
|
||||||
if data:
|
if data and data.n:
|
||||||
n: int = int(data.n)
|
n = int(data.n)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
top10: list[tuple] = await self.db.get_top(n=n)
|
top10: Optional[list[tuple]] = await self.db.get_top(n=n)
|
||||||
|
if not top10:
|
||||||
|
return {
|
||||||
|
'err': True,
|
||||||
|
'errorText': 'General failure',
|
||||||
|
}
|
||||||
return top10
|
return top10
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -10,14 +10,13 @@ from .constructors import ValidArtistSearchRequest, ValidAlbumDetailRequest,\
|
|||||||
|
|
||||||
class LastFM(FastAPI):
|
class LastFM(FastAPI):
|
||||||
"""Last.FM Endpoints"""
|
"""Last.FM Endpoints"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state) -> None: # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants) -> None: # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
self.lastfm = importlib.import_module("lastfm_wrapper").LastFM()
|
self.lastfm = importlib.import_module("lastfm_wrapper").LastFM()
|
||||||
|
|
||||||
self.endpoints = {
|
self.endpoints: dict = {
|
||||||
"lastfm/get_artist_by_name": self.artist_by_name_handler,
|
"lastfm/get_artist_by_name": self.artist_by_name_handler,
|
||||||
"lastfm/get_artist_albums": self.artist_album_handler,
|
"lastfm/get_artist_albums": self.artist_album_handler,
|
||||||
"lastfm/get_release": self.release_detail_handler,
|
"lastfm/get_release": self.release_detail_handler,
|
||||||
@ -71,7 +70,7 @@ class LastFM(FastAPI):
|
|||||||
seen_release_titles: list = []
|
seen_release_titles: list = []
|
||||||
|
|
||||||
for release in album_result:
|
for release in album_result:
|
||||||
release_title: str = release.get('title')
|
release_title: str = release.get('title', 'Unknown')
|
||||||
if release_title.lower() in seen_release_titles:
|
if release_title.lower() in seen_release_titles:
|
||||||
continue
|
continue
|
||||||
seen_release_titles.append(release_title.lower())
|
seen_release_titles.append(release_title.lower())
|
||||||
|
@ -7,7 +7,8 @@ import urllib.parse
|
|||||||
import regex
|
import regex
|
||||||
import aiosqlite as sqlite3
|
import aiosqlite as sqlite3
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from typing import LiteralString, Optional, Pattern
|
from typing import LiteralString, Optional, Callable
|
||||||
|
from regex import Pattern
|
||||||
from .constructors import ValidTypeAheadRequest, ValidLyricRequest
|
from .constructors import ValidTypeAheadRequest, ValidLyricRequest
|
||||||
from lyric_search.constructors import LyricsResult
|
from lyric_search.constructors import LyricsResult
|
||||||
from lyric_search.sources import aggregate
|
from lyric_search.sources import aggregate
|
||||||
@ -15,32 +16,31 @@ from lyric_search import notifier
|
|||||||
|
|
||||||
class CacheUtils:
|
class CacheUtils:
|
||||||
"""Lyrics Cache DB Utils"""
|
"""Lyrics Cache DB Utils"""
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.lyrics_db_path: LiteralString = os.path.join("/", "usr", "local", "share",
|
self.lyrics_db_path: LiteralString = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "cached_lyrics.db")
|
"sqlite_dbs", "cached_lyrics.db")
|
||||||
|
|
||||||
async def check_typeahead(self, s: str, pre_query: str | None = None) -> Optional[list[dict]]:
|
async def check_typeahead(self, s: str, pre_query: str | None = None) -> list[dict]:
|
||||||
"""Check s against artists stored - for typeahead"""
|
"""Check s against artists stored - for typeahead"""
|
||||||
async with sqlite3.connect(self.lyrics_db_path,
|
async with sqlite3.connect(self.lyrics_db_path,
|
||||||
timeout=2) as db_conn:
|
timeout=2) as db_conn:
|
||||||
db_conn.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
|
db_conn.row_factory = sqlite3.Row
|
||||||
if not pre_query:
|
if not pre_query:
|
||||||
query: str = "SELECT distinct(artist) FROM lyrics WHERE artist LIKE ? LIMIT 15"
|
query: str = "SELECT distinct(artist) FROM lyrics WHERE artist LIKE ? LIMIT 15"
|
||||||
query_params: tuple = (f"%{s}%",)
|
query_params: tuple = (f"%{s}%",)
|
||||||
else:
|
else:
|
||||||
query: str = "SELECT distinct(song) FROM lyrics WHERE artist LIKE ? AND song LIKE ? LIMIT 15"
|
query = "SELECT distinct(song) FROM lyrics WHERE artist LIKE ? AND song LIKE ? LIMIT 15"
|
||||||
query_params: tuple = (f"%{pre_query}%", f"%{s}%",)
|
query_params = (f"%{pre_query}%", f"%{s}%",)
|
||||||
async with await db_conn.execute(query, query_params) as db_cursor:
|
async with await db_conn.execute(query, query_params) as db_cursor:
|
||||||
return await db_cursor.fetchall()
|
return await db_cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
class LyricSearch(FastAPI):
|
class LyricSearch(FastAPI):
|
||||||
"""Lyric Search Endpoint"""
|
"""Lyric Search Endpoint"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state): # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants): # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
self.cache_utils = CacheUtils()
|
self.cache_utils = CacheUtils()
|
||||||
self.notifier = notifier.DiscordNotifier()
|
self.notifier = notifier.DiscordNotifier()
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ class LyricSearch(FastAPI):
|
|||||||
'errorText': 'Invalid request',
|
'errorText': 'Invalid request',
|
||||||
}
|
}
|
||||||
query: str = data.query
|
query: str = data.query
|
||||||
typeahead_result: Optional[list[dict]] = await self.cache_utils.check_typeahead(query)
|
typeahead_result: list[dict] = await self.cache_utils.check_typeahead(query)
|
||||||
typeahead_list: list[str] = [str(r.get('artist')) for r in typeahead_result]
|
typeahead_list: list[str] = [str(r.get('artist')) for r in typeahead_result]
|
||||||
return typeahead_list
|
return typeahead_list
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class LyricSearch(FastAPI):
|
|||||||
}
|
}
|
||||||
pre_query: str = data.pre_query
|
pre_query: str = data.pre_query
|
||||||
query: str = data.query
|
query: str = data.query
|
||||||
typeahead_result: Optional[list[dict]] = await self.cache_utils.check_typeahead(query, pre_query)
|
typeahead_result: list[dict] = await self.cache_utils.check_typeahead(query, pre_query)
|
||||||
typeahead_list: list[str] = [str(r.get('song')) for r in typeahead_result]
|
typeahead_list: list[str] = [str(r.get('song')) for r in typeahead_result]
|
||||||
return typeahead_list
|
return typeahead_list
|
||||||
|
|
||||||
@ -122,24 +122,30 @@ class LyricSearch(FastAPI):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if not data.t:
|
if not data.t:
|
||||||
search_artist: str = data.a
|
search_artist: Optional[str] = data.a
|
||||||
search_song: str = data.s
|
search_song: Optional[str] = data.s
|
||||||
else:
|
else:
|
||||||
t_split = data.t.split(" - ", maxsplit=1)
|
t_split = data.t.split(" - ", maxsplit=1)
|
||||||
search_artist: str = t_split[0]
|
search_artist = t_split[0]
|
||||||
search_song: str = t_split[1]
|
search_song = t_split[1]
|
||||||
|
|
||||||
|
|
||||||
if search_artist and search_song:
|
if search_artist and search_song:
|
||||||
search_artist: str = self.constants.DOUBLE_SPACE_REGEX.sub(" ", search_artist.strip())
|
search_artist = str(self.constants.DOUBLE_SPACE_REGEX.sub(" ", search_artist.strip()))
|
||||||
search_song: str = self.constants.DOUBLE_SPACE_REGEX.sub(" ", search_song.strip())
|
search_song = str(self.constants.DOUBLE_SPACE_REGEX.sub(" ", search_song.strip()))
|
||||||
search_artist: str = urllib.parse.unquote(search_artist)
|
search_artist = urllib.parse.unquote(search_artist)
|
||||||
search_song: str = urllib.parse.unquote(search_song)
|
search_song = urllib.parse.unquote(search_song)
|
||||||
|
|
||||||
excluded_sources: list = data.excluded_sources
|
if not isinstance(search_artist, str) or not isinstance(search_song, str):
|
||||||
|
return {
|
||||||
|
'err': True,
|
||||||
|
'errorText': 'Invalid request',
|
||||||
|
}
|
||||||
|
|
||||||
|
excluded_sources: Optional[list] = data.excluded_sources
|
||||||
aggregate_search = aggregate.Aggregate(exclude_methods=excluded_sources)
|
aggregate_search = aggregate.Aggregate(exclude_methods=excluded_sources)
|
||||||
plain_lyrics: bool = not data.lrc
|
plain_lyrics: bool = not data.lrc
|
||||||
result: Optional[LyricsResult] = await aggregate_search.search(search_artist, search_song, plain_lyrics)
|
result: Optional[LyricsResult|dict] = await aggregate_search.search(search_artist, search_song, plain_lyrics)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
return {
|
return {
|
||||||
@ -147,15 +153,15 @@ class LyricSearch(FastAPI):
|
|||||||
'errorText': 'Sources exhausted, lyrics not located.',
|
'errorText': 'Sources exhausted, lyrics not located.',
|
||||||
}
|
}
|
||||||
|
|
||||||
result: dict = result.todict()
|
result = vars(result)
|
||||||
|
|
||||||
if data.sub and not data.lrc:
|
if data.sub and not data.lrc:
|
||||||
seeked_found_line: Optional[int] = None
|
seeked_found_line: Optional[int] = None
|
||||||
lyric_lines: list[str] = result['lyrics'].strip().split(" / ")
|
lyric_lines: list[str] = result['lyrics'].strip().split(" / ")
|
||||||
for i, line in enumerate(lyric_lines):
|
for i, line in enumerate(lyric_lines):
|
||||||
line: str = regex.sub(r'\u2064', '', line.strip())
|
line = regex.sub(r'\u2064', '', line.strip())
|
||||||
if data.sub.strip().lower() in line.strip().lower():
|
if data.sub.strip().lower() in line.strip().lower():
|
||||||
seeked_found_line: int = i
|
seeked_found_line = i
|
||||||
logging.debug("Found %s at %s, match for %s!",
|
logging.debug("Found %s at %s, match for %s!",
|
||||||
line, seeked_found_line, data.sub) # REMOVEME: DEBUG
|
line, seeked_found_line, data.sub) # REMOVEME: DEBUG
|
||||||
break
|
break
|
||||||
|
@ -9,11 +9,10 @@ from lyric_search.sources import private, cache as LyricsCache, redis_cache
|
|||||||
|
|
||||||
class Misc(FastAPI):
|
class Misc(FastAPI):
|
||||||
"""Misc Endpoints"""
|
"""Misc Endpoints"""
|
||||||
def __init__(self, app: FastAPI, my_util, constants, glob_state, radio): # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, my_util, constants, radio): # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = my_util
|
self.util = my_util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
self.radio_pubkey: str = "XC-AJCJS89-AOLOFKZ92921AK-AKASKZJAN178-3D1"
|
self.radio_pubkey: str = "XC-AJCJS89-AOLOFKZ92921AK-AKASKZJAN178-3D1"
|
||||||
self.lyr_cache = LyricsCache.Cache()
|
self.lyr_cache = LyricsCache.Cache()
|
||||||
self.redis_cache = redis_cache.RedisCache()
|
self.redis_cache = redis_cache.RedisCache()
|
||||||
|
@ -28,12 +28,11 @@ TODO:
|
|||||||
|
|
||||||
class Radio(FastAPI):
|
class Radio(FastAPI):
|
||||||
"""Radio Endpoints"""
|
"""Radio Endpoints"""
|
||||||
def __init__(self, app: FastAPI, my_util, constants, glob_state) -> None: # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, my_util, constants) -> None: # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = my_util
|
self.util = my_util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.radio_util = radio_util.RadioUtil(self.constants)
|
self.radio_util = radio_util.RadioUtil(self.constants)
|
||||||
self.glob_state = glob_state
|
|
||||||
|
|
||||||
self.endpoints: dict = {
|
self.endpoints: dict = {
|
||||||
"radio/np": self.radio_now_playing,
|
"radio/np": self.radio_now_playing,
|
||||||
@ -64,8 +63,10 @@ class Radio(FastAPI):
|
|||||||
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
if data.skipTo:
|
if data.skipTo:
|
||||||
(x, _) = self.radio_util.get_queue_item_by_uuid(data.skipTo)
|
queue_item = self.radio_util.get_queue_item_by_uuid(data.skipTo)
|
||||||
self.radio_util.active_playlist = self.radio_util.active_playlist[x:]
|
if not queue_item:
|
||||||
|
return False
|
||||||
|
self.radio_util.active_playlist = self.radio_util.active_playlist[queue_item[0]:]
|
||||||
if not self.radio_util.active_playlist:
|
if not self.radio_util.active_playlist:
|
||||||
await self.radio_util.load_playlist()
|
await self.radio_util.load_playlist()
|
||||||
return await self.radio_util._ls_skip()
|
return await self.radio_util._ls_skip()
|
||||||
@ -112,7 +113,13 @@ class Radio(FastAPI):
|
|||||||
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
|
|
||||||
(x, item) = self.radio_util.get_queue_item_by_uuid(data.uuid)
|
queue_item = self.radio_util.get_queue_item_by_uuid(data.uuid)
|
||||||
|
if not queue_item:
|
||||||
|
return {
|
||||||
|
'err': True,
|
||||||
|
'errorText': 'Queue item not found.',
|
||||||
|
}
|
||||||
|
(x, item) = queue_item
|
||||||
self.radio_util.active_playlist.pop(x)
|
self.radio_util.active_playlist.pop(x)
|
||||||
self.radio_util.active_playlist.insert(0, item)
|
self.radio_util.active_playlist.insert(0, item)
|
||||||
if not data.next:
|
if not data.next:
|
||||||
@ -126,18 +133,18 @@ class Radio(FastAPI):
|
|||||||
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
|
|
||||||
(x, found_item) = self.radio_util.get_queue_item_by_uuid(data.uuid)
|
queue_item = self.radio_util.get_queue_item_by_uuid(data.uuid)
|
||||||
if not found_item:
|
if not queue_item:
|
||||||
return {
|
return {
|
||||||
'ok': False,
|
'err': True,
|
||||||
'err': 'UUID not found in play queue',
|
'errorText': 'Queue item not found.',
|
||||||
}
|
}
|
||||||
self.radio_util.active_playlist.pop(x)
|
self.radio_util.active_playlist.pop(queue_item[0])
|
||||||
return {
|
return {
|
||||||
'ok': True,
|
'ok': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def album_art_handler(self, request: Request, track_id: Optional[int] = None) -> bytes:
|
async def album_art_handler(self, request: Request, track_id: Optional[int] = None) -> Response:
|
||||||
"""
|
"""
|
||||||
Get album art, optional parameter track_id may be specified.
|
Get album art, optional parameter track_id may be specified.
|
||||||
Otherwise, current track album art will be pulled.
|
Otherwise, current track album art will be pulled.
|
||||||
@ -182,13 +189,13 @@ class Radio(FastAPI):
|
|||||||
if not isinstance(self.radio_util.active_playlist, list) or not self.radio_util.active_playlist:
|
if not isinstance(self.radio_util.active_playlist, list) or not self.radio_util.active_playlist:
|
||||||
await self.radio_util.load_playlist()
|
await self.radio_util.load_playlist()
|
||||||
await self.radio_util._ls_skip()
|
await self.radio_util._ls_skip()
|
||||||
return
|
return None
|
||||||
next = self.radio_util.active_playlist.pop(0)
|
next = self.radio_util.active_playlist.pop(0)
|
||||||
if not isinstance(next, dict):
|
if not isinstance(next, dict):
|
||||||
logging.critical("next is of type: %s, reloading playlist...", type(next))
|
logging.critical("next is of type: %s, reloading playlist...", type(next))
|
||||||
await self.radio_util.load_playlist()
|
await self.radio_util.load_playlist()
|
||||||
await self.radio_util._ls_skip()
|
await self.radio_util._ls_skip()
|
||||||
return
|
return None
|
||||||
|
|
||||||
duration: int = next['duration']
|
duration: int = next['duration']
|
||||||
time_started: int = int(time.time())
|
time_started: int = int(time.time())
|
||||||
@ -209,19 +216,21 @@ class Radio(FastAPI):
|
|||||||
try:
|
try:
|
||||||
if not await self.radio_util.get_album_art(file_path=next['file_path']):
|
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'])
|
album_art = await self.radio_util.get_album_art(file_path=next['file_path'])
|
||||||
|
if not album_art:
|
||||||
|
return None
|
||||||
await self.radio_util.cache_album_art(next['id'], album_art)
|
await self.radio_util.cache_album_art(next['id'], album_art)
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return next
|
return next
|
||||||
|
|
||||||
|
|
||||||
async def radio_request(self, data: ValidRadioSongRequest, request: Request) -> Response:
|
async def radio_request(self, data: ValidRadioSongRequest, request: Request) -> dict:
|
||||||
"""Song request handler"""
|
"""Song request handler"""
|
||||||
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
if not self.util.check_key(path=request.url.path, req_type=4, key=data.key):
|
||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
artistsong: str = data.artistsong
|
artistsong: Optional[str] = data.artistsong
|
||||||
artist: str = data.artist
|
artist: Optional[str] = data.artist
|
||||||
song: str = data.song
|
song: Optional[str] = data.song
|
||||||
if artistsong and (artist or song):
|
if artistsong and (artist or song):
|
||||||
return {
|
return {
|
||||||
'err': True,
|
'err': True,
|
||||||
|
@ -13,7 +13,7 @@ import os
|
|||||||
import gpt
|
import gpt
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
import aiosqlite as sqlite3
|
import aiosqlite as sqlite3
|
||||||
from typing import Optional, LiteralString
|
from typing import Union, Optional, LiteralString
|
||||||
from uuid import uuid4 as uuid
|
from uuid import uuid4 as uuid
|
||||||
from .constructors import RadioException
|
from .constructors import RadioException
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ class RadioUtil:
|
|||||||
self.active_playlist_path: str|LiteralString = os.path.join("/usr/local/share",
|
self.active_playlist_path: str|LiteralString = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "track_file_map.db")
|
"sqlite_dbs", "track_file_map.db")
|
||||||
self.active_playlist_name = "default" # not used
|
self.active_playlist_name = "default" # not used
|
||||||
self.active_playlist: list = []
|
self.active_playlist: list[dict] = []
|
||||||
self.now_playing: dict = {
|
self.now_playing: dict = {
|
||||||
'artist': 'N/A',
|
'artist': 'N/A',
|
||||||
'song': 'N/A',
|
'song': 'N/A',
|
||||||
@ -75,8 +75,6 @@ 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_artist: Optional[str] = None
|
|
||||||
search_song: Optional[str] = None
|
|
||||||
search_query: str = 'SELECT id, artist, song, (artist || " - " || song) AS artistsong, genre, file_path, duration FROM tracks\
|
search_query: str = 'SELECT id, artist, song, (artist || " - " || song) AS artistsong, genre, 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'
|
||||||
@ -84,10 +82,10 @@ class RadioUtil:
|
|||||||
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)
|
||||||
else:
|
else:
|
||||||
search_artist: str = artist
|
search_artist = artist
|
||||||
search_song: str = song
|
search_song = song
|
||||||
if not artistsong:
|
if not artistsong:
|
||||||
artistsong: str = f"{search_artist} - {search_song}"
|
artistsong = f"{search_artist} - {search_song}"
|
||||||
search_params = (search_artist.lower(), search_song.lower(), artistsong.lower(),)
|
search_params = (search_artist.lower(), search_song.lower(), artistsong.lower(),)
|
||||||
async with sqlite3.connect(self.active_playlist_path,
|
async with sqlite3.connect(self.active_playlist_path,
|
||||||
timeout=2) as db_conn:
|
timeout=2) as db_conn:
|
||||||
@ -97,7 +95,7 @@ class RadioUtil:
|
|||||||
db_conn.row_factory = sqlite3.Row
|
db_conn.row_factory = sqlite3.Row
|
||||||
async with await db_conn.execute(search_query, search_params) as db_cursor:
|
async with await db_conn.execute(search_query, search_params) as db_cursor:
|
||||||
result: Optional[sqlite3.Row|bool] = await db_cursor.fetchone()
|
result: Optional[sqlite3.Row|bool] = await db_cursor.fetchone()
|
||||||
if not result:
|
if not result or not isinstance(result, sqlite3.Row):
|
||||||
return False
|
return False
|
||||||
pushObj: dict = {
|
pushObj: dict = {
|
||||||
'id': result['id'],
|
'id': result['id'],
|
||||||
@ -116,7 +114,7 @@ class RadioUtil:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def load_playlist(self):
|
async def load_playlist(self) -> None:
|
||||||
"""Load Playlist"""
|
"""Load Playlist"""
|
||||||
try:
|
try:
|
||||||
logging.info(f"Loading playlist...")
|
logging.info(f"Loading playlist...")
|
||||||
@ -135,12 +133,19 @@ class RadioUtil:
|
|||||||
"grunge", "house", "dubstep", "hardcore", "hair metal", "horror punk", "folk punk", "breakcore",\
|
"grunge", "house", "dubstep", "hardcore", "hair metal", "horror punk", "folk punk", "breakcore",\
|
||||||
"post-rock", "deathcore", "hardcore punk", "synthwave", "trap") GROUP BY artistdashsong ORDER BY RANDOM()'
|
"post-rock", "deathcore", "hardcore punk", "synthwave", "trap") GROUP BY artistdashsong ORDER BY RANDOM()'
|
||||||
|
|
||||||
|
"""
|
||||||
|
LIMITED TO ONE ARTIST...
|
||||||
|
"""
|
||||||
|
|
||||||
|
# db_query: str = 'SELECT distinct(artist || " - " || song) AS artistdashsong, id, artist, song, genre, file_path, duration FROM tracks\
|
||||||
|
# WHERE artist LIKE "%bad omens%" GROUP BY artistdashsong ORDER BY RANDOM()'
|
||||||
|
|
||||||
async with sqlite3.connect(self.active_playlist_path,
|
async with sqlite3.connect(self.active_playlist_path,
|
||||||
timeout=2) as db_conn:
|
timeout=2) as db_conn:
|
||||||
db_conn.row_factory = sqlite3.Row
|
db_conn.row_factory = sqlite3.Row
|
||||||
async with await db_conn.execute(db_query) as db_cursor:
|
async with await db_conn.execute(db_query) as db_cursor:
|
||||||
results: Optional[list[sqlite3.Row]] = await db_cursor.fetchall()
|
results: list[sqlite3.Row] = await db_cursor.fetchall()
|
||||||
self.active_playlist: list[dict] = [{
|
self.active_playlist = [{
|
||||||
'uuid': str(uuid().hex),
|
'uuid': str(uuid().hex),
|
||||||
'id': r['id'],
|
'id': r['id'],
|
||||||
'artist': double_space.sub(' ', r['artist']).strip(),
|
'artist': double_space.sub(' ', r['artist']).strip(),
|
||||||
@ -174,7 +179,7 @@ class RadioUtil:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
async def get_album_art(self, track_id: Optional[int] = None,
|
async def get_album_art(self, track_id: Optional[int] = None,
|
||||||
file_path: Optional[str] = None) -> bytes:
|
file_path: Optional[str] = None) -> Optional[bytes]:
|
||||||
"""
|
"""
|
||||||
Get Album Art
|
Get Album Art
|
||||||
Args:
|
Args:
|
||||||
@ -191,18 +196,18 @@ class RadioUtil:
|
|||||||
query_params: tuple = (track_id,)
|
query_params: tuple = (track_id,)
|
||||||
|
|
||||||
if file_path and not track_id:
|
if file_path and not track_id:
|
||||||
query: str = "SELECT album_art FROM tracks WHERE file_path = ?"
|
query = "SELECT album_art FROM tracks WHERE file_path = ?"
|
||||||
query_params: tuple = (file_path,)
|
query_params = (file_path,)
|
||||||
|
|
||||||
async with await db_conn.execute(query,
|
async with await db_conn.execute(query,
|
||||||
query_params) as db_cursor:
|
query_params) as db_cursor:
|
||||||
result: Optional[sqlite3.Row|bool] = await db_cursor.fetchone()
|
result: Optional[sqlite3.Row|bool] = await db_cursor.fetchone()
|
||||||
if not result:
|
if not result or not isinstance(result, sqlite3.Row):
|
||||||
return
|
return None
|
||||||
return result['album_art']
|
return result['album_art']
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return
|
return None
|
||||||
|
|
||||||
def get_queue_item_by_uuid(self, uuid: str) -> Optional[tuple[int, dict]]:
|
def get_queue_item_by_uuid(self, uuid: str) -> Optional[tuple[int, dict]]:
|
||||||
"""
|
"""
|
||||||
@ -249,7 +254,7 @@ class RadioUtil:
|
|||||||
response: Optional[str] = await self.gpt.get_completion(prompt=f"I am going to listen to {song} by {artist}.")
|
response: Optional[str] = await self.gpt.get_completion(prompt=f"I am going to listen to {song} by {artist}.")
|
||||||
if not response:
|
if not response:
|
||||||
logging.critical("No response received from GPT?")
|
logging.critical("No response received from GPT?")
|
||||||
return
|
return None
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def webhook_song_change(self, track: dict) -> None:
|
async def webhook_song_change(self, track: dict) -> None:
|
||||||
@ -314,7 +319,7 @@ class RadioUtil:
|
|||||||
if not ai_response:
|
if not ai_response:
|
||||||
return
|
return
|
||||||
|
|
||||||
hook_data: dict = {
|
hook_data = {
|
||||||
'username': 'GPT',
|
'username': 'GPT',
|
||||||
"embeds": [{
|
"embeds": [{
|
||||||
"title": "AI Feedback",
|
"title": "AI Feedback",
|
||||||
|
@ -2,29 +2,28 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
from typing import LiteralString
|
from typing import LiteralString, Optional
|
||||||
import aiosqlite as sqlite3
|
import aiosqlite as sqlite3
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from .constructors import RandMsgRequest
|
from .constructors import RandMsgRequest
|
||||||
|
|
||||||
class RandMsg(FastAPI):
|
class RandMsg(FastAPI):
|
||||||
"""Random Message Endpoint"""
|
"""Random Message Endpoint"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state): # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants): # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
|
|
||||||
self.endpoint_name = "randmsg"
|
self.endpoint_name = "randmsg"
|
||||||
|
|
||||||
app.add_api_route(f"/{self.endpoint_name}", self.randmsg_handler, methods=["POST"])
|
app.add_api_route(f"/{self.endpoint_name}", self.randmsg_handler, methods=["POST"])
|
||||||
|
|
||||||
async def randmsg_handler(self, data: RandMsgRequest = None):
|
async def randmsg_handler(self, data: RandMsgRequest):
|
||||||
"""
|
"""
|
||||||
Get a randomly generated message
|
Get a randomly generated message
|
||||||
"""
|
"""
|
||||||
random.seed()
|
random.seed()
|
||||||
short: bool = data.short if data else False
|
short: bool = data.short if data.short else False
|
||||||
|
|
||||||
if not short:
|
if not short:
|
||||||
db_rand_selected = random.choice([0, 1, 3])
|
db_rand_selected = random.choice([0, 1, 3])
|
||||||
else:
|
else:
|
||||||
@ -33,15 +32,13 @@ class RandMsg(FastAPI):
|
|||||||
|
|
||||||
match db_rand_selected:
|
match db_rand_selected:
|
||||||
case 0:
|
case 0:
|
||||||
randmsg_db_path = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs", "qajoke.db") # For qajoke db
|
"sqlite_dbs", "qajoke.db") # For qajoke db
|
||||||
db_query = "SELECT id, ('<b>Q:</b> ' || question || '<br/><b>A:</b> ' \
|
db_query = "SELECT id, ('<b>Q:</b> ' || question || '<br/><b>A:</b> ' \
|
||||||
|| answer) FROM jokes ORDER BY RANDOM() LIMIT 1" # For qajoke db
|
|| answer) FROM jokes ORDER BY RANDOM() LIMIT 1" # For qajoke db
|
||||||
title_attr = "QA Joke DB"
|
title_attr = "QA Joke DB"
|
||||||
case 1 | 9:
|
case 1 | 9:
|
||||||
randmsg_db_path = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"randmsg.db") # For randmsg db
|
"randmsg.db") # For randmsg db
|
||||||
db_query = "SELECT id, msg FROM msgs WHERE \
|
db_query = "SELECT id, msg FROM msgs WHERE \
|
||||||
@ -50,46 +47,41 @@ class RandMsg(FastAPI):
|
|||||||
db_query = db_query.replace("<= 180", "<= 126")
|
db_query = db_query.replace("<= 180", "<= 126")
|
||||||
title_attr = "Random Msg DB"
|
title_attr = "Random Msg DB"
|
||||||
case 2:
|
case 2:
|
||||||
randmsg_db_path = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"trump.db") # For Trump Tweet DB
|
"trump.db") # For Trump Tweet DB
|
||||||
db_query = "SELECT id, content FROM tweets \
|
db_query = "SELECT id, content FROM tweets \
|
||||||
ORDER BY RANDOM() LIMIT 1" # For Trump Tweet DB
|
ORDER BY RANDOM() LIMIT 1" # For Trump Tweet DB
|
||||||
title_attr = "Trump Tweet DB"
|
title_attr = "Trump Tweet DB"
|
||||||
case 3:
|
case 3:
|
||||||
randmsg_db_path: str|LiteralString = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"philo.db") # For Philo DB
|
"philo.db") # For Philo DB
|
||||||
db_query: str = "SELECT id, (content || '<br> - ' || speaker) FROM quotes \
|
db_query = "SELECT id, (content || '<br> - ' || speaker) FROM quotes \
|
||||||
ORDER BY RANDOM() LIMIT 1" # For Philo DB
|
ORDER BY RANDOM() LIMIT 1" # For Philo DB
|
||||||
title_attr: str = "Philosophical Quotes DB"
|
title_attr = "Philosophical Quotes DB"
|
||||||
case 4:
|
case 4:
|
||||||
randmsg_db_path: str|LiteralString = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"hate.db") # For Hate DB
|
"hate.db") # For Hate DB
|
||||||
db_query: str = """SELECT id, ("<font color='#FF0000'>" || comment) FROM hate_speech \
|
db_query = """SELECT id, ("<font color='#FF0000'>" || comment) FROM hate_speech \
|
||||||
WHERE length(comment) <= 180 ORDER BY RANDOM() LIMIT 1"""
|
WHERE length(comment) <= 180 ORDER BY RANDOM() LIMIT 1"""
|
||||||
title_attr: str = "Hate Speech DB"
|
title_attr = "Hate Speech DB"
|
||||||
case 5:
|
case 5:
|
||||||
randmsg_db_path: str|LiteralString = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"rjokes.db") # r/jokes DB
|
"rjokes.db") # r/jokes DB
|
||||||
db_query: str = """SELECT id, (title || "<br>" || body) FROM jokes \
|
db_query = """SELECT id, (title || "<br>" || body) FROM jokes \
|
||||||
WHERE score >= 10000 ORDER BY RANDOM() LIMIT 1"""
|
WHERE score >= 10000 ORDER BY RANDOM() LIMIT 1"""
|
||||||
title_attr: str = "r/jokes DB"
|
title_attr = "r/jokes DB"
|
||||||
case 6:
|
case 6:
|
||||||
randmsg_db_path: str|LiteralString = os.path.join("/",
|
randmsg_db_path = os.path.join("/usr/local/share",
|
||||||
"usr", "local", "share",
|
|
||||||
"sqlite_dbs",
|
"sqlite_dbs",
|
||||||
"donnies.db") # Donnies DB
|
"donnies.db") # Donnies DB
|
||||||
random.seed()
|
random.seed()
|
||||||
twilight_or_mice: str = random.choice(["twilight", "mice"])
|
twilight_or_mice: str = random.choice(["twilight", "mice"])
|
||||||
db_query: str = f"SELECT id, text FROM {twilight_or_mice} ORDER BY RANDOM() LIMIT 1"
|
db_query = f"SELECT id, text FROM {twilight_or_mice} ORDER BY RANDOM() LIMIT 1"
|
||||||
title_attr: str = "Donnies DB"
|
title_attr = "Donnies DB"
|
||||||
|
|
||||||
async with sqlite3.connect(database=randmsg_db_path, timeout=1) as _db:
|
async with sqlite3.connect(database=randmsg_db_path, timeout=1) as _db:
|
||||||
async with await _db.execute(db_query) as _cursor:
|
async with await _db.execute(db_query) as _cursor:
|
||||||
|
@ -8,11 +8,10 @@ from .constructors import ValidShowEpisodeLineRequest, ValidShowEpisodeListReque
|
|||||||
|
|
||||||
class Transcriptions(FastAPI):
|
class Transcriptions(FastAPI):
|
||||||
"""Transcription Endpoints"""
|
"""Transcription Endpoints"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state) -> None: # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants) -> None: # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
|
|
||||||
self.endpoints: dict = {
|
self.endpoints: dict = {
|
||||||
"transcriptions/get_episodes": self.get_episodes_handler,
|
"transcriptions/get_episodes": self.get_episodes_handler,
|
||||||
@ -34,39 +33,39 @@ class Transcriptions(FastAPI):
|
|||||||
if show_id is None:
|
if show_id is None:
|
||||||
return {
|
return {
|
||||||
'err': True,
|
'err': True,
|
||||||
'errorText': 'Invalid request'
|
'errorText': 'Invalid request',
|
||||||
}
|
}
|
||||||
|
|
||||||
show_id: int = int(show_id)
|
show_id = int(show_id)
|
||||||
|
|
||||||
if not(str(show_id).isnumeric()) or show_id not in [0, 1, 2]:
|
if not(str(show_id).isnumeric()) or show_id not in [0, 1, 2]:
|
||||||
return {
|
return {
|
||||||
'err': True,
|
'err': True,
|
||||||
'errorText': 'Show not found.'
|
'errorText': 'Show not found.',
|
||||||
}
|
}
|
||||||
|
|
||||||
match show_id:
|
match show_id:
|
||||||
case 0:
|
case 0:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "sp.db")
|
"sqlite_dbs", "sp.db")
|
||||||
db_query: str = """SELECT DISTINCT(("S" || Season || "E" || Episode || " " || Title)), ID FROM SP_DAT ORDER BY Season, Episode"""
|
db_query = """SELECT DISTINCT(("S" || Season || "E" || Episode || " " || Title)), ID FROM SP_DAT ORDER BY Season, Episode"""
|
||||||
show_title: str = "South Park"
|
show_title = "South Park"
|
||||||
case 1:
|
case 1:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "futur.db")
|
"sqlite_dbs", "futur.db")
|
||||||
db_query: str = """SELECT DISTINCT(("S" || EP_S || "E" || EP_EP || " " || EP_TITLE)), EP_ID FROM clean_dialog ORDER BY EP_S, EP_EP"""
|
db_query = """SELECT DISTINCT(("S" || EP_S || "E" || EP_EP || " " || EP_TITLE)), EP_ID FROM clean_dialog ORDER BY EP_S, EP_EP"""
|
||||||
show_title: str = "Futurama"
|
show_title = "Futurama"
|
||||||
case 2:
|
case 2:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "parks.db")
|
"sqlite_dbs", "parks.db")
|
||||||
db_query: str = """SELECT DISTINCT(("S" || EP_S || "E" || EP_EP || " " || EP_TITLE)), EP_ID FROM clean_dialog ORDER BY EP_S, EP_EP"""
|
db_query = """SELECT DISTINCT(("S" || EP_S || "E" || EP_EP || " " || EP_TITLE)), EP_ID FROM clean_dialog ORDER BY EP_S, EP_EP"""
|
||||||
show_title: str = "Parks And Rec"
|
show_title = "Parks And Rec"
|
||||||
case _:
|
case _:
|
||||||
return {
|
return {
|
||||||
'err': True,
|
'err': True,
|
||||||
'errorText': 'Unknown error.'
|
'errorText': 'Unknown error.'
|
||||||
}
|
}
|
||||||
await self.glob_state.increment_counter('transcript_list_requests')
|
|
||||||
async with sqlite3.connect(database=db_path, timeout=1) as _db:
|
async with sqlite3.connect(database=db_path, timeout=1) as _db:
|
||||||
async with await _db.execute(db_query) as _cursor:
|
async with await _db.execute(db_query) as _cursor:
|
||||||
result: list[tuple] = await _cursor.fetchall()
|
result: list[tuple] = await _cursor.fetchall()
|
||||||
@ -86,17 +85,17 @@ class Transcriptions(FastAPI):
|
|||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
match show_id:
|
match show_id:
|
||||||
case 0:
|
case 0:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "sp.db")
|
"sqlite_dbs", "sp.db")
|
||||||
db_query: str = """SELECT ("S" || Season || "E" || Episode || " " || Title), Character, Line FROM SP_DAT WHERE ID = ?"""
|
db_query = """SELECT ("S" || Season || "E" || Episode || " " || Title), Character, Line FROM SP_DAT WHERE ID = ?"""
|
||||||
case 1:
|
case 1:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "futur.db")
|
"sqlite_dbs", "futur.db")
|
||||||
db_query: str = """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"""
|
||||||
case 2:
|
case 2:
|
||||||
db_path: str|LiteralString = os.path.join("/", "usr", "local", "share",
|
db_path = os.path.join("/usr/local/share",
|
||||||
"sqlite_dbs", "parks.db")
|
"sqlite_dbs", "parks.db")
|
||||||
db_query: str = """SELECT ("S" || EP_S || "E" || EP_EP || " " || EP_TITLE), EP_LINE_SPEAKER, EP_LINE FROM clean_dialog WHERE EP_ID = ? ORDER BY id ASC"""
|
db_query = """SELECT ("S" || EP_S || "E" || EP_EP || " " || EP_TITLE), EP_LINE_SPEAKER, EP_LINE FROM clean_dialog WHERE EP_ID = ? ORDER BY id ASC"""
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
return {
|
return {
|
||||||
@ -104,7 +103,6 @@ class Transcriptions(FastAPI):
|
|||||||
'errorText': 'Unknown error'
|
'errorText': 'Unknown error'
|
||||||
}
|
}
|
||||||
|
|
||||||
await self.glob_state.increment_counter('transcript_requests')
|
|
||||||
async with sqlite3.connect(database=db_path, timeout=1) as _db:
|
async with sqlite3.connect(database=db_path, timeout=1) as _db:
|
||||||
params: tuple = (episode_id,)
|
params: tuple = (episode_id,)
|
||||||
async with await _db.execute(db_query, params) as _cursor:
|
async with await _db.execute(db_query, params) as _cursor:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3.12
|
#!/usr/bin/env python3.12
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
from fastapi import FastAPI, Request, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
@ -9,12 +10,10 @@ from .constructors import ValidXCRequest
|
|||||||
|
|
||||||
class XC(FastAPI):
|
class XC(FastAPI):
|
||||||
"""XC (CrossComm) Endpoints"""
|
"""XC (CrossComm) Endpoints"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state) -> None: # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants) -> None: # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
|
|
||||||
|
|
||||||
self.endpoints: dict = {
|
self.endpoints: dict = {
|
||||||
"xc": self.xc_handler,
|
"xc": self.xc_handler,
|
||||||
@ -31,7 +30,7 @@ class XC(FastAPI):
|
|||||||
key: str = data.key
|
key: str = data.key
|
||||||
bid: int = data.bid
|
bid: int = data.bid
|
||||||
cmd: str = data.cmd
|
cmd: str = data.cmd
|
||||||
cmd_data: dict = data.data
|
cmd_data: Optional[dict] = data.data
|
||||||
if not self.util.check_key(path=request.url.path, req_type=0, key=key):
|
if not self.util.check_key(path=request.url.path, req_type=0, key=key):
|
||||||
raise HTTPException(status_code=403, detail="Unauthorized")
|
raise HTTPException(status_code=403, detail="Unauthorized")
|
||||||
|
|
||||||
@ -50,11 +49,15 @@ class XC(FastAPI):
|
|||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
async with await session.post(f"{bot_api_url}{cmd}", json=cmd_data, headers={
|
async with await session.post(f"{bot_api_url}{cmd}", json=cmd_data, headers={
|
||||||
'Content-Type': 'application/json; charset=utf-8'
|
'Content-Type': 'application/json; charset=utf-8'
|
||||||
}, timeout=ClientTimeout(connect=5, sock_read=5)) as request:
|
}, timeout=ClientTimeout(connect=5, sock_read=5)) as aiohttp_request:
|
||||||
response: dict = await request.json()
|
response: dict = await aiohttp_request.json()
|
||||||
return {
|
return {
|
||||||
'success': True,
|
'success': True,
|
||||||
'response': response
|
'response': response
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug("Error: %s", str(e))
|
logging.debug("Error: %s", str(e))
|
||||||
|
return {
|
||||||
|
'err': True,
|
||||||
|
'errorText': 'General error.',
|
||||||
|
}
|
@ -8,11 +8,10 @@ from .constructors import ValidYTSearchRequest
|
|||||||
|
|
||||||
class YT(FastAPI):
|
class YT(FastAPI):
|
||||||
"""YT Endpoints"""
|
"""YT Endpoints"""
|
||||||
def __init__(self, app: FastAPI, util, constants, glob_state) -> None: # pylint: disable=super-init-not-called
|
def __init__(self, app: FastAPI, util, constants) -> None: # pylint: disable=super-init-not-called
|
||||||
self.app = app
|
self.app = app
|
||||||
self.util = util
|
self.util = util
|
||||||
self.constants = constants
|
self.constants = constants
|
||||||
self.glob_state = glob_state
|
|
||||||
self.ytsearch = importlib.import_module("youtube_search_async").YoutubeSearch()
|
self.ytsearch = importlib.import_module("youtube_search_async").YoutubeSearch()
|
||||||
|
|
||||||
self.endpoints: dict = {
|
self.endpoints: dict = {
|
||||||
|
@ -12,7 +12,7 @@ class GPT:
|
|||||||
)
|
)
|
||||||
self.default_system_prompt = "You are a helpful assistant who will provide only totally accurate tidbits of info on the specific songs the user may listen to."
|
self.default_system_prompt = "You are a helpful assistant who will provide only totally accurate tidbits of info on the specific songs the user may listen to."
|
||||||
|
|
||||||
async def get_completion(self, prompt: str, system_prompt: Optional[str] = None) -> None:
|
async def get_completion(self, prompt: str, system_prompt: Optional[str] = None) -> str:
|
||||||
if not system_prompt:
|
if not system_prompt:
|
||||||
system_prompt = self.default_system_prompt
|
system_prompt = self.default_system_prompt
|
||||||
chat_completion = await self.client.chat.completions.create(
|
chat_completion = await self.client.chat.completions.create(
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional, Union
|
||||||
import regex
|
import regex
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
from constants import Constants
|
from constants import Constants
|
||||||
@ -30,13 +30,13 @@ class LastFM:
|
|||||||
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
data: dict = await request.json()
|
data: dict = await request.json()
|
||||||
data = data.get('artist')
|
data = data.get('artist', 'N/A')
|
||||||
|
|
||||||
ret_obj: dict = {
|
ret_obj: dict = {
|
||||||
'id': data.get('mbid'),
|
'id': data.get('mbid'),
|
||||||
'touring': data.get('ontour'),
|
'touring': data.get('ontour'),
|
||||||
'name': data.get('name'),
|
'name': data.get('name'),
|
||||||
'bio': data.get('bio').get('summary').strip()\
|
'bio': data.get('bio', None).get('summary').strip()\
|
||||||
.split("<a href")[0],
|
.split("<a href")[0],
|
||||||
}
|
}
|
||||||
return ret_obj
|
return ret_obj
|
||||||
@ -68,10 +68,10 @@ class LastFM:
|
|||||||
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
data: dict = await request.json()
|
data: dict = await request.json()
|
||||||
data = data.get('track')
|
data = data.get('track', None)
|
||||||
ret_obj: dict = {
|
ret_obj: dict = {
|
||||||
'artist_mbid': data.get('artist').get('mbid'),
|
'artist_mbid': data.get('artist', None).get('mbid'),
|
||||||
'album': data.get('album').get('title'),
|
'album': data.get('album', None).get('title'),
|
||||||
}
|
}
|
||||||
return ret_obj
|
return ret_obj
|
||||||
except:
|
except:
|
||||||
@ -97,8 +97,8 @@ class LastFM:
|
|||||||
'err': 'No artist or album specified',
|
'err': 'No artist or album specified',
|
||||||
}
|
}
|
||||||
|
|
||||||
tracks: list|dict = await self.get_release(artist=artist, album=album)
|
tracks: dict = await self.get_release(artist=artist, album=album)
|
||||||
tracks: list|dict = tracks.get('tracks')
|
tracks = tracks.get('tracks', None)
|
||||||
ret_obj: dict = {
|
ret_obj: dict = {
|
||||||
'tracks': tracks,
|
'tracks': tracks,
|
||||||
}
|
}
|
||||||
@ -129,9 +129,9 @@ class LastFM:
|
|||||||
async with await session.get(f"{self.api_base_url}artist.gettopalbums&artist={artist}&api_key={self.creds.get('key')}&autocorrect=1&format=json",
|
async with await session.get(f"{self.api_base_url}artist.gettopalbums&artist={artist}&api_key={self.creds.get('key')}&autocorrect=1&format=json",
|
||||||
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
data: dict = await request.json()
|
json_data: dict = await request.json()
|
||||||
data: str = data.get('topalbums').get('album')
|
data: dict = data.get('topalbums', None).get('album')
|
||||||
ret_obj: dict = [
|
ret_obj: list = [
|
||||||
{
|
{
|
||||||
'title': item.get('name')
|
'title': item.get('name')
|
||||||
} for item in data if not(item.get('name').lower() == "(null)") and int(item.get('playcount')) >= 50
|
} for item in data if not(item.get('name').lower() == "(null)") and int(item.get('playcount')) >= 50
|
||||||
@ -143,7 +143,7 @@ class LastFM:
|
|||||||
'err': 'Failed',
|
'err': 'Failed',
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_artist_id(self, artist: Optional[str] = None) -> int|dict:
|
async def get_artist_id(self, artist: Optional[str] = None) -> int:
|
||||||
"""
|
"""
|
||||||
Get Artist ID from LastFM
|
Get Artist ID from LastFM
|
||||||
Args:
|
Args:
|
||||||
@ -153,22 +153,16 @@ class LastFM:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if artist is None:
|
if artist is None:
|
||||||
return {
|
return -1
|
||||||
'err': 'No artist specified.',
|
|
||||||
}
|
|
||||||
artist_search: dict = await self.search_artist(artist=artist)
|
artist_search: dict = await self.search_artist(artist=artist)
|
||||||
if not artist_search:
|
if not artist_search:
|
||||||
logging.debug("[get_artist_id] Throwing no result error")
|
logging.debug("[get_artist_id] Throwing no result error")
|
||||||
return {
|
return -1
|
||||||
'err': 'No results.',
|
|
||||||
}
|
|
||||||
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:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return {
|
return -1
|
||||||
'err': 'Failed',
|
|
||||||
}
|
|
||||||
|
|
||||||
async def get_artist_info_by_id(self, artist_id: Optional[int] = None) -> dict:
|
async def get_artist_info_by_id(self, artist_id: Optional[int] = None) -> dict:
|
||||||
"""
|
"""
|
||||||
@ -219,12 +213,12 @@ class LastFM:
|
|||||||
return {
|
return {
|
||||||
'err': 'No artist specified.',
|
'err': 'No artist specified.',
|
||||||
}
|
}
|
||||||
artist_id: int = await self.get_artist_id(artist=artist)
|
artist_id: Optional[int] = await self.get_artist_id(artist=artist)
|
||||||
if not artist_id:
|
if not artist_id:
|
||||||
return {
|
return {
|
||||||
'err': 'Failed',
|
'err': 'Failed',
|
||||||
}
|
}
|
||||||
artist_info: dict = await self.get_artist_info_by_id(artist_id=artist_id)
|
artist_info: Optional[dict] = await self.get_artist_info_by_id(artist_id=artist_id)
|
||||||
if not artist_info:
|
if not artist_info:
|
||||||
return {
|
return {
|
||||||
'err': 'Failed',
|
'err': 'Failed',
|
||||||
@ -258,21 +252,21 @@ class LastFM:
|
|||||||
async with await session.get(req_url,
|
async with await session.get(req_url,
|
||||||
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
timeout=ClientTimeout(connect=3, sock_read=8)) as request:
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
data: dict = await request.json()
|
json_data: dict = await request.json()
|
||||||
data: dict = data.get('album')
|
data: dict = json_data.get('album', None)
|
||||||
ret_obj: dict = {
|
ret_obj: dict = {
|
||||||
'id': data.get('mbid'),
|
'id': data.get('mbid'),
|
||||||
'artists': data.get('artist'),
|
'artists': data.get('artist'),
|
||||||
'tags': data.get('tags'),
|
'tags': data.get('tags'),
|
||||||
'title': data.get('name'),
|
'title': data.get('name'),
|
||||||
'summary': data.get('wiki').get('summary').split("<a href")[0]\
|
'summary': data.get('wiki', None).get('summary').split("<a href")[0]\
|
||||||
if "wiki" in data.keys()\
|
if "wiki" in data.keys()\
|
||||||
else "No summary available for this release.",
|
else "No summary available for this release.",
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
track_key: list = data.get('tracks').get('track')
|
track_key: list = data.get('tracks', None).get('track')
|
||||||
except:
|
except:
|
||||||
track_key: list = []
|
track_key = []
|
||||||
if isinstance(track_key, list):
|
if isinstance(track_key, list):
|
||||||
ret_obj['tracks'] = [
|
ret_obj['tracks'] = [
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,3 @@ class LyricsResult:
|
|||||||
lyrics: str|list
|
lyrics: str|list
|
||||||
confidence: int
|
confidence: int
|
||||||
time: float = 0.00
|
time: float = 0.00
|
||||||
|
|
||||||
def todict(self) -> dict:
|
|
||||||
"""Return as dict"""
|
|
||||||
return asdict(self)
|
|
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3.12
|
#!/usr/bin/env python3.12
|
||||||
SCRAPE_HEADERS = {
|
SCRAPE_HEADERS: dict[str, str] = {
|
||||||
'accept': '*/*',
|
'accept': '*/*',
|
||||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0',
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0',
|
||||||
}
|
}
|
@ -14,7 +14,6 @@ from . import private, common, cache, redis_cache
|
|||||||
from lyric_search import utils
|
from lyric_search import utils
|
||||||
from lyric_search.constructors import LyricsResult
|
from lyric_search.constructors import LyricsResult
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
log_level = logging.getLevelName(logger.level)
|
log_level = logging.getLevelName(logger.level)
|
||||||
|
|
||||||
|
@ -23,3 +23,5 @@ dependencies = [
|
|||||||
"typing-inspect>=0.9.0",
|
"typing-inspect>=0.9.0",
|
||||||
"http3>=0.6.7",
|
"http3>=0.6.7",
|
||||||
]
|
]
|
||||||
|
[tool.mypy]
|
||||||
|
disable_error_code = ["import-untyped"]
|
111
state.py
111
state.py
@ -1,111 +0,0 @@
|
|||||||
#!/usr/bin/env python3.12
|
|
||||||
# pylint: disable=bare-except, broad-exception-raised
|
|
||||||
|
|
||||||
"""Global State Storage/Counters"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import aiosqlite as sqlite3
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from fastapi_utils.tasks import repeat_every
|
|
||||||
|
|
||||||
|
|
||||||
class State(FastAPI):
|
|
||||||
"""Global State for API"""
|
|
||||||
def __init__(self, app: FastAPI, util, constants): # pylint: disable=unused-argument
|
|
||||||
super().__init__()
|
|
||||||
self.counter_db_path = os.path.join("/", "usr", "local", "share",
|
|
||||||
"sqlite_dbs", "stats.db")
|
|
||||||
self.counters = {
|
|
||||||
str(counter): 0 for counter in constants.AVAILABLE_COUNTERS
|
|
||||||
}
|
|
||||||
self.counters_initialized = False
|
|
||||||
logging.debug("[State] Counters: %s", self.counters)
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
|
||||||
async def get_counters():
|
|
||||||
logging.info("[State] Initializing counters...")
|
|
||||||
async with sqlite3.connect(self.counter_db_path, timeout=2) as _db:
|
|
||||||
_query = "SELECT ai_requests, lyric_requests, transcript_list_requests, transcript_requests, lyrichistory_requests, \
|
|
||||||
failedlyric_requests, misc_failures, claude_ai_requests FROM counters LIMIT 1"
|
|
||||||
await _db.executescript("pragma journal_mode = WAL; pragma synchronous = normal; pragma temp_store = memory; pragma mmap_size = 30000000000;")
|
|
||||||
async with _db.execute(_query) as _cursor:
|
|
||||||
_result = await _cursor.fetchone()
|
|
||||||
(ai_requests,
|
|
||||||
lyric_requests,
|
|
||||||
transcript_list_requests,
|
|
||||||
transcript_requests,
|
|
||||||
lyrichistory_requests,
|
|
||||||
failedlyric_requests,
|
|
||||||
misc_failures,
|
|
||||||
claude_ai_requests) = _result
|
|
||||||
self.counters = {
|
|
||||||
'ai_requests': ai_requests,
|
|
||||||
'lyric_requests': lyric_requests,
|
|
||||||
'transcript_list_requests': transcript_list_requests,
|
|
||||||
'transcript_requests': transcript_requests,
|
|
||||||
'lyrichistory_requests': lyrichistory_requests,
|
|
||||||
'failedlyric_requests': failedlyric_requests,
|
|
||||||
'misc_failures': misc_failures,
|
|
||||||
'claude_ai_requests': claude_ai_requests
|
|
||||||
}
|
|
||||||
self.counters_initialized = True
|
|
||||||
logging.info("Counters loaded from db: %s", self.counters)
|
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
|
||||||
@repeat_every(seconds=10)
|
|
||||||
async def update_db():
|
|
||||||
if not self.counters_initialized:
|
|
||||||
logging.debug("[State] TICK: Counters not yet initialized")
|
|
||||||
return
|
|
||||||
|
|
||||||
ai_requests = self.counters.get('ai_requests')
|
|
||||||
lyric_requests = self.counters.get('lyric_requests')
|
|
||||||
transcript_list_requests = self.counters.get('transcript_list_requests')
|
|
||||||
transcript_requests = self.counters.get('transcript_requests')
|
|
||||||
lyrichistory_requests = self.counters.get('lyrichistory_requests')
|
|
||||||
failedlyric_requests = self.counters.get('failedlyric_requests')
|
|
||||||
claude_ai_requests = self.counters.get('claude_ai_requests')
|
|
||||||
|
|
||||||
async with sqlite3.connect(self.counter_db_path, timeout=2) as _db:
|
|
||||||
_query = "UPDATE counters SET ai_requests = ?, lyric_requests = ?, transcript_list_requests = ?, \
|
|
||||||
transcript_requests = ?, lyrichistory_requests = ?, failedlyric_requests = ?, \
|
|
||||||
claude_ai_requests = ?"
|
|
||||||
|
|
||||||
_params = (ai_requests,
|
|
||||||
lyric_requests,
|
|
||||||
transcript_list_requests,
|
|
||||||
transcript_requests,
|
|
||||||
lyrichistory_requests,
|
|
||||||
failedlyric_requests,
|
|
||||||
claude_ai_requests)
|
|
||||||
|
|
||||||
await _db.executescript("pragma journal_mode = WAL; pragma synchronous = normal; pragma temp_store = memory; pragma mmap_size = 30000000000;")
|
|
||||||
async with _db.execute(_query, _params) as _cursor:
|
|
||||||
if _cursor.rowcount != 1:
|
|
||||||
logging.error("Failed to update DB")
|
|
||||||
return
|
|
||||||
await _db.commit()
|
|
||||||
logging.debug("[State] Updated DB")
|
|
||||||
|
|
||||||
|
|
||||||
async def increment_counter(self, counter: str):
|
|
||||||
"""Increment Counter"""
|
|
||||||
if not counter in self.counters.keys():
|
|
||||||
raise BaseException(f"[State] Counter {counter} does not exist")
|
|
||||||
|
|
||||||
self.counters[counter] += 1
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def get_counter(self, counter: str):
|
|
||||||
"""Get Counter"""
|
|
||||||
if not counter in self.counters.keys():
|
|
||||||
raise BaseException(f"[State] Counter {counter} does not exist")
|
|
||||||
|
|
||||||
return self.counters[counter]
|
|
||||||
|
|
||||||
async def get_all_counters(self):
|
|
||||||
"""Get All Counters"""
|
|
||||||
return self.counters
|
|
Loading…
x
Reference in New Issue
Block a user