96 lines
4.5 KiB
Python
96 lines
4.5 KiB
Python
# playlists/playlist_db.py
|
|
import db
|
|
import json
|
|
from playlists.playlist_model import Playlist, RuleSet
|
|
|
|
def load_all_playlists():
|
|
"""Retourne une liste de Playlist (Pydantic) — tolérant aux rules_json nuls / vides."""
|
|
with db.get_conn() as conn:
|
|
# s'assurer que les lignes sont accessibles par nom (si get_conn ne l'a pas fait)
|
|
try:
|
|
conn.row_factory = conn.row_factory # no-op si déjà réglé
|
|
except Exception:
|
|
pass
|
|
|
|
rows = conn.execute("SELECT * FROM playlists ORDER BY created_at DESC").fetchall()
|
|
playlists = []
|
|
for row in rows:
|
|
# si row est sqlite3.Row, on peut accéder par nom, sinon c'est un tuple et on mappe par index
|
|
if hasattr(row, "__getitem__") and isinstance(row, dict) is False and getattr(row, "keys", None):
|
|
# sqlite3.Row behaves like mapping
|
|
row_dict = {k: row[k] for k in row.keys()}
|
|
elif isinstance(row, dict):
|
|
row_dict = row
|
|
else:
|
|
# fallback: convert tuple -> dict using cursor.description
|
|
# but here we assume conn.row_factory set in db.get_conn; keep robust fallback
|
|
cols = [d[0] for d in conn.execute("PRAGMA table_info(playlists)").fetchall()]
|
|
row_dict = dict(zip(cols, row))
|
|
|
|
try:
|
|
pl = Playlist(
|
|
id=row_dict.get("id"),
|
|
name=row_dict.get("name") or "",
|
|
description=row_dict.get("description") or "",
|
|
type=row_dict.get("type") or "manual",
|
|
rules=row_dict.get("rules_json")
|
|
)
|
|
playlists.append(pl)
|
|
except Exception as e:
|
|
# Ne bloque pas toute la lecture : logue et passe à la suivante
|
|
print(f"⚠️ Ignored invalid playlist row (id={row_dict.get('id')}, name={row_dict.get('name')}): {e}")
|
|
return playlists
|
|
|
|
def delete_playlist(playlist_id):
|
|
with db.get_conn() as conn:
|
|
conn.execute("DELETE FROM playlists WHERE id = ?", (playlist_id,))
|
|
conn.commit()
|
|
|
|
def get_videos_for_playlist(playlist: Playlist):
|
|
"""Retourne les vidéos selon le type"""
|
|
with db.get_conn() as conn:
|
|
if playlist.type == "manual":
|
|
q = """
|
|
SELECT v.*
|
|
FROM videos v
|
|
JOIN video_playlists vp ON vp.video_file_name = v.file_name
|
|
WHERE vp.playlist_id = ?
|
|
ORDER BY vp.position
|
|
"""
|
|
return conn.execute(q, (playlist.id,)).fetchall()
|
|
else:
|
|
rules = playlist.rules
|
|
clauses = []
|
|
params = []
|
|
|
|
if rules.include_labels:
|
|
placeholders = ",".join("?" * len(rules.include_labels))
|
|
clauses.append(f"v.file_name IN (SELECT vl.video_file_name FROM video_labels vl JOIN labels l ON l.id=vl.label_id WHERE l.name IN ({placeholders}))")
|
|
params += rules.include_labels
|
|
|
|
if rules.exclude_labels:
|
|
placeholders = ",".join("?" * len(rules.exclude_labels))
|
|
clauses.append(f"v.file_name NOT IN (SELECT vl.video_file_name FROM video_labels vl JOIN labels l ON l.id=vl.label_id WHERE l.name IN ({placeholders}))")
|
|
params += rules.exclude_labels
|
|
|
|
if rules.include_playlists:
|
|
placeholders = ",".join("?" * len(rules.include_playlists))
|
|
clauses.append(f"v.file_name IN (SELECT vp.video_file_name FROM video_playlists vp JOIN playlists p ON vp.playlist_id=p.id WHERE p.name IN ({placeholders}))")
|
|
params += rules.include_playlists
|
|
|
|
if rules.exclude_playlists:
|
|
placeholders = ",".join("?" * len(rules.exclude_playlists))
|
|
clauses.append(f"v.file_name NOT IN (SELECT vp.video_file_name FROM video_playlists vp JOIN playlists p ON vp.playlist_id=p.id WHERE p.name IN ({placeholders}))")
|
|
params += rules.exclude_playlists
|
|
|
|
if rules.date_after:
|
|
clauses.append("v.record_datetime >= ?")
|
|
params.append(rules.date_after)
|
|
if rules.date_before:
|
|
clauses.append("v.record_datetime <= ?")
|
|
params.append(rules.date_before)
|
|
|
|
where_clause = f" {' AND ' if rules.logic == 'AND' else ' OR '} ".join(clauses) if clauses else "1=1"
|
|
q = f"SELECT v.* FROM videos v WHERE {where_clause} ORDER BY v.record_datetime DESC"
|
|
return conn.execute(q, params).fetchall()
|