2025-04-17 12:11:51 +02:00
use regex ::Regex ;
2026-02-14 12:12:59 +01:00
use std ::{
collections ::HashSet ,
string ::ToString ,
sync ::{ atomic ::AtomicBool , Arc , LazyLock },
};
2025-04-17 12:11:51 +02:00
2026-02-23 11:46:21 +01:00
pub const DEFAULT_HOME_ENV_VAR : & str = "TULIPROX_HOME" ;
pub const DEFAULT_WEB_ROOT_ENV_VAR : & str = "TULIPROX_WEB_ROOT" ;
2026-03-06 17:29:42 +01:00
pub const DEFAULT_USER_AGENT : & str = "VLC/3.0.16 LibVLC/3.0.16" ;
pub const DEFAULT_BACKUP_DIR : & str = "backup" ;
pub const DEFAULT_CACHE_DIR : & str = "cache" ;
pub const DEFAULT_STORAGE_TEMP_DIR : & str = "tmp" ;
pub const DEFAULT_USER_CONFIG_DIR : & str = "user_config" ;
pub const DEFAULT_DOWNLOAD_DIR : & str = "downloads" ;
pub const DEFAULT_CUSTOM_STREAM_RESPONSE_PATH : & str = "resources" ;
pub const DNS_RESOLVED_FILE : & str = "provider_dns_resolved.json" ;
2025-04-17 12:11:51 +02:00
pub const USER_FILE : & str = "user.txt" ;
pub const CONFIG_PATH : & str = "config" ;
pub const CONFIG_FILE : & str = "config.yml" ;
pub const SOURCE_FILE : & str = "source.yml" ;
pub const MAPPING_FILE : & str = "mapping.yml" ;
2026-02-23 17:00:11 +01:00
pub const TEMPLATE_FILE : & str = "template.yml" ;
2025-04-17 12:11:51 +02:00
pub const API_PROXY_FILE : & str = "api-proxy.yml" ;
2026-02-23 11:46:21 +01:00
pub const DEFAULT_WEB_DIR : & str = "web" ;
2026-03-06 17:29:42 +01:00
pub const DEFAULT_STORAGE_DIR : & str = "data" ; // TODO rename to storage and use data for config, storage, ...
2026-02-23 11:46:21 +01:00
pub const DEFAULT_PORT : u16 = 8901 ;
2025-04-17 12:11:51 +02:00
pub const ENCODING_GZIP : & str = "gzip" ;
pub const ENCODING_DEFLATE : & str = "deflate" ;
pub const HLS_EXT : & str = ".m3u8" ;
pub const DASH_EXT : & str = ".mpd" ;
2025-04-17 15:11:28 +02:00
pub const HLS_PREFIX : & str = "hls" ;
2025-10-16 11:58:40 +02:00
pub const CUSTOM_VIDEO_PREFIX : & str = "cvs" ;
2025-04-17 15:11:28 +02:00
2025-04-17 12:11:51 +02:00
pub const HLS_EXT_QUERY : & str = ".m3u8?" ;
pub const HLS_EXT_FRAGMENT : & str = ".m3u8#" ;
pub const DASH_EXT_QUERY : & str = ".mpd?" ;
pub const DASH_EXT_FRAGMENT : & str = ".mpd#" ;
2026-03-06 17:29:42 +01:00
pub const DEFAULT_EPISODE_PATTERN : & str = r ".*(?P<episode>[Ss]\d{1,2}(.*?)[Ee]\d{1,2}).*" ;
2025-04-17 12:11:51 +02:00
pub const FILENAME_TRIM_PATTERNS : & [ char ] = & [ '.' , '-' , '_' ];
2025-05-09 17:13:37 +02:00
const SUPPORTED_RESPONSE_HEADERS : & [ & str ] = & [
2025-05-09 18:18:59 +02:00
//"accept",
2025-05-09 17:13:37 +02:00
"accept-ranges" ,
"content-type" ,
"content-length" ,
"content-range" ,
"vary" ,
"transfer-encoding" ,
2025-05-09 22:25:44 +02:00
//"connection",
2025-05-09 17:13:37 +02:00
"access-control-allow-origin" ,
"access-control-allow-credentials" ,
"icy-metadata" ,
2026-01-04 10:54:41 +01:00
"icy-metaint" ,
2025-05-09 17:13:37 +02:00
"referer" ,
"last-modified" ,
"cache-control" ,
"etag" ,
2026-02-14 12:12:59 +01:00
"expires" ,
2025-05-09 17:13:37 +02:00
];
2026-02-14 12:12:59 +01:00
pub fn filter_response_header ( key : & str ) -> bool { SUPPORTED_RESPONSE_HEADERS . contains ( & key ) }
2025-05-09 17:13:37 +02:00
pub fn filter_request_header ( key : & str ) -> bool {
2025-05-09 22:25:44 +02:00
if key == "host" || key == "connection" {
2025-05-09 17:13:37 +02:00
return false ;
}
true
}
2025-04-17 12:11:51 +02:00
2025-06-12 17:34:15 +02:00
/// Configuration for media export naming styles (Kodi, Plex, Emby, Jellyfin)
pub struct ExportStyleConfig {
2025-04-17 12:11:51 +02:00
pub year : Regex ,
pub season : Regex ,
pub episode : Regex ,
pub whitespace : Regex ,
pub alphanumeric : Regex ,
2025-09-20 15:32:14 +02:00
pub paaren : Regex ,
2025-04-17 12:11:51 +02:00
}
pub struct Constants {
2025-05-19 15:47:00 +02:00
pub re_credentials : Regex ,
pub re_ipv4 : Regex ,
pub re_ipv6 : Regex ,
2025-04-17 15:11:28 +02:00
pub re_stream_url : Regex ,
pub re_url : Regex ,
2025-07-28 14:46:13 +02:00
pub re_password : Regex ,
2025-08-12 16:27:15 +02:00
pub re_base_href_tag : Regex ,
2025-04-17 15:11:28 +02:00
pub re_base_href : Regex ,
2025-08-12 16:27:15 +02:00
pub re_base_href_wasm : Regex ,
2025-04-17 15:11:28 +02:00
pub re_env_var : Regex ,
pub re_memory_usage : Regex ,
2026-01-13 16:37:27 +01:00
pub re_epg_normalize : Arc < Regex > ,
2025-04-17 15:11:28 +02:00
pub re_template_var : Regex ,
pub re_template_tag : Regex ,
pub re_template_attribute : Regex ,
pub re_filename : Regex ,
pub re_remove_filename_ending : Regex ,
pub re_whitespace : Regex ,
pub re_hls_uri : Regex ,
2025-04-17 12:11:51 +02:00
pub sanitize : AtomicBool ,
2025-06-12 17:34:15 +02:00
pub export_style_config : ExportStyleConfig ,
2025-04-17 12:11:51 +02:00
pub country_codes : HashSet <& 'static str > ,
2025-04-17 20:09:29 +02:00
pub allowed_output_formats : Vec < String > ,
2025-12-10 12:04:27 +01:00
pub re_trakt_year : Regex ,
pub re_quality : Regex ,
2025-12-10 09:18:49 +01:00
pub re_classifier_year : Regex ,
pub re_classifier_cleanup : Regex ,
pub re_classifier_episode : Regex ,
pub re_classifier_season : Regex ,
2025-12-15 17:54:19 +01:00
pub re_classifier_moviedb_id : Regex ,
pub re_classifier_camel_case : Regex ,
pub re_classifier_brackets_info : Regex ,
2026-02-12 15:06:57 +01:00
pub re_clean_title : Regex ,
pub re_html_tag : Regex ,
2025-04-17 12:11:51 +02:00
}
2026-02-14 12:12:59 +01:00
pub static CONSTANTS : LazyLock < Constants > = LazyLock ::new ( || {
2025-04-17 12:11:51 +02:00
Constants {
2026-02-12 15:06:57 +01:00
re_credentials : Regex ::new ( r "((username|password|token|api_key)=)[^&]*" ). unwrap (),
2025-05-19 15:47:00 +02:00
re_ipv4 : Regex ::new ( r "\b((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\b" ). unwrap (),
2025-05-19 15:50:51 +02:00
re_ipv6 : Regex ::new ( r "\b([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\b|\b([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b|\b::ffff:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b" ). unwrap (),
2025-04-23 20:51:58 +02:00
re_stream_url : Regex ::new ( r "(?i)^(?P<scheme>https?://)[^/]+/(?P<ctx>live|video|movie|series|m3u-stream|resource)/[^/]+/[^/]+/" ). unwrap (),
2025-04-17 15:11:28 +02:00
re_url : Regex ::new ( r "(.*://).*?/(.*)" ). unwrap (),
2025-07-28 14:46:13 +02:00
re_password : Regex ::new ( r "password:\s*(\w+)" ). unwrap (),
2025-08-12 16:27:15 +02:00
re_base_href_tag : Regex ::new ( r "(?is)<base\b[^>]*>" ). unwrap (),
2025-04-17 15:11:28 +02:00
re_base_href : Regex ::new ( r #"(href|src)="/([^"]*)""# ). unwrap (),
2025-08-12 16:27:15 +02:00
re_base_href_wasm : Regex ::new ( "'(/frontend \\ -)" ). unwrap (),
2025-04-17 15:11:28 +02:00
re_env_var : Regex ::new ( r "\$\{env:(?P<var>[a-zA-Z_][a-zA-Z0-9_]*)}" ). unwrap (),
re_memory_usage : Regex ::new ( r "VmRSS:\s+(\d+) kB" ). unwrap (),
2026-01-13 16:37:27 +01:00
re_epg_normalize : Arc ::new ( Regex ::new ( r "[^a-zA-Z0-9\-]" ). unwrap ()),
2025-04-17 15:11:28 +02:00
re_template_var : Regex ::new ( "!(.*?)!" ). unwrap (),
re_template_tag : Regex ::new ( "<tag:(.*?)>" ). unwrap (),
re_template_attribute : Regex ::new ( "<(.*?)>" ). unwrap (),
re_filename : Regex ::new ( r "[^A-Za-z0-9_.-]" ). unwrap (),
re_remove_filename_ending : Regex ::new ( r "[_.\s-]$" ). unwrap (),
re_whitespace : Regex ::new ( r "\s+" ). unwrap (),
2026-01-20 10:09:58 +01:00
re_hls_uri : Regex ::new ( r #"URI=["']([^"']+)["']"# ). unwrap (),
2025-04-17 15:02:35 +02:00
2025-04-17 12:11:51 +02:00
sanitize : AtomicBool ::new ( true ),
2025-06-12 17:34:15 +02:00
export_style_config : ExportStyleConfig {
2025-04-17 12:11:51 +02:00
season : Regex ::new ( r "[Ss]\d{1,2}" ). unwrap (),
episode : Regex ::new ( r "[Ee]\d{1,2}" ). unwrap (),
2025-06-12 17:34:15 +02:00
year : Regex ::new ( r "(\d{4})" ). unwrap (),
2025-04-17 12:11:51 +02:00
whitespace : Regex ::new ( r "\s+" ). unwrap (),
alphanumeric : Regex ::new ( r "[^\w\s]" ). unwrap (),
2025-09-20 15:32:14 +02:00
paaren : Regex ::new ( r "(\(\)|\[\]|\{\})" ). unwrap (),
2025-04-17 12:11:51 +02:00
},
2025-04-17 20:09:29 +02:00
allowed_output_formats : Vec ::from ([ "m3u8" . to_string (), "ts" . to_string ()]),
2025-04-17 12:11:51 +02:00
country_codes : vec ! [
"af" , "al" , "dz" , "ad" , "ao" , "ag" , "ar" , "am" , "au" , "at" , "az" , "bs" , "bh" , "bd" , "bb" , "by" ,
2026-01-04 16:17:47 +01:00
"be" , "bz" , "bj" , "bt" , "bo" , "ba" , "bw" , "br" , "bn" , "bg" , "bf" , "bi" , "bu" , "cv" , "kh" , "cm" ,
"ca" , "cf" , "td" , "cl" , "cn" , "co" , "km" , "cg" , "cr" , "hr" , "cu" , "cy" , "cz" , "cd" , "dk" , "dj" ,
"dm" , "do" , "tl" , "ec" , "eg" , "sv" , "gq" , "er" , "ee" , "sz" , "et" , "fj" , "fi" , "fr" , "ga" , "gm" ,
"ge" , "de" , "gh" , "gr" , "gd" , "gt" , "gn" , "gw" , "gy" , "ht" , "hn" , "hu" , "is" , "in" , "id" , "ir" ,
"iq" , "ie" , "il" , "it" , "ci" , "jm" , "jp" , "jo" , "kz" , "ke" , "ki" , "kp" , "kr" , "kw" , "kg" , "la" ,
"lv" , "lb" , "ls" , "lr" , "ly" , "li" , "lt" , "lu" , "mg" , "mw" , "my" , "mv" , "ml" , "mt" , "mh" , "mr" ,
"mu" , "mx" , "fm" , "md" , "mc" , "mn" , "me" , "ma" , "mz" , "mm" , "na" , "nr" , "np" , "nl" , "nz" , "ni" ,
"ne" , "ng" , "mk" , "no" , "om" , "pk" , "pw" , "pa" , "pg" , "py" , "pe" , "ph" , "pl" , "pt" , "qa" , "ro" ,
"ru" , "rw" , "kn" , "lc" , "vc" , "ws" , "sm" , "st" , "sa" , "sn" , "rs" , "sc" , "sl" , "sg" , "sk" , "si" ,
"sb" , "so" , "za" , "ss" , "es" , "lk" , "sd" , "sr" , "se" , "ch" , "sy" , "tw" , "tj" , "tz" , "th" , "tg" ,
"to" , "tt" , "tn" , "tr" , "tm" , "tv" , "ug" , "ua" , "ae" , "gb" , "us" , "uy" , "uz" , "vu" , "va" , "ve" ,
"vn" , "ye" , "zm" , "zw" , "sat" , "4k" ,
2025-04-17 12:11:51 +02:00
]. into_iter (). collect ::< HashSet <& str >> (),
2025-06-16 17:53:03 +02:00
re_trakt_year : Regex ::new ( r "\(?(\d{4})\)?$" ). unwrap (),
2025-12-20 15:14:03 +01:00
re_quality : Regex ::new ( r "(?i)\b(x265|4K|UHD|8K|2160p?|1080p?|720p?|480p?|BLURAY|HDTV|DVDRIP|BRRIP|CAM|TS|HDR|DV|SDR)\b" ). unwrap (),
2025-12-19 16:41:12 +01:00
re_classifier_year : Regex ::new ( r "[\(\[]?(\d{4})[\)\]]?" ). unwrap (),
2025-12-10 09:18:49 +01:00
re_classifier_cleanup : Regex ::new ( r "(?i)[\s\._-]*(?:s\d+e\d+|\d+x\d+|season[\s\._-]*\d+|episode[\s\._-]*\d+).*$" ). unwrap (),
re_classifier_episode : Regex ::new ( r "(?i)(?:e|episode|x)[\s\._-]*(\d+)" ). unwrap (),
re_classifier_season : Regex ::new ( r "(?i)(?:s|season)[\s\._-]*(\d+)" ). unwrap (),
2025-12-15 17:54:19 +01:00
re_classifier_moviedb_id : Regex ::new ( r "(?i)\b(tmdb|tvdb|imdb)[\s._=-]?(\d+)\b" ). unwrap (),
re_classifier_camel_case : Regex ::new ( r "([a-z])([A-Z])" ). unwrap (),
2025-12-19 16:41:12 +01:00
re_classifier_brackets_info : Regex ::new ( r "[\[\{\(].*?[\]\}\)]" ). unwrap (),
2026-02-12 15:06:57 +01:00
re_clean_title : Regex ::new ( r "^(?:\s*[\[\(┃|].*?[\]\)┃|]\s*)+" ). unwrap (), // Matches patterns like "┃DE┃", "[US]", "(FR)", "|EN|" at the start of the string
re_html_tag : Regex ::new ( r "</?([a-zA-Z0-9]+)[^>]*>" ). unwrap ()
2025-04-17 12:11:51 +02:00
}
2026-02-14 12:12:59 +01:00
});