0ea5f10b31
Ampel / ampel (push) Failing after 12m31s
- Metadaten-Preview WIEDERHERGESTELLT (Stub ueberschattete echte prescan-Implementierung), tote Altmodule geloescht - Celery update_state statt Phantom-Task/erfundener API - abcde-Kommando korrigiert (CD-Ripping war nie funktionsfaehig) - JWT: fester Schluessel Pflicht, echtes Logout, Cleanup nur Abgelaufene - main.py: crashende Endpoints (Path/secrets/api_keys), year-Bug, Admin-Login aus .env - Ruff gruen (29 Funde), Tests: auth/cache_keys/ripping_helpers, Placebo-test_health raus - SAVEPOINT: offene MakeMKV-Entscheidung SICHTBAR gemacht (Regel B)
161 lines
4.2 KiB
Python
161 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
udev-Daemon für Rippy
|
|
Erkennt Disc-Einwurf/-auswurf und erstellt Celery-Jobs.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import redis
|
|
import json
|
|
|
|
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
|
|
DISC_DEVICE_PATH = "/dev/disc"
|
|
|
|
# Redis verbinden
|
|
def get_redis_client():
|
|
try:
|
|
return redis.from_url(REDIS_URL)
|
|
except Exception as e:
|
|
print(f"Fehler beim Verbinden mit Redis: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
def get_device_info(device_name: str) -> dict:
|
|
"""Ermittle Device-Info via udevadm."""
|
|
try:
|
|
result = subprocess.run(
|
|
["udevadm", "info", "-q", "property", "-n", f"/dev/{device_name}"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
|
|
info = {}
|
|
for line in result.stdout.strip().split('\n'):
|
|
if '=' in line:
|
|
key, value = line.split('=', 1)
|
|
info[key] = value
|
|
|
|
return info
|
|
except Exception as e:
|
|
print(f"Fehler beim Auslesen von Device {device_name}: {e}")
|
|
return {}
|
|
|
|
|
|
def create_device_symlink(device_name: str, info: dict) -> str:
|
|
"""Erstelle Symlink mit UUID/Serial-Nummer."""
|
|
serial = info.get("ID_SERIAL", "unknown")
|
|
model = info.get("ID_MODEL", "unknown")
|
|
|
|
symlink_name = f"{model}_{serial}".replace(" ", "_")
|
|
symlink_path = f"{DISC_DEVICE_PATH}/{symlink_name}"
|
|
|
|
os.makedirs(DISC_DEVICE_PATH, exist_ok=True)
|
|
|
|
# Alten Symlink entfernen falls vorhanden
|
|
if os.path.exists(symlink_path):
|
|
os.unlink(symlink_path)
|
|
|
|
# Neuen Symlink erstellen
|
|
os.symlink(f"/dev/{device_name}", symlink_path)
|
|
|
|
return symlink_path
|
|
|
|
|
|
def delete_device_symlink(device_name: str):
|
|
"""Lösche Symlink beim Auswurf."""
|
|
symlink_path = f"{DISC_DEVICE_PATH}/{device_name}"
|
|
if os.path.exists(symlink_path):
|
|
os.unlink(symlink_path)
|
|
|
|
|
|
def detect_disc_type(device_path: str) -> str:
|
|
"""Erkenne Disc-Typ (CD/DVD/Blu-ray)."""
|
|
try:
|
|
result = subprocess.run(
|
|
["isoinfo", "-d", "-i", device_path],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
|
|
output = result.stdout.lower()
|
|
|
|
if "rock ridge" in output or "joliet" in output:
|
|
if "blu-ray" in output:
|
|
return "bluray"
|
|
return "dvd"
|
|
elif "cda" in output:
|
|
return "cd"
|
|
|
|
return "unknown"
|
|
except Exception:
|
|
return "unknown"
|
|
|
|
|
|
def create_job(device_path: str, disc_type: str):
|
|
"""Erstelle Celery-Job für Disc-Erkennung."""
|
|
try:
|
|
client = get_redis_client()
|
|
|
|
job_data = {
|
|
"device_path": device_path,
|
|
"disc_type": disc_type,
|
|
"timestamp": str(int(subprocess.check_output(["date", "+%s"]).decode().strip())),
|
|
"status": "pending"
|
|
}
|
|
|
|
client.lpush("rippy:jobs", json.dumps(job_data))
|
|
print(f"Job erstellt: {disc_type} -> {device_path}")
|
|
|
|
except Exception as e:
|
|
print(f"Fehler beim Erstellen des Jobs: {e}")
|
|
|
|
|
|
def handle_add(device_name: str):
|
|
"""Handle Disc-Einwurf."""
|
|
print(f"Disc-Einwurf erkannt: {device_name}")
|
|
|
|
info = get_device_info(device_name)
|
|
if not info:
|
|
print("Konnte Device-Info nicht auslesen")
|
|
return
|
|
|
|
symlink_path = create_device_symlink(device_name, info)
|
|
print(f"Symlink erstellt: {symlink_path}")
|
|
|
|
disc_type = detect_disc_type(symlink_path)
|
|
print(f"Disc-Typ erkannt: {disc_type}")
|
|
|
|
create_job(symlink_path, disc_type)
|
|
|
|
|
|
def handle_remove(device_name: str):
|
|
"""Handle Disc-Auswurf."""
|
|
print(f"Disc-Auswurf erkannt: {device_name}")
|
|
delete_device_symlink(device_name)
|
|
print(f"Symlink gelöscht: /dev/disc/{device_name}")
|
|
|
|
|
|
def main():
|
|
"""Hauptfunktion."""
|
|
if len(sys.argv) < 3:
|
|
print("Usage: udev_daemon.py <action> <device>")
|
|
sys.exit(1)
|
|
|
|
action = sys.argv[1]
|
|
device = sys.argv[2]
|
|
|
|
if action == "add":
|
|
handle_add(device)
|
|
elif action == "remove":
|
|
handle_remove(device)
|
|
else:
|
|
print(f"Unbekannte Aktion: {action}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|