Refactor gateway into modular architecture
Split 1878-line server.py into 15 focused modules:
- config.py: all env vars and constants
- database.py: schema, init, seed logic
- sessions.py: session/token CRUD
- proxy.py: proxy_request, SERVICE_MAP, resolve_service
- responses.py: ResponseMixin for handler helpers
- auth.py: login/logout/register handlers
- dashboard.py: dashboard, apps, connections, pinning
- command.py: AI command bar
- integrations/booklore.py: auth, books, cover, import
- integrations/kindle.py: send-to-kindle, file finder
- integrations/karakeep.py: save/delete bookmarks
- integrations/qbittorrent.py: download status
- integrations/image_proxy.py: external image proxy
server.py is now thin routing only (~344 lines).
All routes, methods, status codes, and responses preserved exactly.
Added PYTHONUNBUFFERED=1 to Dockerfile for live logging.
2026-03-29 00:14:46 -05:00
|
|
|
"""
|
|
|
|
|
Platform Gateway — qBittorrent integration (download status).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import urllib.request
|
|
|
|
|
import urllib.parse
|
|
|
|
|
|
2026-03-29 07:02:09 -05:00
|
|
|
from config import QBITTORRENT_HOST, QBITTORRENT_PORT, QBITTORRENT_USERNAME, QBITTORRENT_PASSWORD
|
|
|
|
|
|
Refactor gateway into modular architecture
Split 1878-line server.py into 15 focused modules:
- config.py: all env vars and constants
- database.py: schema, init, seed logic
- sessions.py: session/token CRUD
- proxy.py: proxy_request, SERVICE_MAP, resolve_service
- responses.py: ResponseMixin for handler helpers
- auth.py: login/logout/register handlers
- dashboard.py: dashboard, apps, connections, pinning
- command.py: AI command bar
- integrations/booklore.py: auth, books, cover, import
- integrations/kindle.py: send-to-kindle, file finder
- integrations/karakeep.py: save/delete bookmarks
- integrations/qbittorrent.py: download status
- integrations/image_proxy.py: external image proxy
server.py is now thin routing only (~344 lines).
All routes, methods, status codes, and responses preserved exactly.
Added PYTHONUNBUFFERED=1 to Dockerfile for live logging.
2026-03-29 00:14:46 -05:00
|
|
|
|
|
|
|
|
def handle_downloads_status(handler):
|
|
|
|
|
"""Get active downloads from qBittorrent."""
|
2026-03-29 07:02:09 -05:00
|
|
|
base = f"http://{QBITTORRENT_HOST}:{QBITTORRENT_PORT}"
|
Refactor gateway into modular architecture
Split 1878-line server.py into 15 focused modules:
- config.py: all env vars and constants
- database.py: schema, init, seed logic
- sessions.py: session/token CRUD
- proxy.py: proxy_request, SERVICE_MAP, resolve_service
- responses.py: ResponseMixin for handler helpers
- auth.py: login/logout/register handlers
- dashboard.py: dashboard, apps, connections, pinning
- command.py: AI command bar
- integrations/booklore.py: auth, books, cover, import
- integrations/kindle.py: send-to-kindle, file finder
- integrations/karakeep.py: save/delete bookmarks
- integrations/qbittorrent.py: download status
- integrations/image_proxy.py: external image proxy
server.py is now thin routing only (~344 lines).
All routes, methods, status codes, and responses preserved exactly.
Added PYTHONUNBUFFERED=1 to Dockerfile for live logging.
2026-03-29 00:14:46 -05:00
|
|
|
try:
|
|
|
|
|
# Login
|
2026-03-29 07:02:09 -05:00
|
|
|
login_data = urllib.parse.urlencode({"username": QBITTORRENT_USERNAME, "password": QBITTORRENT_PASSWORD}).encode()
|
Refactor gateway into modular architecture
Split 1878-line server.py into 15 focused modules:
- config.py: all env vars and constants
- database.py: schema, init, seed logic
- sessions.py: session/token CRUD
- proxy.py: proxy_request, SERVICE_MAP, resolve_service
- responses.py: ResponseMixin for handler helpers
- auth.py: login/logout/register handlers
- dashboard.py: dashboard, apps, connections, pinning
- command.py: AI command bar
- integrations/booklore.py: auth, books, cover, import
- integrations/kindle.py: send-to-kindle, file finder
- integrations/karakeep.py: save/delete bookmarks
- integrations/qbittorrent.py: download status
- integrations/image_proxy.py: external image proxy
server.py is now thin routing only (~344 lines).
All routes, methods, status codes, and responses preserved exactly.
Added PYTHONUNBUFFERED=1 to Dockerfile for live logging.
2026-03-29 00:14:46 -05:00
|
|
|
req = urllib.request.Request(f"{base}/api/v2/auth/login", data=login_data)
|
|
|
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
|
|
|
cookie = resp.headers.get("Set-Cookie", "").split(";")[0]
|
|
|
|
|
|
|
|
|
|
# Get torrents
|
|
|
|
|
req2 = urllib.request.Request(f"{base}/api/v2/torrents/info?filter=all&sort=added_on&reverse=true&limit=20",
|
|
|
|
|
headers={"Cookie": cookie})
|
|
|
|
|
with urllib.request.urlopen(req2, timeout=5) as resp2:
|
|
|
|
|
torrents_raw = json.loads(resp2.read())
|
|
|
|
|
|
|
|
|
|
torrents = []
|
|
|
|
|
for t in torrents_raw:
|
|
|
|
|
torrents.append({
|
|
|
|
|
"hash": t["hash"],
|
|
|
|
|
"name": t["name"],
|
|
|
|
|
"progress": round(t["progress"] * 100, 1),
|
|
|
|
|
"state": t["state"],
|
|
|
|
|
"size": t["total_size"],
|
|
|
|
|
"downloaded": t["downloaded"],
|
|
|
|
|
"dlSpeed": t["dlspeed"],
|
|
|
|
|
"upSpeed": t["upspeed"],
|
|
|
|
|
"eta": t.get("eta", 0),
|
|
|
|
|
"addedOn": t.get("added_on", 0),
|
|
|
|
|
"category": t.get("category", ""),
|
|
|
|
|
})
|
|
|
|
|
handler._send_json({"torrents": torrents, "total": len(torrents)})
|
|
|
|
|
except Exception as e:
|
|
|
|
|
handler._send_json({"torrents": [], "total": 0, "error": str(e)})
|