🎉 Initial commit: AudiOhm - Alternative à Spotify avec streaming YouTube
Features: - Frontend Flutter avec thème néon cyberpunk - Backend FastAPI avec streaming YouTube - Base de données PostgreSQL + Redis - Authentification JWT complète - Recherche multi-source (DB + YouTube) - Playlists CRUD avec drag & drop - Queue management - Settings avec audio quality - Interface adaptative (Desktop + Mobile) Tech Stack: - Frontend: Flutter 3.2+, Riverpod - Backend: Python 3.11+, FastAPI - Database: PostgreSQL 15+ - Cache: Redis 7+ - Streaming: yt-dlp + FFmpeg 🚀 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Playlist-Track association model."""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Integer, ForeignKey, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.track import Track
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
class PlaylistTrack(Base):
|
||||
"""Association model for Playlist-Track many-to-many relationship."""
|
||||
|
||||
__tablename__ = "playlist_tracks"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("playlist_id", "position", name="uq_playlist_position"),
|
||||
)
|
||||
|
||||
# Primary key
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
primary_key=True,
|
||||
default=uuid.uuid4,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# Foreign keys
|
||||
playlist_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("playlists.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
track_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("tracks.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# Position in playlist (starts at 0)
|
||||
position: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# User who added this track to playlist
|
||||
added_by: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("users.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# Timestamp when track was added
|
||||
added_at: Mapped[datetime] = mapped_column(
|
||||
default=datetime.utcnow,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# Relationships
|
||||
playlist: Mapped["Playlist"] = relationship(
|
||||
"Playlist",
|
||||
back_populates="playlist_tracks",
|
||||
lazy="selectin",
|
||||
)
|
||||
track: Mapped["Track"] = relationship(
|
||||
"Track",
|
||||
lazy="selectin",
|
||||
)
|
||||
added_by_user: Mapped["User"] = relationship(
|
||||
"User",
|
||||
back_populates="added_playlist_tracks",
|
||||
lazy="selectin",
|
||||
foreign_keys=[added_by],
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<PlaylistTrack playlist={self.playlist_id} track={self.track_id} pos={self.position}>"
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert playlist-track model to dictionary."""
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"playlist_id": str(self.playlist_id),
|
||||
"track_id": str(self.track_id),
|
||||
"position": self.position,
|
||||
"added_by": str(self.added_by) if self.added_by else None,
|
||||
"added_at": self.added_at.isoformat(),
|
||||
}
|
||||
Reference in New Issue
Block a user