Skip to content

Commit bff65f8

Browse files
authored
feat(Format): Support caption tracks in adaptive formats (#598)
1 parent dac5eb7 commit bff65f8

File tree

2 files changed

+42
-15
lines changed

2 files changed

+42
-15
lines changed

src/parser/classes/misc/Format.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default class Format {
4545
target_duration_dec?: number;
4646
has_audio: boolean;
4747
has_video: boolean;
48+
has_text: boolean;
4849
language?: string | null;
4950
is_dubbed?: boolean;
5051
is_descriptive?: boolean;
@@ -56,6 +57,14 @@ export default class Format {
5657
matrix_coefficients?: string;
5758
};
5859

60+
caption_track?: {
61+
display_name: string;
62+
vss_id: string;
63+
language_code: string;
64+
kind?: 'asr' | 'frc';
65+
id: string;
66+
};
67+
5968
constructor(data: RawNode, this_response_nsig_cache?: Map<string, string>) {
6069
if (this_response_nsig_cache) {
6170
this.#this_response_nsig_cache = this_response_nsig_cache;
@@ -96,32 +105,50 @@ export default class Format {
96105
this.target_duration_dec = data.targetDurationSec;
97106
this.has_audio = !!data.audioBitrate || !!data.audioQuality;
98107
this.has_video = !!data.qualityLabel;
108+
this.has_text = !!data.captionTrack;
99109

100110
this.color_info = data.colorInfo ? {
101111
primaries: data.colorInfo.primaries?.replace('COLOR_PRIMARIES_', ''),
102112
transfer_characteristics: data.colorInfo.transferCharacteristics?.replace('COLOR_TRANSFER_CHARACTERISTICS_', ''),
103113
matrix_coefficients: data.colorInfo.matrixCoefficients?.replace('COLOR_MATRIX_COEFFICIENTS_', '')
104114
} : undefined;
105115

106-
if (this.has_audio) {
116+
if (Reflect.has(data, 'audioTrack')) {
117+
this.audio_track = {
118+
audio_is_default: data.audioTrack.audioIsDefault,
119+
display_name: data.audioTrack.displayName,
120+
id: data.audioTrack.id
121+
};
122+
}
123+
124+
if (Reflect.has(data, 'captionTrack')) {
125+
this.caption_track = {
126+
display_name: data.captionTrack.displayName,
127+
vss_id: data.captionTrack.vssId,
128+
language_code: data.captionTrack.languageCode,
129+
kind: data.captionTrack.kind,
130+
id: data.captionTrack.id
131+
};
132+
}
133+
134+
if (this.has_audio || this.has_text) {
107135
const args = new URLSearchParams(this.cipher || this.signature_cipher);
108136
const url_components = new URLSearchParams(args.get('url') || this.url);
109137

110138
const xtags = url_components.get('xtags')?.split(':');
111139

112-
const audio_content = xtags?.find((x) => x.startsWith('acont='))?.split('=')[1];
113-
114140
this.language = xtags?.find((x: string) => x.startsWith('lang='))?.split('=')[1] || null;
115-
this.is_dubbed = audio_content === 'dubbed';
116-
this.is_descriptive = audio_content === 'descriptive';
117-
this.is_original = audio_content === 'original' || (!this.is_dubbed && !this.is_descriptive);
118-
119-
if (Reflect.has(data, 'audioTrack')) {
120-
this.audio_track = {
121-
audio_is_default: data.audioTrack.audioIsDefault,
122-
display_name: data.audioTrack.displayName,
123-
id: data.audioTrack.id
124-
};
141+
142+
if (this.has_audio) {
143+
const audio_content = xtags?.find((x) => x.startsWith('acont='))?.split('=')[1];
144+
this.is_dubbed = audio_content === 'dubbed';
145+
this.is_descriptive = audio_content === 'descriptive';
146+
this.is_original = audio_content === 'original' || (!this.is_dubbed && !this.is_descriptive);
147+
}
148+
149+
// Some text tracks don't have xtags while others do
150+
if (this.has_text && !this.language && this.caption_track) {
151+
this.language = this.caption_track.language_code;
125152
}
126153
}
127154
}

src/utils/FormatUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ export function chooseFormat(options: FormatOptions, streaming_data?: IStreaming
169169
if (requires_audio && !requires_video) {
170170
const audio_only = candidates.filter((format) => {
171171
if (language !== 'original') {
172-
return !format.has_video && format.language === language;
172+
return !format.has_video && !format.has_text && format.language === language;
173173
}
174-
return !format.has_video && format.is_original;
174+
return !format.has_video && !format.has_text && format.is_original;
175175

176176
});
177177
if (audio_only.length > 0) {

0 commit comments

Comments
 (0)