1use std::time::{SystemTime, UNIX_EPOCH};
7
8use tokio::task::JoinHandle;
9
10use crate::error::Result;
11
12pub mod fs;
13pub mod http;
14pub mod network;
15pub mod platform;
16pub mod subtitle;
17pub mod validation;
18
19pub use fs::*;
22pub use network::{retry, url_expiry};
23pub use platform::Platform;
24pub use subtitle::subtitle_converter::convert_subtitle;
25pub use subtitle::subtitle_validator::{ValidationResult, is_format_compatible, validate_subtitle};
26pub use url_expiry::{ExpiryConfig, UrlStatus, check_download_error, should_refresh_url};
27
28pub fn to_owned(vec: Vec<impl AsRef<str>>) -> Vec<String> {
38 vec.into_iter().map(|s| s.as_ref().to_owned()).collect()
39}
40
41pub fn find_executable(name: impl AsRef<str>) -> String {
51 let platform = Platform::detect();
52 let name_str = name.as_ref();
53
54 match platform {
55 Platform::Windows => format!("{}.exe", name_str),
56 _ => name_str.to_string(),
57 }
58}
59
60pub async fn await_two<T: std::fmt::Debug>(
68 first: JoinHandle<Result<T>>,
69 second: JoinHandle<Result<T>>,
70) -> Result<(T, T)> {
71 tracing::debug!("⚙️ Awaiting two futures");
72
73 let (first_result, second_result) = tokio::try_join!(first, second)?;
74
75 let first = first_result?;
76 let second = second_result?;
77
78 tracing::debug!("✅ Both futures completed successfully");
79
80 Ok((first, second))
81}
82
83pub async fn await_all<T, I>(handles: I) -> Result<Vec<T>>
98where
99 I: IntoIterator<Item = JoinHandle<Result<T>>> + std::fmt::Debug,
100 T: Send + 'static,
101{
102 tracing::debug!("⚙️ Awaiting multiple futures");
103
104 let results = futures_util::future::try_join_all(handles).await?;
105
106 let result_vec: Result<Vec<T>> = results.into_iter().collect();
107
108 if let Ok(ref vec) = result_vec {
109 tracing::debug!(completed_count = vec.len(), "✅ All futures completed successfully");
110 }
111
112 result_vec
113}
114
115pub fn current_timestamp() -> i64 {
121 SystemTime::now()
122 .duration_since(UNIX_EPOCH)
123 .unwrap_or_default()
124 .as_secs() as i64
125}
126
127pub fn is_expired(cached_at: i64, ttl: u64) -> bool {
138 let now = current_timestamp();
139 (now - cached_at) > ttl as i64
140}