From 475201d640b2f09f0faeec8a41437747175ce8c6 Mon Sep 17 00:00:00 2001 From: euzu Date: Thu, 18 Dec 2025 16:51:09 +0100 Subject: [PATCH] fetching tmdb data for series --- backend/src/api/api_utils.rs | 25 ++++-- backend/src/library/tmdb.rs | 2 +- backend/src/library/tmdb_client.rs | 88 ------------------- .../src/processing/processor/xtream_vod.rs | 2 +- 4 files changed, 19 insertions(+), 98 deletions(-) diff --git a/backend/src/api/api_utils.rs b/backend/src/api/api_utils.rs index a8432a7ff..cdf0d37fc 100644 --- a/backend/src/api/api_utils.rs +++ b/backend/src/api/api_utils.rs @@ -427,9 +427,7 @@ async fn create_stream_response_details( force_provider: Option<&str>, ) -> StreamDetails { let mut streaming_strategy = resolve_streaming_strategy(app_state, stream_url, fingerprint, input, force_provider).await; - let config_grace_period_millis = app_state - .app_config - .config + let config_grace_period_millis = app_state.app_config.config .load() .reverse_proxy .as_ref() @@ -1039,8 +1037,7 @@ pub async fn local_stream_response( app_state, &fingerprint.addr, CustomVideoStreamType::UserConnectionsExhausted, - ).await - .into_response(); + ).await.into_response(); } let path = PathBuf::from(pli.url.strip_prefix("file://").unwrap_or(&pli.url)); @@ -1056,9 +1053,9 @@ pub async fn local_stream_response( // Verify path is within allowed media directories // (requires configuration of allowed base paths) - // if !is_path_within_allowed_directories(&path, app_state) { - // return StatusCode::FORBIDDEN.into_response(); - // } + if !is_path_within_allowed_directories(&path, &app_state.app_config.paths.load().library_file_path) { + return StatusCode::FORBIDDEN.into_response(); + } let Ok(mut file) = tokio::fs::File::open(&path).await else { return StatusCode::NOT_FOUND.into_response() }; let Ok(metadata) = file.metadata().await else { return StatusCode::INTERNAL_SERVER_ERROR.into_response() }; @@ -1134,6 +1131,18 @@ pub async fn local_stream_response( response } +fn is_path_within_allowed_directories(sub_path: &PathBuf, root_path: &str) -> bool { + let sub_path = match sub_path.canonicalize() { + Ok(p) => p, + Err(_) => return false, + }; + let root_path = match PathBuf::from(root_path).canonicalize() { + Ok(p) => p, + Err(_) => return false, + }; + + sub_path.starts_with(&root_path) +} pub fn is_stream_share_enabled(item_type: PlaylistItemType, target: &ConfigTarget) -> bool { (item_type == PlaylistItemType::Live/* || item_type == PlaylistItemType::LiveHls */) diff --git a/backend/src/library/tmdb.rs b/backend/src/library/tmdb.rs index 4497046d1..6204873aa 100644 --- a/backend/src/library/tmdb.rs +++ b/backend/src/library/tmdb.rs @@ -156,7 +156,7 @@ impl TmdbMovieDetails { }) .and_then(some_if_nonempty), studios: self.production_companies.as_ref().map(|list| list.iter().map(|n| n.name.clone()).collect()).and_then(some_if_nonempty), - poster: as Clone>::clone(&self.poster_path).map(|p| format!("{TMDB_IMAGE_BASE_URL}{p}")), + poster: self.poster_path.as_ref().map(|p| format!("{TMDB_IMAGE_BASE_URL}{p}")), fanart: self.backdrop_path.clone().map(|p| format!("{TMDB_IMAGE_BASE_URL}{p}")), source: MetadataSource::Tmdb, last_updated: chrono::Utc::now().timestamp(), diff --git a/backend/src/library/tmdb_client.rs b/backend/src/library/tmdb_client.rs index a9edb6501..a9a25f866 100644 --- a/backend/src/library/tmdb_client.rs +++ b/backend/src/library/tmdb_client.rs @@ -253,94 +253,6 @@ impl TmdbClient { Ok(None) } - // async fn fetch_series_details( - // &self, - // series_id: u32, - // ) -> Result, String> { - // if self.fetched_series_metadata.read().await.contains(&series_id) { - // return Ok(None); - // } - // - // sleep(Duration::from_millis(self.rate_limit_ms)).await; - // - // let url = format!("{TMDB_API_BASE_URL}/tv/{series_id}?api_key={}&append_to_response=credits,videos,external_ids", self.api_key); - // let response = self.client.get(&url).send().await.map_err(|e| format!("TMDB API request failed: {e}"))?; - // - // if !response.status().is_success() { - // error!("TMDB API error fetching series details: {}", response.status()); - // return Err(format!("TMDB API error fetching series details: {}", response.status())); - // } - // - // let series_content = response.bytes().await.map_err(|e| format!("Failed to read TMDB response body: {e}"))?; - // - // self.fetched_series_metadata.write().await.insert(series_id); - // - // let mut series = serde_json::from_slice::(&series_content) - // .map_err(|e| format!("Failed to parse TMDB series details: {e}"))?; - // - // let season_count = self.detect_season_count(&series); - // if season_count > 0 { - // let season_infos = self.fetch_seasons(series_id, season_count).await; - // if !season_infos.is_empty() { - // - // let raw_series = serde_json::from_slice::>(&series_content); - // - // if let Some(seasons) = series.seasons.as_mut() { - // for season in seasons { - // let season_no = season.season_number; - // for (season_details, raw_season_content) in &season_infos { - // if season_details.season_number == season_no { - // season.episodes = Some(season_details.episodes.clone()); - // season.networks = Some(season_details.networks.clone()); - // season.credits = season_details.credits.clone(); - // - // if let Ok(series_json) = raw_series { - // if let Ok(series_season_details) = serde_json::from_slice::>(raw_season_content.as_ref()) { - // if let Some(season_entry) = series_json.get("seasons") { - // match season_entry { - // Value::Array(season_entry_list) => { - // for season_item in season_entry_list { - // if let Some(season_number) = season_item.get("season_number") { - // match season_number { - // Value::Number(season_item_no) => { - // if let Some(no) = season_item_no.as_u64() { - // if season_no as u64 == no { - // season_item.insert("episodes", series_season_details.get("episodes")); - // season_item.insert("networks", series_season_details.get("networks")); - // season_item.insert("credits", series_season_details.get("credits")); - // } - // } - // } - // _ => {} - // } - // } - // } - // } - // _ => {} - // } - // } - // } - // } - // continue; - // } - // } - // } - // } - // - // if let Ok(raw_series_content) = &raw_series { - // if let Ok(series_content) = serde_json::to_vec(raw_series_content) { - // if let Err(err) = self.storage.store_tmdb_series_info(series_id, &series_content).await { - // error!("Failed to store raw TMDB series info: {err}"); - // } - // } - // } - // return Ok(Some(MediaMetadata::Series(series.to_meta_data()))); - // } - // } - // - // Ok(None) - // } - fn detect_season_count(series: &TmdbSeriesInfoDetails) -> u32 { if series.number_of_seasons > 0 { series.number_of_seasons diff --git a/backend/src/processing/processor/xtream_vod.rs b/backend/src/processing/processor/xtream_vod.rs index b70774463..d848ec349 100644 --- a/backend/src/processing/processor/xtream_vod.rs +++ b/backend/src/processing/processor/xtream_vod.rs @@ -100,7 +100,7 @@ pub async fn playlist_resolve_vod(app_config: &AppConfig, client: &reqwest::Clie for plg in &mut fpl.playlistgroups { for pli in &mut plg.channels { // LocalVideo files are not resolved - if pli.header.xtream_cluster != XtreamCluster::Video && pli.header.item_type != PlaylistItemType::Video { + if pli.header.xtream_cluster != XtreamCluster::Video || pli.header.item_type != PlaylistItemType::Video { continue; } let (should_update, provider_id, _ts) = should_update_vod_info(pli, &processed_info_ids);