67 lines
2.8 KiB
Python
67 lines
2.8 KiB
Python
import datetime
|
|
import json
|
|
import logging
|
|
|
|
from bs4 import BeautifulSoup
|
|
|
|
from gallery.sketch.schedule.api import ScheduleApi
|
|
from gallery.sketch.schedule.model import Channel, Schedule, ScheduleValue
|
|
from gallery.sketch.source import ApiSource
|
|
|
|
from ...sketch.headers import build_headers
|
|
|
|
logger = logging.getLogger("matchtv")
|
|
|
|
|
|
class YandexTvApi(ScheduleApi):
|
|
PROVIDER = "yandextv"
|
|
|
|
lr = 213 # magic id
|
|
|
|
def _build_source(self) -> ApiSource:
|
|
return ApiSource("https://tv.yandex.ru", headers=build_headers("tv.yandex.ru"))
|
|
|
|
async def find_channels(self, query: str) -> list[Channel]:
|
|
url = (
|
|
"https://suggest-multi.yandex.ru/suggest-tv2?"
|
|
f"v=4&uil=ru&lr={self.lr}&count_channels=4&count_programs=4&sn=50&part={query}"
|
|
)
|
|
_, values = json.loads(await self.source.request(url))
|
|
result = []
|
|
for _, name, content in values:
|
|
if content["label"] == "Каналы":
|
|
channel_id = content["url"].split("/")[-1]
|
|
result.append(Channel(id=channel_id, name=name, provider=self.provider))
|
|
return result
|
|
|
|
async def get_schedule(self, channel_id: str, date: datetime.date) -> Schedule:
|
|
endpoint = f"{self.lr}/channel/{channel_id}?date={date:%Y-%m-%d}"
|
|
data = await self.source.request(endpoint)
|
|
soup = BeautifulSoup(data, features="html.parser")
|
|
if soup.select_one(".CheckboxCaptcha") is not None:
|
|
raise RuntimeError("Captcha")
|
|
values = []
|
|
channel_name = soup.select_one(".channel-header__text").text.strip()
|
|
current_day = datetime.datetime.combine(date.today(), datetime.datetime.min.time())
|
|
end = current_day + datetime.timedelta(days=1, hours=6)
|
|
prev_value: ScheduleValue | None = None
|
|
for item in soup.select(".channel-schedule .channel-schedule__event"):
|
|
title = item.select_one(".channel-schedule__title").text.strip()
|
|
time_str = item.select_one(".channel-schedule__time").text.strip()
|
|
hours, minutes = map(int, time_str.split(":"))
|
|
item_date = current_day.replace(hour=hours, minute=minutes)
|
|
if prev_value is not None and item_date.hour < prev_value.start.hour:
|
|
current_day += datetime.timedelta(days=1)
|
|
item_date += datetime.timedelta(days=1)
|
|
live = item.select_one(".channel-schedule__info .icon_live") is not None
|
|
value = ScheduleValue(start=item_date, end=end, label=title, live=live)
|
|
values.append(value)
|
|
if prev_value is not None:
|
|
prev_value.end = item_date
|
|
prev_value = value
|
|
return Schedule(
|
|
channel=Channel(id=channel_id, name=channel_name, provider=self.provider),
|
|
date=date,
|
|
values=values,
|
|
)
|