123 lines
3.4 KiB
Python
123 lines
3.4 KiB
Python
"""Data models for the web application."""
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timezone
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class SearchResult:
|
|
"""Represents a YouTube search result."""
|
|
id: str
|
|
title: str
|
|
url: str
|
|
thumbnail: str
|
|
author: str
|
|
length: str
|
|
view_count: Optional[int] = None
|
|
is_short: bool = False
|
|
is_playlist: bool = False
|
|
description: str = ""
|
|
published: str = ""
|
|
|
|
|
|
@dataclass
|
|
class QueueItem:
|
|
"""Represents a download queue item."""
|
|
id: str
|
|
video_id: str
|
|
title: str
|
|
url: str
|
|
thumbnail: str = ""
|
|
status: str = "pending" # pending, downloading, completed, failed, cancelled
|
|
progress: float = 0.0
|
|
category: str = ""
|
|
network_folder: Optional[str] = None
|
|
added_at: str = ""
|
|
completed_at: Optional[str] = None
|
|
error_message: Optional[str] = None
|
|
download_path: Optional[str] = None
|
|
file_size: Optional[str] = None
|
|
speed: Optional[str] = None
|
|
eta: Optional[str] = None
|
|
item_type: str = "video" # video or playlist
|
|
quality: Optional[str] = None # e.g. "360", "480", "720", "1080", "best"
|
|
|
|
def __post_init__(self):
|
|
if not self.added_at:
|
|
self.added_at = datetime.now(timezone.utc).isoformat()
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"id": self.id,
|
|
"videoId": self.video_id,
|
|
"title": self.title,
|
|
"url": self.url,
|
|
"thumbnail": self.thumbnail,
|
|
"status": self.status,
|
|
"progress": self.progress,
|
|
"category": self.category,
|
|
"network_folder": self.network_folder,
|
|
"addedAt": self.added_at,
|
|
"completedAt": self.completed_at,
|
|
"errorMessage": self.error_message,
|
|
"downloadPath": self.download_path,
|
|
"fileSize": self.file_size,
|
|
"speed": self.speed,
|
|
"eta": self.eta,
|
|
"type": self.item_type,
|
|
"quality": self.quality,
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class ArchiveItem:
|
|
"""Represents a downloaded video in the archive."""
|
|
video_id: str
|
|
title: str
|
|
url: str
|
|
description: str = ""
|
|
thumbnail: str = ""
|
|
channel: str = ""
|
|
views: int = 0
|
|
duration: str = ""
|
|
category: str = ""
|
|
download_path: str = ""
|
|
network_share_path: Optional[str] = None
|
|
file_size: Optional[int] = None
|
|
download_date: str = ""
|
|
item_type: str = "video" # video or playlist
|
|
|
|
def __post_init__(self):
|
|
if not self.download_date:
|
|
self.download_date = datetime.now(timezone.utc).isoformat()
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"videoId": self.video_id,
|
|
"title": self.title,
|
|
"url": self.url,
|
|
"description": self.description,
|
|
"thumbnail": self.thumbnail,
|
|
"channel": self.channel,
|
|
"views": self.views,
|
|
"duration": self.duration,
|
|
"category": self.category,
|
|
"downloadPath": self.download_path,
|
|
"networkSharePath": self.network_share_path,
|
|
"fileSize": self.file_size,
|
|
"downloadDate": self.download_date,
|
|
"type": self.item_type,
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class SearchRecent:
|
|
"""Represents a recent search query."""
|
|
query: str
|
|
searched_at: str = ""
|
|
|
|
def __post_init__(self):
|
|
if not self.searched_at:
|
|
self.searched_at = datetime.now(timezone.utc).isoformat()
|