157 lines
4.9 KiB
Python
157 lines
4.9 KiB
Python
"""Playlist model for managing sound playlists."""
|
|
|
|
from datetime import datetime
|
|
from typing import TYPE_CHECKING, Optional
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import db
|
|
|
|
if TYPE_CHECKING:
|
|
from app.models.playlist_sound import PlaylistSound
|
|
from app.models.user import User
|
|
|
|
|
|
class Playlist(db.Model):
|
|
"""Model for playlists containing sounds."""
|
|
|
|
__tablename__ = "playlist"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
genre: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
|
|
user_id: Mapped[Optional[int]] = mapped_column(
|
|
Integer, ForeignKey("user.id"), nullable=True
|
|
)
|
|
is_main: Mapped[bool] = mapped_column(
|
|
Boolean, default=False, nullable=False
|
|
)
|
|
is_deletable: Mapped[bool] = mapped_column(
|
|
Boolean, default=True, nullable=True
|
|
)
|
|
is_current: Mapped[bool] = mapped_column(
|
|
Boolean, default=False, nullable=False
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=lambda: datetime.now(tz=ZoneInfo("UTC")),
|
|
nullable=False,
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=lambda: datetime.now(tz=ZoneInfo("UTC")),
|
|
onupdate=lambda: datetime.now(tz=ZoneInfo("UTC")),
|
|
nullable=False,
|
|
)
|
|
|
|
# Relationships
|
|
user: Mapped[Optional["User"]] = relationship(
|
|
"User", back_populates="playlists"
|
|
)
|
|
playlist_sounds: Mapped[list["PlaylistSound"]] = relationship(
|
|
"PlaylistSound", back_populates="playlist", cascade="all, delete-orphan"
|
|
)
|
|
|
|
def __repr__(self) -> str:
|
|
"""String representation of the playlist."""
|
|
return f"<Playlist(id={self.id}, name='{self.name}', user_id={self.user_id})>"
|
|
|
|
def to_dict(self) -> dict:
|
|
"""Convert playlist to dictionary representation."""
|
|
return {
|
|
"id": self.id,
|
|
"name": self.name,
|
|
"description": self.description,
|
|
"genre": self.genre,
|
|
"user_id": self.user_id,
|
|
"is_main": self.is_main,
|
|
"is_deletable": self.is_deletable,
|
|
"is_current": self.is_current,
|
|
"created_at": (
|
|
self.created_at.isoformat() if self.created_at else None
|
|
),
|
|
"updated_at": (
|
|
self.updated_at.isoformat() if self.updated_at else None
|
|
),
|
|
"sound_count": (
|
|
len(self.playlist_sounds) if self.playlist_sounds else 0
|
|
),
|
|
}
|
|
|
|
@classmethod
|
|
def create_playlist(
|
|
cls,
|
|
name: str,
|
|
description: Optional[str] = None,
|
|
genre: Optional[str] = None,
|
|
user_id: Optional[int] = None,
|
|
is_main: bool = False,
|
|
is_deletable: bool = True,
|
|
is_current: bool = False,
|
|
commit: bool = True,
|
|
) -> "Playlist":
|
|
"""Create a new playlist."""
|
|
playlist = cls(
|
|
name=name,
|
|
description=description,
|
|
genre=genre,
|
|
user_id=user_id,
|
|
is_main=is_main,
|
|
is_deletable=is_deletable,
|
|
is_current=is_current,
|
|
)
|
|
|
|
db.session.add(playlist)
|
|
if commit:
|
|
db.session.commit()
|
|
|
|
return playlist
|
|
|
|
@classmethod
|
|
def find_current_playlist(
|
|
cls, user_id: Optional[int] = None
|
|
) -> Optional["Playlist"]:
|
|
"""Find the current active playlist."""
|
|
query = cls.query.filter_by(is_current=True)
|
|
if user_id is not None:
|
|
query = query.filter_by(user_id=user_id)
|
|
return query.first()
|
|
|
|
@classmethod
|
|
def find_main_playlist(
|
|
cls, user_id: Optional[int] = None
|
|
) -> Optional["Playlist"]:
|
|
"""Find the main playlist."""
|
|
query = cls.query.filter_by(is_main=True)
|
|
if user_id is not None:
|
|
query = query.filter_by(user_id=user_id)
|
|
return query.first()
|
|
|
|
def add_sound(
|
|
self, sound_id: int, order: Optional[int] = None, commit: bool = True
|
|
) -> "PlaylistSound":
|
|
"""Add a sound to the playlist."""
|
|
from app.models.playlist_sound import PlaylistSound
|
|
|
|
if order is None:
|
|
# Get the next order number
|
|
max_order = (
|
|
db.session.query(db.func.max(PlaylistSound.order))
|
|
.filter_by(playlist_id=self.id)
|
|
.scalar()
|
|
)
|
|
order = (max_order or 0) + 1
|
|
|
|
playlist_sound = PlaylistSound(
|
|
playlist_id=self.id, sound_id=sound_id, order=order
|
|
)
|
|
|
|
db.session.add(playlist_sound)
|
|
if commit:
|
|
db.session.commit()
|
|
|
|
return playlist_sound
|