75 lines
1.8 KiB
Python
75 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from typing import Any, Optional, TypedDict
|
|
|
|
|
|
class VideoData(TypedDict):
|
|
video_id: str
|
|
name: str
|
|
url: str
|
|
channel_id: str
|
|
channel_name: str
|
|
timestamp: datetime
|
|
watch_timestamp: Optional[datetime]
|
|
|
|
|
|
class ChannelData(TypedDict):
|
|
channel_id: str
|
|
name: str
|
|
new_videos: dict[str, Any]
|
|
watched_videos: dict[str, Any]
|
|
|
|
|
|
@dataclass
|
|
class Video:
|
|
video_id: str
|
|
name: str
|
|
url: str
|
|
channel_id: str
|
|
channel_name: str
|
|
timestamp: datetime
|
|
watch_timestamp: Optional[datetime] = None
|
|
|
|
def __str__(self) -> str:
|
|
return f'{self.channel_name} - {self.name} - {self.video_id}'
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: VideoData) -> Video:
|
|
return cls(**data)
|
|
|
|
|
|
@dataclass
|
|
class Channel:
|
|
channel_id: str
|
|
name: str
|
|
new_videos: dict[str, Video] = field(default_factory=lambda: dict())
|
|
watched_videos: dict[str, Video] = field(default_factory=lambda: dict())
|
|
|
|
def add_video(self, video: Video) -> bool:
|
|
if (
|
|
video.video_id in self.watched_videos
|
|
or video.video_id in self.new_videos
|
|
):
|
|
return False
|
|
|
|
self.new_videos[video.video_id] = video
|
|
return True
|
|
|
|
def mark_video_as_watched(self, video: Video) -> None:
|
|
self.new_videos.pop(video.video_id)
|
|
self.watched_videos[video.video_id] = video
|
|
|
|
def __str__(self) -> str:
|
|
return f'{self.name} - {len(self.new_videos)}'
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: ChannelData) -> Channel:
|
|
return cls(
|
|
channel_id=data['channel_id'],
|
|
name=data['name'],
|
|
new_videos=data.get('new_videos', {}).copy(),
|
|
watched_videos=data.get('watched_videos', {}).copy(),
|
|
)
|