File size: 1,301 Bytes
bc50ea0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | """JSON-only contracts for grouped project audio; no media or runtime imports."""
AUDIO_TRACK_ROLES = ("full_mix", "vocals", "instrumental")
def audio_track_bindings(value, assets):
if value is None:
return None
if not isinstance(value, dict) or set(value) - set(AUDIO_TRACK_ROLES):
raise ValueError("Audio tracks must map full_mix, vocals, and instrumental to asset IDs.")
known = {str(asset.get("id") or ""): asset for asset in assets}
result = {}
for role in AUDIO_TRACK_ROLES:
raw = value.get(role, "")
if raw is not None and not isinstance(raw, str):
raise ValueError("Audio track IDs must be strings.")
asset_id = str(raw or "").strip()
if asset_id and (asset_id not in known or known[asset_id].get("kind") != "audio"):
raise ValueError("Audio track %s must reference an existing audio asset in this project." % role)
result[role] = asset_id
selected = [asset_id for asset_id in result.values() if asset_id]
if not selected:
raise ValueError("Select at least one audio track, or reset to the original single track.")
if len(selected) != len(set(selected)):
raise ValueError("The same audio asset cannot be both a mix and a stem, or both stems.")
return result
|