diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ff9b6fc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/gallery.code-workspace b/gallery.code-workspace index ffd578d..72d0b3a 100644 --- a/gallery.code-workspace +++ b/gallery.code-workspace @@ -1,19 +1,29 @@ { "folders": [ { - "path": "." - } + "path": ".", + }, ], "settings": { "python.testing.pytestArgs": ["tests", "-s"], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, + "python-envs.pythonProjects": [ + { + "path": ".", + "envManager": "ms-python.python:poetry", + "packageManager": "ms-python.python:poetry", + }, + ], + "files.associations": { + "*.html": "jinja-html", + }, "files.exclude": { - "**/__pycache__": true + "**/__pycache__": true, }, "terminal.integrated.env.linux": { - "PYTHONPATH": "${workspaceFolder}" - } + "PYTHONPATH": "${workspaceFolder}", + }, }, "launch": { "version": "0.2.1", @@ -27,9 +37,9 @@ "gallery.main:app", "--reload", "--log-config", - "gallery/logging.yaml" - ] - } - ] - } + "gallery/logging.yaml", + ], + }, + ], + }, } diff --git a/gallery/easel/route/view/common/__init__.py b/gallery/easel/route/view/common/__init__.py index bd7f99e..442a098 100644 --- a/gallery/easel/route/view/common/__init__.py +++ b/gallery/easel/route/view/common/__init__.py @@ -29,7 +29,7 @@ def mount(app: FastAPI): async def get_section_list(request: Request): return templates.TemplateResponse( request=request, - name="index.html", + name="root_index.html", context={ "version": __version__, "sections": SECTIONS, diff --git a/gallery/easel/route/view/common/static/style.css b/gallery/easel/route/view/common/static/style.css index 57a926b..4f5ff36 100644 --- a/gallery/easel/route/view/common/static/style.css +++ b/gallery/easel/route/view/common/static/style.css @@ -47,25 +47,32 @@ app */ .app-container { display: flex; - flex-direction: column; + flex-direction: row; flex-wrap: nowrap; - align-items: center; + align-items: stretch; +} + +.app-menu { + display: flex; + flex-direction: column; + margin: 0.5rem; +} + +.app-content { + display: flex; + flex: 1; + flex-direction: column; } .app-header { width: 100%; display: flex; flex-direction: row; -} - -.app-title { - display: flex; + gap: 0.5rem; justify-content: center; - flex-grow: 1; } .app-link-home > * { - margin-left: 2rem; width: 2rem; height: 2rem; background-image: url("/static/common/gallery.png"); @@ -81,6 +88,7 @@ app ul.app-list { list-style: none; + padding-left: 0; } ul.app-list > li { diff --git a/gallery/easel/route/view/common/templates/base.html b/gallery/easel/route/view/common/templates/base.html new file mode 100644 index 0000000..42ad0da --- /dev/null +++ b/gallery/easel/route/view/common/templates/base.html @@ -0,0 +1,38 @@ + + + + + {% block head %} + + + + {% block title %}{% endblock %} + + + {% endblock %} + + + +
+ +
+
+
+
+

+ {% block header %}{% endblock %} +

+ {% block content %}{% endblock %} + +
+ + + \ No newline at end of file diff --git a/gallery/easel/route/view/common/templates/index.html b/gallery/easel/route/view/common/templates/index.html deleted file mode 100644 index a9d16c3..0000000 --- a/gallery/easel/route/view/common/templates/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - Информация - - - - - -

- -
-
-
- Информация -
-

- - - - \ No newline at end of file diff --git a/gallery/easel/route/view/common/templates/root_index.html b/gallery/easel/route/view/common/templates/root_index.html new file mode 100644 index 0000000..5d7855e --- /dev/null +++ b/gallery/easel/route/view/common/templates/root_index.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} +{% block title %}Информация{% endblock %} +{% block head %} +{{ super() }} +{% endblock %} + +{% block header %}Информация{% endblock %} + +{% block content %} + +{% endblock %} \ No newline at end of file diff --git a/gallery/easel/route/view/schedule/__init__.py b/gallery/easel/route/view/schedule/__init__.py index 441b22e..7d2d655 100644 --- a/gallery/easel/route/view/schedule/__init__.py +++ b/gallery/easel/route/view/schedule/__init__.py @@ -17,7 +17,12 @@ from .filters import timedelta_format def mount(app: FastAPI): base_dir = Path(__file__).parent app.mount("/static/schedule", StaticFiles(directory=base_dir / "static")) - templates = Jinja2Templates(directory=base_dir / "templates") + templates = Jinja2Templates( + directory=[ + base_dir.parent / "common/templates", + base_dir / "templates", + ] + ) templates.env.filters["timedelta_format"] = timedelta_format @app.get("/schedule", response_class=HTMLResponse) diff --git a/gallery/easel/route/view/schedule/templates/channel.html b/gallery/easel/route/view/schedule/templates/channel.html index 6e49e7f..db938c5 100644 --- a/gallery/easel/route/view/schedule/templates/channel.html +++ b/gallery/easel/route/view/schedule/templates/channel.html @@ -1,57 +1,43 @@ - - +{% extends "base.html" %} +{% block title %} +Программа | {{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}} +{% endblock %} +{% block head %} +{{ super() }} + + +{% endblock %} - - - - - Программа | {{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}} - - - - +{% block header %} +⬅️ +⬆️ +{{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}} +➡️ +{% endblock %} - -

- -
-
-
- ⬅️ - ⬆️ - {{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}} - ➡️ -
-

- - - - - - - - - - - {% for value in response.values %} - - - - - - {% endfor %} - -
{{value.start.strftime('%H:%M')}}{{(value.end - value.start) | timedelta_format}}{{value.label}}
- - - \ No newline at end of file +{% block content %} + + + + + + + + + + {% for value in response.values %} + + + + + + {% endfor %} + +
{{value.start.strftime('%H:%M')}}{{(value.end - value.start) | timedelta_format}}{{value.label}}
+{% endblock %} \ No newline at end of file diff --git a/gallery/easel/route/view/schedule/templates/index.html b/gallery/easel/route/view/schedule/templates/index.html index 2414898..35e15a4 100644 --- a/gallery/easel/route/view/schedule/templates/index.html +++ b/gallery/easel/route/view/schedule/templates/index.html @@ -1,38 +1,21 @@ - - +{% extends "base.html" %} +{% block title %}ТВ{% endblock %} +{% block head %} +{{ super() }} + + +{% endblock %} - - - - - ТВ - - - - +{% block header %}Телепрограмма{% endblock %} - -

- -
-
-
- Телепрограмма -
-

- - - - \ No newline at end of file +{% block content %} + +{% endblock %} \ No newline at end of file diff --git a/gallery/easel/route/view/schedule/templates/schedule.html b/gallery/easel/route/view/schedule/templates/schedule.html index 520a7af..1d745db 100644 --- a/gallery/easel/route/view/schedule/templates/schedule.html +++ b/gallery/easel/route/view/schedule/templates/schedule.html @@ -1,69 +1,57 @@ - - +{% extends "base.html" %} +{% block title %} +{{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}} +{% endblock %} +{% block head %} +{{ super() }} + + +{% endblock %} - - - - - ТВ - - - - +{% block header %} +⬅️ +⬆️ +{{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}} +➡️ +{% endblock %} - -

- -
-
-
- ⬅️ - ⬆️ - {{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}} - ➡️ -
-

- - - - - - - - - - - {% for response in responses %} - {% set values = (response.values|selectattr('live') if live else response.values)|list %} - {% if values|length > 0 %} - - - - - - {% for value in values %} - - - - - - {% endfor %} - {% endif %} - {% endfor %} - -
-
{{response.channel.name}}
-
{{value.start.strftime('%H:%M')}}{{(value.end - value.start) | timedelta_format}}{{value.label}}
- - - \ No newline at end of file +{% block content %} +
+ + + + + + + + + + {% for response in responses %} + {% set values = (response.values|selectattr('live') if live else response.values)|list %} + {% if values|length > 0 %} + + + + + + {% for value in values %} + + + + + + {% endfor %} + {% endif %} + {% endfor %} + +
+
{{response.channel.name}}
+
{{value.start.strftime('%H:%M')}}{{(value.end - value.start) | timedelta_format}}{{value.label}}
+
+{% endblock %} \ No newline at end of file diff --git a/gallery/easel/route/view/weather/__init__.py b/gallery/easel/route/view/weather/__init__.py index b03f300..1fd22b1 100644 --- a/gallery/easel/route/view/weather/__init__.py +++ b/gallery/easel/route/view/weather/__init__.py @@ -19,7 +19,12 @@ from .filters import cloudness_icon, wind_direction_icon def mount(app: FastAPI): base_dir = Path(__file__).parent app.mount("/static/weather", StaticFiles(directory=base_dir / "static")) - templates = Jinja2Templates(directory=base_dir / "templates") + templates = Jinja2Templates( + directory=[ + base_dir.parent / "common/templates", + base_dir / "templates", + ] + ) templates.env.filters["wind_direction_icon"] = wind_direction_icon templates.env.filters["cloudness_icon"] = cloudness_icon diff --git a/gallery/easel/route/view/weather/templates/index.html b/gallery/easel/route/view/weather/templates/index.html index d0dea15..0a4a53c 100644 --- a/gallery/easel/route/view/weather/templates/index.html +++ b/gallery/easel/route/view/weather/templates/index.html @@ -1,37 +1,20 @@ - - +{% extends "base.html" %} +{% block title %}Погода{% endblock %} +{% block head %} +{{ super() }} + + +{% endblock %} - - - - - Погода - - - - +{% block header %}Погода{% endblock %} - -

- -
-
-
- Погода -
-

- - - - \ No newline at end of file +{% block content %} + +{% endblock %} \ No newline at end of file diff --git a/gallery/easel/route/view/weather/templates/weather.html b/gallery/easel/route/view/weather/templates/weather.html index 6a0ce4d..dbee134 100644 --- a/gallery/easel/route/view/weather/templates/weather.html +++ b/gallery/easel/route/view/weather/templates/weather.html @@ -1,184 +1,171 @@ - - +{% extends "base.html" %} +{% block title %}Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}{% endblock %} +{% block head %} +{{ super() }} + + +{% endblock %} - - - - - Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}} - - - - +{% block header %} +{% if response.period == 'day' %} +⬅️ +⬆️ +{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}} +➡️ +{% endif %} +{% if response.period == 'days' %} +{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}} +{% endif %} +{% endblock %} - -

