feat/flask: reworked downloads page

- new table styles
- info about last version and build date
- "viruses" warning paragraph
This commit is contained in:
2025-10-04 17:13:08 +03:00
parent 16b4e7a919
commit 1155ec24f9
13 changed files with 220 additions and 76 deletions
+72 -29
View File
@@ -1,30 +1,23 @@
import threading
import time
import json
import re
from os import path, listdir
from datetime import date, datetime, timezone
from datetime import date
from configparser import ConfigParser
from urllib.request import urlopen
import sass
from flask import (
Flask,
redirect,
render_template,
request,
url_for,
g,
Response
)
from flask import Flask, redirect, render_template, request, url_for, g, Response
# ---------- ENV VARS --------------------------------------------------------
GIT_URL = "https://git.kolibrios.org/api/v1/repos/KolibriOS/kolibrios/branches/main"
GIT_FETCH_DELAY_SEC = 300 # 5 minutes
STATUS_URL = "https://builds.kolibrios.org/status.html"
STATUS_FETCH_DELAY_SEC = 300 # 5 minutes
# ---------- APP CONFIG ------------------------------------------------------
@@ -40,18 +33,64 @@ with open("static/style.css", "w", encoding="utf-8") as f:
autobuild_date = "DD.MM.YYYY"
autobuild_vers = "0.0.0.0+0000-0000000"
def _refresh_build_date_once():
global autobuild_date
global autobuild_date, autobuild_vers
try:
with urlopen(GIT_URL, timeout=10) as r:
b = json.load(r)
c = b.get("commit", {}) or {}
ts = c.get("timestamp")
if ts:
dt = datetime.fromisoformat(ts.replace("Z", "+00:00")).astimezone(timezone.utc)
autobuild_date = dt.strftime("%d.%m.%Y")
from urllib.request import Request, urlopen
import re
req = Request(
STATUS_URL,
headers={
"User-Agent": "Mozilla/5.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
},
)
with urlopen(req, timeout=10) as r:
html = r.read().decode(
r.headers.get_content_charset() or "utf-8", "replace"
)
rows = re.findall(r"(<tr\b[^>]*>.*?</tr>)", html, flags=re.I | re.S)
if not rows:
return
last_commit_ver = None
for row in rows:
cls = re.search(r'class\s*=\s*"([^"]*)"', row, flags=re.I)
classes = cls.group(1).lower() if cls else ""
text = re.sub(r"<[^>]+>", " ", row)
if "commit" in classes:
mver = re.search(
r"\b(\d+\.\d+\.\d+\.\d+\+\d{3,8}-[0-9a-fA-F]{7,40})\b", row
)
if mver:
last_commit_ver = mver.group(1)
elif "success" in classes:
mts = re.search(
r"\b(\d{4})\.(\d{2})\.(\d{2})\s+\d{2}:\d{2}:\d{2}\b", text
)
if not mts:
mds = re.search(r"\b(\d{2})\.(\d{2})\.(\d{4})\b", text)
if mds:
autobuild_date = f"{mds.group(1)}.{mds.group(2)}.{mds.group(3)}"
else:
return
else:
y, mo, d = mts.groups()
autobuild_date = f"{d}.{mo}.{y}"
if last_commit_ver:
autobuild_vers = last_commit_ver
return
except Exception:
pass
@@ -59,7 +98,7 @@ def _refresh_build_date_once():
def _updater_loop():
while True:
_refresh_build_date_once()
time.sleep(GIT_FETCH_DELAY_SEC)
time.sleep(STATUS_FETCH_DELAY_SEC)
_started = False
@@ -68,6 +107,7 @@ _refresh_build_date_once()
# Flask 3.x fix: start updater lazily on first request (since before_first_request is removed)
_updater_lock = threading.Lock()
@app.before_request
def _ensure_updater_started():
global _started
@@ -78,6 +118,11 @@ def _ensure_updater_started():
threading.Thread(target=_updater_loop, daemon=True).start()
@app.context_processor
def _inject_autobuild_vers():
return {"autobuild_vers": autobuild_vers}
@app.context_processor
def _inject_autobuild_date():
return {"autobuild_date": autobuild_date}
@@ -90,7 +135,7 @@ def load_all_locales():
translations = {}
locales_dir = "locales"
locales_code_default = ('en', 'ru', 'es')
locales_code_default = ("en", "ru", "es")
locales_code_extra = []
locales_code = ()
@@ -109,7 +154,7 @@ def load_all_locales():
}
locales_code = locales_code_default + tuple(sorted(locales_code_extra))
locales_name = {l: translations[l]['title']['language'] for l in locales_code}
locales_name = {l: translations[l]["title"]["language"] for l in locales_code}
return translations, locales_name, locales_code
@@ -137,7 +182,7 @@ def render_localized_template(lang, template_name):
@app.before_request
def before_request():
if args := request.view_args:
g.locale = args.get('lang', 'en')
g.locale = args.get("lang", "en")
g.translations = translations.get(g.locale, get_best_lang())
g.locales_name = locales_name
@@ -147,16 +192,14 @@ def inject_translations():
def translate(text, **kwargs):
section, key = text.split(":", 1)
template = g.translations \
.get(section, {}) \
.get(key, f"${section}: {key}$")
template = g.translations.get(section, {}).get(key, f"${section}: {key}$")
try:
return template.format(**kwargs)
except Exception:
return template
return {'_': translate}
return {"_": translate}
# ---------- MAIN PAGES ------------------------------------------------------
+7
View File
@@ -44,6 +44,9 @@ p_subscription = Wir hoffen, es gefällt Ihnen!
[downloads]
header = Herunterladen
version = Version:
date = Build-Datum:
img-descr = Disketten-Image
iso-descr = LiveCD-Abbild
distr-descr = Universal Flash/Multi-Boot-Abbild
@@ -68,6 +71,10 @@ download_description = Auf dieser Seite können Sie die nächtlichen Build-Distr
{git} verfügbar.
git-server = Git-Server
download_warn = Gelegentlich stufen einige Antivirenprogramme das {kolibrios}-Image fälschlicherweise als Bedrohung ein.
Das ist ein Fehlalarm.
{kolibrios} ist vollständig quelloffen, und Sie können es jederzeit selbst erstellen, um sicherzugehen, dass es vollständig sicher ist.
[screenshots]
header = Bildschirmfotos
+7
View File
@@ -45,6 +45,9 @@ p_subscription = We hope you will enjoy it!
[downloads]
header = Downloads
version = Version:
date = Build date:
img-descr = Floppy disk image
iso-descr = LiveCD image
distr-descr = Universal Flash/Multi-boot image
@@ -66,6 +69,10 @@ download_description = On this page you can download the nightly builds distribu
distributed under {gpl} license, its source code is available on our {git}.
git-server = Git server
download_warn = Occasionally, some antivirus software may incorrectly flag the {kolibrios} image as a threat.
This is a false positive.
{kolibrios} is fully open source, and you can always build it yourself to be sure that it is completely safe.
[screenshots]
header = Screenshots
+7
View File
@@ -41,6 +41,9 @@ p_subscription = ¡Esperamos que lo disfrutes!
[downloads]
header = Descargas
version = Versión:
date = Fecha de compilación:
img-descr = Imagen de disquete
iso-descr = Imagen LiveCD
distr-descr = Imagen Flash Universal/Multi-boot
@@ -63,6 +66,10 @@ download_description = En esta página puedes descargar la distribución de comp
disponible en nuestro {git}.
git-server = servidor Git
download_warn = Ocasionalmente, algunos programas antivirus pueden marcar incorrectamente la imagen de {kolibrios} como una amenaza.
Esto es un falso positivo.
{kolibrios} es completamente de código abierto y siempre puedes compilarlo tú mismo para asegurarte de que es totalmente seguro.
[screenshots]
header = Pantallas
+7
View File
@@ -48,6 +48,9 @@ p_subscription = Nous espérons que vous l`apprécierez !
[downloads]
header = Téléchargements
version = Version :
date = Date de compilation :
img-descr = Image de la disquette
iso-descr = Image du LiveCD
distr-descr = Image Universal Flash/Multi-boot
@@ -66,6 +69,10 @@ download_help = Pour un débutant, le LiveCD est le meilleur.\n\
download_description = Sur cette page, vous pouvez télécharger la distribution des builds nocturnes, ce qui signifie qu`ils contiennent toujours les modifications les plus récentes du système et peuvent donc être instables. Tous les fichiers sont compressés avec {zip}. {kolibrios} est distribué sous licence {gpl} et son code source est disponible sur notre {git}.
git-server = serveur Git
download_warn = Il arrive que certains antivirus signalent à tort limage {kolibrios} comme une menace.
Il sagit dun faux positif.
{kolibrios} est entièrement open source et vous pouvez toujours le compiler vous-même pour vous assurer quil est totalement sûr.
[screenshots]
header = Captures d`écran
+7
View File
@@ -40,6 +40,9 @@ p_subscription = Ci auguriamo che vi piaccia!
[downloads]
header = Scaricamento
version = Versione:
date = Data di compilazione:
img-descr = Immagine su dischetto
iso-descr = Immagine LiveCD
distr-descr = Immagine universale Flash/MultiBoot
@@ -62,6 +65,10 @@ download_description = In questa pagina puoi scaricare la distribuzione delle bu
disponibile sul nostro {git}.
git-server = server Git
download_warn = Occasionalmente, alcuni software antivirus potrebbero segnalare erroneamente limmagine di {kolibrios} come una minaccia.
Si tratta di un falso positivo.
{kolibrios} è completamente open source e puoi sempre compilarlo tu stesso per essere certo che è del tutto sicuro.
[screenshots]
header = Captures d`écran
+7
View File
@@ -46,6 +46,9 @@ p_subscription = We hopen dat je ervan zult genieten!
[downloads]
header = Downloads
version = Versie:
date = Builddatum:
img-descr = Afbeelding op diskette
iso-descr = LiveCD-afbeelding
distr-descr = Universele Flash/Multi-boot image
@@ -67,6 +70,10 @@ download_description = Op deze pagina kunt u de nightly builds-distributie downl
verspreid onder de {gpl}-licentie, en de broncode is beschikbaar op onze {git}.
git-server = Git-server
download_warn = Af en toe kunnen sommige antivirusprogrammas het {kolibrios}-image ten onrechte als een bedreiging aanmerken.
Dit is een vals-positief.
{kolibrios} is volledig open-source en je kunt het altijd zelf bouwen om er zeker van te zijn dat het volledig veilig is.
[screenshots]
header = Schermafbeeldingen
+8 -1
View File
@@ -24,7 +24,7 @@ p1 = {kolibrios} — это крошечная, но невероятно мощ
мегабайт места на диске, процессора i586 и 12 МБ оперативной памяти. При
этом она содержит богатый набор приложений, таких как текстовый редактор,
просмотрщик изображений, графический редактор, веб-браузер и более 30
захватывающих игр.Имеется полная поддержка файловых систем FAT12/16/32,
захватывающих игр. Имеется полная поддержка файловых систем FAT12/16/32,
только на чтение доступны NTFS, exFAT, ISO9660 и Ext2/3/4, а также
присутсвтвует обширный набор {drivers} для популярных звуковых, сетевых и графических карт.
drivers = драйверов
@@ -48,6 +48,9 @@ p_subscription = Надеемся, вам понравится!
[downloads]
header = Скачать
version = Версия:
date = Дата сборки:
img-descr = Образ дискеты
iso-descr = Образ LiveCD
distr-descr = Универсальный образ Flash/Multi-boot
@@ -72,6 +75,10 @@ download_description = На этой странице вы можете скач
исходный код доступен на нашем {git}.
git-server = Git-сервере
download_warn = Иногда антивирусы могут по ошибке помечать образ {kolibrios} как угрозу.
Это ложное срабатывание.
{kolibrios} имеет полностью открытый исходный код, и вы всегда можете собрать её самостоятельно, чтобы убедиться, что она абсолютно безопасна.
[screenshots]
header = Скриншоты
Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

