diff --git a/gallery/easel/route/view/common/static/style.css b/gallery/easel/route/view/common/static/style.css index 4f5ff36..b5eac59 100644 --- a/gallery/easel/route/view/common/static/style.css +++ b/gallery/easel/route/view/common/static/style.css @@ -89,6 +89,8 @@ app ul.app-list { list-style: none; padding-left: 0; + width: 30rem; + margin: auto; } ul.app-list > li { @@ -104,9 +106,9 @@ ul.app-list > li > a { } ul.app-list > li:hover { - border-color: blue; + border-color: rgb(125, 125, 255); } ul.app-list > li:hover > a { - color: blue; + color: rgb(125, 125, 255); } diff --git a/gallery/easel/route/view/schedule/__init__.py b/gallery/easel/route/view/schedule/__init__.py index 2417118..57fb7db 100644 --- a/gallery/easel/route/view/schedule/__init__.py +++ b/gallery/easel/route/view/schedule/__init__.py @@ -44,11 +44,7 @@ def mount(app: FastAPI): async def get_schedule_tag(request: AppRequest, tag: str, live: bool = False): tag_value = TagUtil.parse_tag(tag) schedule_api = request.app.state.api.schedule - channels = await schedule_api.get_channels() - responses = [ - await schedule_api.get_channel_schedule(channel, tag_value.date) - for channel in channels - ] + results = await schedule_api.get_all_schedules(tag_value.date) return templates.TemplateResponse( request=request, name="schedule.html", @@ -56,9 +52,8 @@ def mount(app: FastAPI): "version": __version__, "tag_util": TagUtil, "datetime": datetime, - "channels": channels, - "response": responses[0], - "responses": responses, + "response": results[0], + "responses": results, "live": live, }, ) diff --git a/gallery/easel/route/view/schedule/static/style.css b/gallery/easel/route/view/schedule/static/style.css index 3d7778a..e48a870 100644 --- a/gallery/easel/route/view/schedule/static/style.css +++ b/gallery/easel/route/view/schedule/static/style.css @@ -1,18 +1,25 @@ -tr { +table.schedule-table { + width: 60rem; + margin: auto; + table-layout: auto +} + +table.schedule-table tr { border-bottom: 1px solid lightgray; } -td { +table.schedule-table td { text-align: left; } -tr.live { +table.schedule-table tr.live { font-weight: bold; } -.title { +table.schedule-table .title { margin-top: 0.5rem; font-style: italic; font-weight: bold; font-size: 120%; + background-color: lightgray; } diff --git a/gallery/easel/route/view/schedule/templates/channel.html b/gallery/easel/route/view/schedule/templates/channel.html index db938c5..091f53e 100644 --- a/gallery/easel/route/view/schedule/templates/channel.html +++ b/gallery/easel/route/view/schedule/templates/channel.html @@ -22,7 +22,7 @@ {% endblock %} {% block content %} - +
diff --git a/gallery/easel/route/view/schedule/templates/schedule.html b/gallery/easel/route/view/schedule/templates/schedule.html index 1d745db..887ff75 100644 --- a/gallery/easel/route/view/schedule/templates/schedule.html +++ b/gallery/easel/route/view/schedule/templates/schedule.html @@ -23,7 +23,7 @@ {% block content %}
-
+
@@ -35,9 +35,9 @@ {% for response in responses %} {% set values = (response.values|selectattr('live') if live else response.values)|list %} {% if values|length > 0 %} - + diff --git a/gallery/painting/yandextv/api.py b/gallery/painting/yandextv/api.py index 360a7fc..b9856c9 100644 --- a/gallery/painting/yandextv/api.py +++ b/gallery/painting/yandextv/api.py @@ -18,13 +18,20 @@ CHANNELS_MAP: dict[ChannelId, str] = { ChannelId.MATCH_FUTBOL_3: "match-futbol-3-797", ChannelId.MATCH_STRANA: "match-strana-1356", ChannelId.MATCH_PLANETA: "match-planeta-1177", - ChannelId.EUROSPORT: "eurosport-677", - ChannelId.EUROSPORT_2: "eurosport-2-720", + # ChannelId.EUROSPORT: "eurosport-677", + # ChannelId.EUROSPORT_2: "eurosport-2-720", ChannelId.START: "start-103", } HEADERS: dict[str, str] = { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Accept": ( + "text/html," + "application/xhtml+xml," + "application/xml;q=0.9," + "image/avif,image/webp," + "image/apng,*/*;q=0.8," + "application/signed-exchange;v=b3;q=0.9" + ), "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Connection": "keep-alive", @@ -37,7 +44,12 @@ HEADERS: dict[str, str] = { "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", - "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.133 Safari/537.36", + "User-Agent": ( + "Mozilla/5.0 (X11; Linux x86_64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/100.0.4896.133 " + "Safari/537.36" + ), } diff --git a/gallery/sketch/cached.py b/gallery/sketch/cached.py index 290babc..52f7aa4 100644 --- a/gallery/sketch/cached.py +++ b/gallery/sketch/cached.py @@ -1,13 +1,19 @@ -from typing import Generic +from typing import Generic, NamedTuple from gallery.util import TimeUnit from .api import API, Api +class CachePreset(NamedTuple): + ttl: int = TimeUnit.HOUR + alias: str = "redis" + + +DEFAULT_CACHE_PRESET = CachePreset() + + class CachedApi(Api, Generic[API]): - CACHE_TTL: int = TimeUnit.HOUR - CACHE_ALIAS: str = "redis" CACHE_KEY: str def __init__(self, api: API): diff --git a/gallery/sketch/schedule/api.py b/gallery/sketch/schedule/api.py index ec962a1..e7b9832 100644 --- a/gallery/sketch/schedule/api.py +++ b/gallery/sketch/schedule/api.py @@ -1,3 +1,4 @@ +import asyncio import datetime from ..api import Api @@ -5,6 +6,8 @@ from .model import ChannelId, Schedule class ScheduleApi(Api): + INTERVAL: float = 0.5 + async def get_channels(self) -> list[ChannelId]: raise NotImplementedError @@ -12,3 +15,14 @@ class ScheduleApi(Api): self, channel_id: ChannelId, 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 diff --git a/gallery/sketch/schedule/cached.py b/gallery/sketch/schedule/cached.py index 3427599..7182df1 100644 --- a/gallery/sketch/schedule/cached.py +++ b/gallery/sketch/schedule/cached.py @@ -2,21 +2,21 @@ import datetime from aiocache import cached -from gallery.sketch.cached import CachedApi +from gallery.sketch.cached import CachedApi, CachePreset from gallery.util import TimeUnit from .api import ScheduleApi from .model import ChannelId, Schedule +CACHE_PRESET = CachePreset(ttl=TimeUnit.HOUR * 6) + class CachedScheduleApi(ScheduleApi, CachedApi[ScheduleApi]): CACHE_KEY = "schedule" - CACHE_TTL = TimeUnit.HOUR * 6 @cached( key_builder=lambda fun, self: f"api.{self.CACHE_KEY}.{self.provider}.channels", - alias=CachedApi.CACHE_ALIAS, - ttl=CachedApi.CACHE_TTL, + **CACHE_PRESET._asdict(), ) async def get_channels(self) -> list[ChannelId]: return await self._api.get_channels() @@ -25,10 +25,18 @@ class CachedScheduleApi(ScheduleApi, CachedApi[ScheduleApi]): key_builder=lambda fun, self, channel_id, date: ( f"api.{self.CACHE_KEY}.{self.provider}.channel.{channel_id}.{date}" ), - alias=CachedApi.CACHE_ALIAS, - ttl=CachedApi.CACHE_TTL, + **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) diff --git a/gallery/sketch/weather/cached.py b/gallery/sketch/weather/cached.py index 7aab27a..b45ba27 100644 --- a/gallery/sketch/weather/cached.py +++ b/gallery/sketch/weather/cached.py @@ -2,19 +2,20 @@ import datetime from aiocache import cached -from gallery.sketch.cached import CachedApi +from gallery.sketch.cached import DEFAULT_CACHE_PRESET, CachedApi from .api import WeatherApi from .model import WeatherResponse +CACHE_PRESET = DEFAULT_CACHE_PRESET + class CachedWeatherApi(WeatherApi, CachedApi[WeatherApi]): CACHE_KEY = "weather" @cached( key_builder=lambda fun, self: f"api.{self.CACHE_KEY}.{self.provider}.locations", - alias=CachedApi.CACHE_ALIAS, - ttl=CachedApi.CACHE_TTL, + **CACHE_PRESET._asdict(), ) async def get_locations(self) -> list[str]: return await self._api.get_locations() @@ -23,8 +24,7 @@ class CachedWeatherApi(WeatherApi, CachedApi[WeatherApi]): key_builder=lambda fun, self, location_id, date: ( f"api.{self.CACHE_KEY}.{self.provider}.day.{location_id}.{date}" ), - alias=CachedApi.CACHE_ALIAS, - ttl=CachedApi.CACHE_TTL, + **CACHE_PRESET._asdict(), ) async def get_day(self, location_id: str, date: datetime.date) -> WeatherResponse: return await self._api.get_day(location_id, date) @@ -33,8 +33,7 @@ class CachedWeatherApi(WeatherApi, CachedApi[WeatherApi]): key_builder=lambda fun, self, location_id, date: ( f"api.{self.CACHE_KEY}.{self.provider}.day.{location_id}.{date}" ), - alias=CachedApi.CACHE_ALIAS, - ttl=CachedApi.CACHE_TTL, + **CACHE_PRESET._asdict(), ) async def get_days(self, location_id: str, days: int) -> WeatherResponse: return await self._api.get_days(location_id, days) diff --git a/tests/test_yandextv_api.py b/tests/test_yandextv_api.py index 9886709..1dbb77c 100644 --- a/tests/test_yandextv_api.py +++ b/tests/test_yandextv_api.py @@ -2,7 +2,7 @@ import datetime import pytest -from gallery.painting.yandextv.api import YandexTvApi +from gallery.painting.yandextv.api import CHANNELS_MAP, YandexTvApi from gallery.painting.yandextv.mock import YANDEXTV_MOCK_DATA from gallery.sketch.schedule.model import ChannelId @@ -15,6 +15,8 @@ def yandextv_api_fixture() -> YandexTvApi: api = YandexTvApi() api.SOURCE = MockSource() + + CHANNELS_MAP[ChannelId("test")] = "test" return api
-
{{response.channel.name}}
+
{{response.channel.name}}