mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-18 05:42:16 +02:00
config added to shared model
This commit is contained in:
Generated
+1
@@ -2581,6 +2581,7 @@ name = "shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"enum-iterator",
|
||||
"rand",
|
||||
"regex",
|
||||
"serde",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::api::model::app_state::AppState;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::utils;
|
||||
use crate::utils::is_directory;
|
||||
use log::{debug, error, info};
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::sync::Arc;
|
||||
use std::{fs};
|
||||
use axum::response::IntoResponse;
|
||||
use shared::utils::bytes_to_megabytes;
|
||||
use crate::tuliprox_error::to_io_error;
|
||||
use shared::error::to_io_error;
|
||||
use crate::utils::request::create_client;
|
||||
|
||||
async fn download_file(active: Arc<RwLock<Option<FileDownload>>>, client: &reqwest::Client) -> Result<(), String> {
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::api::model::config::{ServerConfig, ServerInputConfig, ServerSourceCon
|
||||
use crate::api::model::request::{PlaylistRequest, PlaylistRequestType};
|
||||
use crate::auth::create_access_token;
|
||||
use crate::auth::validator_admin;
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use crate::model::StatusCheck;
|
||||
use crate::model::XtreamPlaylistItem;
|
||||
use crate::model::{Config, ConfigDto, ConfigInput, ConfigInputOptions, ConfigSource, ConfigTarget, InputType};
|
||||
|
||||
@@ -16,9 +16,9 @@ use crate::model::{ProxyType, ProxyUserCredentials, UserConnectionPermission};
|
||||
use crate::repository::playlist_repository::get_target_id_mapping;
|
||||
use crate::repository::storage::{get_target_storage_path};
|
||||
use crate::repository::{storage_const, user_repository, xtream_repository};
|
||||
use crate::tuliprox_error::create_tuliprox_error_result;
|
||||
use crate::tuliprox_error::info_err;
|
||||
use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::create_tuliprox_error_result;
|
||||
use shared::error::info_err;
|
||||
use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::utils::{generate_playlist_uuid, hex_encode};
|
||||
use crate::utils::get_u32_from_serde_value;
|
||||
use crate::utils::request::{extract_extension_from_url, sanitize_sensitive_info};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ProcessingOrder, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigRename, ConfigSort, ConfigTargetOptions, TargetOutput, WebUiConfig, ProxyConfig, IpCheckConfig};
|
||||
use shared::model::ProcessingOrder;
|
||||
use crate::model::{ApiProxyConfig, ConfigApi, InputType, LogConfig, MessagingConfig, ReverseProxyConfig, ScheduleConfig, VideoConfig, ConfigRename, ConfigSort, ConfigTargetOptions, TargetOutput, WebUiConfig, ProxyConfig, IpCheckConfig};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct ServerInputConfig {
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::api::api_utils::get_username_from_auth_header;
|
||||
use crate::model::WebAuthConfig;
|
||||
use crate::api::model::app_state::AppState;
|
||||
use crate::auth::AuthBearer;
|
||||
use crate::tuliprox_error::to_io_error;
|
||||
use shared::error::to_io_error;
|
||||
|
||||
const ROLE_ADMIN: &str = "ADMIN";
|
||||
const ROLE_USER: &str = "USER";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use rand::{Rng};
|
||||
use rand::distr::Alphanumeric;
|
||||
use crate::tuliprox_error::str_to_io_error;
|
||||
use shared::error::str_to_io_error;
|
||||
|
||||
fn generate_salt(length: usize) -> String {
|
||||
let salt: String = rand::rng()
|
||||
|
||||
@@ -8,11 +8,11 @@ use pest::iterators::Pair;
|
||||
use pest::Parser;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistItemType};
|
||||
use crate::model::{PlaylistItem, ItemField};
|
||||
use shared::model::{FieldGetAccessor, FieldSetAccessor, ItemField, PlaylistItemType};
|
||||
use crate::model::{PlaylistItem};
|
||||
use crate::tools::directed_graph::DirectedGraph;
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::CONSTANTS;
|
||||
|
||||
pub fn get_field_value(pli: &PlaylistItem, field: ItemField) -> String {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::foundation::filter::{PatternTemplate, TemplateValue, ValueAccessor};
|
||||
use crate::foundation::mapper::EvalResult::{AnyValue, Failure, Named, Number, Undefined, Value};
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::Capitalize;
|
||||
use log::{debug, trace};
|
||||
use pest::iterators::{Pair, Pairs};
|
||||
|
||||
@@ -2,18 +2,7 @@ use std::sync::Arc;
|
||||
use crate::model::{MessagingConfig};
|
||||
use log::{debug, error};
|
||||
use reqwest::{header};
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
pub enum MsgKind {
|
||||
#[serde(rename = "info")]
|
||||
Info,
|
||||
#[serde(rename = "stats")]
|
||||
Stats,
|
||||
#[serde(rename = "error")]
|
||||
Error,
|
||||
#[serde(rename = "watch")]
|
||||
Watch,
|
||||
}
|
||||
use shared::model::MsgKind;
|
||||
|
||||
fn is_enabled(kind: MsgKind, cfg: &MessagingConfig) -> bool {
|
||||
cfg.notify_on.contains(&kind)
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use arc_swap::{ArcSwapOption};
|
||||
use enum_iterator::Sequence;
|
||||
use std::collections::{HashSet};
|
||||
use std::fmt::Display;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use log::{debug, error, warn};
|
||||
@@ -14,7 +11,7 @@ use rand::Rng;
|
||||
|
||||
use crate::model::{ApiProxyConfig, ApiProxyServerInfo, Mappings, ProxyUserCredentials, SourcesConfig};
|
||||
use crate::model::{ConfigInput, ConfigInputOptions, ConfigTarget, HdHomeRunConfig, IpCheckConfig, LogConfig, MessagingConfig, ProxyConfig, TargetOutput, VideoConfig, WebUiConfig};
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::{parse_to_kbps, default_connect_timeout_secs, default_grace_period_millis, default_grace_period_timeout_secs};
|
||||
|
||||
const STREAM_QUEUE_SIZE: usize = 1024; // mpsc channel holding messages. with 8192byte chunks and 2Mbit/s approx 8MB
|
||||
@@ -43,84 +40,6 @@ use crate::api::model::streams::transport_stream_buffer::TransportStreamBuffer;
|
||||
use crate::model::config_cache::CacheConfig;
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, Eq, PartialEq)]
|
||||
pub enum ItemField {
|
||||
#[serde(rename = "group")]
|
||||
Group,
|
||||
#[serde(rename = "name")]
|
||||
Name,
|
||||
#[serde(rename = "title")]
|
||||
Title,
|
||||
#[serde(rename = "url")]
|
||||
Url,
|
||||
#[serde(rename = "input")]
|
||||
Input,
|
||||
#[serde(rename = "type")]
|
||||
Type,
|
||||
#[serde(rename = "caption")]
|
||||
Caption,
|
||||
}
|
||||
|
||||
impl ItemField {
|
||||
const GROUP: &'static str = "Group";
|
||||
const NAME: &'static str = "Name";
|
||||
const TITLE: &'static str = "Title";
|
||||
const URL: &'static str = "Url";
|
||||
const INPUT: &'static str = "Input";
|
||||
const TYPE: &'static str = "Type";
|
||||
const CAPTION: &'static str = "Caption";
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Self::Group => Self::GROUP,
|
||||
Self::Name => Self::NAME,
|
||||
Self::Title => Self::TITLE,
|
||||
Self::Url => Self::URL,
|
||||
Self::Input => Self::INPUT,
|
||||
Self::Type => Self::TYPE,
|
||||
Self::Caption => Self::CAPTION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ItemField {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
Self::Group => Self::GROUP,
|
||||
Self::Name => Self::NAME,
|
||||
Self::Title => Self::TITLE,
|
||||
Self::Url => Self::URL,
|
||||
Self::Input => Self::INPUT,
|
||||
Self::Type => Self::TYPE,
|
||||
Self::Caption => Self::CAPTION,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ItemField {
|
||||
type Err = TuliproxError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, TuliproxError> {
|
||||
if s.eq_ignore_ascii_case(Self::GROUP) {
|
||||
Ok(Self::Group)
|
||||
} else if s.eq_ignore_ascii_case(Self::NAME) {
|
||||
Ok(Self::Name)
|
||||
} else if s.eq_ignore_ascii_case(Self::TITLE) {
|
||||
Ok(Self::Title)
|
||||
} else if s.eq_ignore_ascii_case(Self::CAPTION) {
|
||||
Ok(Self::Caption)
|
||||
} else if s.eq_ignore_ascii_case(Self::URL) {
|
||||
Ok(Self::Url)
|
||||
} else if s.eq_ignore_ascii_case(Self::INPUT) {
|
||||
Ok(Self::Input)
|
||||
} else if s.eq_ignore_ascii_case(Self::TYPE) {
|
||||
Ok(Self::Type)
|
||||
} else {
|
||||
create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown InputType: {}", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum FilterMode {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::api::model::app_state::AppState;
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config};
|
||||
use crate::repository::user_repository::{backup_api_user_db_file, get_api_user_db_path, load_api_user, merge_api_user};
|
||||
use crate::utils::{save_api_proxy};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
use log::error;
|
||||
use path_clean::PathClean;
|
||||
use crate::tuliprox_error::{info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::parse_size_base_2;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use regex::Regex;
|
||||
use std::borrow::BorrowMut;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::CONSTANTS;
|
||||
use log::warn;
|
||||
use regex::Regex;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
use log::warn;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
fn default_friendly_name() -> String { String::from("TuliproxTV") }
|
||||
fn default_manufacturer() -> String { String::from("Silicondust") }
|
||||
fn default_model_name() -> String { String::from("HDTC-2US") }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{EpgConfig};
|
||||
use shared::utils::default_as_true;
|
||||
use shared::utils::get_trimmed_string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use regex::Regex;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::messaging::MsgKind;
|
||||
use shared::model::MsgKind;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use shared::model::ItemField;
|
||||
use crate::foundation::filter::{apply_templates_to_pattern_single, PatternTemplate};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
use crate::model::ItemField;
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use regex::Regex;
|
||||
use crate::foundation::filter::{apply_templates_to_pattern, apply_templates_to_pattern_single, PatternTemplate, TemplateValue};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error, handle_tuliprox_error_result_list};
|
||||
use crate::model::{ItemField};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error, handle_tuliprox_error_result_list};
|
||||
use shared::model::ItemField;
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SortOrder {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use crate::foundation::filter::{prepare_templates, PatternTemplate};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind, handle_tuliprox_error_result_list, create_tuliprox_error_result};
|
||||
use crate::model::{ConfigInput, ProcessTargets};
|
||||
use crate::model::config_target::ConfigTarget;
|
||||
use shared::utils::default_as_default;
|
||||
|
||||
@@ -2,40 +2,16 @@ use crate::foundation::filter::{get_filter, Filter, PatternTemplate, ValueProvid
|
||||
use crate::model::config_rename::ConfigRename;
|
||||
use crate::model::config_sort::ConfigSort;
|
||||
use crate::model::mapping::Mapping;
|
||||
use crate::model::processing_order::ProcessingOrder;
|
||||
use crate::model::trakt::TraktConfig;
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::utils::{default_as_default, default_as_true, default_resolve_delay_secs};
|
||||
use arc_swap::ArcSwapOption;
|
||||
use enum_iterator::Sequence;
|
||||
use shared::model::ClusterFlags;
|
||||
use shared::model::{ClusterFlags, ProcessingOrder, StrmExportStyle};
|
||||
use shared::model::PlaylistItemType;
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Copy,
|
||||
Clone,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
Sequence,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Default
|
||||
)]
|
||||
pub enum ExportStyle {
|
||||
#[serde(rename = "kodi")]
|
||||
#[default]
|
||||
Kodi,
|
||||
#[serde(rename = "plex")]
|
||||
Plex,
|
||||
#[serde(rename = "emby")]
|
||||
Emby,
|
||||
#[serde(rename = "jellyfin")]
|
||||
Jellyfin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)]
|
||||
pub enum TargetType {
|
||||
@@ -165,7 +141,7 @@ pub struct StrmTargetOutput {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub username: Option<String>,
|
||||
#[serde(default)]
|
||||
pub style: ExportStyle,
|
||||
pub style: StrmExportStyle,
|
||||
#[serde(default)]
|
||||
pub flat: bool,
|
||||
#[serde(default)]
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::fs::File;
|
||||
use std::io::BufRead;
|
||||
use std::path::PathBuf;
|
||||
use crate::auth::UserCredential;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind, create_tuliprox_error_result};
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use shared::utils::default_as_true;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::WebAuthConfig;
|
||||
|
||||
const RESERVED_PATHS: &[&str] = &[
|
||||
|
||||
@@ -7,8 +7,8 @@ use log::{trace};
|
||||
use crate::foundation::filter::{apply_templates_to_pattern_single, get_filter, prepare_templates, Filter, PatternTemplate};
|
||||
use crate::foundation::mapper::MapperScript;
|
||||
use crate::model::valid_property;
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
|
||||
pub const COUNTER_FIELDS: &[&str] = &["name", "title", "caption", "chno"];
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ mod config_hdhomerun;
|
||||
mod config_ip_check;
|
||||
mod config_sort;
|
||||
mod config_rename;
|
||||
mod processing_order;
|
||||
mod config_target;
|
||||
mod config_source;
|
||||
mod config_proxy;
|
||||
@@ -42,7 +41,6 @@ pub use self::config_webui::*;
|
||||
pub use self::config_ip_check::*;
|
||||
pub use self::config_sort::*;
|
||||
pub use self::config_rename::*;
|
||||
pub use self::processing_order::*;
|
||||
pub use self::config_target::*;
|
||||
pub use self::config_source::*;
|
||||
pub use self::config_proxy::*;
|
||||
|
||||
@@ -8,7 +8,6 @@ macro_rules! include_modules {
|
||||
extern crate pest_derive;
|
||||
pub mod api;
|
||||
pub mod auth;
|
||||
pub mod tuliprox_error;
|
||||
pub mod messaging;
|
||||
pub mod model;
|
||||
pub mod processing;
|
||||
|
||||
@@ -544,7 +544,7 @@ mod tests {
|
||||
assert_eq!("odisea.bg", normalize_channel_name("BG | ODISEA ᵁᴴᴰ ³⁸⁴⁰ᴾ", &epg_smart_cfg));
|
||||
}
|
||||
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use rphonetic::{Encoder, Metaphone};
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::ConfigInput;
|
||||
use crate::model::{PlaylistGroup, PlaylistItem, PlaylistItemHeader};
|
||||
use crate::model::{XtreamCategory, XtreamSeriesInfo, XtreamSeriesInfoEpisode, XtreamStream};
|
||||
|
||||
@@ -2,7 +2,8 @@ use std::collections::BTreeSet;
|
||||
use std::path::{Path};
|
||||
use std::sync::Arc;
|
||||
use log::{error, info};
|
||||
use crate::messaging::{MsgKind, send_message};
|
||||
use shared::model::MsgKind;
|
||||
use crate::messaging::{send_message};
|
||||
use crate::model::Config;
|
||||
use crate::model::PlaylistGroup;
|
||||
use crate::utils;
|
||||
|
||||
@@ -10,17 +10,17 @@ use std::thread;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::foundation::filter::{get_field_value, set_field_value, ValueProvider, ValueAccessor};
|
||||
use crate::messaging::{send_message, MsgKind};
|
||||
use crate::model::{ConfigTarget, InputType, ItemField, ProcessTargets, ProcessingOrder};
|
||||
use crate::messaging::{send_message};
|
||||
use crate::model::{ConfigTarget, InputType, ProcessTargets};
|
||||
use crate::model::{CounterModifier, Mapping};
|
||||
use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem};
|
||||
use shared::model::{FieldGetAccessor, FieldSetAccessor, PlaylistEntry, UUIDType, XtreamCluster};
|
||||
use shared::model::{FieldGetAccessor, FieldSetAccessor, ItemField, MsgKind, PlaylistEntry, ProcessingOrder, UUIDType, XtreamCluster};
|
||||
use crate::model::{InputStats, PlaylistStats, SourceStats, TargetStats};
|
||||
use crate::processing::playlist_watch::process_group_watch;
|
||||
use crate::processing::processor::xtream_series::playlist_resolve_series;
|
||||
use crate::processing::processor::trakt::process_trakt_categories_for_target;
|
||||
use crate::repository::playlist_repository::persist_playlist;
|
||||
use crate::tuliprox_error::{get_errors_notify_message, notify_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{get_errors_notify_message, notify_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::utils::debug_if_enabled;
|
||||
use shared::utils::default_as_default;
|
||||
use deunicode::deunicode;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||
use crate::model::{ConfigTarget, PlaylistGroup, PlaylistItem};
|
||||
use shared::model::{FieldGetAccessor, FieldSetAccessor, XtreamCluster};
|
||||
use crate::model::{TraktConfig, TraktContentType, TraktListConfig, TraktListItem, TraktMatchItem, TraktMatchResult};
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use crate::utils::trakt::TraktClient;
|
||||
use crate::utils::trakt::extract_year_from_title;
|
||||
use crate::utils::trakt::normalize_title_for_matching;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::tuliprox_error::{info_err, notify_err};
|
||||
use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{info_err, notify_err};
|
||||
use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config, ConfigInput};
|
||||
use crate::model::{FetchedPlaylist, PlaylistItem};
|
||||
use shared::model::{PlaylistEntry, PlaylistItemType, XtreamCluster};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config, ConfigTarget, InputType};
|
||||
use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem};
|
||||
use shared::model::{PlaylistItemType, XtreamCluster};
|
||||
@@ -8,7 +8,7 @@ use crate::processing::processor::xtream::{create_resolve_episode_wal_files, cre
|
||||
use crate::repository::storage::get_input_storage_path;
|
||||
use crate::repository::xtream_repository::{write_series_info_to_wal_file, xtream_get_info_file_paths, xtream_update_input_info_file, xtream_update_input_series_episodes_record_from_wal_file, xtream_update_input_series_record_from_wal_file};
|
||||
use crate::repository::IndexedDocumentReader;
|
||||
use crate::tuliprox_error::{notify_err, info_err};
|
||||
use shared::error::{notify_err, info_err};
|
||||
use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config, ConfigTarget, InputType};
|
||||
use crate::model::{FetchedPlaylist, PlaylistItem};
|
||||
use shared::model::{PlaylistItemType, XtreamCluster};
|
||||
use crate::processing::processor::xtream::{create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info};
|
||||
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 crate::tuliprox_error::{notify_err};
|
||||
use shared::error::{notify_err};
|
||||
use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target};
|
||||
use crate::utils::{get_u32_from_serde_value, get_u64_from_serde_value, get_string_from_serde_value};
|
||||
use crate::repository::xtream_repository::xtream_get_input_info;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::io::{self, BufReader, Read, Seek, SeekFrom, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::path::Path;
|
||||
use crate::tuliprox_error::{str_to_io_error, to_io_error};
|
||||
use shared::error::{str_to_io_error, to_io_error};
|
||||
use log::error;
|
||||
use ruzstd::decoding::StreamingDecoder;
|
||||
use ruzstd::encoding::{compress_to_vec, CompressionLevel};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{notify_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{notify_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config, ConfigTarget, TargetOutput};
|
||||
use crate::model::Epg;
|
||||
use crate::repository::m3u_repository::m3u_get_epg_file_path;
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::repository::bplustree::{BPlusTree, BPlusTreeQuery};
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tempfile::NamedTempFile;
|
||||
use crate::tuliprox_error::{str_to_io_error, to_io_error};
|
||||
use shared::error::{str_to_io_error, to_io_error};
|
||||
use crate::utils;
|
||||
use crate::utils::{bincode_deserialize, bincode_serialize};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::tuliprox_error::info_err;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::info_err;
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{ProxyType, ProxyUserCredentials};
|
||||
use crate::model::{Config, ConfigTarget, ConfigTargetOptions, TargetType};
|
||||
use crate::model::{M3uPlaylistItem};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error,info_err};
|
||||
use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error,info_err};
|
||||
use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::ProxyUserCredentials;
|
||||
use crate::model::{Config, ConfigTarget, M3uTargetOutput};
|
||||
use crate::model::{M3uPlaylistItem, PlaylistGroup, PlaylistItem};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::tuliprox_error::info_err;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::info_err;
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config, ConfigTarget, TargetOutput};
|
||||
use crate::model::{PlaylistGroup};
|
||||
use shared::model::{PlaylistItemType};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{Config};
|
||||
use crate::tuliprox_error::{notify_err};
|
||||
use shared::error::{notify_err};
|
||||
use crate::repository::storage_const;
|
||||
use crate::utils;
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err};
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{ApiProxyServerInfo, ProxyUserCredentials};
|
||||
use crate::model::{Config, ConfigTarget, StrmTargetOutput};
|
||||
use crate::model::{PlaylistGroup, PlaylistItem, ExportStyle,
|
||||
};
|
||||
use crate::model::{PlaylistGroup, PlaylistItem};
|
||||
use crate::model::XtreamSeriesEpisode;
|
||||
use crate::repository::bplustree::BPlusTree;
|
||||
use crate::repository::storage::{ensure_target_storage_path, get_input_storage_path};
|
||||
@@ -23,7 +22,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use tokio::fs::{create_dir_all, remove_dir, remove_file, File};
|
||||
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter};
|
||||
use shared::model::{ClusterFlags, FieldGetAccessor, PlaylistItemType, UUIDType};
|
||||
use shared::model::{ClusterFlags, FieldGetAccessor, PlaylistItemType, StrmExportStyle, UUIDType};
|
||||
use crate::utils;
|
||||
|
||||
/// Sanitizes a string to be safe for use as a file or directory name by
|
||||
@@ -673,7 +672,7 @@ async fn style_based_rename(
|
||||
cfg: &Config,
|
||||
strm_item_info: &StrmItemInfo,
|
||||
input_tmdb_indexes: &mut InputTmdbIndexMap,
|
||||
style: &ExportStyle,
|
||||
style: &StrmExportStyle,
|
||||
underscore_whitespace: bool,
|
||||
flat: bool,
|
||||
) -> (PathBuf, String) {
|
||||
@@ -694,10 +693,10 @@ async fn style_based_rename(
|
||||
|
||||
// Dispatch the call to the responsible function based on the style.
|
||||
match style {
|
||||
ExportStyle::Kodi => format_for_kodi(strm_item_info, tmdb_id, separator, flat),
|
||||
ExportStyle::Plex => format_for_plex(strm_item_info, tmdb_id, separator, flat),
|
||||
ExportStyle::Emby => format_for_emby(strm_item_info, tmdb_id, separator, flat),
|
||||
ExportStyle::Jellyfin => format_for_jellyfin(strm_item_info, tmdb_id, separator, flat),
|
||||
StrmExportStyle::Kodi => format_for_kodi(strm_item_info, tmdb_id, separator, flat),
|
||||
StrmExportStyle::Plex => format_for_plex(strm_item_info, tmdb_id, separator, flat),
|
||||
StrmExportStyle::Emby => format_for_emby(strm_item_info, tmdb_id, separator, flat),
|
||||
StrmExportStyle::Jellyfin => format_for_jellyfin(strm_item_info, tmdb_id, separator, flat),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,7 +705,7 @@ async fn prepare_strm_files(
|
||||
new_playlist: &mut [PlaylistGroup],
|
||||
_root_path: &Path,
|
||||
underscore_whitespace: bool,
|
||||
style: &ExportStyle,
|
||||
style: &StrmExportStyle,
|
||||
flat: bool,
|
||||
) -> Vec<StrmFile> {
|
||||
let channel_count = new_playlist
|
||||
@@ -769,13 +768,13 @@ async fn prepare_strm_files(
|
||||
// A style-specific match is not strictly necessary here but is good practice for future flexibility.
|
||||
let new_filename = match style {
|
||||
// Plex, Emby, and Kodi all follow the `Filename - Suffix` pattern.
|
||||
ExportStyle::Plex | ExportStyle::Emby | ExportStyle::Kodi => {
|
||||
StrmExportStyle::Plex | StrmExportStyle::Emby | StrmExportStyle::Kodi => {
|
||||
format!("{base_filename}{version_separator}{version_label}")
|
||||
}
|
||||
|
||||
// Jellyfin also follows this pattern, but explicitly shows an option for " - [Label]".
|
||||
// Using brackets makes the version distinct and is a clean implementation.
|
||||
ExportStyle::Jellyfin => {
|
||||
StrmExportStyle::Jellyfin => {
|
||||
format!("{base_filename}{version_separator}[{version_label}]")
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use log::error;
|
||||
use shared::model::XtreamCluster;
|
||||
use crate::tuliprox_error::info_err;
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::info_err;
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{ProxyUserCredentials};
|
||||
use crate::model::{Config, ConfigTarget, TargetType};
|
||||
use crate::model::{XtreamPlaylistItem};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error, create_tuliprox_error_result, info_err, notify_err, str_to_io_error, to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error, create_tuliprox_error_result, info_err, notify_err, str_to_io_error, to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{ProxyUserCredentials};
|
||||
use crate::model::{Config, ConfigInput, ConfigTarget, XtreamTargetOutput};
|
||||
use crate::model::{PlaylistGroup, PlaylistItem, XtreamPlaylistItem};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use crate::tuliprox_error::to_io_error;
|
||||
use shared::error::to_io_error;
|
||||
|
||||
#[inline]
|
||||
pub fn bincode_serialize<T>(value: &T) -> io::Result<Vec<u8>>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use openssl::symm::{Cipher, Crypter, Mode};
|
||||
use rand::Rng;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::model::{ApiProxyConfig, SourcesConfig};
|
||||
use crate::model::{Config, ConfigDto};
|
||||
use crate::tuliprox_error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error, info_err, to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::utils::{open_file, EnvResolvingReader};
|
||||
use crate::utils::{file_reader};
|
||||
use crate::utils::sys_utils::exit;
|
||||
@@ -73,8 +73,6 @@ pub fn read_sources(sources_file: &str, resolve_env: bool, include_computed: boo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn read_config(config_path: &str, config_file: &str, sources_file: &str, api_proxy_file: &str, mappings_file: Option<String>, include_computed: bool) -> Result<Config, TuliproxError> {
|
||||
|
||||
let resolve_env = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::model::{ConfigInput, ConfigInputAlias, InputType};
|
||||
use crate::tuliprox_error::{str_to_io_error, to_io_error};
|
||||
use shared::error::{str_to_io_error, to_io_error};
|
||||
use crate::utils::request::{get_credentials_from_url, get_local_file_content};
|
||||
use crate::utils::EnvResolvingReader;
|
||||
use crate::utils::{file_reader, resolve_relative_path};
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use std::{fmt, io};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use crate::tuliprox_error::str_to_io_error;
|
||||
use shared::error::str_to_io_error;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FileLockManager {
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::io::{BufReader, BufWriter, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs};
|
||||
|
||||
use crate::tuliprox_error::str_to_io_error;
|
||||
use shared::error::str_to_io_error;
|
||||
use crate::utils::debug_if_enabled;
|
||||
use shared::utils::{API_PROXY_FILE, CONFIG_FILE, CONFIG_PATH, MAPPING_FILE, SOURCE_FILE, USER_FILE};
|
||||
use log::{debug, error};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::foundation::filter::PatternTemplate;
|
||||
use crate::model::{Mapping, MappingDefinition, Mappings};
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::utils::traverse_dir;
|
||||
use crate::utils::{config_file_reader, open_file};
|
||||
use log::{warn};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use crate::model::{Config, ConfigInput, PersistedEpgSource};
|
||||
use crate::model::TVGuide;
|
||||
use crate::utils::{add_prefix_to_filename, cleanup_unlisted_files_with_suffix, prepare_file_path, short_hash};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::IpCheckConfig;
|
||||
use regex::Regex;
|
||||
use reqwest::Client;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use crate::model::{Config, ConfigInput};
|
||||
use crate::model::PlaylistGroup;
|
||||
use crate::processing::parser::m3u;
|
||||
|
||||
@@ -15,8 +15,8 @@ use reqwest::header::CONTENT_ENCODING;
|
||||
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
||||
use url::Url;
|
||||
|
||||
use crate::tuliprox_error::create_tuliprox_error_result;
|
||||
use crate::tuliprox_error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::create_tuliprox_error_result;
|
||||
use shared::error::{str_to_io_error, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{format_elapsed_time, Config};
|
||||
use crate::model::{ConfigInput, InputFetchMethod};
|
||||
use crate::repository::storage::{get_input_storage_path};
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::model::{PlaylistGroup, XtreamPlaylistItem};
|
||||
use crate::processing::parser::xtream;
|
||||
use crate::repository::xtream_repository;
|
||||
use crate::repository::xtream_repository::{rewrite_xtream_series_info_content, rewrite_xtream_vod_info_content, xtream_get_input_info};
|
||||
use crate::tuliprox_error::{str_to_io_error, TuliproxError};
|
||||
use shared::error::{str_to_io_error, TuliproxError};
|
||||
use crate::utils;
|
||||
use crate::utils::{get_string_from_serde_value, request};
|
||||
use crate::utils::request::extract_extension_from_url;
|
||||
@@ -15,8 +15,8 @@ use std::io::Error;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use shared::model::{PlaylistEntry, XtreamCluster};
|
||||
use crate::messaging::{send_message, MsgKind};
|
||||
use shared::model::{MsgKind, PlaylistEntry, XtreamCluster};
|
||||
use crate::messaging::{send_message};
|
||||
|
||||
#[inline]
|
||||
pub fn get_xtream_stream_url_base(url: &str, username: &str, password: &str) -> String {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::model::{TraktApiConfig, TraktListConfig, TraktListItem};
|
||||
use crate::tuliprox_error::TuliproxError;
|
||||
use shared::error::TuliproxError;
|
||||
use reqwest::header::{HeaderMap, HeaderValue};
|
||||
use std::sync::Arc;
|
||||
use log::{debug, info};
|
||||
use crate::tuliprox_error::{info_err, TuliproxErrorKind};
|
||||
use shared::error::{info_err, TuliproxErrorKind};
|
||||
use super::errors::{handle_trakt_api_error};
|
||||
|
||||
pub struct TraktClient {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use shared::error::{create_tuliprox_error_result, TuliproxError, TuliproxErrorKind};
|
||||
use reqwest::StatusCode;
|
||||
|
||||
/// Handle Trakt API response status and convert to appropriate error
|
||||
|
||||
@@ -8,3 +8,4 @@ bitflags = "2.9.1"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
rand = "0.9.1"
|
||||
regex = "1.11.1"
|
||||
enum-iterator = "2"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
mod tuliprox_error;
|
||||
|
||||
pub use tuliprox_error::*;
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod error;
|
||||
pub mod model;
|
||||
pub mod utils;
|
||||
@@ -0,0 +1,56 @@
|
||||
use crate::model::{WebUiConfigDto, MessagingConfigDto, IpCheckConfigDto, HdHomeRunConfigDto, VideoConfigDto, ScheduleConfigDto, LogConfigDto, ReverseProxyConfigDto, ProxyConfigDto};
|
||||
use crate::utils::{default_connect_timeout_secs};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigApiDto {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
#[serde(default)]
|
||||
pub web_root: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigDto {
|
||||
#[serde(default)]
|
||||
pub threads: u8,
|
||||
pub api: ConfigApiDto,
|
||||
pub working_dir: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub backup_dir: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub user_config_dir: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub mapping_path: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub custom_stream_response_path: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub video: Option<VideoConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub schedules: Option<Vec<ScheduleConfigDto>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub log: Option<LogConfigDto>,
|
||||
#[serde(default)]
|
||||
pub user_access_control: bool,
|
||||
#[serde(default = "default_connect_timeout_secs")]
|
||||
pub connect_timeout_secs: u32,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sleep_timer_mins: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub update_on_boot: bool,
|
||||
#[serde(default)]
|
||||
pub config_hot_reload: bool,
|
||||
#[serde(default)]
|
||||
pub web_ui: Option<WebUiConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub messaging: Option<MessagingConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub reverse_proxy: Option<ReverseProxyConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub hdhomerun: Option<HdHomeRunConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub proxy: Option<ProxyConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ipcheck: Option<IpCheckConfigDto>,
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CacheConfigDto {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub size: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub dir: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EpgSourceDto {
|
||||
pub url: String,
|
||||
#[serde(default)]
|
||||
pub priority: i16,
|
||||
#[serde(default)]
|
||||
pub logo_override: bool,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum EpgNamePrefix {
|
||||
#[default]
|
||||
Ignore,
|
||||
Suffix(String),
|
||||
Prefix(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EpgSmartMatchConfigDto {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
pub normalize_regex: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub strip: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub name_prefix: EpgNamePrefix,
|
||||
#[serde(default)]
|
||||
pub name_prefix_separator: Option<Vec<char>>,
|
||||
#[serde(default)]
|
||||
pub fuzzy_matching: bool,
|
||||
#[serde(default)]
|
||||
pub match_threshold: u16,
|
||||
#[serde(default)]
|
||||
pub best_match_threshold: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EpgConfigDto {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sources: Option<Vec<EpgSourceDto>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub smart_match: Option<EpgSmartMatchConfigDto>,
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
fn default_friendly_name() -> String { String::from("TuliproxTV") }
|
||||
fn default_manufacturer() -> String { String::from("Silicondust") }
|
||||
fn default_model_name() -> String { String::from("HDTC-2US") }
|
||||
fn default_firmware_name() -> String { String::from("hdhomeruntc_atsc") }
|
||||
fn default_firmware_version() -> String { String::from("20170930") }
|
||||
fn default_device_type() -> String { String::from("urn:schemas-upnp-org:device:MediaServer:1") }
|
||||
fn default_device_udn() -> String { String::from("uuid:12345678-90ab-cdef-1234-567890abcdef::urn:dial-multicast:com.silicondust.hdhomerun") }
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct HdHomeRunDeviceConfigDto {
|
||||
#[serde(default = "default_friendly_name")]
|
||||
pub friendly_name: String,
|
||||
#[serde(default = "default_manufacturer")]
|
||||
pub manufacturer: String,
|
||||
#[serde(default = "default_model_name")]
|
||||
pub model_name: String,
|
||||
#[serde(default = "default_model_name")]
|
||||
pub model_number: String,
|
||||
#[serde(default = "default_firmware_name")]
|
||||
pub firmware_name: String,
|
||||
#[serde(default = "default_firmware_version")]
|
||||
pub firmware_version: String,
|
||||
// pub device_auth: String,
|
||||
#[serde(default = "default_device_type")]
|
||||
pub device_type: String,
|
||||
#[serde(default = "default_device_udn")]
|
||||
pub device_udn: String,
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub port: u16,
|
||||
#[serde(default)]
|
||||
pub tuner_count: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct HdHomeRunConfigDto {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub auth: bool,
|
||||
pub devices: Vec<HdHomeRunDeviceConfigDto>,
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
use std::collections::HashMap;
|
||||
use enum_iterator::Sequence;
|
||||
use crate::model::{EpgConfigDto};
|
||||
use crate::utils::{default_as_true};
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence,
|
||||
PartialEq, Eq, Default)]
|
||||
pub enum InputType {
|
||||
#[serde(rename = "m3u")]
|
||||
#[default]
|
||||
M3u,
|
||||
#[serde(rename = "xtream")]
|
||||
Xtream,
|
||||
#[serde(rename = "m3u_batch")]
|
||||
M3uBatch,
|
||||
#[serde(rename = "xtream_batch")]
|
||||
XtreamBatch,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigInputOptionsDto {
|
||||
#[serde(default)]
|
||||
pub xtream_skip_live: bool,
|
||||
#[serde(default)]
|
||||
pub xtream_skip_vod: bool,
|
||||
#[serde(default)]
|
||||
pub xtream_skip_series: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub xtream_live_stream_use_prefix: bool,
|
||||
#[serde(default)]
|
||||
pub xtream_live_stream_without_extension: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigInputAliasDto {
|
||||
#[serde(skip)]
|
||||
pub id: u16,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub username: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub password: Option<String>,
|
||||
#[serde(default)]
|
||||
pub priority: i16,
|
||||
#[serde(default)]
|
||||
pub max_connections: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence,
|
||||
PartialEq, Eq, Default)]
|
||||
pub enum InputFetchMethod {
|
||||
#[default]
|
||||
GET,
|
||||
POST,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigInputDto {
|
||||
#[serde(skip)]
|
||||
pub id: u16,
|
||||
pub name: String,
|
||||
#[serde(default, rename = "type")]
|
||||
pub input_type: InputType,
|
||||
#[serde(default)]
|
||||
pub headers: HashMap<String, String>,
|
||||
pub url: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub epg: Option<EpgConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub username: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub password: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub persist: Option<String>,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub options: Option<ConfigInputOptionsDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub aliases: Option<Vec<ConfigInputAliasDto>>,
|
||||
#[serde(default)]
|
||||
pub priority: i16,
|
||||
#[serde(default)]
|
||||
pub max_connections: u16,
|
||||
#[serde(default)]
|
||||
pub method: InputFetchMethod,
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct IpCheckConfigDto {
|
||||
/// URL that may return both IPv4 and IPv6 in one response
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub url: Option<String>,
|
||||
|
||||
/// Dedicated URL to fetch only IPv4
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub url_ipv4: Option<String>,
|
||||
|
||||
/// Dedicated URL to fetch only IPv6
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub url_ipv6: Option<String>,
|
||||
|
||||
/// Optional regex pattern to extract IPv4
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub pattern_ipv4: Option<String>,
|
||||
|
||||
/// Optional regex pattern to extract IPv6
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub pattern_ipv6: Option<String>,
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use crate::utils::{default_as_true};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LogConfigDto {
|
||||
#[serde(default = "default_as_true")]
|
||||
pub sanitize_sensitive_info: bool,
|
||||
#[serde(default)]
|
||||
pub log_active_user: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub log_level: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
use crate::model::MsgKind;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TelegramMessagingConfigDto {
|
||||
pub bot_token: String,
|
||||
pub chat_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RestMessagingConfigDto {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PushoverMessagingConfigDto {
|
||||
pub url: Option<String>,
|
||||
pub token: String,
|
||||
pub user: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct MessagingConfigDto {
|
||||
#[serde(default)]
|
||||
pub notify_on: Vec<MsgKind>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub telegram: Option<TelegramMessagingConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub rest: Option<RestMessagingConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub pushover: Option<PushoverMessagingConfigDto>,
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
mod trakt;
|
||||
mod base;
|
||||
mod web;
|
||||
mod messaging;
|
||||
mod hdhomerun;
|
||||
mod ipcheck;
|
||||
mod source;
|
||||
mod target;
|
||||
mod sort;
|
||||
mod video;
|
||||
mod schedule;
|
||||
mod log;
|
||||
mod input;
|
||||
mod stream;
|
||||
mod epg;
|
||||
mod reverse_proxy;
|
||||
mod cache;
|
||||
mod rate_limit;
|
||||
mod proxy;
|
||||
|
||||
pub use base::*;
|
||||
pub use web::*;
|
||||
pub use messaging::*;
|
||||
pub use hdhomerun::*;
|
||||
pub use ipcheck::*;
|
||||
pub use source::*;
|
||||
pub use sort::*;
|
||||
pub use video::*;
|
||||
pub use schedule::*;
|
||||
pub use log::*;
|
||||
pub use input::*;
|
||||
pub use stream::*;
|
||||
pub use epg::*;
|
||||
pub use cache::*;
|
||||
pub use rate_limit::*;
|
||||
pub use reverse_proxy::*;
|
||||
pub use proxy::*;
|
||||
pub use trakt::*;
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ProxyConfigDto {
|
||||
pub url: String,
|
||||
pub username: Option<String>,
|
||||
pub password: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RateLimitConfigDto {
|
||||
pub enabled: bool,
|
||||
pub period_millis: u64,
|
||||
pub burst_size: u32,
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use crate::model::{CacheConfigDto, RateLimitConfigDto, StreamConfigDto};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ReverseProxyConfigDto {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub stream: Option<StreamConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cache: Option<CacheConfigDto>,
|
||||
#[serde(default)]
|
||||
pub resource_rewrite_disabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub rate_limit: Option<RateLimitConfigDto>,
|
||||
#[serde(default)]
|
||||
pub disable_referer_header: bool,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ScheduleConfigDto {
|
||||
#[serde(default)]
|
||||
pub schedule: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub targets: Option<Vec<String>>,
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
use crate::model::ItemField;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigSortGroupDto {
|
||||
pub order: SortOrder,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sequence: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SortOrder {
|
||||
#[serde(rename = "asc")]
|
||||
Asc,
|
||||
#[serde(rename = "desc")]
|
||||
Desc,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigSortChannelDto {
|
||||
// channel field
|
||||
pub field: ItemField,
|
||||
// match against group title
|
||||
pub group_pattern: String,
|
||||
pub order: SortOrder,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sequence: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigSortDto {
|
||||
#[serde(default)]
|
||||
pub match_as_ascii: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub groups: Option<ConfigSortGroupDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub channels: Option<Vec<ConfigSortChannelDto>>,
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
use crate::model::{ConfigInputDto, ItemField};
|
||||
use crate::model::config::target::ConfigTargetDto;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum TemplateValue {
|
||||
Single(String),
|
||||
Multi(Vec<String>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PatternTemplateDto {
|
||||
pub name: String,
|
||||
pub value: TemplateValue,
|
||||
#[serde(skip)]
|
||||
pub placeholder: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigRenameDto {
|
||||
pub field: ItemField,
|
||||
pub pattern: String,
|
||||
pub new_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigSourceDto {
|
||||
pub inputs: Vec<ConfigInputDto>,
|
||||
pub targets: Vec<ConfigTargetDto>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SourcesConfigDto {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub templates: Option<Vec<PatternTemplateDto>>,
|
||||
pub sources: Vec<ConfigSourceDto>,
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
use crate::utils::{default_grace_period_millis, default_grace_period_timeout_secs};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct StreamBufferConfigDto {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct StreamConfigDto {
|
||||
#[serde(default)]
|
||||
pub retry: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub buffer: Option<StreamBufferConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub throttle: Option<String>,
|
||||
#[serde(default = "default_grace_period_millis")]
|
||||
pub grace_period_millis: u64,
|
||||
#[serde(default = "default_grace_period_timeout_secs")]
|
||||
pub grace_period_timeout_secs: u64,
|
||||
#[serde(default)]
|
||||
pub forced_retry_interval_secs: u32,
|
||||
#[serde(default, skip)]
|
||||
pub throttle_kbps: u64,
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
use crate::model::{ClusterFlags, ConfigSortDto, ProcessingOrder, StrmExportStyle, TargetType, TraktConfigDto};
|
||||
use crate::model::config::source::ConfigRenameDto;
|
||||
use crate::utils::{default_as_true, default_resolve_delay_secs, default_as_default};
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigTargetOptionsDto {
|
||||
#[serde(default)]
|
||||
pub ignore_logo: bool,
|
||||
#[serde(default)]
|
||||
pub share_live_streams: bool,
|
||||
#[serde(default)]
|
||||
pub remove_duplicates: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub force_redirect: Option<ClusterFlags>,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct XtreamTargetOutputDto {
|
||||
#[serde(default = "default_as_true")]
|
||||
pub skip_live_direct_source: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub skip_video_direct_source: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub skip_series_direct_source: bool,
|
||||
#[serde(default)]
|
||||
pub resolve_series: bool,
|
||||
#[serde(default = "default_resolve_delay_secs")]
|
||||
pub resolve_series_delay: u16,
|
||||
#[serde(default)]
|
||||
pub resolve_vod: bool,
|
||||
#[serde(default = "default_resolve_delay_secs")]
|
||||
pub resolve_vod_delay: u16,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub trakt: Option<TraktConfigDto>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct M3uTargetOutputDto {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filename: Option<String>,
|
||||
#[serde(default)]
|
||||
pub include_type_in_url: bool,
|
||||
#[serde(default)]
|
||||
pub mask_redirect_url: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct StrmTargetOutputDto {
|
||||
pub directory: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub username: Option<String>,
|
||||
#[serde(default)]
|
||||
pub style: StrmExportStyle,
|
||||
#[serde(default)]
|
||||
pub flat: bool,
|
||||
#[serde(default)]
|
||||
pub underscore_whitespace: bool,
|
||||
#[serde(default)]
|
||||
pub cleanup: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub strm_props: Option<Vec<String>>,
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct HdHomeRunTargetOutputDto {
|
||||
pub device: String,
|
||||
pub username: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub use_output: Option<TargetType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields, tag = "type", rename_all = "lowercase")]
|
||||
pub enum TargetOutput {
|
||||
Xtream(XtreamTargetOutputDto),
|
||||
M3u(M3uTargetOutputDto),
|
||||
Strm(StrmTargetOutputDto),
|
||||
HdHomeRun(HdHomeRunTargetOutputDto),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigTargetDto {
|
||||
#[serde(skip)]
|
||||
pub id: u16,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_as_default")]
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub options: Option<ConfigTargetOptionsDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sort: Option<ConfigSortDto>,
|
||||
pub filter: String,
|
||||
#[serde(default)]
|
||||
pub output: Vec<TargetOutput>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rename: Option<Vec<ConfigRenameDto>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mapping: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub processing_order: ProcessingOrder,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub watch: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn default_fuzzy_threshold() -> u8 {
|
||||
80
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum TraktContentType {
|
||||
Vod,
|
||||
Series,
|
||||
Both,
|
||||
}
|
||||
|
||||
impl Default for TraktContentType {
|
||||
fn default() -> Self {
|
||||
Self::Both
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TraktApiConfigDto {
|
||||
#[serde(default)]
|
||||
pub(crate) key: String,
|
||||
#[serde(default)]
|
||||
pub(crate) version: String,
|
||||
#[serde(default)]
|
||||
pub(crate) url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TraktListConfigDto {
|
||||
pub user: String,
|
||||
pub list_slug: String,
|
||||
pub category_name: String,
|
||||
pub content_type: TraktContentType,
|
||||
#[serde(default = "default_fuzzy_threshold")]
|
||||
pub fuzzy_match_threshold: u8, // Percentage (0-100)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TraktConfigDto {
|
||||
#[serde(default)]
|
||||
pub api: TraktApiConfigDto,
|
||||
pub lists: Vec<TraktListConfigDto>,
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct VideoDownloadConfigDto {
|
||||
#[serde(default)]
|
||||
pub headers: HashMap<String, String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub directory: Option<String>,
|
||||
#[serde(default)]
|
||||
pub organize_into_directories: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub episode_pattern: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct VideoConfigDto {
|
||||
#[serde(default)]
|
||||
pub extensions: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub download: Option<VideoDownloadConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub web_search: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
use crate::utils::{default_as_true};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WebAuthConfigDto {
|
||||
#[serde(default = "default_as_true")]
|
||||
pub enabled: bool,
|
||||
pub issuer: String,
|
||||
pub secret: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub userfile: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WebUiConfigDto {
|
||||
#[serde(default = "default_as_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub user_ui_enabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub path: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub auth: Option<WebAuthConfigDto>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_server: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use enum_iterator::Sequence;
|
||||
use crate::create_tuliprox_error_result;
|
||||
use crate::error::{TuliproxError, TuliproxErrorKind};
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, Eq, PartialEq)]
|
||||
pub enum ItemField {
|
||||
#[serde(rename = "group")]
|
||||
Group,
|
||||
#[serde(rename = "name")]
|
||||
Name,
|
||||
#[serde(rename = "title")]
|
||||
Title,
|
||||
#[serde(rename = "url")]
|
||||
Url,
|
||||
#[serde(rename = "input")]
|
||||
Input,
|
||||
#[serde(rename = "type")]
|
||||
Type,
|
||||
#[serde(rename = "caption")]
|
||||
Caption,
|
||||
}
|
||||
|
||||
impl ItemField {
|
||||
const GROUP: &'static str = "Group";
|
||||
const NAME: &'static str = "Name";
|
||||
const TITLE: &'static str = "Title";
|
||||
const URL: &'static str = "Url";
|
||||
const INPUT: &'static str = "Input";
|
||||
const TYPE: &'static str = "Type";
|
||||
const CAPTION: &'static str = "Caption";
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Self::Group => Self::GROUP,
|
||||
Self::Name => Self::NAME,
|
||||
Self::Title => Self::TITLE,
|
||||
Self::Url => Self::URL,
|
||||
Self::Input => Self::INPUT,
|
||||
Self::Type => Self::TYPE,
|
||||
Self::Caption => Self::CAPTION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ItemField {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
Self::Group => Self::GROUP,
|
||||
Self::Name => Self::NAME,
|
||||
Self::Title => Self::TITLE,
|
||||
Self::Url => Self::URL,
|
||||
Self::Input => Self::INPUT,
|
||||
Self::Type => Self::TYPE,
|
||||
Self::Caption => Self::CAPTION,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ItemField {
|
||||
type Err = TuliproxError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, TuliproxError> {
|
||||
if s.eq_ignore_ascii_case(Self::GROUP) {
|
||||
Ok(Self::Group)
|
||||
} else if s.eq_ignore_ascii_case(Self::NAME) {
|
||||
Ok(Self::Name)
|
||||
} else if s.eq_ignore_ascii_case(Self::TITLE) {
|
||||
Ok(Self::Title)
|
||||
} else if s.eq_ignore_ascii_case(Self::CAPTION) {
|
||||
Ok(Self::Caption)
|
||||
} else if s.eq_ignore_ascii_case(Self::URL) {
|
||||
Ok(Self::Url)
|
||||
} else if s.eq_ignore_ascii_case(Self::INPUT) {
|
||||
Ok(Self::Input)
|
||||
} else if s.eq_ignore_ascii_case(Self::TYPE) {
|
||||
Ok(Self::Type)
|
||||
} else {
|
||||
create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown InputType: {}", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
pub enum MsgKind {
|
||||
#[serde(rename = "info")]
|
||||
Info,
|
||||
#[serde(rename = "stats")]
|
||||
Stats,
|
||||
#[serde(rename = "error")]
|
||||
Error,
|
||||
#[serde(rename = "watch")]
|
||||
Watch,
|
||||
}
|
||||
+13
-1
@@ -1,5 +1,17 @@
|
||||
mod cluster_flags;
|
||||
mod playlist;
|
||||
mod messaging;
|
||||
mod item_field;
|
||||
mod target_type;
|
||||
mod processing_order;
|
||||
mod config;
|
||||
mod strm_export_style;
|
||||
|
||||
pub use self::cluster_flags::*;
|
||||
pub use self::playlist::*;
|
||||
pub use self::playlist::*;
|
||||
pub use self::messaging::*;
|
||||
pub use self::item_field::*;
|
||||
pub use self::target_type::*;
|
||||
pub use self::processing_order::*;
|
||||
pub use self::config::*;
|
||||
pub use self::strm_export_style::*;
|
||||
@@ -0,0 +1,15 @@
|
||||
use enum_iterator::Sequence;
|
||||
|
||||
#[derive( Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence,
|
||||
PartialEq, Eq, Hash, Default)]
|
||||
pub enum StrmExportStyle {
|
||||
#[serde(rename = "kodi")]
|
||||
#[default]
|
||||
Kodi,
|
||||
#[serde(rename = "plex")]
|
||||
Plex,
|
||||
#[serde(rename = "emby")]
|
||||
Emby,
|
||||
#[serde(rename = "jellyfin")]
|
||||
Jellyfin,
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use std::fmt::Display;
|
||||
use enum_iterator::Sequence;
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Sequence, PartialEq, Eq, Hash)]
|
||||
pub enum TargetType {
|
||||
#[serde(rename = "m3u")]
|
||||
M3u,
|
||||
#[serde(rename = "xtream")]
|
||||
Xtream,
|
||||
#[serde(rename = "strm")]
|
||||
Strm,
|
||||
#[serde(rename = "hdhomerun")]
|
||||
HdHomeRun,
|
||||
}
|
||||
|
||||
impl TargetType {
|
||||
const M3U: &'static str = "M3u";
|
||||
const XTREAM: &'static str = "Xtream";
|
||||
const STRM: &'static str = "Strm";
|
||||
const HDHOMERUN: &'static str = "HdHomeRun";
|
||||
}
|
||||
|
||||
impl Display for TargetType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
Self::M3u => Self::M3U,
|
||||
Self::Xtream => Self::XTREAM,
|
||||
Self::Strm => Self::STRM,
|
||||
Self::HdHomeRun => Self::HDHOMERUN,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user