feat: add catalog
This commit is contained in:
@@ -7,6 +7,7 @@ from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from gallery.sketch.schedule.api import ScheduleApi
|
||||
from gallery.sketch.schedule.catalog import BUNDLE
|
||||
from gallery.version import __version__
|
||||
|
||||
from ..common.util import TagType, TagUtil
|
||||
@@ -23,12 +24,13 @@ def mount(app: FastAPI):
|
||||
async def get_schedule_list(request: Request):
|
||||
schedule_api: ScheduleApi = request.app.state.schedule_api
|
||||
channels = await schedule_api.get_channels()
|
||||
channels_data = BUNDLE.select_items(channels)
|
||||
return templates.TemplateResponse(
|
||||
request=request,
|
||||
name="index.html",
|
||||
context={
|
||||
"version": __version__,
|
||||
"channels": channels,
|
||||
"channels": channels_data,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
</div>
|
||||
</h3>
|
||||
<ul class="app-list">
|
||||
<li style="margin-bottom: 0.25rem;"><a href="schedule/tag/today">all</a></li>
|
||||
<li style="margin-bottom: 0.25rem; font-weight: bold;"><a href="schedule/tag/today">Все</a></li>
|
||||
{% for channel in channels %}
|
||||
<li><a href="schedule/{{channel}}">{{channel}}</a></li>
|
||||
<li><a href="schedule/{{channel.id}}">{{channel.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
@@ -7,6 +7,7 @@ from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from gallery.sketch.weather.api import WeatherApi
|
||||
from gallery.sketch.weather.catalog import BUNDLE
|
||||
from gallery.sketch.weather.mock import WEATHER_MOCK_DATA
|
||||
from gallery.sketch.weather.model import WeatherResponse
|
||||
from gallery.version import __version__
|
||||
@@ -38,12 +39,13 @@ def mount(app: FastAPI):
|
||||
async def get_weather_list(request: Request):
|
||||
weather_api: WeatherApi = request.app.state.weather_api
|
||||
locations = await weather_api.get_locations()
|
||||
locations_data = BUNDLE.select_items(locations)
|
||||
return templates.TemplateResponse(
|
||||
request=request,
|
||||
name="index.html",
|
||||
context={
|
||||
"version": __version__,
|
||||
"locations": locations,
|
||||
"locations": locations_data,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</h3>
|
||||
<ul class="app-list">
|
||||
{% for location in locations %}
|
||||
<li><a href="weather/{{location}}">{{location}}</a></li>
|
||||
<li><a href="weather/{{location.id}}">{{location.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
@@ -7,6 +7,7 @@ from aiocache import cached
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from gallery.sketch.weather.api import WeatherApi
|
||||
from gallery.sketch.weather.catalog import LocationId
|
||||
from gallery.sketch.weather.model import WeatherResponse, WeatherValue
|
||||
|
||||
from . import datehelp
|
||||
@@ -81,8 +82,8 @@ class GismeteoApi(WeatherApi):
|
||||
|
||||
async def get_locations(self) -> list[str]:
|
||||
return [
|
||||
"orel-4432",
|
||||
"zmiyevka-184640",
|
||||
LocationId.OREL,
|
||||
LocationId.ZMIYEVKA,
|
||||
]
|
||||
|
||||
@cached(ttl=CACHE_TTL)
|
||||
|
||||
@@ -6,23 +6,12 @@ from aiocache import cached
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from gallery.sketch.schedule.api import ScheduleApi
|
||||
from gallery.sketch.schedule.catalog import ChannelId
|
||||
from gallery.sketch.schedule.model import Channel, Schedule, ScheduleValue
|
||||
|
||||
logger = logging.getLogger("matchtv")
|
||||
|
||||
|
||||
CHANNEL_LIST = [
|
||||
"matchtv",
|
||||
"igra",
|
||||
"arena",
|
||||
"futbol-1",
|
||||
"futbol-2",
|
||||
"futbol-3",
|
||||
"strana",
|
||||
# "planeta",
|
||||
]
|
||||
|
||||
|
||||
class MatchTvApi(ScheduleApi):
|
||||
BASE_URL = "https://matchtv.ru"
|
||||
CACHE_TTL = 30 * 60
|
||||
@@ -46,7 +35,15 @@ class MatchTvApi(ScheduleApi):
|
||||
return await response.text()
|
||||
|
||||
async def get_channels(self) -> list[str]:
|
||||
return CHANNEL_LIST
|
||||
return [
|
||||
ChannelId.MATCH_TV,
|
||||
ChannelId.MATCH_IGRA,
|
||||
ChannelId.MATCH_ARENA,
|
||||
ChannelId.MATCH_FUTBOL_1,
|
||||
ChannelId.MATCH_FUTBOL_2,
|
||||
ChannelId.MATCH_FUTBOL_3,
|
||||
ChannelId.MATCH_STRANA,
|
||||
]
|
||||
|
||||
@cached(ttl=CACHE_TTL)
|
||||
async def get_channel_schedule(
|
||||
|
||||
11
gallery/sketch/catalog.py
Normal file
11
gallery/sketch/catalog.py
Normal file
@@ -0,0 +1,11 @@
|
||||
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 select_items(self, ids: list[str]) -> list[T]:
|
||||
return [self._items_by_id[id_] for id_ in ids]
|
||||
31
gallery/sketch/schedule/catalog.py
Normal file
31
gallery/sketch/schedule/catalog.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from enum import Enum
|
||||
|
||||
from gallery.sketch.catalog import CatalogBundle
|
||||
|
||||
from .model import Channel
|
||||
|
||||
|
||||
class ChannelId(str, Enum):
|
||||
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"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
|
||||
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="Матч! Страна"),
|
||||
]
|
||||
)
|
||||
21
gallery/sketch/weather/catalog.py
Normal file
21
gallery/sketch/weather/catalog.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from enum import Enum
|
||||
|
||||
from gallery.sketch.catalog import CatalogBundle
|
||||
|
||||
from .model import Location
|
||||
|
||||
|
||||
class LocationId(str, Enum):
|
||||
OREL = "orel-4432"
|
||||
ZMIYEVKA = "zmiyevka-184640"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
|
||||
BUNDLE = CatalogBundle(
|
||||
[
|
||||
Location(id=LocationId.OREL, name="Орёл"),
|
||||
Location(id=LocationId.ZMIYEVKA, name="Змиёвка"),
|
||||
]
|
||||
)
|
||||
@@ -9,6 +9,11 @@ class Model(BaseModel):
|
||||
use_enum_values = True
|
||||
|
||||
|
||||
class Location(Model):
|
||||
id: str
|
||||
name: str
|
||||
|
||||
|
||||
class Cloudness(str, Enum):
|
||||
CLEAR = "clear"
|
||||
PARTLY_CLOUDY = "party_cloudy"
|
||||
|
||||
@@ -20,5 +20,4 @@ def matchtv_api_fixture() -> MatchTvApi:
|
||||
async def test_channel(matchtv_api: MatchTvApi):
|
||||
result = await matchtv_api.get_channel_schedule("matchtv", datetime.date.today())
|
||||
assert result is not None
|
||||
assert len(result.items) > 0
|
||||
print(">>", "\n".join(map(str, result.items)))
|
||||
assert len(result.values) > 0
|
||||
|
||||
Reference in New Issue
Block a user