diff --git a/gallery/easel/route/view/common/utils/tag.py b/gallery/easel/route/view/common/utils/tag.py index cb149b7..1de7d95 100644 --- a/gallery/easel/route/view/common/utils/tag.py +++ b/gallery/easel/route/view/common/utils/tag.py @@ -40,7 +40,9 @@ class TagUtil: elif tag.startswith("days-"): days = int(tag.split("-")[-1]) return Tag(TagType.DAYS, datetime.date.today(), days) - raise ValueError(tag) + else: + date = datetime.date.strptime(tag, "%Y-%m-%d") + return cls.create_tag(TagType.DAY, date) @classmethod def create_tag( diff --git a/gallery/easel/route/view/common/utils/template.py b/gallery/easel/route/view/common/utils/template.py index c724e45..35eeda9 100644 --- a/gallery/easel/route/view/common/utils/template.py +++ b/gallery/easel/route/view/common/utils/template.py @@ -29,8 +29,21 @@ def base_context_processor(request: Request) -> dict: } -def build_url(request: Request, query: dict | None = None) -> str: +def build_url( + request: Request, *, path: list[str] | None = None, up: int | None = None, query: dict | None = None +) -> str: + print("!", path) parts = urlsplit(str(request.url)) + if up: + path = [".."] * up + if path: + path_parts = parts.path.split("/") + for item in path: + if item == "..": + path_parts = path_parts[:-1] + else: + path_parts.append(str(item)) + parts = parts._replace(path="/".join(path_parts)) if query: query_dict = {**dict(parse_qsl(parts.query)), **query} parts = parts._replace(query=urlencode(query_dict)) diff --git a/gallery/easel/route/view/depends/tag.py b/gallery/easel/route/view/depends/tag.py new file mode 100644 index 0000000..e5e7c8f --- /dev/null +++ b/gallery/easel/route/view/depends/tag.py @@ -0,0 +1,18 @@ +import datetime +from typing import Annotated + +from fastapi import Depends + +from ..common.utils.tag import Tag, TagType, TagUtil + + +def _resolve_tag(date: datetime.date | None = None, tag: str | None = None) -> Tag: + if tag: + result = TagUtil.parse_tag(tag) + else: + date = date or datetime.date.today() + result = TagUtil.create_tag(TagType.DAY, date) + return result + + +TagDepends = Annotated[Tag, Depends(_resolve_tag)] diff --git a/gallery/easel/route/view/schedule/__init__.py b/gallery/easel/route/view/schedule/__init__.py index 518039d..2b6f557 100644 --- a/gallery/easel/route/view/schedule/__init__.py +++ b/gallery/easel/route/view/schedule/__init__.py @@ -1,91 +1 @@ -import datetime -from pathlib import Path - -from fastapi import APIRouter -from fastapi.responses import HTMLResponse, RedirectResponse - -from gallery.easel.core import AppRequest -from gallery.easel.depends.api import api_resolver -from gallery.easel.depends.schedule import ScheduleApiDepends -from gallery.sketch.schedule.api import ScheduleApi - -from ..common.utils.tag import TagType, TagUtil -from ..common.utils.template import build_templates -from .filters import timedelta_format - - -def context_procesor(request: AppRequest) -> dict: - return { - "providers": request.app.state.api.get_api_providers(ScheduleApi), - } - - -templates = build_templates( - Path(__file__).parent / "templates", - { - "timedelta_format": timedelta_format, - }, - context_procesor, -) - -router = APIRouter(prefix="/schedule") - - -@router.get("/", response_class=HTMLResponse) -async def get_schedule_index(request: AppRequest, provider: str | None = None, query: str | None = None): - if query and provider: - schedule_api = api_resolver(ScheduleApi)(request, provider) - channels = await schedule_api.find_channels(query) - else: - channels = [] - return templates.TemplateResponse( - request=request, - name="index.html", - context={ - "channels": channels, - }, - ) - - -@router.get("/{provider}/{channel}", response_class=RedirectResponse) -async def get_channel_default(channel: str): - return RedirectResponse(f"{channel}/tag/today") - - -@router.get("/{provider}/{channel}/tag/{tag}", response_class=HTMLResponse) -async def get_channel_tag(request: AppRequest, schedule_api: ScheduleApiDepends, channel: str, tag: str): - tag_value = TagUtil.parse_tag(tag) - if tag_value.type == TagType.DAY: - response = await schedule_api.get_schedule(channel, tag_value.date) - else: - raise ValueError(tag) - return templates.TemplateResponse( - request=request, - name="channel.html", - context={ - "tag_util": TagUtil, - "datetime": datetime, - "response": response, - }, - ) - - -@router.get("/group", response_class=HTMLResponse) -async def get_group(request: AppRequest, ids: str, date: datetime.date | None = None, tag: str | None = None): - date = date or datetime.date.today() - if tag: - date = TagUtil.parse_tag(tag).date - channels = [item.split(":") for item in ids.split(" ")] - responses = [ - await request.app.state.api.get_api(ScheduleApi, provider).get_schedule(channel_id, date) - for provider, channel_id in channels - ] - return templates.TemplateResponse( - request=request, - name="group.html", - context={ - "tag_util": TagUtil, - "datetime": datetime, - "responses": responses, - }, - ) +from .route import router diff --git a/gallery/easel/route/view/schedule/bundle.py b/gallery/easel/route/view/schedule/bundle.py new file mode 100644 index 0000000..123e159 --- /dev/null +++ b/gallery/easel/route/view/schedule/bundle.py @@ -0,0 +1,12 @@ +GROUP_MAP = { + "sport": [ + ("matchtv", "matchtv"), + ("matchtv", "igra"), + ("matchtv", "arena"), + ("matchtv", "futbol-1"), + ("matchtv", "futbol-2"), + ("matchtv", "futbol-3"), + ("matchtv", "strana"), + ("yandextv", "1799"), # start + ] +} diff --git a/gallery/easel/route/view/schedule/route.py b/gallery/easel/route/view/schedule/route.py new file mode 100644 index 0000000..0f57d41 --- /dev/null +++ b/gallery/easel/route/view/schedule/route.py @@ -0,0 +1,90 @@ +import datetime +from pathlib import Path +from urllib import parse + +from fastapi import APIRouter +from fastapi.responses import HTMLResponse, RedirectResponse + +from gallery.easel.core import AppRequest +from gallery.easel.depends.api import api_resolver +from gallery.easel.depends.schedule import ScheduleApiDepends +from gallery.sketch.bundle import ApiBundle +from gallery.sketch.schedule.api import ScheduleApi +from gallery.sketch.schedule.model import Schedule + +from ..common.utils.tag import TagType +from ..common.utils.template import build_templates +from ..depends.tag import TagDepends +from .bundle import GROUP_MAP +from .filters import timedelta_format + + +def context_procesor(request: AppRequest) -> dict: + return { + "providers": request.app.state.api.get_api_providers(ScheduleApi), + } + + +templates = build_templates( + Path(__file__).parent / "templates", + { + "timedelta_format": timedelta_format, + }, + context_procesor, +) + +router = APIRouter(prefix="/schedule") + + +@router.get("/", response_class=HTMLResponse) +async def get_schedule_index(request: AppRequest, provider: str | None = None, query: str | None = None): + if query and provider: + schedule_api = api_resolver(ScheduleApi)(request, provider) + channels = await schedule_api.find_channels(query) + else: + channels = [] + return templates.TemplateResponse( + request=request, + name="index.html", + context={"channels": channels}, + ) + + +async def _get_group_schedule(api: ApiBundle, channels: list[tuple[str, str]], date: datetime.date) -> list[Schedule]: + return [ + await api.get_api(ScheduleApi, provider).get_schedule(channel_id, date) for provider, channel_id in channels + ] + + +@router.get("/group/{group_id}", response_class=RedirectResponse) +async def get_group_default(group_id: str): + return RedirectResponse(f"{parse.quote(group_id)}/today") + + +@router.get("/group/{group_id}/{tag}", response_class=HTMLResponse) +async def get_group(request: AppRequest, group_id: str, tag: TagDepends): + channels = GROUP_MAP.get(group_id, [tuple(item.split(":")) for item in group_id.split(",")]) + responses = await _get_group_schedule(request.app.state.api, channels, tag.date) + return templates.TemplateResponse( + request=request, + name="group.html", + context={"responses": responses}, + ) + + +@router.get("/{provider}/{channel}", response_class=RedirectResponse) +async def get_channel_default(channel: str): + return RedirectResponse(f"{channel}/today") + + +@router.get("/{provider}/{channel}/{tag}", response_class=HTMLResponse) +async def get_channel_tag(request: AppRequest, schedule_api: ScheduleApiDepends, channel: str, tag: TagDepends): + if tag.type == TagType.DAY: + response = await schedule_api.get_schedule(channel, tag.date) + else: + raise ValueError(tag) + return templates.TemplateResponse( + request=request, + name="channel.html", + context={"response": response}, + ) diff --git a/gallery/easel/route/view/schedule/templates/channel.html b/gallery/easel/route/view/schedule/templates/channel.html index bfb67b8..8261f34 100644 --- a/gallery/easel/route/view/schedule/templates/channel.html +++ b/gallery/easel/route/view/schedule/templates/channel.html @@ -15,11 +15,11 @@ locale=request.state.language)}} {% block content %}

+ href="{{build_url(request, path=['..', date - datetime.timedelta(days=1)])}}"> + href="{{build_url(request, up=3)}}"> {{provider}} {{response.channel.name}} | {{format_date(response.date, DATE_FORMAT, locale=request.state.language)}} + href="{{build_url(request, path=['..', date + datetime.timedelta(days=1)])}}">

diff --git a/gallery/easel/route/view/schedule/templates/group.html b/gallery/easel/route/view/schedule/templates/group.html index a4a55c5..bb12cd7 100644 --- a/gallery/easel/route/view/schedule/templates/group.html +++ b/gallery/easel/route/view/schedule/templates/group.html @@ -14,11 +14,11 @@ {% block content %}

+ href="{{build_url(request, path=['..', date - datetime.timedelta(days=1)])}}"> + href="{{build_url(request, up=3)}}"> {{format_date(date, DATE_FORMAT, locale=request.state.language)}} + href="{{build_url(request, path=['..', date + datetime.timedelta(days=1)])}}">

diff --git a/gallery/easel/route/view/schedule/templates/index.html b/gallery/easel/route/view/schedule/templates/index.html index 0f368d6..3651017 100644 --- a/gallery/easel/route/view/schedule/templates/index.html +++ b/gallery/easel/route/view/schedule/templates/index.html @@ -44,7 +44,10 @@
{% endif %} +