Compare commits
6
Commits
2e64224840
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
160e1f9156 | ||
|
|
ad8f29c5ef | ||
|
|
4fc1c8c8e5 | ||
|
|
e414a93242 | ||
|
|
714fd1567c | ||
|
|
1d1ba69cc8 |
@@ -1,32 +0,0 @@
|
|||||||
name: "Setup"
|
|
||||||
description: "Setup project"
|
|
||||||
inputs:
|
|
||||||
python-version:
|
|
||||||
default: "3.14"
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- id: setup-python
|
|
||||||
uses: actions/setup-python@v7
|
|
||||||
with:
|
|
||||||
python-version: ${{ inputs.python-version }}
|
|
||||||
cache: "pip"
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
pip install project-manager \
|
|
||||||
--index-url https://git.shmyga.ru/api/packages/InfernalGames/pypi/simple/ \
|
|
||||||
--extra-index-url https://pypi.org/simple
|
|
||||||
|
|
||||||
- run: pm setup:config -vv
|
|
||||||
|
|
||||||
# setup python venv
|
|
||||||
- run: pip install poetry
|
|
||||||
|
|
||||||
- id: cache-venv
|
|
||||||
uses: actions/cache@v6
|
|
||||||
with:
|
|
||||||
path: .venv
|
|
||||||
key: venv-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
|
|
||||||
|
|
||||||
- if: steps.cache-venv.outputs.cache-hit != 'true'
|
|
||||||
run: pm setup:python -vv
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: [release]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: appleboy/ssh-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
username: ${{ secrets.DEPLOY_USERNAME }}
|
||||||
|
key: ${{ secrets.DEPLOY_KEY }}
|
||||||
|
passphrase: ${{ secrets.DEPLOY_PASSPHRASE }}
|
||||||
|
script: |
|
||||||
|
cd /opt/gallery
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
@@ -2,20 +2,19 @@ name: release
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags: ["*"]
|
tags:
|
||||||
|
- "[0-9]+.[0-9]+.[0-9]+"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
- uses: ./.gitea/actions/setup
|
- uses: https://git.shmyga.ru/InfernalGames/project-manager@master
|
||||||
- run: pm lint -vv
|
|
||||||
- run: pm test -vv
|
|
||||||
- run: pm build:docker -vv
|
- run: pm build:docker -vv
|
||||||
- uses: docker/login-action@v4
|
- uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: git.shmyga.ru
|
registry: git.shmyga.ru
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
username: ${{ vars.PUBLISH_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.PUBLISH_TOKEN }}
|
||||||
- run: pm publish:docker -vv
|
- run: pm publish:docker -vv
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
- uses: ./.gitea/actions/setup
|
- uses: https://git.shmyga.ru/InfernalGames/project-manager@master
|
||||||
|
with:
|
||||||
|
setup-python: true
|
||||||
- run: pm lint -vv
|
- run: pm lint -vv
|
||||||
- run: pm test -vv
|
- run: pm test -vv
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# API Gallery
|
# API Gallery
|
||||||
|
|
||||||
|
[](https://git.shmyga.ru/InfernalGames/gallery/actions?workflow=test.yaml)
|
||||||
|
|
||||||
Currently implemented APIs:
|
Currently implemented APIs:
|
||||||
|
|
||||||
- Weather forecast
|
- Weather forecast
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import datetime
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
|
||||||
@@ -13,9 +12,7 @@ from gallery.easel.depends.schedule import (
|
|||||||
ScheduleApiDepends,
|
ScheduleApiDepends,
|
||||||
ScheduleGroupChannelsDepends,
|
ScheduleGroupChannelsDepends,
|
||||||
)
|
)
|
||||||
from gallery.sketch.bundle import ApiBundle
|
|
||||||
from gallery.sketch.schedule.api import ScheduleApi
|
from gallery.sketch.schedule.api import ScheduleApi
|
||||||
from gallery.sketch.schedule.model import Schedule
|
|
||||||
|
|
||||||
from ..common.utils.template import build_templates
|
from ..common.utils.template import build_templates
|
||||||
from .filters import timedelta_format
|
from .filters import timedelta_format
|
||||||
@@ -52,12 +49,6 @@ async def get_schedule_index(request: AppRequest, provider: str | None = None, q
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
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)
|
@router.get("/group/{group_id}", response_class=RedirectResponse)
|
||||||
async def get_group_default(group_id: str):
|
async def get_group_default(group_id: str):
|
||||||
return RedirectResponse(f"{parse.quote(group_id)}/today")
|
return RedirectResponse(f"{parse.quote(group_id)}/today")
|
||||||
@@ -72,7 +63,16 @@ async def get_group(request: AppRequest, channels: ScheduleGroupChannelsDepends,
|
|||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="group.html",
|
name="group.html",
|
||||||
context={"responses": responses},
|
context={
|
||||||
|
"responses": responses,
|
||||||
|
"api_route": "/".join(
|
||||||
|
[
|
||||||
|
"/api/schedule/group",
|
||||||
|
request.path_params["group_id"],
|
||||||
|
request.path_params["date"],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -87,5 +87,17 @@ async def get_channel(request: AppRequest, schedule_api: ScheduleApiDepends, cha
|
|||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="channel.html",
|
name="channel.html",
|
||||||
context={"response": response},
|
context={
|
||||||
|
"response": response,
|
||||||
|
"api_route": (
|
||||||
|
"/".join(
|
||||||
|
[
|
||||||
|
"/api/schedule",
|
||||||
|
request.path_params["provider"],
|
||||||
|
request.path_params["channel"],
|
||||||
|
request.path_params["date"],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ locale=request.state.language)}}
|
|||||||
{% block header %}
|
{% block header %}
|
||||||
<app-link href="/schedule"
|
<app-link href="/schedule"
|
||||||
icon="tv">{{_("TV program")}}</app-link>
|
icon="tv">{{_("TV program")}}</app-link>
|
||||||
|
<app-link target="_blank"
|
||||||
|
href="{{ api_route }}"
|
||||||
|
icon="filetype-json"></app-link>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -44,7 +47,8 @@ locale=request.state.language)}}
|
|||||||
{% for value in response.values %}
|
{% for value in response.values %}
|
||||||
<tr class="{{'d-none' if (live and not value.live) else 'table-success' if (not live and value.live) else ''}}">
|
<tr class="{{'d-none' if (live and not value.live) else 'table-success' if (not live and value.live) else ''}}">
|
||||||
<td>
|
<td>
|
||||||
<span>{{value.start.strftime('%H:%M')}}</span> <span class="small ms-1">({{(value.end - value.start) | timedelta_format}})</span>
|
<span>{{value.start.strftime('%H:%M')}}</span> <span class="small ms-1">({{(value.end - value.start) |
|
||||||
|
timedelta_format}})</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{value.label}}</td>
|
<td>{{value.label}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
{% block header %}
|
{% block header %}
|
||||||
<app-link href="/schedule"
|
<app-link href="/schedule"
|
||||||
icon="tv">{{_("TV program")}}</app-link>
|
icon="tv">{{_("TV program")}}</app-link>
|
||||||
|
<app-link target="_blank"
|
||||||
|
href="{{ api_route }}"
|
||||||
|
icon="filetype-json"></app-link>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -37,7 +37,18 @@ def build_weather_response(request: AppRequest, response: WeatherResponse):
|
|||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="weather.html",
|
name="weather.html",
|
||||||
context={"response": response},
|
context={
|
||||||
|
"response": response,
|
||||||
|
"api_route": "/".join(
|
||||||
|
[
|
||||||
|
"/api/weather",
|
||||||
|
request.path_params["provider"],
|
||||||
|
request.path_params["location"],
|
||||||
|
response.period,
|
||||||
|
request.path_params.get("date") or request.path_params.get("days") or "",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ locale=request.state.language)}}{% endblock %}
|
|||||||
{% block header %}
|
{% block header %}
|
||||||
<app-link href="/weather"
|
<app-link href="/weather"
|
||||||
icon="brightness-high">{{_("Weather")}}</app-link>
|
icon="brightness-high">{{_("Weather")}}</app-link>
|
||||||
|
<app-link target="_blank"
|
||||||
|
href="{{ api_route }}"
|
||||||
|
icon="filetype-json"></app-link>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class YandexTVApi(ScheduleApi):
|
|||||||
return self.channel_parser.parse(data)
|
return self.channel_parser.parse(data)
|
||||||
|
|
||||||
async def get_schedule(self, channel_id: str, date: datetime.date) -> Schedule:
|
async def get_schedule(self, channel_id: str, date: datetime.date) -> Schedule:
|
||||||
endpoint = f"{self.lr}/channel/{channel_id}?date={date:%Y-%m-%d}"
|
channel_path_part = "channel" if "-" in channel_id else "channels"
|
||||||
|
endpoint = f"{self.lr}/{channel_path_part}/{channel_id}?date={date:%Y-%m-%d}"
|
||||||
data = await self.source.request(endpoint)
|
data = await self.source.request(endpoint)
|
||||||
return self.schedule_parser.parse(ScheduleData(date, channel_id, data))
|
return self.schedule_parser.parse(ScheduleData(date, channel_id, data))
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "gallery"
|
name = "gallery"
|
||||||
description = ""
|
description = ""
|
||||||
version = "0.10.4"
|
version = "0.10.5"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{ name = "shmyga", email = "shmyga.z@gmail.com" }]
|
authors = [{ name = "shmyga", email = "shmyga.z@gmail.com" }]
|
||||||
requires-python = ">=3.14,<4.0"
|
requires-python = ">=3.14,<4.0"
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.10.4",
|
"version": "0.10.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.10.4",
|
"version": "0.10.5",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.10.4",
|
"version": "0.10.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
|
|||||||
Vendored
+3
@@ -48,4 +48,7 @@
|
|||||||
&.bi-cast {
|
&.bi-cast {
|
||||||
mask-image: url(bootstrap-icons/icons/cast.svg);
|
mask-image: url(bootstrap-icons/icons/cast.svg);
|
||||||
}
|
}
|
||||||
|
&.bi-filetype-json {
|
||||||
|
mask-image: url(bootstrap-icons/icons/filetype-json.svg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user