feat(schedule): implement multiple schedule providers

This commit is contained in:
2026-06-26 16:36:40 +03:00
parent 8b20eb1220
commit 29fe06462e
25 changed files with 1308 additions and 248 deletions

View File

@@ -1,6 +1,4 @@
from .api import API, Api
from .schedule.api import ScheduleApi
from .weather.api import WeatherApi
class ApiBundle:
@@ -21,9 +19,3 @@ class ApiBundle:
if provider is None or provider == value.provider:
return value
raise ValueError(api_type, provider)
def get_weather(self, provider: str | None = None) -> WeatherApi:
return self.get_api(WeatherApi, provider)
def get_schedule(self, provider: str | None = None) -> ScheduleApi:
return self.get_api(ScheduleApi, provider)

View File

@@ -1,14 +0,0 @@
from typing import Generic, TypeVar
T = TypeVar("T")
class CatalogBundle(Generic[T]):
def __init__(self, items: list[T]) -> None:
self._items_by_id = {item.id: item for item in items}
def get_item(self, item_id: str) -> T:
return self._items_by_id[item_id]
def select_items(self, ids: list[str]) -> list[T]:
return [self._items_by_id[id_] for id_ in ids]

View File

@@ -1,25 +1,14 @@
import asyncio
import datetime
from ..api import Api
from .model import ChannelId, Schedule
from .model import Channel, Schedule
class ScheduleApi(Api):
TYPE = "schedule"
INTERVAL: float = 0.5
async def get_channels(self) -> list[ChannelId]:
async def find_channels(self, query: str) -> list[Channel]:
raise NotImplementedError
async def get_channel_schedule(self, channel_id: ChannelId, date: datetime.date) -> Schedule:
async def get_schedule(self, channel_id: str, date: datetime.date) -> Schedule:
raise NotImplementedError
async def get_all_schedules(self, date: datetime.date) -> list[Schedule]:
channels = await self.get_channels()
results = []
for channel in channels:
results.append(await self.get_channel_schedule(channel_id=channel, date=date))
if self.INTERVAL > 0:
await asyncio.sleep(self.INTERVAL)
return results

View File

@@ -6,7 +6,7 @@ from gallery.sketch.cached import CachedApi, CachePreset
from gallery.util import TimeUnit
from .api import ScheduleApi
from .model import ChannelId, Schedule
from .model import Channel, Schedule
CACHE_PRESET = CachePreset(ttl=TimeUnit.HOUR * 6)
@@ -15,11 +15,11 @@ class CachedScheduleApi(ScheduleApi, CachedApi[ScheduleApi]):
CACHE_KEY = ScheduleApi.TYPE
@cached(
key_builder=lambda fun, self: f"api.{self.CACHE_KEY}.{self.provider}.channels",
key_builder=lambda fun, self, query: f"api.{self.CACHE_KEY}.{self.provider}.find.{query}",
**CACHE_PRESET._asdict(),
)
async def get_channels(self) -> list[ChannelId]:
return await self._api.get_channels()
async def find_channels(self, query: str) -> list[Channel]:
return await self._api.find_channels(query)
@cached(
key_builder=lambda fun, self, channel_id, date: (
@@ -27,12 +27,5 @@ class CachedScheduleApi(ScheduleApi, CachedApi[ScheduleApi]):
),
**CACHE_PRESET._asdict(),
)
async def get_channel_schedule(self, channel_id: ChannelId, date: datetime.date) -> Schedule:
return await self._api.get_channel_schedule(channel_id, date)
@cached(
key_builder=lambda fun, self, date: (f"api.{self.CACHE_KEY}.{self.provider}.all.{date}"),
**CACHE_PRESET._asdict(),
)
async def get_all_schedules(self, date: datetime.date) -> list[Schedule]:
return await self._api.get_all_schedules(date)
async def get_schedule(self, channel_id: str, date: datetime.date) -> Schedule:
return await self._api.get_schedule(channel_id, date)

View File

@@ -1,21 +0,0 @@
from gallery.sketch.catalog import CatalogBundle
from .model import Channel, ChannelId
BUNDLE = CatalogBundle(
[
Channel(id=ChannelId.MATCH_TV, name="Матч ТВ"),
Channel(id=ChannelId.MATCH_IGRA, name="Матч! Игра"),
Channel(id=ChannelId.MATCH_ARENA, name="Матч! Арена"),
Channel(id=ChannelId.MATCH_FUTBOL_1, name="Футбол 1"),
Channel(id=ChannelId.MATCH_FUTBOL_2, name="Футбол 2"),
Channel(id=ChannelId.MATCH_FUTBOL_3, name="Футбол 3"),
Channel(id=ChannelId.MATCH_STRANA, name="Матч! Страна"),
Channel(id=ChannelId.MATCH_PLANETA, name="Матч! Планета"),
Channel(id=ChannelId.MATCH_PLANETA, name="Матч! Планета"),
Channel(id=ChannelId.EUROSPORT, name="Europsort"),
Channel(id=ChannelId.EUROSPORT_2, name="Europsort 2"),
Channel(id=ChannelId.START, name="Старт!"),
Channel(id=ChannelId.TEST, name="Тест"),
]
)

View File

@@ -1,5 +1,4 @@
import datetime
from enum import StrEnum
from pydantic import BaseModel
@@ -9,27 +8,10 @@ class Model(BaseModel):
use_enum_values = True
class ChannelId(StrEnum):
MATCH_TV = "matchtv"
MATCH_IGRA = "igra"
MATCH_ARENA = "arena"
MATCH_FUTBOL_1 = "futbol-1"
MATCH_FUTBOL_2 = "futbol-2"
MATCH_FUTBOL_3 = "futbol-3"
MATCH_STRANA = "strana"
MATCH_PLANETA = "planeta"
EUROSPORT = "eurosport"
EUROSPORT_2 = "eurosport-2"
START = "start"
TEST = "test"
def __str__(self) -> str:
return self.value
class Channel(Model):
id: ChannelId
id: str
name: str
provider: str
class ScheduleValue(Model):

View File

@@ -26,7 +26,10 @@ class ApiSource:
self._headers = headers
async def request(self, endpoint: str) -> str:
url = f"{self._base_url}/{endpoint}"
if endpoint.startswith("https:"):
url = endpoint
else:
url = f"{self._base_url}/{endpoint}"
logger.info(url)
headers = {"User-Agent": self._user_agent, **(self._headers or {})}
async with aiohttp.ClientSession(