+43 -29
View File
@@ -223,6 +223,13 @@ p {
&-subscription {
text-align: center;
}
&-warn {
img {
margin-bottom: -2px;
margin-right: 0.25em;
}
}
}
/* DOWNLOADS */
@@ -247,13 +254,21 @@ tr {
vertical-align: middle;
}
.tr-margin {
&-bot > td {
padding-bottom: 1em;
.tr {
&-header {
b {
display: inline;
}
}
&-top > td {
padding-top: 1em;
&-margin {
&-bot > td {
padding-bottom: 1em;
}
&-top > td {
padding-top: 1em;
}
}
}
@@ -284,18 +299,17 @@ td {
}
}
&-date {
text-align: right;
padding-right: 2em;
}
&-languages {
text-align: right;
padding-left: 2em;
a {
display: inline-block;
white-space: nowrap;
}
a + a {
display: inline;
margin-left: 1em;
margin-top: 0em;
}
}
}
@@ -307,16 +321,10 @@ hr {
.help-button {
cursor: pointer;
display: inline-block;
background: #FF9800;
border-radius: 4px;
box-shadow: inset 0 1px rgba(254,181,94,0.9), inset 0 -2px rgba(0,0,0,0.04);
color: #FFFFFF;
padding: 0.5em 1em;
text-align: center;
transition: 0.5s;
color: #609A21;
&:hover {
background: #F6920B;
img {
padding-bottom: 1px;
}
}
@@ -444,22 +452,28 @@ iframe {
margin: 0 0.5em;
}
.tr {
&-header {
b {
display: block;
}
}
}
.td {
&-description {
width: auto;
}
&-date {
display: none;
padding-right: 1em;
padding-left: 1em;
}
&-languages a {
display: block;
width: max-content;
margin-left: auto;
}
&-languages a + a {
display: inline-block;
white-space: nowrap;
margin-top: 0.5em;
margin-left: 0em;
margin-left: auto;
}
}
+55 -17
View File
@@ -11,7 +11,28 @@
<div id="article">
<h1>{{ _('downloads:header') }}</h1>
<table>
<tr class="tr-margin-bot">
<td colspan="3"><hr /></td>
</tr>
<tr class="tr-margin-bot tr-header">
<td class="td-image" width="40">
<img src="{{ url_for('static', filename='img/icons/i_kolibrios.png') }}" alt="kolibrios">
</td>
<td class="td-description">
{{ _('downloads:version') }} <b>{{ autobuild_vers }}</b>
</td>
<td class="td-languages">
{{ _('downloads:date') }} <b>{{ autobuild_date }}</b>
</td>
</tr>
<tr class="tr-margin-bot">
<td colspan="3"><hr /></td>
</tr>
{% for ext, alt in (
('img', 'floppy'),
('iso', 'cd'),
@@ -28,9 +49,6 @@
<span class="beta">BETA</span>
{% endif %}
</td>
<td class="td-date">
{{ autobuild_date }}
</td>
<td class="td-languages">
{% for l, lang in (
('en_US', 'English'),
@@ -38,27 +56,42 @@
('es_ES', 'Español')
) %}
<a href="//builds.kolibrios.org/{{ l }}/latest-{{ ext }}.7z"
title="ver. $autobuild_cmtid_{{ l }}, $autobuild_size_{{ l }}_{{ ext }}">{{ lang }}</a>
title="ver. $autobuild_cmtid_{{ l }}, $autobuild_size_{{ l }}_{{ ext }}"
class="button">
{{ lang }}
{% if l == 'en_US' %}
<img src="{{ url_for('static', filename='img/flags/en.png') }}" alt="{{ lang }}">
{% elif l == 'ru_RU' %}
<img src="{{ url_for('static', filename='img/flags/ru.png') }}" alt="{{ lang }}">
{% elif l == 'es_ES' %}
<img src="{{ url_for('static', filename='img/flags/es.png') }}" alt="{{ lang }}">
{% endif %}</a>
{% endfor %}
</td>
</tr>
{% endfor %}
<tr>
<td colspan="4">
<hr />
</td>
<td colspan="3"><hr /></td>
</tr>
</table>
<table>
<tr class="tr-margin-top">
<td class="td-description" colspan="2">
<div role="button" class="help-button"
onclick="alert('{{ _('downloads:download_help') }}');">
{{ _('downloads:download_choice') }}
onclick="alert('{{ _('downloads:download_help') }}');">
<img src="{{ url_for('static', filename='img/icons/i_info.png') }}" alt="Info">
<u>{{ _('downloads:download_choice') }}</u>
</div>
<td class="td-date">
<a href="//archive.kolibrios.org/ru/">{{ _('downloads:prev_rev') }}</a>
</td>
<td class="td-languages">
<a href="//builds.kolibrios.org/">{{ _('downloads:all_rev') }}</a>
<a href="//archive.kolibrios.org/ru/">
{{ _('downloads:prev_rev') }}
</a>
<a href="//builds.kolibrios.org/">
{{ _('downloads:all_rev') }}
</a>
</td>
</tr>
</table>
@@ -66,12 +99,17 @@
<p>
{{ _(
'downloads:download_description',
kolibrios="<b>{0}</b>"
.format(_('title:index')),
kolibrios="<b>{0}</b>".format(_('title:index')),
zip="<a href='http://www.7-zip.org' target='_blank'>7zip</a>",
gpl="<a href='http://www.gnu.org/licenses/gpl-2.0.html' target='_blank'>GPLv2</a>",
git="<a href='https://git.kolibrios.org'>{0}</a>"
.format(_('downloads:git-server'))
git="<a href='https://git.kolibrios.org'>{0}</a>".format(_('downloads:git-server'))
) | safe }}
</p>
<p class="p-warn">
<img src="{{ url_for('static', filename='img/icons/i_warn.png') }}" alt="Warn">{{ _(
'downloads:download_warn',
kolibrios="<b>{0}</b>".format(_('title:index'))
) | safe }}
</p>
@@ -96,4 +134,4 @@
{% include 'tmpl/_footer.htm' %}
</body>
</html>
</html>