diff --git a/transcoder/src/main.rs b/transcoder/src/main.rs index 24c7ab39..818322a1 100644 --- a/transcoder/src/main.rs +++ b/transcoder/src/main.rs @@ -10,6 +10,12 @@ mod paths; mod transcode; mod utils; +fn get_client_id(req: HttpRequest) -> Result { + req.headers().get("x-client-id") + .ok_or(ApiError::BadRequest { error: String::from("Missing client id. Please specify the X-CLIENT-ID header to a guid constant for the lifetime of the player (but unique per instance)."), }) + .map(|x| x.to_str().unwrap().to_string()) +} + #[get("/movie/direct/{slug}")] async fn get_movie_direct(query: web::Path) -> Result { let slug = query.into_inner(); @@ -28,19 +34,17 @@ async fn transcode_movie( let quality = Quality::from_str(quality.as_str()).map_err(|_| ApiError::BadRequest { error: "Invalid quality".to_string(), })?; - let client_id = req.headers().get("x-client-id") - .ok_or(ApiError::BadRequest { error: String::from("Missing client id. Please specify the X-CLIENT-ID header to a guid constant for the lifetime of the player (but unique per instance)."), })? - .to_str().unwrap(); + let client_id = get_client_id(req)?; let path = paths::get_movie_path(slug); // TODO: Handle start_time that is not 0 transcoder - .transcode(client_id.to_string(), path, quality, 0) + .transcode(client_id, path, quality, 0) .await .map_err(|_| ApiError::InternalError) } -#[get("/movie/{quality}/{slug}/segments/{chunk}")] +#[get("/movie/{quality}/{slug}/segments-{chunk}.ts")] async fn get_movie_chunk( req: HttpRequest, query: web::Path<(String, String, u32)>, @@ -50,16 +54,16 @@ async fn get_movie_chunk( let quality = Quality::from_str(quality.as_str()).map_err(|_| ApiError::BadRequest { error: "Invalid quality".to_string(), })?; - let client_id = req.headers().get("x-client-id") - .ok_or(ApiError::BadRequest { error: String::from("Missing client id. Please specify the X-CLIENT-ID header to a guid constant for the lifetime of the player (but unique per instance)."), })? - .to_str().unwrap(); + let client_id = get_client_id(req)?; let path = paths::get_movie_path(slug); // TODO: Handle start_time that is not 0 transcoder - .get_segment(client_id.to_string(), path, quality, chunk) + .get_segment(client_id, path, quality, chunk) .await - .map_err(|_| ApiError::InternalError) + .map_err(|_| ApiError::BadRequest { + error: "No transcode started for the selected show/quality.".to_string(), + }) .and_then(|path| { NamedFile::open(path).map_err(|_| ApiError::BadRequest { error: "Invalid segment number.".to_string(), diff --git a/transcoder/src/transcode.rs b/transcoder/src/transcode.rs index e40a3a9d..da11a4dd 100644 --- a/transcoder/src/transcode.rs +++ b/transcoder/src/transcode.rs @@ -1,11 +1,11 @@ use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; +use std::collections::HashMap; use std::path::PathBuf; use std::process::Stdio; use std::str::FromStr; use std::sync::atomic::AtomicI32; use std::sync::{Arc, RwLock}; -use std::collections::HashMap; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::{Child, Command}; @@ -54,14 +54,14 @@ fn get_transcode_video_quality_args(quality: &Quality) -> Vec<&'static str> { match quality { Quality::Original => vec![], - Quality::P240 => [enc_base, vec!["-vf", "scale=-1:240"]].concat(), - Quality::P360 => [enc_base, vec!["-vf", "scale=-1:360"]].concat(), - Quality::P480 => [enc_base, vec!["-vf", "scale=-1:480"]].concat(), - Quality::P720 => [enc_base, vec!["-vf", "scale=-1:720"]].concat(), - Quality::P1080 => [enc_base, vec!["-vf", "scale=-1:1080"]].concat(), - Quality::P1440 => [enc_base, vec!["-vf", "scale=-1:1440"]].concat(), - Quality::P4k => [enc_base, vec!["-vf", "scale=-1:2160"]].concat(), - Quality::P8k => [enc_base, vec!["-vf", "scale=-1:4320"]].concat(), + Quality::P240 => [enc_base, vec!["-vf", "scale=-2:240"]].concat(), + Quality::P360 => [enc_base, vec!["-vf", "scale=-2:360"]].concat(), + Quality::P480 => [enc_base, vec!["-vf", "scale=-2:480"]].concat(), + Quality::P720 => [enc_base, vec!["-vf", "scale=-2:720"]].concat(), + Quality::P1080 => [enc_base, vec!["-vf", "scale=-2:1080"]].concat(), + Quality::P1440 => [enc_base, vec!["-vf", "scale=-2:1440"]].concat(), + Quality::P4k => [enc_base, vec!["-vf", "scale=-2:2160"]].concat(), + Quality::P8k => [enc_base, vec!["-vf", "scale=-2:4320"]].concat(), } } @@ -142,7 +142,7 @@ fn get_cache_path(info: &TranscodeInfo) -> PathBuf { } fn get_cache_path_from_uuid(uuid: &String) -> PathBuf { - return PathBuf::from(format!("/cache/{uuid}/stream.m3u8", uuid = &uuid)); + return PathBuf::from(format!("/cache/{uuid}/", uuid = &uuid)); } struct TranscodeInfo { @@ -186,16 +186,20 @@ impl Transcoder { if path != *old_path || quality != *old_qual { job.interrupt()?; } else { - return std::fs::read_to_string(get_cache_path_from_uuid(uuid)); + let mut path = get_cache_path_from_uuid(uuid); + path.push("stream.m3u8"); + return std::fs::read_to_string(path); } } let info = start_transcode(path, quality, start_time).await; - let path = get_cache_path(&info); + let mut path = get_cache_path(&info); + path.push("stream.m3u8"); self.running.write().unwrap().insert(client_id, info); std::fs::read_to_string(path) } + // TODO: Use path/quality instead of client_id pub async fn get_segment( &self, client_id: String,