177 lines
4.2 KiB
Python
177 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from types import get_original_bases
|
|
from typing import Generic, Self, TypeVar, get_args
|
|
|
|
|
|
T = TypeVar('T')
|
|
|
|
|
|
class _Api(Generic[T], ABC):
|
|
@staticmethod
|
|
@abstractmethod
|
|
def from_dict(info: dict) -> T:
|
|
raise NotImplementedError
|
|
|
|
|
|
T_api = TypeVar('T_api', bound=_Api)
|
|
|
|
|
|
# Generic Objects
|
|
|
|
|
|
@dataclass
|
|
class PageInfo(_Api):
|
|
totalResults: int
|
|
resultsPerPage: int
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> PageInfo:
|
|
return PageInfo(totalResults=info['totalResults'], resultsPerPage=info['resultsPerPage'])
|
|
|
|
|
|
@dataclass
|
|
class ThumbnailInfo(_Api):
|
|
url: str
|
|
width: int
|
|
height: int
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> ThumbnailInfo:
|
|
return ThumbnailInfo(url=info['url'], width=info['width'], height=info['height'])
|
|
|
|
|
|
@dataclass
|
|
class Thumbnails(_Api):
|
|
default: ThumbnailInfo
|
|
medium: ThumbnailInfo
|
|
high: ThumbnailInfo
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> Thumbnails:
|
|
return Thumbnails(
|
|
default=ThumbnailInfo.from_dict(info['default']),
|
|
medium=ThumbnailInfo.from_dict(info['medium']),
|
|
high=ThumbnailInfo.from_dict(info['high']))
|
|
|
|
|
|
@dataclass
|
|
class Result(Generic[T_api]):
|
|
kind: str
|
|
etag: str
|
|
nextPageToken: str | None
|
|
pageInfo: PageInfo
|
|
items: list[T_api]
|
|
|
|
@classmethod
|
|
def from_dict(cls, info: dict) -> Self:
|
|
item_type = get_args(get_original_bases(cls)[0])[0]
|
|
return cls(
|
|
kind=info['kind'],
|
|
etag=info['etag'],
|
|
nextPageToken=info.get('nextPageToken'),
|
|
pageInfo=PageInfo.from_dict(info['pageInfo']),
|
|
items=[item_type.from_dict(i) for i in info['items']])
|
|
|
|
|
|
# Channel Objects
|
|
|
|
|
|
@dataclass
|
|
class ChannelSnippet(_Api):
|
|
title: str
|
|
description: str
|
|
customUrl: str
|
|
publishedAt: datetime
|
|
thumbnails: Thumbnails
|
|
country: str
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> ChannelSnippet:
|
|
return ChannelSnippet(
|
|
title=info['title'],
|
|
description=info['description'],
|
|
customUrl=info['customUrl'],
|
|
publishedAt=datetime.fromisoformat(info['publishedAt']),
|
|
thumbnails=Thumbnails.from_dict(info['thumbnails']),
|
|
country=info['country'])
|
|
|
|
|
|
@dataclass
|
|
class ChannelResultItem(_Api):
|
|
kind: str
|
|
etag: str
|
|
id: str
|
|
snippet: ChannelSnippet
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> ChannelResultItem:
|
|
return ChannelResultItem(
|
|
kind=info['kind'],
|
|
etag=info['etag'],
|
|
id=info['id'],
|
|
snippet=ChannelSnippet.from_dict(info['snippet']))
|
|
|
|
|
|
class ChannelResult(Result[ChannelResultItem]):
|
|
pass
|
|
|
|
|
|
# Search Objects
|
|
|
|
|
|
@dataclass
|
|
class SearchResultId(_Api):
|
|
kind: str
|
|
videoId: str
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> SearchResultId:
|
|
return SearchResultId(kind=info['kind'], videoId=info['videoId'])
|
|
|
|
|
|
@dataclass
|
|
class SearchSnippet(_Api):
|
|
publishedAt: datetime
|
|
channelId: str
|
|
title: str
|
|
description: str
|
|
thumbnails: Thumbnails
|
|
channelTitle: str
|
|
liveBroadcastContent: str
|
|
publishTime: datetime
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> SearchSnippet:
|
|
return SearchSnippet(
|
|
publishedAt=datetime.fromisoformat(info['publishedAt']),
|
|
channelId=info['channelId'],
|
|
title=info['title'],
|
|
description=info['description'],
|
|
thumbnails=Thumbnails.from_dict(info['thumbnails']),
|
|
channelTitle=info['channelTitle'],
|
|
liveBroadcastContent=info['liveBroadcastContent'],
|
|
publishTime=datetime.fromisoformat(info['publishTime']))
|
|
|
|
|
|
@dataclass
|
|
class SearchResultItem(_Api):
|
|
kind: str
|
|
etag: str
|
|
id: SearchResultId
|
|
snippet: SearchSnippet
|
|
|
|
@staticmethod
|
|
def from_dict(info: dict) -> SearchResultItem:
|
|
return SearchResultItem(
|
|
kind=info['kind'],
|
|
etag=info['etag'],
|
|
id=SearchResultId.from_dict(info['id']),
|
|
snippet=SearchSnippet.from_dict(info['snippet']))
|
|
|
|
|
|
class SearchResult(Result[SearchResultItem]):
|
|
pass
|