S.H.O.N.A.R._Desktop_Companion/backend/shonar/services/media.py
avi 76c867fca4 Standalone Shonar Desktop: vendor portable sources + local engine; decouple from ~/Projects/Shonar
- 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
2026-09-14 17:14:54 -05:00

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")