780d114fe4
Vorher: Dockerfile unbaubar (makepkg ist ein Arch-Paket, existiert in Debian nicht) und KEIN einziges Ripping-Tool im Image — jeder Rip endete sofort. Disc-Erkennung via `file -L` konnte auf Block-Devices strukturell nie etwas erkennen; ihr Test mockte sich die Ausgabe passend. - makemkv-oss/bin 1.18.4 multi-stage (bookworm-gepinnt), EULA via tmp/eula_accepted, Beta-Key aus MAKEMKV_APP_KEY (entrypoint.sh) - makemkvcon-Aufruf + PRGV-Parsing laut makemkv.com/developers/usage.txt (AGENTS Regel D), HandBrake raus aus dem Ripp-Pfad (KONZEPT: lossless=Muss) - detection.py: CDROM_DISC_STATUS + BLKGETSIZE64 (cd/dvd/bluray), pure classify() mit ehrlichen Tests - tasks.py: rip_disc als einziger Celery-Task, schreibt Status/Fortschritt nach Postgres (db.py), Ausgabe auf /app/media (Volume) statt totem /output Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
"""Disc-Erkennung über Kernel-ioctls — ohne `file`, ohne udev.
|
|
|
|
Warum neu (Review 23.07.): Die alte Erkennung rief `file -L /dev/sr0` auf.
|
|
`file` liest ohne `-s` aber NIE den Inhalt eines Block-Devices — die Ausgabe ist
|
|
immer nur "block special", die Erkennung lieferte also strukturell IMMER
|
|
"unknown". Der alte Test hatte sich die `file`-Ausgabe passend gemockt und
|
|
bewies damit nichts.
|
|
|
|
Die ioctl-Konstanten stammen aus der Kernel-UAPI (include/uapi/linux/cdrom.h
|
|
bzw. linux/fs.h für BLKGETSIZE64) und sind seit Jahrzehnten stabil.
|
|
"""
|
|
|
|
import os
|
|
import struct
|
|
from fcntl import ioctl
|
|
|
|
# include/uapi/linux/cdrom.h
|
|
CDROM_DRIVE_STATUS = 0x5326
|
|
CDROM_DISC_STATUS = 0x5327
|
|
|
|
CDS_NO_DISC = 1
|
|
CDS_TRAY_OPEN = 2
|
|
CDS_DRIVE_NOT_READY = 3
|
|
CDS_DISC_OK = 4
|
|
|
|
CDS_AUDIO = 100
|
|
CDS_DATA_1 = 101
|
|
CDS_DATA_2 = 102
|
|
CDS_XA_2_1 = 103
|
|
CDS_XA_2_2 = 104
|
|
CDS_MIXED = 105
|
|
|
|
# include/uapi/linux/fs.h: BLKGETSIZE64 = _IOR(0x12, 114, size_t) auf 64-bit
|
|
BLKGETSIZE64 = 0x80081272
|
|
|
|
# Eine DVD9 fasst ~8,5 GB; Blu-ray beginnt bei 25 GB (Single Layer).
|
|
# Alles ab 10 GB ist also sicher eine Blu-ray.
|
|
BLURAY_MIN_BYTES = 10 * 1024**3
|
|
|
|
|
|
def _open_nonblock(device_path: str) -> int:
|
|
"""O_NONBLOCK ist Pflicht: ohne blockiert open() bis eine Disc eingelegt ist."""
|
|
return os.open(device_path, os.O_RDONLY | os.O_NONBLOCK)
|
|
|
|
|
|
def drive_status(device_path: str) -> int:
|
|
"""CDROM_DRIVE_STATUS: 1=keine Disc, 2=Schublade offen, 3=nicht bereit, 4=Disc ok."""
|
|
fd = _open_nonblock(device_path)
|
|
try:
|
|
return ioctl(fd, CDROM_DRIVE_STATUS, 0)
|
|
finally:
|
|
os.close(fd)
|
|
|
|
|
|
def disc_status(device_path: str) -> int:
|
|
"""CDROM_DISC_STATUS: 100=Audio, 101-104=Daten, 105=Mixed."""
|
|
fd = _open_nonblock(device_path)
|
|
try:
|
|
return ioctl(fd, CDROM_DISC_STATUS, 0)
|
|
finally:
|
|
os.close(fd)
|
|
|
|
|
|
def disc_size_bytes(device_path: str) -> int:
|
|
"""Größe des eingelegten Mediums in Bytes (BLKGETSIZE64)."""
|
|
fd = _open_nonblock(device_path)
|
|
try:
|
|
buf = bytearray(8)
|
|
ioctl(fd, BLKGETSIZE64, buf)
|
|
return struct.unpack("Q", bytes(buf))[0]
|
|
finally:
|
|
os.close(fd)
|
|
|
|
|
|
def classify(disc_status_code: int, size_bytes: int) -> str:
|
|
"""Pure Zuordnung (testbar): Disc-Status + Größe → cd | dvd | bluray | unknown."""
|
|
if disc_status_code in (CDS_AUDIO, CDS_MIXED):
|
|
return "cd"
|
|
if disc_status_code in (CDS_DATA_1, CDS_DATA_2, CDS_XA_2_1, CDS_XA_2_2):
|
|
return "bluray" if size_bytes >= BLURAY_MIN_BYTES else "dvd"
|
|
return "unknown"
|
|
|
|
|
|
def detect_disc_type(device_path: str) -> str:
|
|
"""Erkennt den Typ der eingelegten Disc; 'no_disc' wenn keine drin ist."""
|
|
try:
|
|
if drive_status(device_path) != CDS_DISC_OK:
|
|
return "no_disc"
|
|
return classify(disc_status(device_path), disc_size_bytes(device_path))
|
|
except OSError:
|
|
return "unknown"
|