Skip to content

Commit 9788f22

Browse files
committed
Fix 400 error.
1 parent 3d977ca commit 9788f22

3 files changed

Lines changed: 105 additions & 47 deletions

File tree

sabr_test/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ Selected Formats:
220220
},
221221
],
222222
bufferedRanges: [], // Empty for initial request
223-
videoPlaybackUstreamerConfig: Buffer.from(videoPlaybackUstreamerConfig).toString("base64"),
223+
videoPlaybackUstreamerConfig: videoPlaybackUstreamerConfig, // Already base64 encoded
224224
poToken: poToken ? Buffer.from(poToken, "utf-8").toString("base64") : undefined,
225225
};
226226

src/sabr_handler.rs

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,26 @@ impl SabrRequestData {
104104
let video_playback_ustreamer_config = json
105105
.get("videoPlaybackUstreamerConfig")
106106
.and_then(|v| v.as_str())
107-
.and_then(|s| general_purpose::STANDARD.decode(s).ok());
107+
.and_then(|s| {
108+
eprintln!("videoPlaybackUstreamerConfig string length: {}", s.len());
109+
eprintln!(
110+
"videoPlaybackUstreamerConfig first 100 chars: {}",
111+
&s[..std::cmp::min(100, s.len())]
112+
);
113+
match general_purpose::URL_SAFE.decode(s) {
114+
Ok(decoded) => {
115+
eprintln!(
116+
"Successfully decoded videoPlaybackUstreamerConfig: {} bytes",
117+
decoded.len()
118+
);
119+
Some(decoded)
120+
}
121+
Err(e) => {
122+
eprintln!("Failed to decode videoPlaybackUstreamerConfig: {}", e);
123+
None
124+
}
125+
}
126+
});
108127

109128
let po_token = json
110129
.get("poToken")
@@ -241,39 +260,8 @@ pub async fn handle_sabr_request(
241260

242261
// If no buffered ranges provided, create initial ones like in the working example
243262
let buffered_ranges = if data.buffered_ranges.is_empty() {
244-
let mut ranges = Vec::new();
245-
246-
// Create buffered range for audio format (like the working example)
247-
if let Some(audio_format) = data.selected_audio_format_ids.first() {
248-
ranges.push(create_buffered_range(
249-
audio_format.clone(),
250-
0, // start_time_ms
251-
20000, // duration_ms (20 seconds like working example)
252-
1, // start_segment_index
253-
2, // end_segment_index
254-
));
255-
}
256-
257-
// Create buffered ranges for video format (like the working example)
258-
if let Some(video_format) = data.selected_video_format_ids.first() {
259-
ranges.push(create_buffered_range(
260-
video_format.clone(),
261-
0, // start_time_ms
262-
15021, // duration_ms (like working example)
263-
1, // start_segment_index
264-
3, // end_segment_index
265-
));
266-
267-
ranges.push(create_buffered_range(
268-
video_format.clone(),
269-
10014, // start_time_ms (like working example)
270-
10014, // duration_ms (like working example)
271-
3, // start_segment_index
272-
4, // end_segment_index
273-
));
274-
}
275-
276-
ranges
263+
// For initial request, buffered ranges should be empty
264+
Vec::new()
277265
} else {
278266
data.buffered_ranges.clone()
279267
};
@@ -378,11 +366,6 @@ pub async fn handle_sabr_request(
378366
let mut request = Request::new(Method::POST, url);
379367
request.body_mut().replace(Body::from(encoded_request));
380368

381-
// Add Content-Type header for protobuf
382-
request
383-
.headers_mut()
384-
.insert("Content-Type", "application/x-protobuf".parse().unwrap());
385-
386369
// Execute the request
387370
let resp = client.execute(request).await?;
388371
let status = resp.status();

src/sabr_request.rs

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,14 @@ pub struct StreamerContext {
6161
pub playback_cookie: Option<Vec<u8>>,
6262
#[prost(bytes = "vec", optional, tag = "4")]
6363
pub gp: Option<Vec<u8>>,
64-
#[prost(bytes = "vec", repeated, tag = "5")]
65-
pub field5: Vec<Vec<u8>>,
64+
#[prost(message, repeated, tag = "5")]
65+
pub field5: Vec<Fqa>,
6666
#[prost(int32, repeated, tag = "6")]
6767
pub field6: Vec<i32>,
6868
#[prost(string, optional, tag = "7")]
6969
pub field7: Option<String>,
70+
#[prost(message, optional, tag = "8")]
71+
pub field8: Option<Gqa>,
7072
}
7173

7274
#[derive(Clone, PartialEq, Message)]
@@ -197,12 +199,16 @@ pub struct VideoPlaybackAbrRequest {
197199
pub player_time_ms: Option<i64>,
198200
#[prost(bytes = "vec", optional, tag = "5")]
199201
pub video_playback_ustreamer_config: Option<Vec<u8>>,
202+
#[prost(message, optional, tag = "6")]
203+
pub lo: Option<Lo>,
200204
#[prost(message, repeated, tag = "16")]
201205
pub selected_audio_format_ids: Vec<FormatId>,
202206
#[prost(message, repeated, tag = "17")]
203207
pub selected_video_format_ids: Vec<FormatId>,
204208
#[prost(message, optional, tag = "19")]
205209
pub streamer_context: Option<StreamerContext>,
210+
#[prost(message, optional, tag = "21")]
211+
pub field21: Option<OQa>,
206212
#[prost(int32, optional, tag = "22")]
207213
pub field22: Option<i32>,
208214
#[prost(int32, optional, tag = "23")]
@@ -251,6 +257,11 @@ impl SabrRequestBuilder {
251257
streamer_context: StreamerContext {
252258
field5: Vec::new(),
253259
field6: Vec::new(),
260+
field7: None,
261+
field8: None,
262+
gp: None,
263+
playback_cookie: None,
264+
po_token: None,
254265
// Basic client info matching googlevideo
255266
client_info: Some(ClientInfo {
256267
client_name: Some(1),
@@ -259,7 +270,6 @@ impl SabrRequestBuilder {
259270
os_version: Some("10.0".to_string()),
260271
..Default::default()
261272
}),
262-
..Default::default()
263273
},
264274
video_playback_ustreamer_config: None,
265275
selected_audio_format_ids: Vec::new(),
@@ -341,10 +351,9 @@ impl SabrRequestBuilder {
341351
}
342352

343353
pub fn build(self) -> VideoPlaybackAbrRequest {
344-
// selectedFormatIds should contain all format IDs (both audio and video)
345-
let mut selected_format_ids = Vec::new();
346-
selected_format_ids.extend(self.selected_audio_format_ids.clone());
347-
selected_format_ids.extend(self.selected_video_format_ids.clone());
354+
// For initial requests, selectedFormatIds should be empty
355+
// It represents previously initialized formats, which don't exist yet
356+
let selected_format_ids = Vec::new();
348357

349358
VideoPlaybackAbrRequest {
350359
client_abr_state: Some(self.client_abr_state),
@@ -358,6 +367,8 @@ impl SabrRequestBuilder {
358367
field22: Some(0),
359368
field23: Some(0),
360369
field1000: Vec::new(),
370+
lo: None,
371+
field21: None,
361372
}
362373
}
363374

@@ -399,6 +410,70 @@ pub fn create_buffered_range(
399410
}
400411
}
401412

413+
#[derive(Clone, PartialEq, Message)]
414+
pub struct LoField4 {
415+
#[prost(int32, optional, tag = "1")]
416+
pub field1: Option<i32>,
417+
#[prost(int32, optional, tag = "2")]
418+
pub field2: Option<i32>,
419+
#[prost(int32, optional, tag = "3")]
420+
pub field3: Option<i32>,
421+
}
422+
423+
#[derive(Clone, PartialEq, Message)]
424+
pub struct Lo {
425+
#[prost(message, optional, tag = "1")]
426+
pub format_id: Option<FormatId>,
427+
#[prost(int32, optional, tag = "2")]
428+
pub lj: Option<i32>,
429+
#[prost(int32, optional, tag = "3")]
430+
pub sequence_number: Option<i32>,
431+
#[prost(message, optional, tag = "4")]
432+
pub field4: Option<LoField4>,
433+
#[prost(int32, optional, tag = "5")]
434+
pub mz: Option<i32>,
435+
}
436+
437+
#[derive(Clone, PartialEq, Message)]
438+
pub struct OQa {
439+
#[prost(string, repeated, tag = "1")]
440+
pub field1: Vec<String>,
441+
#[prost(bytes = "vec", optional, tag = "2")]
442+
pub field2: Option<Vec<u8>>,
443+
#[prost(string, optional, tag = "3")]
444+
pub field3: Option<String>,
445+
#[prost(int32, optional, tag = "4")]
446+
pub field4: Option<i32>,
447+
#[prost(int32, optional, tag = "5")]
448+
pub field5: Option<i32>,
449+
#[prost(string, optional, tag = "6")]
450+
pub field6: Option<String>,
451+
}
452+
453+
#[derive(Clone, PartialEq, Message)]
454+
pub struct Hqa {
455+
#[prost(int32, optional, tag = "1")]
456+
pub code: Option<i32>,
457+
#[prost(string, optional, tag = "2")]
458+
pub message: Option<String>,
459+
}
460+
461+
#[derive(Clone, PartialEq, Message)]
462+
pub struct Gqa {
463+
#[prost(bytes = "vec", optional, tag = "1")]
464+
pub field1: Option<Vec<u8>>,
465+
#[prost(message, optional, tag = "2")]
466+
pub field2: Option<Hqa>,
467+
}
468+
469+
#[derive(Clone, PartialEq, Message)]
470+
pub struct Fqa {
471+
#[prost(int32, optional, tag = "1")]
472+
pub r#type: Option<i32>,
473+
#[prost(bytes = "vec", optional, tag = "2")]
474+
pub value: Option<Vec<u8>>,
475+
}
476+
402477
#[cfg(test)]
403478
mod tests {
404479
use super::*;

0 commit comments

Comments
 (0)