feat(schedule): update view
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<table>
|
||||
<table class="schedule-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<table class="{{'live' if live else ''}}">
|
||||
<table class="schedule-table {{'live' if live else ''}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
@@ -35,9 +35,9 @@
|
||||
{% for response in responses %}
|
||||
{% set values = (response.values|selectattr('live') if live else response.values)|list %}
|
||||
{% if values|length > 0 %}
|
||||
<tr>
|
||||
<tr class="title">
|
||||
<td colspan="3">
|
||||
<div class="title">{{response.channel.name}}</div>
|
||||
<div>{{response.channel.name}}</div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
|
||||
@@ -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"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user