Files
AudiOhm/backend/app/models/playlist.py
T
root a89c7894cf Initial commit: AudiOhm - Alternative Spotify avec streaming YouTube
Backend:
- FastAPI avec PostgreSQL et Redis
- Authentification JWT complète
- API REST pour musique, playlists, recherche
- Streaming audio via yt-dlp
- SQLAlchemy 2.0 async

Frontend:
- Flutter avec thème néon cyberpunk
- State management Riverpod
- Layout adaptatif desktop/mobile
- Lecteur audio avec mini-player

Infrastructure:
- Docker Compose (PostgreSQL + Redis)
- Scripts d'installation automatisés
- Scripts de build pour exécutables

Fichiers ajoutés:
- BUILD_CLIENT_*.bat/sh: Scripts de compilation
- BUILD_CLIENT_README.md: Documentation compilation
- CHECK_FLUTTER.sh: Vérificateur d'environnement
- requirements.txt mis à jour pour Python 3.13
- Modèles SQLAlchemy corrigés (metadata -> extra_metadata)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-18 20:08:36 +00:00

134 lines
3.5 KiB
Python

"""Playlist model."""
import uuid
from datetime import datetime
from typing import TYPE_CHECKING
from sqlalchemy import String, Integer, Text, Boolean, ForeignKey
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
if TYPE_CHECKING:
from app.models.user import User
from app.models.playlist_track import PlaylistTrack
class Playlist(Base):
"""Playlist model representing user playlists."""
__tablename__ = "playlists"
# Primary key
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
primary_key=True,
default=uuid.uuid4,
index=True,
)
# Foreign key to user
user_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("users.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
# Basic info
name: Mapped[str] = mapped_column(
String(255),
nullable=False,
)
description: Mapped[str | None] = mapped_column(
Text,
)
image_url: Mapped[str | None] = mapped_column(
String(500),
)
# Playlist flags
is_public: Mapped[bool] = mapped_column(
Boolean,
default=False,
index=True,
)
is_collaborative: Mapped[bool] = mapped_column(
Boolean,
default=False,
)
is_smart: Mapped[bool] = mapped_column(
Boolean,
default=False,
comment="True for rules-based smart playlists",
)
# Smart playlist rules stored as JSON
smart_rules: Mapped[dict] = mapped_column(
JSONB,
default=dict,
comment="Rules for smart playlists",
)
# Playlist stats
track_count: Mapped[int] = mapped_column(
Integer,
default=0,
)
total_duration: Mapped[int] = mapped_column(
Integer,
default=0,
comment="Total duration in seconds",
)
# Timestamps
created_at: Mapped[datetime] = mapped_column(
default=datetime.utcnow,
nullable=False,
)
updated_at: Mapped[datetime] = mapped_column(
default=datetime.utcnow,
onupdate=datetime.utcnow,
nullable=False,
)
# Relationships
user: Mapped["User"] = relationship(
"User",
back_populates="playlists",
lazy="selectin",
)
playlist_tracks: Mapped[list["PlaylistTrack"]] = relationship(
"PlaylistTrack",
back_populates="playlist",
cascade="all, delete-orphan",
lazy="selectin",
order_by="PlaylistTrack.position",
)
def __repr__(self) -> str:
return f"<Playlist {self.name}>"
def to_dict(self, include_tracks: bool = False) -> dict:
"""Convert playlist model to dictionary."""
data = {
"id": str(self.id),
"user_id": str(self.user_id),
"name": self.name,
"description": self.description,
"image_url": self.image_url,
"is_public": self.is_public,
"is_collaborative": self.is_collaborative,
"is_smart": self.is_smart,
"smart_rules": self.smart_rules,
"track_count": self.track_count,
"total_duration": self.total_duration,
"created_at": self.created_at.isoformat(),
"updated_at": self.updated_at.isoformat(),
}
if include_tracks:
data["tracks"] = [pt.track.to_dict() for pt in self.playlist_tracks]
return data