""" Podcast and Episode models for Podcastrr. """ from datetime import datetime from app.models.database import db class Podcast(db.Model): """ Model representing a podcast. """ __tablename__ = 'podcasts' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(255), nullable=False) author = db.Column(db.String(255)) description = db.Column(db.Text) image_url = db.Column(db.String(512)) feed_url = db.Column(db.String(512), nullable=False, unique=True) external_id = db.Column(db.String(255), unique=True) last_updated = db.Column(db.DateTime, default=datetime.utcnow) last_checked = db.Column(db.DateTime, default=datetime.utcnow) auto_download = db.Column(db.Boolean, default=False) naming_format = db.Column(db.String(255), nullable=True) # If null, use global settings episode_ordering = db.Column(db.String(20), default='absolute') # 'absolute' or 'season_episode' tags = db.Column(db.String(512), nullable=True) # Comma-separated list of tags # Relationships episodes = db.relationship('Episode', backref='podcast', lazy='dynamic', cascade='all, delete-orphan') def __repr__(self): return f'' def to_dict(self): """ Convert podcast to dictionary for API responses. """ return { 'id': self.id, 'title': self.title, 'author': self.author, 'description': self.description, 'image_url': self.image_url, 'feed_url': self.feed_url, 'external_id': self.external_id, 'last_updated': self.last_updated.isoformat() if self.last_updated else None, 'last_checked': self.last_checked.isoformat() if self.last_checked else None, 'auto_download': self.auto_download, 'naming_format': self.naming_format, 'tags': self.tags.split(',') if self.tags else [], 'episode_count': self.episodes.count() } def get_tags(self): """ Get the list of tags for this podcast. Returns: list: List of tags. """ return [tag.strip() for tag in self.tags.split(',')] if self.tags else [] def add_tag(self, tag): """ Add a tag to this podcast. Args: tag (str): Tag to add. """ if not tag: return tags = self.get_tags() if tag not in tags: tags.append(tag) self.tags = ','.join(tags) def remove_tag(self, tag): """ Remove a tag from this podcast. Args: tag (str): Tag to remove. """ if not tag: return tags = self.get_tags() if tag in tags: tags.remove(tag) self.tags = ','.join(tags) if tags else None class Episode(db.Model): """ Model representing a podcast episode. """ __tablename__ = 'episodes' id = db.Column(db.Integer, primary_key=True) podcast_id = db.Column(db.Integer, db.ForeignKey('podcasts.id'), nullable=False) title = db.Column(db.String(255), nullable=False) description = db.Column(db.Text) audio_url = db.Column(db.String(512), nullable=False) image_url = db.Column(db.String(512)) published_date = db.Column(db.DateTime) duration = db.Column(db.Integer) # Duration in seconds file_size = db.Column(db.Integer) # Size in bytes season = db.Column(db.Integer, nullable=True) # Season number episode_number = db.Column(db.String(50)) # Episode number within season or absolute guid = db.Column(db.String(512), unique=True) downloaded = db.Column(db.Boolean, default=False) file_path = db.Column(db.String(512)) explicit = db.Column(db.Boolean, nullable=True) # Whether the episode is marked as explicit download_error = db.Column(db.String(255), nullable=True) # Error message if download failed status_code = db.Column(db.Integer, nullable=True) # HTTP status code from last download attempt def __repr__(self): return f'' def to_dict(self): """ Convert episode to dictionary for API responses. """ return { 'id': self.id, 'podcast_id': self.podcast_id, 'title': self.title, 'description': self.description, 'audio_url': self.audio_url, 'image_url': self.image_url, 'published_date': self.published_date.isoformat() if self.published_date else None, 'duration': self.duration, 'file_size': self.file_size, 'season': self.season, 'episode_number': self.episode_number, 'guid': self.guid, 'downloaded': self.downloaded, 'file_path': self.file_path, 'explicit': self.explicit, 'download_error': self.download_error, 'status_code': self.status_code }