From 09fe7557d65c450947d910050be785eda5e90713 Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Thu, 30 Jul 2026 15:09:46 +0200 Subject: [PATCH] feat(api): expose audioTrack on adaptiveFormats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Videos with multi-language audio carry an `audioTrack` object on each audio entry of `streamingData.adaptiveFormats`, holding the language id (e.g. "en-US.4"), a human-readable `displayName`, and whether the track is the original audio. Invidious already parses and uses all three: the DASH manifest route reads `audioTrack["id"]`, `audioTrack["audioIsDefault"]` and `audioTrack["displayName"]` to label and order its audio AdaptationSets. But `/api/v1/videos` drops it, so an API consumer has no way to tell one audio track from another, and is left scraping it back out of the stream URL query string (`xtags=acont%3Ddubbed%3Alang%3Dfr`) — undocumented, and silent when it changes. Emit the same three fields the manifest route already relies on, each only when present, in the same passthrough style as the neighbouring `colorInfo` and `captionTrack` fields. Additive and optional throughout: a single-audio video carries no `audioTrack` at all and so gains no field, which is correct — there is no second track to distinguish. AI disclosure, per AI_POLICY.md: this patch was written with AI assistance. Exact model: Claude Opus 5, model ID `claude-opus-5[1m]`. Tool used to interact with it: Claude Code, Anthropic's agentic CLI. The change was verified against a live patched instance (see the PR for the measurements) and is running in production on the submitter's instance. Submitted by and the responsibility of @mdbraber. --- src/invidious/jsonify/api_v1/video_json.cr | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/invidious/jsonify/api_v1/video_json.cr b/src/invidious/jsonify/api_v1/video_json.cr index e02e0617..b7658165 100644 --- a/src/invidious/jsonify/api_v1/video_json.cr +++ b/src/invidious/jsonify/api_v1/video_json.cr @@ -150,6 +150,23 @@ module Invidious::JSONify::APIv1 json.field "audioSampleRate", fmt["audioSampleRate"].as_s.to_i if fmt.has_key?("audioSampleRate") json.field "audioChannels", fmt["audioChannels"] if fmt.has_key?("audioChannels") + # Multi-language audio. Only present when a video carries more than + # one audio track. The same data already drives the DASH manifest + # (see `Invidious::Routes::API::Manifest`), but was never exposed on + # the API, leaving clients to scrape `xtags` out of the stream URL. + if audio_track = fmt["audioTrack"]? + json.field "audioTrack" do + json.object do + # Language tag with a track discriminator, e.g. "en-US.4". + json.field "id", audio_track["id"] if audio_track["id"]? + # Human-readable label, e.g. "English (original)". + json.field "displayName", audio_track["displayName"] if audio_track["displayName"]? + # True for the video's original (undubbed) audio. + json.field "audioIsDefault", audio_track["audioIsDefault"] if audio_track["audioIsDefault"]? + end + end + end + # Extra misc stuff json.field "colorInfo", fmt["colorInfo"] if fmt.has_key?("colorInfo") json.field "captionTrack", fmt["captionTrack"] if fmt.has_key?("captionTrack")