first commit

This commit is contained in:
root
2026-05-19 13:43:37 +00:00
commit 9dcd0abd7d
107 changed files with 33622 additions and 0 deletions

79
pytorrent/routes/main.py Normal file
View File

@@ -0,0 +1,79 @@
from __future__ import annotations
from pathlib import Path
from flask import Blueprint, render_template, Response, request, redirect, url_for, abort, send_file
from ..services.preferences import get_preferences, list_profiles, active_profile, BOOTSTRAP_THEMES, FONT_FAMILIES
from ..services import auth
from ..services.frontend_assets import asset_path
# for favicon
from flask import current_app, send_from_directory
bp = Blueprint("main", __name__)
def _asset_url(key: str) -> str:
path = asset_path(key)
return path if path.startswith("http") else url_for("static", filename=path)
@bp.get("/favicon.ico")
def favicon_ico():
response = send_from_directory(
current_app.static_folder,
"favicon.svg",
mimetype="image/svg+xml",
)
return response
@bp.route("/login", methods=["GET", "POST"])
def login():
# Note: When optional authentication is disabled, /login is intentionally unavailable.
if not auth.enabled():
abort(404)
error = ""
if request.method == "POST":
user = auth.login_user(request.form.get("username", ""), request.form.get("password", ""))
if user:
return redirect(request.args.get("next") or url_for("main.index"))
error = "Invalid username or password"
return render_template("login.html", error=error)
@bp.get("/logout")
def logout():
auth.logout_user()
if not auth.enabled():
return redirect(url_for("main.index"))
return redirect(url_for("main.login"))
@bp.get("/")
def index():
prefs = get_preferences()
return render_template(
"index.html",
prefs=prefs,
profiles=list_profiles(),
active_profile=active_profile(),
bootstrap_themes=BOOTSTRAP_THEMES,
font_families=FONT_FAMILIES,
auth_enabled=auth.enabled(),
current_user=auth.current_user(),
)
@bp.get("/docs")
def docs():
html = f"""<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>pyTorrent API Docs</title><link rel="stylesheet" href="{_asset_url('swagger_css')}"></head><body><div id="swagger-ui"></div><script src="{_asset_url('swagger_js')}"></script><script>window.onload=()=>SwaggerUIBundle({{url:'/api/openapi.json',dom_id:'#swagger-ui',deepLinking:true,persistAuthorization:true}});</script></body></html>"""
return Response(html, mimetype="text/html")
@bp.get("/api/openapi.json")
def openapi():
spec_path = Path(current_app.root_path) / "openapi" / "openapi.json"
response = send_file(spec_path, mimetype="application/json", conditional=False, max_age=0)
response.headers["Cache-Control"] = "no-store, no-cache, private"
return response