Skip to content

Commit 7bee0d2

Browse files
authored
feat: Load images through client (#133)
1 parent 4c45b4f commit 7bee0d2

File tree

7 files changed

+116
-134
lines changed

7 files changed

+116
-134
lines changed

Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ run:
2222
REPLEX_AUTO_SELECT_VERSION=0 \
2323
REPLEX_FORCE_MAXIMUM_QUALITY=1 \
2424
REPLEX_CACHE_ROWS=0 \
25-
REPLEX_CACHE_ROWS_REFRESH=0 \
25+
REPLEX_CACHE_ROWS_REFRESH=0 \
2626
REPLEX_HERO_ROWS="home.movies.recent,movies.recent,movie.recentlyadded,movie.topunwatched,movie.recentlyviewed,hub.movie.recentlyreleased,home.television.recent,tv.inprogress,tv.recentlyaired" \
2727
REPLEX_PORT=8000 \
2828
REPLEX_INCLUDE_WATCHED=0 \
@@ -32,10 +32,10 @@ run:
3232
REPLEX_DISABLE_USER_STATE=0 \
3333
REPLEX_ENABLE_CONSOLE=0 \
3434
REPLEX_CACHE_TTL=0 \
35-
REPLEX_NTF_WATCHLIST_FORCE=1 \
35+
REPLEX_NTF_WATCHLIST_FORCE=1 \
3636
RUST_LOG="info,replex=info" \
37-
RUSTFLAGS=-Awarnings \
38-
cargo watch -x run
37+
RUSTFLAGS=-Awarnings \
38+
cargo watch -w src -x run
3939

4040
fix:
4141
cargo fix

src/logging.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl Handler for Logger {
4343
let status = res.status_code.unwrap_or(StatusCode::OK);
4444
tracing::debug!(
4545
status = %status,
46-
//path = %req.uri(),
46+
path = %req.uri(),
4747
duration = ?duration,
4848
"Response"
4949
);

src/models.rs

+3-77
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ pub struct PlexContext {
190190
#[serde(default = "default_as_false", deserialize_with = "bool_from_int")]
191191
#[salvo(extract(rename = "excludeAllLeaves"))]
192192
pub exclude_all_leaves: bool,
193+
// host of the proxy server
194+
#[salvo(extract(rename = "host"))]
195+
pub host: Option<String>,
193196
// photo transcode
194197
pub size: Option<String>,
195198
pub width: Option<i32>,
@@ -1247,83 +1250,6 @@ where
12471250
}
12481251

12491252
impl MetaData {
1250-
// TODO: move to plexclient
1251-
pub async fn get_hero_art(
1252-
&self,
1253-
plex_client: PlexClient,
1254-
) -> Option<String> {
1255-
//return None;
1256-
1257-
self.guid.as_ref()?;
1258-
let mut guid = self.guid.clone().unwrap();
1259-
if guid.starts_with("local://") {
1260-
tracing::debug!(
1261-
"Skipping loading remote metadata for local item: {}",
1262-
guid,
1263-
);
1264-
return None;
1265-
}
1266-
1267-
if guid.starts_with("plex://episode") && self.parent_guid.is_some() {
1268-
guid = self.parent_guid.clone().unwrap();
1269-
// dbg!(&guid);
1270-
}
1271-
1272-
let cache_key = format!("{}:cover_art", guid);
1273-
1274-
let cached_result: Option<Option<String>> =
1275-
GLOBAL_CACHE.get(cache_key.as_str()).await;
1276-
1277-
if cached_result.is_some() {
1278-
return cached_result.unwrap();
1279-
}
1280-
1281-
let guid = self
1282-
.guid
1283-
.clone()
1284-
.unwrap()
1285-
.replace("plex://show/", "")
1286-
.replace("plex://movie/", "")
1287-
.replace("plex://season/", "")
1288-
.replace("plex://episode/", "");
1289-
1290-
let mut container: MediaContainerWrapper<MediaContainer> =
1291-
match plex_client.get_provider_data(guid).await {
1292-
Ok(r) => r,
1293-
Err(e) => {
1294-
tracing::warn!(
1295-
"Problem loading provider metadata for: {} Error: {}",
1296-
self.guid.clone().unwrap(),
1297-
e
1298-
);
1299-
MediaContainerWrapper::default()
1300-
}
1301-
};
1302-
1303-
//let mut container: MediaContainerWrapper<MediaContainer> = MediaContainerWrapper::default();
1304-
// let mut container = plex_client.get_provider_data(guid).await.unwrap();
1305-
let metadata = container.media_container.children_mut().get(0);
1306-
let mut image: Option<String> = None;
1307-
if metadata.is_some() {
1308-
for i in &metadata.unwrap().images {
1309-
if i.r#type == "coverArt" {
1310-
image = Some(i.url.clone());
1311-
break;
1312-
}
1313-
}
1314-
}
1315-
//drop(container);
1316-
let mut cache_expiry = crate::cache::Expiration::Month;
1317-
image.as_ref()?; // dont return and dont cache, let us just retry next time.
1318-
//return image;
1319-
1320-
//dbg!("KAKA");
1321-
let _ = GLOBAL_CACHE
1322-
.insert(cache_key, image.clone(), cache_expiry)
1323-
.await;
1324-
image
1325-
}
1326-
13271253
pub fn children_mut(&mut self) -> &mut Vec<MetaData> {
13281254
if !self.metadata.is_empty() {
13291255
return &mut self.metadata;

src/plex_client.rs

+49-31
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::models::*;
66
use crate::utils::*;
77
use anyhow::Result;
88

9+
use crate::cache::GLOBAL_CACHE;
910
use async_recursion::async_recursion;
1011
use futures_util::Future;
1112
use futures_util::TryStreamExt;
@@ -69,7 +70,7 @@ impl RetryableStrategy for Retry401 {
6970
#[derive(Debug, Clone)]
7071
pub struct PlexClient {
7172
pub http_client: reqwest_middleware::ClientWithMiddleware,
72-
pub host: String, // TODO: Dont think this suppsoed to be here. Should be higher up
73+
pub host: String, // TODO: Dont think this supposed to be here. Should be higher up
7374
pub cache: Cache<String, MediaContainerWrapper<MediaContainer>>,
7475

7576
// /// `X-Plex-Platform` header value.
@@ -123,34 +124,6 @@ impl PlexClient {
123124
header::HeaderValue::from_str(&target_host).unwrap(),
124125
);
125126

126-
// let i = "47.250.115.151".to_string();
127-
// headers.insert(
128-
// FORWARDED,
129-
// header::HeaderValue::from_str(i.as_str()).unwrap(),
130-
// );
131-
// headers.insert(
132-
// "X-Forwarded-For",
133-
// header::HeaderValue::from_str(i.as_str()).unwrap(),
134-
// );
135-
// headers.insert(
136-
// "X-Real-Ip",
137-
// header::HeaderValue::from_str(i.as_str()).unwrap(),
138-
// );
139-
140-
// let reqq = self
141-
// .http_client
142-
// .get(url.clone());
143-
// dbg!(&req);
144-
145-
// reqwest::Client::builder()
146-
// .proxy(reqwest::Proxy::all("http://192.168.2.10:9090".to_string()).unwrap())
147-
// .timeout(Duration::from_secs(30))
148-
// .build()
149-
// .unwrap()
150-
// .get("http://nu.nl")
151-
// .send()
152-
// .await;
153-
154127
let res = self
155128
.http_client
156129
.request(req.method_mut().to_owned(), url)
@@ -324,13 +297,58 @@ impl PlexClient {
324297
Ok(r)
325298
}
326299

300+
pub async fn get_hero_art(
301+
self,
302+
uuid: String,
303+
) -> Option<String> {
304+
let cache_key = format!("{}:cover_art", uuid);
305+
306+
let cached_result: Option<Option<String>> =
307+
GLOBAL_CACHE.get(cache_key.as_str()).await;
308+
309+
if cached_result.is_some() {
310+
return cached_result.unwrap();
311+
}
312+
313+
let mut container: MediaContainerWrapper<MediaContainer> =
314+
match self.get_provider_data(&uuid).await {
315+
Ok(r) => r,
316+
Err(e) => {
317+
tracing::warn!(
318+
"Problem loading provider metadata for: {} Error: {}",
319+
uuid,
320+
e
321+
);
322+
MediaContainerWrapper::default()
323+
}
324+
};
325+
326+
let metadata = container.media_container.children_mut().get(0);
327+
let mut image: Option<String> = None;
328+
if metadata.is_some() {
329+
for i in &metadata.unwrap().images {
330+
if i.r#type == "coverArt" {
331+
image = Some(i.url.clone());
332+
break;
333+
}
334+
}
335+
}
336+
337+
let mut cache_expiry = crate::cache::Expiration::Month;
338+
image.as_ref()?; // dont return and dont cache, let us just retry next time.
339+
let _ = GLOBAL_CACHE
340+
.insert(cache_key, image.clone(), cache_expiry)
341+
.await;
342+
image
343+
}
344+
327345
pub async fn get_provider_data(
328346
self,
329-
guid: String,
347+
uuid: &String,
330348
) -> Result<MediaContainerWrapper<MediaContainer>> {
331349
let url = format!(
332350
"https://metadata.provider.plex.tv/library/metadata/{}",
333-
guid
351+
uuid
334352
);
335353
// let url = "https://httpbin.org/status/401".to_string();
336354
// let wut = reqwest::RequestBuilder::new(http::Method::GET);

src/routes.rs

+34-20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use salvo::routing::PathFilter;
2121
use std::sync::Arc;
2222
use tokio::time::Duration;
2323
use url::Url;
24+
use http;
2425

2526
pub fn route() -> Router {
2627
let config: Config = Config::figment().extract().unwrap();
@@ -153,6 +154,13 @@ pub fn route() -> Router {
153154
//.hoop(default_cache())
154155
.get(transform_hubs_home),
155156
)
157+
.push(
158+
Router::new()
159+
.path("/image/hero/<type>/<uuid>")
160+
// .path("/image/hero.jpg")
161+
.get(hero_image)
162+
//.get(proxy_request),
163+
)
156164
.push(
157165
Router::new()
158166
.path(format!("{}/<id>", PLEX_HUBS_SECTIONS))
@@ -204,15 +212,7 @@ async fn proxy_request(
204212
ctrl: &mut FlowCtrl,
205213
) {
206214
let config: Config = Config::dynamic(req).extract().unwrap();
207-
//let proxy = Proxy::new(
208-
// config.host.clone().unwrap(),
209-
// reqwest::Client::builder()
210-
// .timeout(Duration::from_secs(60 * 200))
211-
// .build()
212-
// .unwrap(),
213-
//);
214215
let proxy = default_proxy();
215-
216216
proxy.handle(req, depot, res, ctrl).await;
217217
}
218218

@@ -242,13 +242,6 @@ async fn should_skip(
242242
{
243243

244244
let config: Config = Config::dynamic(req).extract().unwrap();
245-
//let proxy = Proxy::new(
246-
// config.host.clone().unwrap(),
247-
// reqwest::Client::builder()
248-
// .timeout(Duration::from_secs(60 * 200))
249-
// .build()
250-
// .unwrap(),
251-
//);
252245
let proxy = default_proxy();
253246

254247
proxy.handle(req, depot, res, ctrl).await;
@@ -327,8 +320,8 @@ async fn ntf_watchlist_force(
327320
res: &mut Response,
328321
ctrl: &mut FlowCtrl,
329322
) {
330-
use memory_stats::memory_stats;
331-
dbg!(memory_stats().unwrap().physical_mem / 1024 / 1000);
323+
// use memory_stats::memory_stats;
324+
// dbg!(memory_stats().unwrap().physical_mem / 1024 / 1000);
332325
let params: PlexContext = req.extract().await.unwrap();
333326

334327
if params.clone().token.is_some() {
@@ -384,6 +377,29 @@ pub async fn webhook_plex(
384377
return Ok(());
385378
}
386379

380+
#[handler]
381+
pub async fn hero_image(
382+
req: &mut Request,
383+
res: &mut Response,
384+
ctrl: &mut FlowCtrl,
385+
depot: &mut Depot,
386+
) {
387+
let params: PlexContext = req.extract().await.unwrap();
388+
let plex_client = PlexClient::from_request(req, params.clone());
389+
// dbg!(&req);
390+
let t = req.param::<String>("type").unwrap();
391+
let uuid = req.param::<String>("uuid").unwrap();
392+
let url = plex_client.get_hero_art(uuid).await;
393+
if url.is_none() {
394+
res.status_code(StatusCode::NOT_FOUND);
395+
return
396+
}
397+
let uri = url.unwrap().parse::<http::Uri>().unwrap();;
398+
req.set_uri(uri);
399+
let proxy = proxy("https://metadata-static.plex.tv".to_string());
400+
proxy.handle(req, depot, res, ctrl).await;
401+
}
402+
387403
// if directplay fails we remove it.
388404
#[handler]
389405
pub async fn direct_stream_fallback(
@@ -439,9 +455,6 @@ pub async fn direct_stream_fallback(
439455
}
440456
};
441457

442-
443-
444-
445458
return Ok(());
446459
}
447460

@@ -470,6 +483,7 @@ pub async fn transform_hubs_home(
470483
res.render(container);
471484
return Ok(());
472485
}
486+
//dbg!(&req);
473487

474488
if params.clone().pinned_content_directory_id.is_some() {
475489
// first directory, load everything here because we wanna reemiiiixxx

src/transform.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,17 @@ impl Transform for MediaStyleTransform {
792792
if style_def.child_type.clone().is_some() {
793793
item.r#type = style_def.child_type.clone().unwrap();
794794
}
795-
let cover_art = item.get_hero_art(plex_client).await;
795+
796+
let mut guid = item.guid.clone().unwrap();
797+
if guid.starts_with("plex://episode") && item.parent_guid.is_some() {
798+
guid = item.parent_guid.clone().unwrap();
799+
}
800+
guid = guid
801+
.replace("plex://", "");
802+
803+
//let cover_art = item.get_hero_art(plex_client).await;
804+
let cover_art = Some(format!("{}/image/hero/{}", options.host.clone().unwrap(), guid));
805+
//dbg!(&options);
796806
if cover_art.is_some() {
797807
// c.art = art.clone();
798808
item.images = vec![Image {

src/utils.rs

+14
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ pub fn default_proxy() -> Proxy<String, ReqwestClient> {
6565
}
6666

6767

68+
69+
pub fn proxy(upstream: String) -> Proxy<String, ReqwestClient> {
70+
let mut proxy = Proxy::new(
71+
upstream,
72+
ReqwestClient::new(reqwest::Client::builder()
73+
.build()
74+
.unwrap())
75+
);
76+
proxy = proxy.url_path_getter(default_url_path_getter);
77+
proxy = proxy.url_query_getter(default_url_query_getter);
78+
79+
proxy
80+
}
81+
6882
pub fn get_collection_id_from_child_path(path: String) -> i32 {
6983
let mut path = path.replace("/library/collections/", "");
7084
path = path.replace("/children", "");

0 commit comments

Comments
 (0)