- -
-
-
- {% if response.period == 'day' %} - ⬅️ - ⬆️ - {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}} - ➡️ - {% endif %} - {% if response.period == 'days' %} - {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}} - {% endif %} -
-

- - - - - {% for value in response.values %} - {% if response.period == 'day' %} - - {% endif %} - {% if response.period == 'days' %} - - {% endif %} - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - - - - - - {% for value in response.values %} - - {% endfor %} - - -
- {{value.date.strftime('%H:%M')}} - - - - {{value.date.strftime('%a %d')}} - - -
- Облачность -
- {% for icon in value.sky | cloudness_icon %} -
{{icon}}
- {% endfor %} -
- Температура, °C -
- {% for temperature in value.temperature %} -
- {{temperature}} -
- {% endfor %} -
- Направление ветра -
- {{value.wind_direction | wind_direction_icon}} -
- Скорость ветра, м/с -
- {{value.wind_speed}} - {% if value.wind_gust != value.wind_speed %} - - ({{value.wind_gust}}) - - {% endif %} -
- Осадки, мм -
- {{value.precipitation or ' '}} -
- Давление, мм рт. ст. -
- {% for pressure in value.pressure %} -
- {{pressure}}
- {% endfor %} -
- Влажность, % -
- {{value.humidity}} -
- - - \ No newline at end of file +{% block content %} +
+ + + + + {% for value in response.values %} + {% if response.period == 'day' %} + + {% endif %} + {% if response.period == 'days' %} + + {% endif %} + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + + + + + + {% for value in response.values %} + + {% endfor %} + + +
+ {{value.date.strftime('%H:%M')}} + + + + {{value.date.strftime('%a %d')}} + + +
+ Облачность +
+ {% for icon in value.sky | cloudness_icon %} +
{{icon}}
+ {% endfor %} +
+ Температура, °C +
+ {% for temperature in value.temperature %} +
+ {{temperature}} +
+ {% endfor %} +
+ Направление ветра +
+ {{value.wind_direction | wind_direction_icon}} +
+ Скорость ветра, м/с +
+ {{value.wind_speed}} + {% if value.wind_gust != value.wind_speed %} + + ({{value.wind_gust}}) + + {% endif %} +
+ Осадки, мм +
+ {{value.precipitation or ' '}} +
+ Давление, мм рт. ст. +
+ {% for pressure in value.pressure %} +
+ {{pressure}}
+ {% endfor %} +
+ Влажность, % +
+ {{value.humidity}} +
+
+{% endblock %} \ No newline at end of file diff --git a/gallery/painting/matchtv/api.py b/gallery/painting/matchtv/api.py index 22c44d9..5bb9e47 100644 --- a/gallery/painting/matchtv/api.py +++ b/gallery/painting/matchtv/api.py @@ -29,19 +29,25 @@ class MatchTvApi(ScheduleApi): async def get_channel_schedule( self, channel_id: str, date: datetime.date ) -> Schedule: - endpoint = f"channel/{channel_id}/tvguide?date={date:%d-%m-%Y}" + endpoint = f"tvguide/{channel_id}?date={date:%Y%m%d}" data = await self.SOURCE.request(endpoint) soup = BeautifulSoup(data, features="html.parser") values = [] - channel_name = soup.select_one(".caption__heading").text.split("|")[0].strip() + channel_name = ( + soup.select_one(".p-tv-guide-header__title") + .text.replace("Телепрограмма ", "") + .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(".teleprogram-schedule .teleprogram-schedule__item"): - title = item.select_one(".teleprogram-item__title").text.strip() - time_str = item.select_one(".teleprogram-item__time").text.strip() + for item in soup.select( + ".p-tv-guide-schedule-channel-carcass__transmissions .p-tv-guide-schedule-channel-transmission" + ): + title = item.select_one(".p-tv-guide-schedule-channel-transmission__title").text.strip() + time_str = item.select_one(".p-tv-guide-schedule-channel-transmission__time-block").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: