Add AMOLED theme, fullscreen, settings tab, and NTFY notifications

This commit is contained in:
purplebored committed 2026-11-08 19:38:17 +01:00
1 parent fe13a4d989
commit bbf92bb478
6 files changed
+429 -4

No files matched your search

+53 -1
View File
@@ -17,8 +17,9 @@ import secrets
import time
from dataclasses import dataclass, field
from pathlib import Path
from urllib.parse import urlparse
from urllib.parse import quote, urlparse
import aiohttp
from aiohttp import web
from bs4 import BeautifulSoup, Comment
@@ -421,6 +422,56 @@ async def api_conferences(request):
return json_response({"conferences": data or []})
async def api_ntfy(request):
"""Proxy a notification to an NTFY server (avoids browser CORS/CSP limits)."""
get_session(request) # require an authenticated session
try:
body = await request.json()
except Exception:
raise ApiError(400, "Expected a JSON object.")
if not isinstance(body, dict):
raise ApiError(400, "Expected a JSON object.")
server = str(body.get("server") or "").strip()
topic = str(body.get("topic") or "").strip()
token = str(body.get("token") or "").strip()
title = str(body.get("title") or "librus-tui").strip()[:120]
message = str(body.get("message") or "").strip()[:4000]
priority = body.get("priority")
if not server or not topic:
raise ApiError(400, "NTFY server and topic are required.")
parsed = urlparse(server)
if parsed.scheme not in ("http", "https") or not parsed.netloc:
raise ApiError(400, "Invalid NTFY server URL.")
host = (parsed.hostname or "").lower()
if host in ("localhost", "127.0.0.1", "::1") or host.startswith("169.254."):
raise ApiError(400, "NTFY server host is not allowed.")
url = server.rstrip("/") + "/" + quote(topic, safe="")
headers = {
"Title": title or "librus-tui",
"Content-Type": "text/plain; charset=utf-8",
}
if token:
headers["Authorization"] = f"Bearer {token}"
if priority is not None:
headers["Priority"] = str(priority)
timeout = aiohttp.ClientTimeout(total=15)
try:
async with aiohttp.ClientSession(timeout=timeout) as client:
async with client.post(url, headers=headers, data=message.encode("utf-8")) as response:
text = await response.text()
if response.status >= 400:
raise ApiError(502, f"NTFY returned {response.status}: {text[:200].strip()}")
return json_response({"ok": True, "status": response.status})
except ApiError:
raise
except Exception as exc:
raise ApiError(502, f"NTFY request failed: {exc}")
# --------------------------------------------------------------------------- static
@@ -557,6 +608,7 @@ def create_app(demo=False):
app.router.add_get("/api/download", api_download)
app.router.add_get("/api/freedays", api_freedays)
app.router.add_get("/api/conferences", api_conferences)
app.router.add_post("/api/ntfy", api_ntfy)
app.router.add_get("/healthz", healthz)
app.router.add_get("/", index)