#!/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 from pathlib import Path from time import sleep 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 ") 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()