Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2cd18386b | |||
| 2bca3dd75a | |||
| 469bd9bc1f | |||
| 027d1e2d55 | |||
| 7cf0012229 | |||
| edc014d98c |
@@ -7,7 +7,9 @@ WORKDIR /app
|
|||||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||||
COPY pyproject.toml poetry.lock README.md ./
|
COPY pyproject.toml poetry.lock README.md ./
|
||||||
RUN poetry config virtualenvs.in-project true
|
RUN poetry config virtualenvs.in-project true
|
||||||
RUN poetry install --with app --no-root
|
RUN --mount=type=cache,target=/root/.cache/pypoetry/cache \
|
||||||
|
--mount=type=cache,target=/root/.cache/pypoetry/artifacts \
|
||||||
|
poetry install --with app --no-root
|
||||||
COPY locales ./locales
|
COPY locales ./locales
|
||||||
RUN cd locales/ru/LC_MESSAGES && msgfmt messages.po
|
RUN cd locales/ru/LC_MESSAGES && msgfmt messages.po
|
||||||
|
|
||||||
@@ -15,7 +17,8 @@ FROM node:24 AS node-builder
|
|||||||
ENV PATH=/app/node_modules/.bin:$PATH
|
ENV PATH=/app/node_modules/.bin:$PATH
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY static/package.json static/package-lock.json ./
|
COPY static/package.json static/package-lock.json ./
|
||||||
RUN npm ci
|
RUN --mount=type=cache,target=/root/.npm \
|
||||||
|
npm ci
|
||||||
COPY static ./
|
COPY static ./
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
@@ -27,7 +30,6 @@ ENV TZ="Europe/Moscow"
|
|||||||
COPY --from=builder /app ./
|
COPY --from=builder /app ./
|
||||||
COPY --from=node-builder /app/dist ./static/dist
|
COPY --from=node-builder /app/dist ./static/dist
|
||||||
COPY gallery gallery/
|
COPY gallery gallery/
|
||||||
#COPY --from=builder /app/gallery/easel/route/view/locales /app/gallery/easel/route/view/locales
|
|
||||||
COPY --from=builder --parents locales/**/*.mo ./
|
COPY --from=builder --parents locales/**/*.mo ./
|
||||||
|
|
||||||
CMD ["uvicorn", "gallery.main:app", "--host", "0.0.0.0", "--port", "80", "--log-config", "gallery/logging.yaml"]
|
CMD ["uvicorn", "gallery.main:app", "--host", "0.0.0.0", "--port", "80", "--log-config", "gallery/logging.yaml"]
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 182 KiB |
@@ -4,8 +4,7 @@ from fastapi.staticfiles import StaticFiles
|
|||||||
from gallery.sketch.bundle import ApiBundle
|
from gallery.sketch.bundle import ApiBundle
|
||||||
from gallery.util import root_path
|
from gallery.util import root_path
|
||||||
|
|
||||||
from .route import api, doc
|
from .route import api, doc, view
|
||||||
from .route.view import router as view_router
|
|
||||||
|
|
||||||
|
|
||||||
def build_app(api_bundle: ApiBundle) -> FastAPI:
|
def build_app(api_bundle: ApiBundle) -> FastAPI:
|
||||||
@@ -17,6 +16,6 @@ def build_app(api_bundle: ApiBundle) -> FastAPI:
|
|||||||
app.state.api = api_bundle
|
app.state.api = api_bundle
|
||||||
app.mount("/static", StaticFiles(directory=root_path / "static/dist"))
|
app.mount("/static", StaticFiles(directory=root_path / "static/dist"))
|
||||||
doc.mount(app)
|
doc.mount(app)
|
||||||
api.mount(app)
|
app.include_router(api.router)
|
||||||
app.include_router(view_router)
|
app.include_router(view.router)
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from . import schedule, weather
|
from . import schedule, weather
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/api", tags=["API"])
|
||||||
def mount(app: FastAPI):
|
router.include_router(weather.router)
|
||||||
weather.mount(app)
|
router.include_router(schedule.router)
|
||||||
schedule.mount(app)
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
from gallery.easel.core import AppRequest
|
||||||
from gallery.sketch.schedule.model import ChannelId, Schedule
|
from gallery.sketch.schedule.model import ChannelId, Schedule
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/schedule")
|
||||||
|
|
||||||
def mount(app: FastAPI):
|
|
||||||
@app.get("/api/schedule/channels", tags=["API"])
|
@router.get("/channels")
|
||||||
async def get_api_schedule_channels(request: AppRequest) -> list[ChannelId]:
|
async def get_api_schedule_channels(request: AppRequest) -> list[ChannelId]:
|
||||||
schedule_api = request.app.state.api.schedule
|
schedule_api = request.app.state.api.schedule
|
||||||
return await schedule_api.get_channels()
|
return await schedule_api.get_channels()
|
||||||
|
|
||||||
@app.get("/api/schedule/{channel}/{date}", tags=["API"])
|
|
||||||
async def get_api_schedule_channel_schedule(request: AppRequest, channel: str, date: datetime.date) -> Schedule:
|
@router.get("/{channel}/{date}")
|
||||||
|
async def get_api_schedule_channel_schedule(request: AppRequest, channel: str, date: datetime.date) -> Schedule:
|
||||||
schedule_api = request.app.state.api.schedule
|
schedule_api = request.app.state.api.schedule
|
||||||
return await schedule_api.get_channel_schedule(ChannelId(channel), date)
|
return await schedule_api.get_channel_schedule(ChannelId(channel), date)
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
from gallery.easel.core import AppRequest
|
||||||
from gallery.sketch.weather.model import Location, WeatherResponse
|
from gallery.sketch.weather.model import Location, WeatherResponse
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/weather")
|
||||||
|
|
||||||
def mount(app: FastAPI):
|
|
||||||
@app.get("/api/weather/locations", tags=["API"])
|
@router.get("/locations")
|
||||||
async def get_api_weather_locations(request: AppRequest, query: str) -> list[Location]:
|
async def get_api_weather_locations(request: AppRequest, query: str) -> list[Location]:
|
||||||
weather_api = request.app.state.api.weather
|
weather_api = request.app.state.api.weather
|
||||||
return await weather_api.find_locations(query)
|
return await weather_api.find_locations(query)
|
||||||
|
|
||||||
@app.get("/api/weather/{location}/day/{date}", tags=["API"])
|
|
||||||
async def get_api_weather_day(request: AppRequest, location: str, date: datetime.date) -> WeatherResponse:
|
@router.get("/{location}/day/{date}")
|
||||||
|
async def get_api_weather_day(request: AppRequest, location: str, date: datetime.date) -> WeatherResponse:
|
||||||
weather_api = request.app.state.api.weather
|
weather_api = request.app.state.api.weather
|
||||||
return await weather_api.get_day(location, date)
|
return await weather_api.get_day(location, date)
|
||||||
|
|
||||||
@app.get("/api/weather/{location}/days/{days}", tags=["API"])
|
|
||||||
async def get_api_weather_days(request: AppRequest, location: str, days: int) -> WeatherResponse:
|
@router.get("/{location}/days/{days}")
|
||||||
|
async def get_api_weather_days(request: AppRequest, location: str, days: int) -> WeatherResponse:
|
||||||
weather_api = request.app.state.api.weather
|
weather_api = request.app.state.api.weather
|
||||||
return await weather_api.get_days(location, days)
|
return await weather_api.get_days(location, days)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .schedule import router as schedule_router
|
|||||||
from .translation import set_language
|
from .translation import set_language
|
||||||
from .weather import router as weather_router
|
from .weather import router as weather_router
|
||||||
|
|
||||||
router = APIRouter(dependencies=[Depends(set_language)])
|
router = APIRouter(tags=["view"], dependencies=[Depends(set_language)])
|
||||||
router.include_router(common_router)
|
router.include_router(common_router)
|
||||||
router.include_router(weather_router)
|
router.include_router(weather_router)
|
||||||
router.include_router(schedule_router)
|
router.include_router(schedule_router)
|
||||||
|
|||||||
@@ -30,6 +30,9 @@
|
|||||||
{% block header %}{% endblock %}
|
{% block header %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
|
<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
|
||||||
|
<li class="nav-item me-2">
|
||||||
|
<span class="nav-link">{{ version }}</span>
|
||||||
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<button class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle d-flex align-items-center"
|
<button class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle d-flex align-items-center"
|
||||||
id="bd-language"
|
id="bd-language"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{_("TV program")}} | {{response.channel.name}} | {{format_date(response.date, 'E, d MMMM Y', locale=request.state.language)}}
|
{{_("TV program")}} | {{response.channel.name}} | {{format_date(response.date, DATE_FORMAT,
|
||||||
|
locale=request.state.language)}}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
@@ -10,13 +11,19 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h4>
|
<h4>
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<a class="icon-link {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">
|
||||||
<a class="button"
|
<i class="bi bi-arrow-left-square"></i>
|
||||||
href="../..">⬆️</a>
|
</a>
|
||||||
<span>{{response.channel.name}} | {{format_date(response.date, 'E, d MMMM Y', locale=request.state.language)}}</span>
|
<a class="icon-link"
|
||||||
<a class="button"
|
href="../..">
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
<i class="bi bi-arrow-up-square"></i>
|
||||||
|
</a>
|
||||||
|
<span>{{response.channel.name}} | {{format_date(response.date, DATE_FORMAT, locale=request.state.language)}}</span>
|
||||||
|
<a class="icon-link"
|
||||||
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">
|
||||||
|
<i class="bi bi-arrow-right-square"></i>
|
||||||
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{_("Live broadcasts") if live else _("TV program")}} | {{format_date(response.date, 'E, d MMMM Y', locale=request.state.language)}}
|
{{_("Live broadcasts") if live else _("TV program")}} | {{format_date(response.date, DATE_FORMAT,
|
||||||
|
locale=request.state.language)}}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
@@ -10,13 +11,20 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h4>
|
<h4>
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<a class="icon-link {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">
|
||||||
<a class="button"
|
<i class="bi bi-arrow-left-square"></i>
|
||||||
href="..">⬆️</a>
|
</a>
|
||||||
<span>{{_("Live broadcasts") if live else _("TV program")}} | {{format_date(response.date, 'E, d MMMM Y', locale=request.state.language)}}</span>
|
<a class="icon-link"
|
||||||
<a class="button"
|
href="..">
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
<i class="bi bi-arrow-up-square"></i>
|
||||||
|
</a>
|
||||||
|
<span>{{_("Live broadcasts") if live else _("TV program")}} | {{format_date(response.date, DATE_FORMAT,
|
||||||
|
locale=request.state.language)}}</span>
|
||||||
|
<a class="icon-link"
|
||||||
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">
|
||||||
|
<i class="bi bi-arrow-right-square"></i>
|
||||||
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
__version__ = "0.2.2"
|
|
||||||
|
|
||||||
import tomllib
|
import tomllib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "gallery"
|
name = "gallery"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["shmyga <shmyga.z@gmail.com>"]
|
authors = ["shmyga <shmyga.z@gmail.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
4
static/package-lock.json
generated
4
static/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gallery",
|
"name": "gallery",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"dev": "vite build --watch"
|
"dev": "vite build --watch"
|
||||||
|
|||||||
Reference in New Issue
Block a user