Dashboard
Deine gesamte Medienbibliothek und Systemauslastung auf einen Blick.
Systemauslastung
Aktuelle Werte aus dem Dashboard-Container
Dienste
Verbindung und Bibliotheksstatus
| Film | Quality | Status | Audio | Untertitel | Video | Größe |
|---|
diff --git a/app.py b/app.py index 9b8ae81..1287b55 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,8 @@ import os import sqlite3 import subprocess import threading +import time +import shutil import re from concurrent.futures import ThreadPoolExecutor from datetime import datetime @@ -31,6 +33,8 @@ app = Flask(__name__) executor = ThreadPoolExecutor(max_workers=int(os.environ.get("SCAN_WORKERS", "2"))) jobs = {"radarr": {"state": "idle", "total": 0, "done": 0, "error": None}, "sonarr": {"state": "idle", "total": 0, "done": 0, "error": None}} job_lock = threading.Lock() +system_lock = threading.Lock() +previous_cpu = None LANG_NAMES = {"de":"Deutsch", "deu":"Deutsch", "ger":"Deutsch", "en":"Englisch", "eng":"Englisch", "ja":"Japanisch", "jpn":"Japanisch", "ko":"Koreanisch", "kor":"Koreanisch", "fr":"Französisch", "fra":"Französisch", "fre":"Französisch", "es":"Spanisch", "spa":"Spanisch", "it":"Italienisch", "ita":"Italienisch", "ru":"Russisch", "rus":"Russisch", "zh":"Chinesisch", "zho":"Chinesisch", "chi":"Chinesisch", "und":"Unbekannt", "":"Unbekannt"} FLAGS = {"Deutsch":"🇩🇪", "Englisch":"🇬🇧", "Japanisch":"🇯🇵", "Koreanisch":"🇰🇷", "Französisch":"🇫🇷", "Spanisch":"🇪🇸", "Italienisch":"🇮🇹", "Russisch":"🇷🇺", "Chinesisch":"🇨🇳", "Unbekannt":"❓"} @@ -77,6 +81,47 @@ def format_bytes(size): return f"{value:.1f} {unit}" value /= 1024 +def cpu_usage_percent(): + global previous_cpu + try: + fields = Path("/proc/stat").read_text().splitlines()[0].split()[1:] + values = [int(value) for value in fields] + idle = values[3] + (values[4] if len(values) > 4 else 0) + total = sum(values) + with system_lock: + current = (total, idle) + if previous_cpu is None: + previous_cpu = current + return 0.0 + total_delta = total - previous_cpu[0] + idle_delta = idle - previous_cpu[1] + previous_cpu = current + return round(max(0.0, min(100.0, (1 - idle_delta / total_delta) * 100)), 1) if total_delta else 0.0 + except (OSError, ValueError, IndexError): + return 0.0 + +def system_metrics(): + memory = {line.split(":", 1)[0]: int(line.split()[1]) * 1024 for line in Path("/proc/meminfo").read_text().splitlines() if ":" in line} + total_memory = memory.get("MemTotal", 0) + available_memory = memory.get("MemAvailable", memory.get("MemFree", 0)) + used_memory = max(0, total_memory - available_memory) + mount_paths = [("System", "/"), ("Daten", "/data"), ("Filme", "/media/filme"), ("Serien", "/media/serien")] + disks, seen_devices = [], set() + for label, path in mount_paths: + try: + target = Path(path) + if not target.exists(): + continue + device = target.stat().st_dev + if device in seen_devices: + continue + seen_devices.add(device) + usage = shutil.disk_usage(target) + disks.append({"label": label, "path": path, "total": format_bytes(usage.total), "used": format_bytes(usage.used), "free": format_bytes(usage.free), "used_bytes": usage.used, "total_bytes": usage.total, "percent": round(usage.used / usage.total * 100, 1) if usage.total else 0}) + except OSError: + continue + return {"cpu_percent": cpu_usage_percent(), "memory": {"used": format_bytes(used_memory), "total": format_bytes(total_memory), "percent": round(used_memory / total_memory * 100, 1) if total_memory else 0}, "disks": disks, "timestamp": time.time()} + def release_languages(name): value = f" {name.lower().replace('.', ' ').replace('-', ' ')} " found = [] @@ -292,6 +337,14 @@ def downloads(): log.exception("SABnzbd konnte nicht abgefragt werden") return jsonify({"items": [], "queue_status": "Fehler", "speed": "—", "paused": False, "active_count": 0, "history_count": 0, "remaining": "—", "error": str(exc)}), 502 +@app.get("/api/system") +def system(): + try: + return jsonify(system_metrics()) + except Exception as exc: + log.exception("Systemmetriken konnten nicht gelesen werden") + return jsonify({"error": str(exc), "cpu_percent": 0, "memory": {}, "disks": []}), 500 + @app.get("/health") def health(): return jsonify({"ok":True, "radarr_url":RADARR_URL, "sonarr_enabled":bool(SONARR_URL and SONARR_API_KEY), "sab_enabled":bool(SAB_URL and SAB_API_KEY)}) diff --git a/templates/index.html b/templates/index.html index bfaba23..58b5ab1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,12 +3,15 @@
Deine gesamte Medienbibliothek und Systemauslastung auf einen Blick.
Aktuelle Werte aus dem Dashboard-Container
Verbindung und Bibliotheksstatus
| Film | Quality | Status | Audio | Untertitel | Video | Größe |
|---|