diff --git a/src/client.rs b/src/client.rs index c138907..b0f1e77 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,7 +2,7 @@ use std::{io::ErrorKind, path::Path, time::Duration}; use anyhow::anyhow; use futures_util::StreamExt as _; -use http::{header::{CONTENT_TYPE, RANGE}, request::Builder as RequestBuilder, uri::{Authority, Scheme}, Request, Response, StatusCode, Uri}; +use http::{header::{CONTENT_LENGTH, CONTENT_TYPE, RANGE}, request::Builder as RequestBuilder, uri::{Authority, Scheme}, HeaderValue, Request, Response, StatusCode, Uri}; use http_body_util::BodyDataStream; use m3u8_rs::{MediaPlaylist, MediaSegment, Playlist}; use reqwest::{redirect::Policy, Body}; @@ -114,10 +114,20 @@ impl State { . await . map_err(|e| DownloadError::new(uri.clone(), Some(e)))?; - // We always need the content-type to be able to decide - let content_type = response.headers()[CONTENT_TYPE].to_str() - . expect("No content-type header found in response"); + match response.headers().get("x-finished") { + None => (), + Some(v) => if let Ok(v) = v.to_str() { + if v == "true" { + return Ok(()) + } + }, + } + // We always need the content-type to be able to decide + let content_type = response.headers().get(CONTENT_TYPE) + . expect("No content-type header found in response") + . to_str() + . expect("Can't create &str from content-type header") ; if content_type != "video/MP2T" { let message = format!("unexpected content-type: {}", content_type); log!(Level::Debug, "{}", message); @@ -208,6 +218,43 @@ impl State { async fn request(&mut self, uri: &Uri, from: u64) -> anyhow::Result> { + let request = RequestBuilder::new() + . method("HEAD") + . uri(uri) + . body(Body::default())?; + + log!(Level::Debug, "{:?}", request); + + // Send get request with timeout. + // let send_fut = self.client.get(uri).send()?; + let send_fut = self.client.execute(request); + let response = timeout(self.timeout, send_fut).await??; + + anyhow::ensure!( response.status().is_success() + , "resonse status failed: {}" + , response.status() ); + + log!(Level::Debug, "{:?}", response); + + let content_length: u64 = response.headers().get(CONTENT_LENGTH) + . or(Some(&HeaderValue::from(0))) + . expect("No CONTENT-LENGTH in response") + . to_str() + . expect("unable to get CONTENT-LENGTH value") + . parse() + . expect("unable to parse CONTENT-LENGTH value"); + + if from != 0 && content_length - 1 <= from { + let response = Response::builder() + . header("x-finished", "true") + . body(Body::default()) + . expect("Unable to create default response"); + + log!(Level::Debug, "content_length: {}, from: {}", content_length, from); + + return Ok(response); + } + let request = RequestBuilder::new() . uri(uri) . header(RANGE, format!("bytes={}-", from))