Integrate local movie file into playlist

This commit is contained in:
euzu
2025-12-16 20:35:19 +01:00
parent 5f9fa8ea56
commit c8d34e0dfd
7 changed files with 38 additions and 23 deletions
+6 -3
View File
@@ -1051,9 +1051,12 @@ pub async fn local_stream_response(
.and_then(|v| v.to_str().ok())
.and_then(parse_range);
let (start, end) = if let Some((start, end)) = range {
let end = end.unwrap_or(file_size - 1);
(start, end.min(file_size - 1))
let (start, end) = if let Some((req_start, req_end)) = range {
if file_size == 0 || req_start >= file_size {
return StatusCode::RANGE_NOT_SATISFIABLE.into_response();
}
let end = req_end.unwrap_or(file_size - 1).min(file_size - 1);
(req_start, end)
} else {
if file_size == 0 {
// Serve empty file
+1 -1
View File
@@ -1005,7 +1005,7 @@ async fn xtream_get_stream_info_response(
axum::http::header::CONTENT_TYPE,
mime::APPLICATION_JSON.to_string()
)
.body(axum::body::Body::from(additional_properties.clone())));
.body(axum::body::Body::from(additional_properties.to_owned())));
}
}
+3 -3
View File
@@ -17,7 +17,7 @@ pub struct ScannedMediaFile {
impl ScannedMediaFile {
/// Creates a new `ScannedMediaFile` from a path and metadata
pub async fn from_path(path: PathBuf) -> io::Result<Self> {
pub async fn from_path(path: &Path) -> io::Result<Self> {
let metadata = fs::metadata(&path).await?;
let file_name = path
.file_name()
@@ -38,7 +38,7 @@ impl ScannedMediaFile {
Ok(Self {
file_path: path.display().to_string(),
path,
path: path.to_path_buf(),
file_name,
extension,
size_bytes: metadata.len(),
@@ -138,7 +138,7 @@ impl LibraryScanner {
if let Some(ext) = entry_path.extension().and_then(|e| e.to_str()) {
let ext_lower = ext.to_lowercase();
if self.config.supported_extensions.contains(&ext_lower) {
match ScannedMediaFile::from_path(entry_path.clone()).await {
match ScannedMediaFile::from_path(&entry_path).await {
Ok(video_file) => {
trace!("Found video file: {}", video_file.file_path);
files.push(video_file);
+7
View File
@@ -26,6 +26,13 @@ impl ConfigSource {
None
}
// Determines whether this source should be processed for the given user targets.
//
// Returns `true` if:
// - `user_targets.targets` is empty (process all sources), OR
// - At least one target in this source matches an ID in `user_targets.targets`
//
// Returns `false` otherwise.
pub fn should_process_for_user_targets(&self, user_targets: &ProcessTargets) -> bool {
user_targets.targets.is_empty()
|| self.targets.iter().any(|t| user_targets.targets.contains(&t.id))
+1
View File
@@ -224,6 +224,7 @@ pub struct XtreamMovieInfoDetails {
pub plot: Option<String>,
pub age: Option<String>,
pub mpaa_rating: Option<String>,
#[serde(default)]
pub rating_count_kinopoisk: u32,
pub country: Option<String>,
pub genre: Option<String>,
+19 -15
View File
@@ -1,22 +1,22 @@
use shared::model::InputType;
use shared::error::{TuliproxError};
use crate::model::{AppConfig, ConfigTarget};
use crate::model::{FetchedPlaylist};
use shared::model::{PlaylistItem, PlaylistItemType, XtreamCluster};
use crate::model::FetchedPlaylist;
use crate::processing::processor::xtream::normalize_json_content;
use crate::processing::processor::xtream::{create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info};
use crate::processing::processor::{create_resolve_options_function_for_xtream_target, handle_error, handle_error_and_return};
use crate::repository::xtream_repository::{write_vod_info_to_wal_file, xtream_update_input_info_file, xtream_update_input_vod_record_from_wal_file, InputVodInfoRecord};
use shared::error::{notify_err};
use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target};
use shared::utils::{get_u32_from_serde_value, get_u64_from_serde_value, get_string_from_serde_value};
use serde_json::{Map, Value};
use std::collections::{HashMap, HashSet};
use std::io::{Write};
use std::time::Instant;
use crate::utils;
use crate::utils::IO_BUFFER_SIZE;
use log::{info, log_enabled, Level};
use serde_json::value::RawValue;
use crate::utils;
use crate::processing::processor::xtream::normalize_json_content;
use crate::utils::IO_BUFFER_SIZE;
use serde_json::{Map, Value};
use shared::error::notify_err;
use shared::error::TuliproxError;
use shared::model::{InputType, PlaylistEntry};
use shared::model::{PlaylistItem, PlaylistItemType, XtreamCluster};
use shared::utils::{get_string_from_serde_value, get_u32_from_serde_value, get_u64_from_serde_value};
use std::collections::{HashMap, HashSet};
use std::io::Write;
use std::time::Instant;
create_resolve_options_function_for_xtream_target!(vod);
@@ -101,7 +101,11 @@ pub async fn playlist_resolve_vod(app_config: &AppConfig, client: &reqwest::Clie
}
let (should_update, provider_id, _ts) = should_update_vod_info(pli, &processed_info_ids);
if should_update && provider_id != 0 && fetched_in_run.insert(provider_id) {
if let Some(content) = playlist_resolve_download_playlist_item(client, pli, fpl.input, errors, resolve_delay, XtreamCluster::Video).await {
if let Some(content) = if pli.get_item_type().is_local() {
pli.header.additional_properties.as_ref().map(ToString::to_string)
} else {
playlist_resolve_download_playlist_item(client, pli, fpl.input, errors, resolve_delay, XtreamCluster::Video).await
} {
let normalized_content = normalize_json_content(content);
let normalized_str: &str = &normalized_content;
if let Some((provider_id, info_record)) = extract_info_record_from_vod_info(normalized_str) {
+1 -1
View File
@@ -533,7 +533,7 @@ fn format_for_plex(
(dir_path, final_filename)
}
PlaylistItemType::Series
| PlaylistItemType::LocalSeries=> {
| PlaylistItemType::LocalSeries => {
let id_string = if tmdb_id > 0 { format!("{separator}{{tmdb-{tmdb_id}}}") } else { String::new() };
let series_name_raw = strm_item_info.series_name.as_ref().unwrap_or(&strm_item_info.title);
let (name, year) = style_rename_year(series_name_raw, &CONSTANTS.export_style_config, strm_item_info.release_date.as_ref());