feat: Phase 3 AI Radio (DJ Host & interleaved playlist) and Like/Dislike/Delete actions
- Add Like button: promotes wave track to permanent library and refills buffer - Add Dislike button: blacklists track in SQLite disliked_tracks, removes audio, refills buffer - Add Delete button in history table for library file removal - Add AI Radio module: wttr.in weather, Qwen 2.5 host monologues, speech synthesis, ID3 tags - Generate interleaved 'AI Радио.m3u8' alongside clean 'Моя Волна.m3u8' - Update Web UI with Radio DJ card, voice selection, and track actions
This commit is contained in:
1 parent
3db9bdb38b
commit
e5afeb06cc
15 files changed
+945
-8
No files matched your search
@@ -44,6 +44,17 @@ def init_db():
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
# Disliked / Blacklisted tracks table
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS disliked_tracks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
artist TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
disliked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(artist, title)
|
||||
)
|
||||
""")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
@@ -66,6 +77,42 @@ def record_downloaded_track(service: str, service_id: str, artist: str, title: s
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def remove_downloaded_track(file_path: str):
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM downloaded_tracks WHERE file_path = ?", (file_path,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def add_disliked_track(artist: str, title: str):
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
INSERT OR IGNORE INTO disliked_tracks (artist, title)
|
||||
VALUES (?, ?)
|
||||
""", (artist.strip(), title.strip()))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def get_disliked_track_keys() -> set:
|
||||
import re
|
||||
def _norm(s: str) -> str:
|
||||
s = s.lower()
|
||||
s = re.sub(r"[^\w\s]", "", s)
|
||||
return " ".join(s.split())
|
||||
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT artist, title FROM disliked_tracks")
|
||||
keys = set()
|
||||
for r in cursor.fetchall():
|
||||
art = _norm(r[0])
|
||||
tit = _norm(r[1])
|
||||
if art and tit:
|
||||
keys.add(f"{art}|{tit}")
|
||||
conn.close()
|
||||
return keys
|
||||
|
||||
def get_recent_tracks(limit: int = 50) -> List[Dict[str, Any]]:
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
Reference in new issue
Block a user