pub mod error;
pub mod mode;
pub mod provider;
pub mod template;
pub use error::CatchupError;
pub use mode::{CatchupConfig, CatchupMode, IGNORE_CATCHUP_DAYS, configure_catchup};
pub use template::{
format_catchup_url, format_catchup_url_with_granularity, format_now_only,
is_within_catchup_window,
};
use chrono::Utc;
pub fn process_programme_for_timeshift(
config: &CatchupConfig,
programme_start: i64,
programme_end: i64,
programme_catchup_id: Option<&str>,
timezone_shift_secs: i32,
) -> String {
let mut duration = programme_end - programme_start;
let now = Utc::now().timestamp();
if programme_start + duration > now {
duration = now - programme_start;
}
if duration < 0 {
duration = 0;
}
format_catchup_url_with_granularity(
&config.source,
programme_start,
duration,
programme_catchup_id,
timezone_shift_secs,
config.granularity_seconds,
)
}
pub fn process_programme_for_vod(config: &CatchupConfig, programme_catchup_id: &str) -> String {
let now = Utc::now().timestamp();
format_catchup_url_with_granularity(
&config.source,
now,
0,
Some(programme_catchup_id),
0,
config.granularity_seconds,
)
}
pub fn process_channel_for_live(config: &CatchupConfig) -> String {
format_now_only(&config.source, 0, 0, 0)
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeZone;
fn fixed_start() -> i64 {
Utc.with_ymd_and_hms(2024, 3, 15, 14, 30, 45)
.unwrap()
.timestamp()
}
fn make_config(source: &str, granularity: i32) -> CatchupConfig {
CatchupConfig {
mode: CatchupMode::Default,
source: source.to_string(),
catchup_days: 7,
supports_timeshifting: true,
terminates: true,
granularity_seconds: granularity,
is_ts_stream: false,
}
}
#[test]
fn process_programme_for_timeshift_produces_correct_url() {
let start = fixed_start();
let end = start + 3600;
let config = make_config(
"http://example.com/catchup?start={utc}&end={utcend}&id={catchup-id}",
1,
);
let result = process_programme_for_timeshift(&config, start, end, Some("prog_123"), 0);
assert!(result.contains(&format!("start={start}")));
assert!(result.contains("id=prog_123"));
assert!(!result.contains("{utc}"));
assert!(!result.contains("{utcend}"));
assert!(!result.contains("{catchup-id}"));
}
#[test]
fn process_programme_for_vod_substitutes_catchup_id() {
let config = make_config("http://example.com/vod/{catchup-id}", 1);
let result = process_programme_for_vod(&config, "movie_456");
assert_eq!(result, "http://example.com/vod/movie_456");
}
#[test]
fn process_channel_for_live_uses_current_time() {
let config = make_config("http://example.com/live?now=${now}", 1);
let before = Utc::now().timestamp();
let result = process_channel_for_live(&config);
let after = Utc::now().timestamp();
let now_str = result.split("now=").nth(1).unwrap();
let now_val: i64 = now_str.parse().expect("should be a timestamp");
assert!(now_val >= before && now_val <= after);
}
}