feat(easel): add base template
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -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
|
||||||
@@ -1,19 +1,29 @@
|
|||||||
{
|
{
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"path": "."
|
"path": ".",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"python.testing.pytestArgs": ["tests", "-s"],
|
"python.testing.pytestArgs": ["tests", "-s"],
|
||||||
"python.testing.unittestEnabled": false,
|
"python.testing.unittestEnabled": false,
|
||||||
"python.testing.pytestEnabled": true,
|
"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": {
|
"files.exclude": {
|
||||||
"**/__pycache__": true
|
"**/__pycache__": true,
|
||||||
},
|
},
|
||||||
"terminal.integrated.env.linux": {
|
"terminal.integrated.env.linux": {
|
||||||
"PYTHONPATH": "${workspaceFolder}"
|
"PYTHONPATH": "${workspaceFolder}",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"launch": {
|
"launch": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
@@ -27,9 +37,9 @@
|
|||||||
"gallery.main:app",
|
"gallery.main:app",
|
||||||
"--reload",
|
"--reload",
|
||||||
"--log-config",
|
"--log-config",
|
||||||
"gallery/logging.yaml"
|
"gallery/logging.yaml",
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def mount(app: FastAPI):
|
|||||||
async def get_section_list(request: Request):
|
async def get_section_list(request: Request):
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="index.html",
|
name="root_index.html",
|
||||||
context={
|
context={
|
||||||
"version": __version__,
|
"version": __version__,
|
||||||
"sections": SECTIONS,
|
"sections": SECTIONS,
|
||||||
|
|||||||
@@ -47,25 +47,32 @@ app
|
|||||||
*/
|
*/
|
||||||
.app-container {
|
.app-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
flex-wrap: nowrap;
|
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 {
|
.app-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
gap: 0.5rem;
|
||||||
|
|
||||||
.app-title {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-grow: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-link-home > * {
|
.app-link-home > * {
|
||||||
margin-left: 2rem;
|
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
background-image: url("/static/common/gallery.png");
|
background-image: url("/static/common/gallery.png");
|
||||||
@@ -81,6 +88,7 @@ app
|
|||||||
|
|
||||||
ul.app-list {
|
ul.app-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.app-list > li {
|
ul.app-list > li {
|
||||||
|
|||||||
38
gallery/easel/route/view/common/templates/base.html
Normal file
38
gallery/easel/route/view/common/templates/base.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible"
|
||||||
|
content="ie=edge">
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/common/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/common/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="app-container">
|
||||||
|
<div class="app-menu">
|
||||||
|
<a class="app-link-home"
|
||||||
|
href="/">
|
||||||
|
<div></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="app-content">
|
||||||
|
<h3 class="app-header">
|
||||||
|
{% block header %}{% endblock %}</span>
|
||||||
|
</h3>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
<div class="app-footer">
|
||||||
|
{% block footer %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible"
|
|
||||||
content="ie=edge">
|
|
||||||
<title>Информация</title>
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/common/style.css?v={{version}}">
|
|
||||||
<link rel="icon"
|
|
||||||
href="/static/common/favicon.ico?v={{version}}"
|
|
||||||
type="image/x-icon">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
|
||||||
<h3 class="app-header">
|
|
||||||
<a class="app-link-home"
|
|
||||||
href="/">
|
|
||||||
<div></div>
|
|
||||||
</a>
|
|
||||||
<div class="app-title">
|
|
||||||
<span>Информация</span>
|
|
||||||
</div>
|
|
||||||
</h3>
|
|
||||||
<ul class="app-list">
|
|
||||||
{% for section in sections %}
|
|
||||||
<li>
|
|
||||||
<a href="{{section.link}}">
|
|
||||||
<span class="icon"
|
|
||||||
style="background-image: url(/static/{{section.link}}/{{section.link}}.png);"></span>
|
|
||||||
<span>{{section.title}}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
21
gallery/easel/route/view/common/templates/root_index.html
Normal file
21
gallery/easel/route/view/common/templates/root_index.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Информация{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}Информация{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<ul class="app-list">
|
||||||
|
{% for section in sections %}
|
||||||
|
<li>
|
||||||
|
<a href="{{section.link}}">
|
||||||
|
<span class="icon"
|
||||||
|
style="background-image: url(/static/{{section.link}}/{{section.link}}.png);"></span>
|
||||||
|
<span>{{section.title}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
@@ -17,7 +17,12 @@ from .filters import timedelta_format
|
|||||||
def mount(app: FastAPI):
|
def mount(app: FastAPI):
|
||||||
base_dir = Path(__file__).parent
|
base_dir = Path(__file__).parent
|
||||||
app.mount("/static/schedule", StaticFiles(directory=base_dir / "static"))
|
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
|
templates.env.filters["timedelta_format"] = timedelta_format
|
||||||
|
|
||||||
@app.get("/schedule", response_class=HTMLResponse)
|
@app.get("/schedule", response_class=HTMLResponse)
|
||||||
|
|||||||
@@ -1,57 +1,43 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% block title %}
|
||||||
|
Программа | {{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}}
|
||||||
|
{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/schedule/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/schedule/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<head>
|
{% block header %}
|
||||||
<meta charset="UTF-8">
|
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
<meta name="viewport"
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
||||||
content="width=device-width, initial-scale=1.0">
|
<a class="button"
|
||||||
<meta http-equiv="X-UA-Compatible"
|
href="../..">⬆️</a>
|
||||||
content="ie=edge">
|
<span>{{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
<title>Программа | {{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
|
<a class="button"
|
||||||
<link rel="stylesheet"
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
||||||
href="/static/common/style.css?v={{version}}">
|
{% endblock %}
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/schedule/style.css?v={{version}}">
|
|
||||||
<link rel="icon"
|
|
||||||
href="/static/schedule/favicon.ico?v={{version}}"
|
|
||||||
type="image/x-icon">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
{% block content %}
|
||||||
<h3 class="app-header">
|
<table>
|
||||||
<a class="app-link-home"
|
<thead>
|
||||||
href="/">
|
<tr>
|
||||||
<div></div>
|
<td></td>
|
||||||
</a>
|
<td></td>
|
||||||
<div class="app-title">
|
<td></td>
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
</tr>
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
</thead>
|
||||||
<a class="button"
|
<tbody>
|
||||||
href="../..">⬆️</a>
|
{% for value in response.values %}
|
||||||
<span>{{response.channel.name}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
<tr class="{{'live' if value.live else ''}}">
|
||||||
<a class="button"
|
<td>{{value.start.strftime('%H:%M')}}</td>
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
<td>{{(value.end - value.start) | timedelta_format}}</td>
|
||||||
</div>
|
<td>{{value.label}}</td>
|
||||||
</h3>
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
<table>
|
</tbody>
|
||||||
<thead>
|
</table>
|
||||||
<tr>
|
{% endblock %}
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for value in response.values %}
|
|
||||||
<tr class="{{'live' if value.live else ''}}">
|
|
||||||
<td>{{value.start.strftime('%H:%M')}}</td>
|
|
||||||
<td>{{(value.end - value.start) | timedelta_format}}</td>
|
|
||||||
<td>{{value.label}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,38 +1,21 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% block title %}ТВ{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/schedule/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/schedule/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<head>
|
{% block header %}Телепрограмма{% endblock %}
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible"
|
|
||||||
content="ie=edge">
|
|
||||||
<title>ТВ</title>
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/common/style.css?v={{version}}">
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/schedule/style.css?v={{version}}">
|
|
||||||
<link rel="icon"
|
|
||||||
href="/static/schedule/favicon.ico?v={{version}}"
|
|
||||||
type="image/x-icon">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
{% block content %}
|
||||||
<h3 class="app-header">
|
<ul class="app-list">
|
||||||
<a class="app-link-home"
|
<li style="margin-bottom: 0.25rem; font-weight: bold;"><a href="schedule/tag/today">Все</a></li>
|
||||||
href="/">
|
{% for channel in channels %}
|
||||||
<div></div>
|
<li><a href="schedule/{{channel.id}}">{{channel.name}}</a></li>
|
||||||
</a>
|
{% endfor %}
|
||||||
<div class="app-title">
|
</ul>
|
||||||
<span>Телепрограмма</span>
|
{% endblock %}
|
||||||
</div>
|
|
||||||
</h3>
|
|
||||||
<ul class="app-list">
|
|
||||||
<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.id}}">{{channel.name}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,69 +1,57 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% block title %}
|
||||||
|
{{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}}
|
||||||
|
{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/schedule/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/schedule/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<head>
|
{% block header %}
|
||||||
<meta charset="UTF-8">
|
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
<meta name="viewport"
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
||||||
content="width=device-width, initial-scale=1.0">
|
<a class="button"
|
||||||
<meta http-equiv="X-UA-Compatible"
|
href="..">⬆️</a>
|
||||||
content="ie=edge">
|
<span>{{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
<title>ТВ</title>
|
<a class="button"
|
||||||
<link rel="stylesheet"
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
||||||
href="/static/common/style.css?v={{version}}">
|
{% endblock %}
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/schedule/style.css?v={{version}}">
|
|
||||||
<link rel="icon"
|
|
||||||
href="/static/schedule/favicon.ico?v={{version}}"
|
|
||||||
type="image/x-icon">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
{% block content %}
|
||||||
<h3 class="app-header">
|
<div>
|
||||||
<a class="app-link-home"
|
<table class="{{'live' if live else ''}}">
|
||||||
href="/">
|
<thead>
|
||||||
<div></div>
|
<tr>
|
||||||
</a>
|
<td></td>
|
||||||
<div class="app-title">
|
<td></td>
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<td></td>
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
</tr>
|
||||||
<a class="button"
|
</thead>
|
||||||
href="..">⬆️</a>
|
<tbody>
|
||||||
<span>{{'Прямые трансляции' if live else 'Программа'}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
{% for response in responses %}
|
||||||
<a class="button"
|
{% set values = (response.values|selectattr('live') if live else response.values)|list %}
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
{% if values|length > 0 %}
|
||||||
</div>
|
<tr>
|
||||||
</h3>
|
<td colspan="3">
|
||||||
|
<div class="title">{{response.channel.name}}</div>
|
||||||
<table class="{{'live' if live else ''}}">
|
</td>
|
||||||
<thead>
|
<td></td>
|
||||||
<tr>
|
<td></td>
|
||||||
<td></td>
|
</tr>
|
||||||
<td></td>
|
{% for value in values %}
|
||||||
<td></td>
|
<tr class="{{'live' if not live and value.live else ''}}">
|
||||||
</tr>
|
<td>{{value.start.strftime('%H:%M')}}</td>
|
||||||
</thead>
|
<td>{{(value.end - value.start) | timedelta_format}}</td>
|
||||||
<tbody>
|
<td>{{value.label}}</td>
|
||||||
{% for response in responses %}
|
</tr>
|
||||||
{% set values = (response.values|selectattr('live') if live else response.values)|list %}
|
{% endfor %}
|
||||||
{% if values|length > 0 %}
|
{% endif %}
|
||||||
<tr>
|
{% endfor %}
|
||||||
<td colspan="3">
|
</tbody>
|
||||||
<div class="title">{{response.channel.name}}</div>
|
</table>
|
||||||
</td>
|
</div>
|
||||||
<td></td>
|
{% endblock %}
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
{% for value in values %}
|
|
||||||
<tr class="{{'live' if not live and value.live else ''}}">
|
|
||||||
<td>{{value.start.strftime('%H:%M')}}</td>
|
|
||||||
<td>{{(value.end - value.start) | timedelta_format}}</td>
|
|
||||||
<td>{{value.label}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -19,7 +19,12 @@ from .filters import cloudness_icon, wind_direction_icon
|
|||||||
def mount(app: FastAPI):
|
def mount(app: FastAPI):
|
||||||
base_dir = Path(__file__).parent
|
base_dir = Path(__file__).parent
|
||||||
app.mount("/static/weather", StaticFiles(directory=base_dir / "static"))
|
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["wind_direction_icon"] = wind_direction_icon
|
||||||
templates.env.filters["cloudness_icon"] = cloudness_icon
|
templates.env.filters["cloudness_icon"] = cloudness_icon
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% block title %}Погода{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/weather/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/weather/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<head>
|
{% block header %}Погода{% endblock %}
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible"
|
|
||||||
content="ie=edge">
|
|
||||||
<title>Погода</title>
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/common/style.css?v={{version}}">
|
|
||||||
<link rel="stylesheet"
|
|
||||||
href="/static/weather/style.css?v={{version}}">
|
|
||||||
<link rel="icon"
|
|
||||||
href="/static/weather/favicon.ico?v={{version}}"
|
|
||||||
type="image/x-icon">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
{% block content %}
|
||||||
<h3 class="app-header">
|
<ul class="app-list">
|
||||||
<a class="app-link-home"
|
{% for location in locations %}
|
||||||
href="/">
|
<li><a href="weather/{{location.id}}">{{location.name}}</a></li>
|
||||||
<div></div>
|
{% endfor %}
|
||||||
</a>
|
</ul>
|
||||||
<div class="app-title">
|
{% endblock %}
|
||||||
<span>Погода</span>
|
|
||||||
</div>
|
|
||||||
</h3>
|
|
||||||
<ul class="app-list">
|
|
||||||
{% for location in locations %}
|
|
||||||
<li><a href="weather/{{location.id}}">{{location.name}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,184 +1,171 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% block title %}Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}{% endblock %}
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="/static/weather/style.css?v={{version}}">
|
||||||
|
<link rel="icon"
|
||||||
|
href="/static/weather/favicon.ico?v={{version}}"
|
||||||
|
type="image/x-icon">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<head>
|
{% block header %}
|
||||||
<meta charset="UTF-8">
|
{% if response.period == 'day' %}
|
||||||
<meta name="viewport"
|
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
content="width=device-width, initial-scale=1.0">
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
||||||
<meta http-equiv="X-UA-Compatible"
|
<a class="button"
|
||||||
content="ie=edge">
|
href="../tag/days-10">⬆️</a>
|
||||||
<title>Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
|
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
<link rel="stylesheet"
|
<a class="button"
|
||||||
href="/static/common/style.css?v={{version}}">
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
||||||
<link rel="stylesheet"
|
{% endif %}
|
||||||
href="/static/weather/style.css?v={{version}}">
|
{% if response.period == 'days' %}
|
||||||
<link rel="icon"
|
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
href="/static/weather/favicon.ico?v={{version}}"
|
{% endif %}
|
||||||
type="image/x-icon">
|
{% endblock %}
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="app-container">
|
{% block content %}
|
||||||
<h3 class="app-header">
|
<div>
|
||||||
<a class="app-link-home"
|
<table style="margin: auto;">
|
||||||
href="/">
|
<tbody>
|
||||||
<div></div>
|
<!-- date -->
|
||||||
</a>
|
<tr>
|
||||||
<div class="app-title">
|
{% for value in response.values %}
|
||||||
{% if response.period == 'day' %}
|
{% if response.period == 'day' %}
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<td
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
class="date {{'now' if value.date < datetime.datetime.now() and value.date + datetime.timedelta(hours=3) > datetime.datetime.now() else ''}}">
|
||||||
<a class="button"
|
<span class="value">{{value.date.strftime('%H:%M')}}</span>
|
||||||
href="../tag/days-10">⬆️</a>
|
</td>
|
||||||
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
{% endif %}
|
||||||
<a class="button"
|
{% if response.period == 'days' %}
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
||||||
{% endif %}
|
<span class="value">
|
||||||
{% if response.period == 'days' %}
|
<a href="../tag/{{tag_util.create_tag('day', value.date.date())}}">
|
||||||
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
{{value.date.strftime('%a %d')}}
|
||||||
{% endif %}
|
</a>
|
||||||
</div>
|
</span>
|
||||||
</h3>
|
</td>
|
||||||
<table>
|
{% endif %}
|
||||||
<tbody>
|
{% endfor %}
|
||||||
<!-- date -->
|
</tr>
|
||||||
<tr>
|
<!-- cloudness -->
|
||||||
{% for value in response.values %}
|
<tr>
|
||||||
{% if response.period == 'day' %}
|
<td colspan="{{response.values | length}}"
|
||||||
<td
|
class="header">
|
||||||
class="date {{'now' if value.date < datetime.datetime.now() and value.date + datetime.timedelta(hours=3) > datetime.datetime.now() else ''}}">
|
Облачность
|
||||||
<span class="value">{{value.date.strftime('%H:%M')}}</span>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
{% endif %}
|
<tr>
|
||||||
{% if response.period == 'days' %}
|
{% for value in response.values %}
|
||||||
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
<td class="cloudness">
|
||||||
<span class="value">
|
{% for icon in value.sky | cloudness_icon %}
|
||||||
<a href="../tag/{{tag_util.create_tag('day', value.date.date())}}">
|
<div class="icon">{{icon}}</div>
|
||||||
{{value.date.strftime('%a %d')}}
|
{% endfor %}
|
||||||
</a>
|
</td>
|
||||||
</span>
|
{% endfor %}
|
||||||
</td>
|
</tr>
|
||||||
{% endif %}
|
<!-- temperature -->
|
||||||
{% endfor %}
|
<tr>
|
||||||
</tr>
|
<td colspan="{{response.values | length}}"
|
||||||
<!-- cloudness -->
|
class="header">
|
||||||
<tr>
|
Температура, °C
|
||||||
<td colspan="{{response.values | length}}"
|
</td>
|
||||||
class="header">
|
</tr>
|
||||||
Облачность
|
<tr>
|
||||||
</td>
|
{% for value in response.values %}
|
||||||
</tr>
|
<td class="temperature">
|
||||||
<tr>
|
{% for temperature in value.temperature %}
|
||||||
{% for value in response.values %}
|
<div class="value {{'positive' if temperature > 0 else 'negative'}}"
|
||||||
<td class="cloudness">
|
style="background-color: rgba(255, 128, 128, {{(temperature - 10) * 0.015}});">
|
||||||
{% for icon in value.sky | cloudness_icon %}
|
{{temperature}}
|
||||||
<div class="icon">{{icon}}</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
<!-- temperature -->
|
<!-- wind_direction -->
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="{{response.values | length}}"
|
<td colspan="{{response.values | length}}"
|
||||||
class="header">
|
class="header">
|
||||||
Температура, °C
|
Направление ветра
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{% for value in response.values %}
|
{% for value in response.values %}
|
||||||
<td class="temperature">
|
<td class="wind">
|
||||||
{% for temperature in value.temperature %}
|
<span class="icon">{{value.wind_direction | wind_direction_icon}}</span>
|
||||||
<div class="value {{'positive' if temperature > 0 else 'negative'}}"
|
</td>
|
||||||
style="background-color: rgba(255, 128, 128, {{(temperature - 10) * 0.015}});">
|
{% endfor %}
|
||||||
{{temperature}}
|
</tr>
|
||||||
</div>
|
<!-- wind_speed -->
|
||||||
{% endfor %}
|
<tr>
|
||||||
</td>
|
<td colspan="{{response.values | length}}"
|
||||||
{% endfor %}
|
class="header">
|
||||||
</tr>
|
Скорость ветра, м/с
|
||||||
<!-- wind_direction -->
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td colspan="{{response.values | length}}"
|
<tr>
|
||||||
class="header">
|
{% for value in response.values %}
|
||||||
Направление ветра
|
<td class="wind"
|
||||||
</td>
|
style="background-color: rgba(128, 128, 128, {{value.wind_speed * 0.05}});">
|
||||||
</tr>
|
<span class="speed">{{value.wind_speed}}</span>
|
||||||
<tr>
|
{% if value.wind_gust != value.wind_speed %}
|
||||||
{% for value in response.values %}
|
<span class="gust">
|
||||||
<td class="wind">
|
({{value.wind_gust}})
|
||||||
<span class="icon">{{value.wind_direction | wind_direction_icon}}</span>
|
</span>
|
||||||
</td>
|
{% endif %}
|
||||||
{% endfor %}
|
</td>
|
||||||
</tr>
|
{% endfor %}
|
||||||
<!-- wind_speed -->
|
</tr>
|
||||||
<tr>
|
<!-- precipitation -->
|
||||||
<td colspan="{{response.values | length}}"
|
<tr>
|
||||||
class="header">
|
<td colspan="{{response.values | length}}"
|
||||||
Скорость ветра, м/с
|
class="header">
|
||||||
</td>
|
Осадки, мм
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
{% for value in response.values %}
|
<tr>
|
||||||
<td class="wind"
|
{% for value in response.values %}
|
||||||
style="background-color: rgba(128, 128, 128, {{value.wind_speed * 0.05}});">
|
<td class="precipitation"
|
||||||
<span class="speed">{{value.wind_speed}}</span>
|
style="background-color: rgba(0, 128, 255, {{value.precipitation * 0.1}});">
|
||||||
{% if value.wind_gust != value.wind_speed %}
|
<span class="value">{{value.precipitation or ' '}}</span>
|
||||||
<span class="gust">
|
</td>
|
||||||
({{value.wind_gust}})
|
{% endfor %}
|
||||||
</span>
|
</tr>
|
||||||
{% endif %}
|
<!-- pressure -->
|
||||||
</td>
|
<tr>
|
||||||
{% endfor %}
|
<td colspan="{{response.values | length}}"
|
||||||
</tr>
|
class="header">
|
||||||
<!-- precipitation -->
|
Давление, мм рт. ст.
|
||||||
<tr>
|
</td>
|
||||||
<td colspan="{{response.values | length}}"
|
</tr>
|
||||||
class="header">
|
<tr>
|
||||||
Осадки, мм
|
{% for value in response.values %}
|
||||||
</td>
|
<td class="pressure">
|
||||||
</tr>
|
{% for pressure in value.pressure %}
|
||||||
<tr>
|
<div class="value"
|
||||||
{% for value in response.values %}
|
style="background-color: rgba(128, 0, 255, {{(pressure - 720) * 0.008}});">
|
||||||
<td class="precipitation"
|
{{pressure}}</div>
|
||||||
style="background-color: rgba(0, 128, 255, {{value.precipitation * 0.1}});">
|
{% endfor %}
|
||||||
<span class="value">{{value.precipitation or ' '}}</span>
|
</td>
|
||||||
</td>
|
{% endfor %}
|
||||||
{% endfor %}
|
</tr>
|
||||||
</tr>
|
<!-- humidity -->
|
||||||
<!-- pressure -->
|
<tr>
|
||||||
<tr>
|
<td colspan="{{response.values | length}}"
|
||||||
<td colspan="{{response.values | length}}"
|
class="header">
|
||||||
class="header">
|
Влажность, %
|
||||||
Давление, мм рт. ст.
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
{% for value in response.values %}
|
||||||
{% for value in response.values %}
|
<td class="humidity"
|
||||||
<td class="pressure">
|
style="background-color: rgba(128, 128, 255, {{value.humidity * 0.005}});">
|
||||||
{% for pressure in value.pressure %}
|
<span class="value">{{value.humidity}}</span>
|
||||||
<div class="value"
|
</td>
|
||||||
style="background-color: rgba(128, 0, 255, {{(pressure - 720) * 0.008}});">
|
{% endfor %}
|
||||||
{{pressure}}</div>
|
</tr>
|
||||||
{% endfor %}
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
{% endfor %}
|
</div>
|
||||||
</tr>
|
{% endblock %}
|
||||||
<!-- humidity -->
|
|
||||||
<tr>
|
|
||||||
<td colspan="{{response.values | length}}"
|
|
||||||
class="header">
|
|
||||||
Влажность, %
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
{% for value in response.values %}
|
|
||||||
<td class="humidity"
|
|
||||||
style="background-color: rgba(128, 128, 255, {{value.humidity * 0.005}});">
|
|
||||||
<span class="value">{{value.humidity}}</span>
|
|
||||||
</td>
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -29,19 +29,25 @@ class MatchTvApi(ScheduleApi):
|
|||||||
async def get_channel_schedule(
|
async def get_channel_schedule(
|
||||||
self, channel_id: str, date: datetime.date
|
self, channel_id: str, date: datetime.date
|
||||||
) -> Schedule:
|
) -> 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)
|
data = await self.SOURCE.request(endpoint)
|
||||||
soup = BeautifulSoup(data, features="html.parser")
|
soup = BeautifulSoup(data, features="html.parser")
|
||||||
values = []
|
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(
|
current_day = datetime.datetime.combine(
|
||||||
date.today(), datetime.datetime.min.time()
|
date.today(), datetime.datetime.min.time()
|
||||||
)
|
)
|
||||||
end = current_day + datetime.timedelta(days=1, hours=6)
|
end = current_day + datetime.timedelta(days=1, hours=6)
|
||||||
prev_value: ScheduleValue | None = None
|
prev_value: ScheduleValue | None = None
|
||||||
for item in soup.select(".teleprogram-schedule .teleprogram-schedule__item"):
|
for item in soup.select(
|
||||||
title = item.select_one(".teleprogram-item__title").text.strip()
|
".p-tv-guide-schedule-channel-carcass__transmissions .p-tv-guide-schedule-channel-transmission"
|
||||||
time_str = item.select_one(".teleprogram-item__time").text.strip()
|
):
|
||||||
|
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(":"))
|
hours, minutes = map(int, time_str.split(":"))
|
||||||
item_date = current_day.replace(hour=hours, minute=minutes)
|
item_date = current_day.replace(hour=hours, minute=minutes)
|
||||||
if prev_value is not None and item_date.hour < prev_value.start.hour:
|
if prev_value is not None and item_date.hour < prev_value.start.hour:
|
||||||
|
|||||||
Reference in New Issue
Block a user