"""SQLAlchemy models for the media service.""" import uuid from datetime import datetime from sqlalchemy import ( Column, String, Text, Integer, BigInteger, Boolean, Float, DateTime, ForeignKey, Index, UniqueConstraint, ) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from app.database import Base class Show(Base): __tablename__ = "media_shows" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(String(64), nullable=False, index=True) title = Column(String(500), nullable=False) author = Column(String(500)) description = Column(Text) artwork_url = Column(Text) feed_url = Column(Text) local_path = Column(Text) show_type = Column(String(20), nullable=False, default="podcast") etag = Column(String(255)) last_modified = Column(String(255)) last_fetched_at = Column(DateTime) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) episodes = relationship("Episode", back_populates="show", cascade="all, delete-orphan") class Episode(Base): __tablename__ = "media_episodes" __table_args__ = ( UniqueConstraint("show_id", "guid", name="uq_media_episodes_show_guid"), Index("idx_media_episodes_show", "show_id"), Index("idx_media_episodes_published", "published_at"), ) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) show_id = Column(UUID(as_uuid=True), ForeignKey("media_shows.id", ondelete="CASCADE")) user_id = Column(String(64), nullable=False) title = Column(String(1000)) description = Column(Text) audio_url = Column(Text) duration_seconds = Column(Integer) file_size_bytes = Column(BigInteger) published_at = Column(DateTime) guid = Column(String(500)) artwork_url = Column(Text) is_downloaded = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.utcnow) show = relationship("Show", back_populates="episodes") progress = relationship("Progress", back_populates="episode", uselist=False, cascade="all, delete-orphan") class Progress(Base): __tablename__ = "media_progress" __table_args__ = ( UniqueConstraint("user_id", "episode_id", name="uq_media_progress_user_episode"), Index("idx_media_progress_user", "user_id"), ) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(String(64), nullable=False) episode_id = Column(UUID(as_uuid=True), ForeignKey("media_episodes.id", ondelete="CASCADE")) position_seconds = Column(Float, default=0) duration_seconds = Column(Integer) is_completed = Column(Boolean, default=False) playback_speed = Column(Float, default=1.0) last_played_at = Column(DateTime, default=datetime.utcnow) episode = relationship("Episode", back_populates="progress") class QueueItem(Base): __tablename__ = "media_queue" __table_args__ = ( UniqueConstraint("user_id", "episode_id", name="uq_media_queue_user_episode"), Index("idx_media_queue_user_order", "user_id", "sort_order"), ) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(String(64), nullable=False) episode_id = Column(UUID(as_uuid=True), ForeignKey("media_episodes.id", ondelete="CASCADE")) sort_order = Column(Integer, nullable=False, default=0) added_at = Column(DateTime, default=datetime.utcnow) episode = relationship("Episode") class PlaybackEvent(Base): __tablename__ = "media_playback_events" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(String(64), nullable=False) episode_id = Column(UUID(as_uuid=True), ForeignKey("media_episodes.id", ondelete="CASCADE")) event_type = Column(String(20), nullable=False) position_seconds = Column(Float) playback_speed = Column(Float, default=1.0) created_at = Column(DateTime, default=datetime.utcnow) episode = relationship("Episode")