playlists have been stored to redis for faster retrieval; additional work needed (playlist management, typeahead, etc- to move away from SQLite)

This commit is contained in:
2025-07-20 15:50:25 -04:00
parent c42ebbfe53
commit 8603b11438
4 changed files with 79 additions and 81 deletions

View File

@@ -3,7 +3,6 @@ import traceback
import time
import datetime
import os
import random
from uuid import uuid4 as uuid
from typing import Union, Optional, Iterable
from aiohttp import ClientSession, ClientTimeout
@@ -14,6 +13,12 @@ import gpt
import music_tag # type: ignore
from rapidfuzz import fuzz
from endpoints.constructors import RadioException
import redis.asyncio as redis
from redis.commands.search.query import Query # noqa
from redis.commands.search.indexDefinition import IndexDefinition, IndexType # noqa
from redis.commands.search.field import TextField # noqa
from redis.commands.json.path import Path # noqa
from lyric_search.sources import private
double_space: Pattern = regex.compile(r"\s{2,}")
non_alnum: Pattern = regex.compile(r"[^a-zA-Z0-9]")
@@ -28,6 +33,7 @@ class RadioUtil:
self.loop = loop
self.gpt = gpt.GPT(self.constants)
self.ls_uri: str = self.constants.LS_URI
self.redis_client = redis.Redis(password=private.REDIS_PW)
self.sqlite_exts: list[str] = [
"/home/kyle/api/solibs/spellfix1.cpython-311-x86_64-linux-gnu.so"
]
@@ -63,10 +69,18 @@ class RadioUtil:
# # "pop punk",
# # "pop-punk",
]
self.playlists: list = [
"main",
"rock",
"rap",
"electronic",
"classical",
"pop",
]
self.active_playlist: dict[str, list[dict]] = {}
self.playlists_loaded: bool = False
self.now_playing: dict[str, dict] = {
k: {
playlist: {
"artist": "N/A",
"song": "N/A",
"album": "N/A",
@@ -77,7 +91,7 @@ class RadioUtil:
"end": 0,
"file_path": None,
"id": None,
} for k in self.db_queries.keys()
} for playlist in self.playlists
}
self.webhooks: dict = {
"gpt": {
@@ -360,94 +374,76 @@ class RadioUtil:
traceback.print_exc()
return "Not Found"
def load_playlists(self) -> None:
async def load_playlists(self) -> None:
"""Load Playlists"""
try:
logging.info("Loading playlists...")
if isinstance(self.active_playlist, dict):
self.active_playlist.clear()
with sqlite3.connect(
f"file:{self.playback_db_path}?mode=ro", uri=True, timeout=30
) as db_conn:
db_conn.row_factory = sqlite3.Row
for station in self.db_queries:
db_query = self.db_queries.get(station)
if not db_query:
logging.critical("No query found for %s", station)
continue
if station not in self.active_playlist:
self.active_playlist[station] = []
time_start = time.time()
logging.info("[%s] Running query: %s",
time_start, db_query)
db_cursor = db_conn.execute(db_query)
results: list[sqlite3.Row] = db_cursor.fetchall()
time_end = time.time()
logging.info("[%s] Query completed; Time taken: %s", time_end, (time_end - time_start))
self.active_playlist[station] = [
{
"uuid": str(uuid().hex),
"id": r["id"],
"artist": double_space.sub(" ", r["artist"]).strip(),
"song": double_space.sub(" ", r["song"]).strip(),
"album": double_space.sub(" ", r["album"]).strip(),
"genre": r["genre"] if r["genre"] else "Not Found",
"artistsong": double_space.sub(
" ", r["artistdashsong"]
).strip(),
"file_path": r["file_path"],
"duration": r["duration"],
}
for r in results
if r not in self.active_playlist[station]
]
logging.info(
for playlist in self.playlists:
playlist_redis_key: str = f"playlist:{playlist}"
_playlist = await self.redis_client.json().get(playlist_redis_key)
if playlist not in self.active_playlist.keys():
self.active_playlist[playlist] = []
self.active_playlist[playlist] = [
{
"uuid": str(uuid().hex),
"id": r["id"],
"artist": double_space.sub(" ", r["artist"]).strip(),
"song": double_space.sub(" ", r["song"]).strip(),
"album": double_space.sub(" ", r["album"]).strip(),
"genre": r["genre"] if r["genre"] else "Not Found",
"artistsong": double_space.sub(
" ", r["artistdashsong"]
).strip(),
"file_path": r["file_path"],
"duration": r["duration"],
} for r in _playlist
if r not in self.active_playlist[playlist]
]
logging.info(
"Populated playlist: %s with %s items",
station, len(self.active_playlist[station]),
playlist, len(self.active_playlist[playlist]),
)
if not station == "rock":# REMOVE ME, AFI RELATED
random.shuffle(self.active_playlist[station])
"""Dedupe"""
logging.info("Removing duplicate tracks...")
dedupe_processed = []
for item in self.active_playlist[playlist]:
artistsongabc: str = non_alnum.sub("", item.get("artistsong", None))
if not artistsongabc:
logging.info("Missing artistsong: %s", item)
continue
if artistsongabc in dedupe_processed:
self.active_playlist[playlist].remove(item)
dedupe_processed.append(artistsongabc)
"""Dedupe"""
logging.info("Removing duplicate tracks...")
dedupe_processed = []
for item in self.active_playlist[station]:
artistsongabc: str = non_alnum.sub("", item.get("artistsong", None))
if not artistsongabc:
logging.info("Missing artistsong: %s", item)
continue
if artistsongabc in dedupe_processed:
self.active_playlist[station].remove(item)
dedupe_processed.append(artistsongabc)
logging.info(
"Duplicates for playlist: %s removed. New playlist size: %s",
playlist, len(self.active_playlist[playlist]),
)
if playlist == 'main' and self.playback_genres:
new_playlist: list[dict] = []
logging.info("Limiting playback genres")
for item in self.active_playlist[playlist]:
item_genres = item.get("genre", "").strip().lower()
# Check if any genre matches and item isn't already in new_playlist
if any(genre.strip().lower() in item_genres for genre in self.playback_genres):
if item not in new_playlist:
new_playlist.append(item)
self.active_playlist[playlist] = new_playlist
logging.info(
"Duplicates for playlist: %s removed. New playlist size: %s",
station, len(self.active_playlist[station]),
"%s items for playlist: %s remain for playback after filtering",
playlist, len(self.active_playlist[playlist]),
)
# logging.info(
# "Playlist: %s",
# [str(a.get("artistsong", "")) for a in self.active_playlist[station]],
# )
"""Loading Complete"""
logging.info(f"Skipping: {playlist}")
await self._ls_skip(playlist) # Request skip from LS to bring streams current
if station == 'main' and self.playback_genres:
new_playlist: list[dict] = []
logging.info("Limiting playback genres")
for item in self.active_playlist[station]:
item_genres = item.get("genre", "").strip().lower()
# Check if any genre matches and item isn't already in new_playlist
if any(genre.strip().lower() in item_genres for genre in self.playback_genres):
if item not in new_playlist:
new_playlist.append(item)
self.active_playlist[station] = new_playlist
logging.info(
"%s items for playlist: %s remain for playback after filtering",
station, len(self.active_playlist[station]),
)
self.playlists_loaded = True
# self.loop.run_until_complete(self._ls_skip())
except Exception as e:
logging.info("Playlist load failed: %s", str(e))
traceback.print_exc()