use std::time::Duration;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct PodloveChapters {
pub version: String,
pub chapters: Vec<PodloveChapter>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PodloveChapter {
pub start: Duration,
pub title: String,
pub href: Option<String>,
pub image: Option<String>,
}
#[must_use]
pub(crate) fn parse_start(s: &str) -> Duration {
let s = s.trim();
if s.is_empty() {
return Duration::ZERO;
}
let mut parts = s.split(':').rev();
let Some(secs_str) = parts.next() else {
return Duration::ZERO;
};
let secs: f64 = match secs_str.parse::<f64>() {
Ok(v) if v >= 0.0 && v.is_finite() => v,
_ => return Duration::ZERO,
};
let mut total = secs;
if let Some(min_str) = parts.next() {
let Ok(mins) = min_str.parse::<u64>() else {
return Duration::ZERO;
};
total += (mins * 60) as f64;
}
if let Some(hr_str) = parts.next() {
let Ok(hours) = hr_str.parse::<u64>() else {
return Duration::ZERO;
};
total += (hours * 3600) as f64;
}
if parts.next().is_some() {
return Duration::ZERO;
}
Duration::try_from_secs_f64(total).unwrap_or(Duration::ZERO)
}
#[must_use]
pub(crate) fn format_start(d: Duration) -> String {
let total_secs = d.as_secs_f64();
let hours = (total_secs as u64) / 3600;
let rem = total_secs - (hours.saturating_mul(3600) as f64);
let mins = (rem as u64) / 60;
let secs = rem - (mins.saturating_mul(60) as f64);
format!("{hours:02}:{mins:02}:{secs:06.3}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn start_parse_round_trips() {
for &(s, want_secs) in &[
("12.345", 12.345_f64),
("01:23", 83.0),
("01:23.5", 83.5),
("00:01:23.456", 83.456),
("02:03:04.000", 7384.0),
] {
let d = parse_start(s);
let got = d.as_secs_f64();
assert!(
(got - want_secs).abs() < 1e-6,
"{s:?} → {got} (want {want_secs})",
);
}
}
#[test]
fn start_parse_rejects_garbage() {
for s in ["", "abc", "1:2:3:4", "-5", "inf", "nan"] {
assert_eq!(parse_start(s), Duration::ZERO, "{s:?}");
}
}
#[test]
fn start_format_shape() {
assert_eq!(format_start(Duration::ZERO), "00:00:00.000");
assert_eq!(
format_start(Duration::from_secs_f64(83.456)),
"00:01:23.456",
);
assert_eq!(
format_start(Duration::from_secs_f64(7384.0)),
"02:03:04.000",
);
}
}