# playlists/playlist_model.py from pydantic import BaseModel, Field, validator from typing import List, Optional, Literal import json import db class RuleSet(BaseModel): include_labels: List[str] = [] exclude_labels: List[str] = [] include_playlists: List[str] = [] exclude_playlists: List[str] = [] date_after: Optional[str] = None date_before: Optional[str] = None logic: Literal["AND", "OR"] = "AND" def to_json(self) -> str: return json.dumps(self.dict(), ensure_ascii=False, indent=2) @classmethod def from_json(cls, raw): """Accepte None, str vide ou dict JSON.""" if not raw: return cls() if isinstance(raw, dict): return cls(**raw) try: return cls(**json.loads(raw)) except Exception: return cls() class Playlist(BaseModel): id: Optional[int] = None name: str description: Optional[str] = "" type: Literal["manual", "dynamic"] = "manual" rules: RuleSet = Field(default_factory=RuleSet) created_at: Optional[str] = None updated_at: Optional[str] = None @validator("rules", pre=True, always=True) def ensure_rules(cls, v): """Transforme la valeur de rules_json (None, str ou dict) en RuleSet.""" if isinstance(v, RuleSet): return v return RuleSet.from_json(v) def save(self): """Insert or update playlist""" with db.get_conn() as conn: cur = conn.cursor() if self.id: cur.execute(""" UPDATE playlists SET name=?, description=?, type=?, rules_json=?, updated_at=CURRENT_TIMESTAMP WHERE id=? """, (self.name, self.description, self.type, self.rules.to_json(), self.id)) else: cur.execute(""" INSERT INTO playlists (name, description, type, rules_json) VALUES (?, ?, ?, ?) """, (self.name, self.description, self.type, self.rules.to_json())) self.id = cur.lastrowid conn.commit()