diff --git a/Makefile b/Makefile index f10ca32..7a62029 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ run: REPLEX_AUTO_SELECT_VERSION=0 \ REPLEX_FORCE_MAXIMUM_QUALITY=1 \ REPLEX_CACHE_ROWS=0 \ - REPLEX_CACHE_ROWS_REFRESH=0 \ + REPLEX_CACHE_ROWS_REFRESH=0 \ REPLEX_HERO_ROWS="home.movies.recent,movies.recent,movie.recentlyadded,movie.topunwatched,movie.recentlyviewed,hub.movie.recentlyreleased,home.television.recent,tv.inprogress,tv.recentlyaired" \ REPLEX_PORT=8000 \ REPLEX_INCLUDE_WATCHED=0 \ @@ -32,10 +32,10 @@ run: REPLEX_DISABLE_USER_STATE=0 \ REPLEX_ENABLE_CONSOLE=0 \ REPLEX_CACHE_TTL=0 \ - REPLEX_NTF_WATCHLIST_FORCE=1 \ + REPLEX_NTF_WATCHLIST_FORCE=1 \ RUST_LOG="info,replex=info" \ - RUSTFLAGS=-Awarnings \ - cargo watch -x run + RUSTFLAGS=-Awarnings \ + cargo watch -w src -x run fix: cargo fix diff --git a/src/logging.rs b/src/logging.rs index d578e1b..1c08c04 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -43,7 +43,7 @@ impl Handler for Logger { let status = res.status_code.unwrap_or(StatusCode::OK); tracing::debug!( status = %status, - //path = %req.uri(), + path = %req.uri(), duration = ?duration, "Response" ); diff --git a/src/models.rs b/src/models.rs index fd5f7a4..6698b1f 100644 --- a/src/models.rs +++ b/src/models.rs @@ -190,6 +190,9 @@ pub struct PlexContext { #[serde(default = "default_as_false", deserialize_with = "bool_from_int")] #[salvo(extract(rename = "excludeAllLeaves"))] pub exclude_all_leaves: bool, + // host of the proxy server + #[salvo(extract(rename = "host"))] + pub host: Option, // photo transcode pub size: Option, pub width: Option, @@ -1247,83 +1250,6 @@ where } impl MetaData { - // TODO: move to plexclient - pub async fn get_hero_art( - &self, - plex_client: PlexClient, - ) -> Option { - //return None; - - self.guid.as_ref()?; - let mut guid = self.guid.clone().unwrap(); - if guid.starts_with("local://") { - tracing::debug!( - "Skipping loading remote metadata for local item: {}", - guid, - ); - return None; - } - - if guid.starts_with("plex://episode") && self.parent_guid.is_some() { - guid = self.parent_guid.clone().unwrap(); - // dbg!(&guid); - } - - let cache_key = format!("{}:cover_art", guid); - - let cached_result: Option> = - GLOBAL_CACHE.get(cache_key.as_str()).await; - - if cached_result.is_some() { - return cached_result.unwrap(); - } - - let guid = self - .guid - .clone() - .unwrap() - .replace("plex://show/", "") - .replace("plex://movie/", "") - .replace("plex://season/", "") - .replace("plex://episode/", ""); - - let mut container: MediaContainerWrapper = - match plex_client.get_provider_data(guid).await { - Ok(r) => r, - Err(e) => { - tracing::warn!( - "Problem loading provider metadata for: {} Error: {}", - self.guid.clone().unwrap(), - e - ); - MediaContainerWrapper::default() - } - }; - - //let mut container: MediaContainerWrapper = MediaContainerWrapper::default(); - // let mut container = plex_client.get_provider_data(guid).await.unwrap(); - let metadata = container.media_container.children_mut().get(0); - let mut image: Option = None; - if metadata.is_some() { - for i in &metadata.unwrap().images { - if i.r#type == "coverArt" { - image = Some(i.url.clone()); - break; - } - } - } - //drop(container); - let mut cache_expiry = crate::cache::Expiration::Month; - image.as_ref()?; // dont return and dont cache, let us just retry next time. - //return image; - - //dbg!("KAKA"); - let _ = GLOBAL_CACHE - .insert(cache_key, image.clone(), cache_expiry) - .await; - image - } - pub fn children_mut(&mut self) -> &mut Vec { if !self.metadata.is_empty() { return &mut self.metadata; diff --git a/src/plex_client.rs b/src/plex_client.rs index d875bf1..c5c67fb 100644 --- a/src/plex_client.rs +++ b/src/plex_client.rs @@ -6,6 +6,7 @@ use crate::models::*; use crate::utils::*; use anyhow::Result; +use crate::cache::GLOBAL_CACHE; use async_recursion::async_recursion; use futures_util::Future; use futures_util::TryStreamExt; @@ -69,7 +70,7 @@ impl RetryableStrategy for Retry401 { #[derive(Debug, Clone)] pub struct PlexClient { pub http_client: reqwest_middleware::ClientWithMiddleware, - pub host: String, // TODO: Dont think this suppsoed to be here. Should be higher up + pub host: String, // TODO: Dont think this supposed to be here. Should be higher up pub cache: Cache>, // /// `X-Plex-Platform` header value. @@ -123,34 +124,6 @@ impl PlexClient { header::HeaderValue::from_str(&target_host).unwrap(), ); - // let i = "47.250.115.151".to_string(); - // headers.insert( - // FORWARDED, - // header::HeaderValue::from_str(i.as_str()).unwrap(), - // ); - // headers.insert( - // "X-Forwarded-For", - // header::HeaderValue::from_str(i.as_str()).unwrap(), - // ); - // headers.insert( - // "X-Real-Ip", - // header::HeaderValue::from_str(i.as_str()).unwrap(), - // ); - - // let reqq = self - // .http_client - // .get(url.clone()); - // dbg!(&req); - - // reqwest::Client::builder() - // .proxy(reqwest::Proxy::all("http://192.168.2.10:9090".to_string()).unwrap()) - // .timeout(Duration::from_secs(30)) - // .build() - // .unwrap() - // .get("http://nu.nl") - // .send() - // .await; - let res = self .http_client .request(req.method_mut().to_owned(), url) @@ -324,13 +297,58 @@ impl PlexClient { Ok(r) } + pub async fn get_hero_art( + self, + uuid: String, + ) -> Option { + let cache_key = format!("{}:cover_art", uuid); + + let cached_result: Option> = + GLOBAL_CACHE.get(cache_key.as_str()).await; + + if cached_result.is_some() { + return cached_result.unwrap(); + } + + let mut container: MediaContainerWrapper = + match self.get_provider_data(&uuid).await { + Ok(r) => r, + Err(e) => { + tracing::warn!( + "Problem loading provider metadata for: {} Error: {}", + uuid, + e + ); + MediaContainerWrapper::default() + } + }; + + let metadata = container.media_container.children_mut().get(0); + let mut image: Option = None; + if metadata.is_some() { + for i in &metadata.unwrap().images { + if i.r#type == "coverArt" { + image = Some(i.url.clone()); + break; + } + } + } + + let mut cache_expiry = crate::cache::Expiration::Month; + image.as_ref()?; // dont return and dont cache, let us just retry next time. + let _ = GLOBAL_CACHE + .insert(cache_key, image.clone(), cache_expiry) + .await; + image + } + pub async fn get_provider_data( self, - guid: String, + uuid: &String, ) -> Result> { let url = format!( "https://metadata.provider.plex.tv/library/metadata/{}", - guid + uuid ); // let url = "https://httpbin.org/status/401".to_string(); // let wut = reqwest::RequestBuilder::new(http::Method::GET); diff --git a/src/routes.rs b/src/routes.rs index e7ae257..66d412b 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -21,6 +21,7 @@ use salvo::routing::PathFilter; use std::sync::Arc; use tokio::time::Duration; use url::Url; +use http; pub fn route() -> Router { let config: Config = Config::figment().extract().unwrap(); @@ -153,6 +154,13 @@ pub fn route() -> Router { //.hoop(default_cache()) .get(transform_hubs_home), ) + .push( + Router::new() + .path("/image/hero//") + // .path("/image/hero.jpg") + .get(hero_image) + //.get(proxy_request), + ) .push( Router::new() .path(format!("{}/", PLEX_HUBS_SECTIONS)) @@ -204,15 +212,7 @@ async fn proxy_request( ctrl: &mut FlowCtrl, ) { let config: Config = Config::dynamic(req).extract().unwrap(); - //let proxy = Proxy::new( - // config.host.clone().unwrap(), - // reqwest::Client::builder() - // .timeout(Duration::from_secs(60 * 200)) - // .build() - // .unwrap(), - //); let proxy = default_proxy(); - proxy.handle(req, depot, res, ctrl).await; } @@ -242,13 +242,6 @@ async fn should_skip( { let config: Config = Config::dynamic(req).extract().unwrap(); - //let proxy = Proxy::new( - // config.host.clone().unwrap(), - // reqwest::Client::builder() - // .timeout(Duration::from_secs(60 * 200)) - // .build() - // .unwrap(), - //); let proxy = default_proxy(); proxy.handle(req, depot, res, ctrl).await; @@ -327,8 +320,8 @@ async fn ntf_watchlist_force( res: &mut Response, ctrl: &mut FlowCtrl, ) { - use memory_stats::memory_stats; - dbg!(memory_stats().unwrap().physical_mem / 1024 / 1000); + // use memory_stats::memory_stats; + // dbg!(memory_stats().unwrap().physical_mem / 1024 / 1000); let params: PlexContext = req.extract().await.unwrap(); if params.clone().token.is_some() { @@ -384,6 +377,29 @@ pub async fn webhook_plex( return Ok(()); } +#[handler] +pub async fn hero_image( + req: &mut Request, + res: &mut Response, + ctrl: &mut FlowCtrl, + depot: &mut Depot, +) { + let params: PlexContext = req.extract().await.unwrap(); + let plex_client = PlexClient::from_request(req, params.clone()); + // dbg!(&req); + let t = req.param::("type").unwrap(); + let uuid = req.param::("uuid").unwrap(); + let url = plex_client.get_hero_art(uuid).await; + if url.is_none() { + res.status_code(StatusCode::NOT_FOUND); + return + } + let uri = url.unwrap().parse::().unwrap();; + req.set_uri(uri); + let proxy = proxy("https://metadata-static.plex.tv".to_string()); + proxy.handle(req, depot, res, ctrl).await; +} + // if directplay fails we remove it. #[handler] pub async fn direct_stream_fallback( @@ -439,9 +455,6 @@ pub async fn direct_stream_fallback( } }; - - - return Ok(()); } @@ -470,6 +483,7 @@ pub async fn transform_hubs_home( res.render(container); return Ok(()); } + //dbg!(&req); if params.clone().pinned_content_directory_id.is_some() { // first directory, load everything here because we wanna reemiiiixxx diff --git a/src/transform.rs b/src/transform.rs index 9b72140..bee6e02 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -792,7 +792,17 @@ impl Transform for MediaStyleTransform { if style_def.child_type.clone().is_some() { item.r#type = style_def.child_type.clone().unwrap(); } - let cover_art = item.get_hero_art(plex_client).await; + + let mut guid = item.guid.clone().unwrap(); + if guid.starts_with("plex://episode") && item.parent_guid.is_some() { + guid = item.parent_guid.clone().unwrap(); + } + guid = guid + .replace("plex://", ""); + + //let cover_art = item.get_hero_art(plex_client).await; + let cover_art = Some(format!("{}/image/hero/{}", options.host.clone().unwrap(), guid)); + //dbg!(&options); if cover_art.is_some() { // c.art = art.clone(); item.images = vec![Image { diff --git a/src/utils.rs b/src/utils.rs index b284c25..0273a62 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -65,6 +65,20 @@ pub fn default_proxy() -> Proxy { } + +pub fn proxy(upstream: String) -> Proxy { + let mut proxy = Proxy::new( + upstream, + ReqwestClient::new(reqwest::Client::builder() + .build() + .unwrap()) + ); + proxy = proxy.url_path_getter(default_url_path_getter); + proxy = proxy.url_query_getter(default_url_query_getter); + + proxy +} + pub fn get_collection_id_from_child_path(path: String) -> i32 { let mut path = path.replace("/library/collections/", ""); path = path.replace("/children", "");