- shared/ = portable Android-origin sources vendored from deferred/desktop-server (app/build.gradle.kts srcDir repointed; PlaybackController.kt excluded as Android-only) - backend/ = bundled-lite engine (SQLite + inline queue); .venv symlinked from the old checkout, PYTHONPATH pins THIS backend's code over any editable install - repoRoot() resolves this project dir (env SHONAR_REPO still wins); desktop-dev.sh watches shared/ + backend/ - Verified: :app:compileKotlin + :app:test green (23 tests); engine boots on :8010, self-migrates, /healthz ok
74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
"""Audio format validation: declared MIME type vs magic bytes.
|
|
|
|
Families decouple declared MIME aliases (audio/mp4 vs audio/m4a) from what
|
|
the bytes actually are. The original file is stored exactly as uploaded —
|
|
validation never rewrites it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
FAMILY_BY_MIME = {
|
|
"audio/mp4": "mp4",
|
|
"audio/m4a": "mp4",
|
|
"audio/aac": "aac",
|
|
"audio/wav": "wav",
|
|
"audio/x-wav": "wav",
|
|
"audio/ogg": "ogg",
|
|
"audio/opus": "ogg",
|
|
"audio/webm": "webm",
|
|
"audio/mpeg": "mpeg",
|
|
}
|
|
|
|
EXT_BY_FAMILY = {
|
|
"mp4": ".m4a",
|
|
"aac": ".aac",
|
|
"wav": ".wav",
|
|
"ogg": ".ogg",
|
|
"webm": ".webm",
|
|
"mpeg": ".mp3",
|
|
}
|
|
|
|
|
|
def sniff_audio_family(data: bytes) -> str | None:
|
|
"""Return the audio family from magic bytes, or None if unrecognized."""
|
|
if len(data) >= 12:
|
|
if data[4:8] == b"ftyp":
|
|
return "mp4"
|
|
if data[:4] == b"RIFF" and data[8:12] == b"WAVE":
|
|
return "wav"
|
|
if data[:4] == b"OggS":
|
|
return "ogg"
|
|
if data[:4] == b"\x1a\x45\xdf\xa3":
|
|
return "webm"
|
|
if data[:3] == b"ID3":
|
|
return "mpeg"
|
|
if len(data) >= 2 and data[0] == 0xFF and (data[1] & 0xF6) == 0xF0:
|
|
# ADTS frame sync: AAC (also accepted as mpeg-family audio)
|
|
return "aac"
|
|
return None
|
|
|
|
|
|
def declared_family(mime_type: str) -> str | None:
|
|
return FAMILY_BY_MIME.get(mime_type.lower().split(";")[0].strip())
|
|
|
|
|
|
def is_compatible(mime_type: str, data: bytes) -> bool:
|
|
"""True when the declared MIME matches the sniffed magic bytes.
|
|
|
|
mpeg and aac are treated as one family: Android records AAC in ADTS or
|
|
in MP4 containers and MIME reporting around these is inconsistent.
|
|
"""
|
|
declared = declared_family(mime_type)
|
|
sniffed = sniff_audio_family(data)
|
|
if declared is None or sniffed is None:
|
|
return False
|
|
if {declared, sniffed} == {"mpeg", "aac"}:
|
|
return True
|
|
return declared == sniffed
|
|
|
|
|
|
def extension_for(mime_type: str, data: bytes) -> str:
|
|
sniffed = sniff_audio_family(data)
|
|
if sniffed is not None:
|
|
return EXT_BY_FAMILY[sniffed]
|
|
return EXT_BY_FAMILY.get(declared_family(mime_type) or "", ".bin")
|