UDF-Volume-Label-Leser (Blu-rays haben keine ISO-Bridge) + Etappe 12 (ARM)
Ampel / ampel (push) Successful in 35s
Ampel / ampel (push) Successful in 35s
Praxis-Befund mit echter BD-50: reines UDF, der ISO-PVD-Leser griff nicht. Jetzt ECMA-167-Weg (AVDP Sektor 256 -> Main VDS -> PVD Tag-ID 1 -> Volume Identifier als d-string), mit Tests fuer das d-string-Parsing. ROADMAP Etappe 12 aus der ARM-Vollanalyse: was wir uebernehmen (Fingerprint-DB, bdmt_eng.xml, Suchdegradation, Manual Mode, Apprise, Multi-Drive, Backup-Modus) und wo wir ARM schlagen (Serien-Episoden- Matching, Main-Feature per Laufzeitabgleich). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,8 @@ def read_iso_volume_label(device_path: str) -> Optional[str]:
|
||||
"""Liest das Volume-Label aus dem ISO-9660 Primary Volume Descriptor.
|
||||
|
||||
Sektor 16 (Offset 32768), Bytes 40-71 = Volume Identifier. Funktioniert für
|
||||
DVDs und die meisten Blu-rays (UDF-Bridge) — ganz ohne Zusatzwerkzeuge.
|
||||
DVDs — Blu-rays sind oft reines UDF ohne ISO-Bridge (dann greift
|
||||
read_udf_volume_label).
|
||||
"""
|
||||
try:
|
||||
with open(device_path, "rb") as f:
|
||||
@@ -50,6 +51,59 @@ def read_iso_volume_label(device_path: str) -> Optional[str]:
|
||||
return None
|
||||
|
||||
|
||||
def parse_udf_dstring(data: bytes) -> str:
|
||||
"""Dekodiert einen UDF d-string (ECMA-167 1/7.2.12; pure Funktion, testbar).
|
||||
|
||||
Letztes Byte = genutzte Länge, erstes Byte = Kompressions-ID
|
||||
(8 = Latin-1, 16 = UTF-16BE), dazwischen der Text.
|
||||
"""
|
||||
if not data:
|
||||
return ""
|
||||
laenge = data[-1]
|
||||
if laenge < 2 or laenge > len(data) - 1:
|
||||
return ""
|
||||
comp_id, text = data[0], data[1:laenge]
|
||||
try:
|
||||
if comp_id == 8:
|
||||
return text.decode("latin-1").strip()
|
||||
if comp_id == 16:
|
||||
return text.decode("utf-16-be").strip()
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
return ""
|
||||
|
||||
|
||||
def read_udf_volume_label(device_path: str) -> Optional[str]:
|
||||
"""Liest das Volume-Label aus dem UDF Primary Volume Descriptor.
|
||||
|
||||
Weg laut ECMA-167: Anchor Volume Descriptor Pointer bei Sektor 256 →
|
||||
zeigt auf die Main Volume Descriptor Sequence → darin der PVD (Tag-ID 1)
|
||||
mit dem Volume Identifier (d-string, 32 Bytes ab Offset 24).
|
||||
"""
|
||||
sektor = 2048
|
||||
try:
|
||||
with open(device_path, "rb") as f:
|
||||
f.seek(256 * sektor)
|
||||
avdp = f.read(sektor)
|
||||
if len(avdp) < 24 or int.from_bytes(avdp[0:2], "little") != 2:
|
||||
return None
|
||||
vds_ort = int.from_bytes(avdp[20:24], "little")
|
||||
f.seek(vds_ort * sektor)
|
||||
# VDS-Deskriptoren durchgehen, bis der PVD (Tag-ID 1) kommt
|
||||
for _ in range(32):
|
||||
block = f.read(sektor)
|
||||
if len(block) < 56:
|
||||
return None
|
||||
tag_id = int.from_bytes(block[0:2], "little")
|
||||
if tag_id == 1:
|
||||
return parse_udf_dstring(block[24:56]) or None
|
||||
if tag_id == 8: # Terminating Descriptor — Sequenz zu Ende
|
||||
return None
|
||||
except OSError:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
class PreScanResult:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -129,11 +183,12 @@ class PreScan:
|
||||
"duration": 0
|
||||
})
|
||||
else:
|
||||
# Titel-Quelle 1: ISO-Volume-Label direkt vom Medium — läuft
|
||||
# überall. (makemkvcon gibt es NUR im Worker-Container; der
|
||||
# alte Aufruf hier scheiterte in der API still und der Titel
|
||||
# blieb ewig "Unknown Title".)
|
||||
label = read_iso_volume_label(device_path)
|
||||
# Titel-Quelle 1: Volume-Label direkt vom Medium — läuft
|
||||
# überall. ISO-9660 für DVDs, UDF für Blu-rays (die haben
|
||||
# meist keine ISO-Bridge). (makemkvcon gibt es NUR im
|
||||
# Worker-Container; der alte Aufruf hier scheiterte in der
|
||||
# API still und der Titel blieb ewig "Unknown Title".)
|
||||
label = read_iso_volume_label(device_path) or read_udf_volume_label(device_path)
|
||||
if label:
|
||||
toc["title"] = normalize_disc_label(label)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user