Propagate auto-track intent to new seasons (#76)
This commit was merged in pull request #76.
This commit is contained in:
@@ -68,12 +68,16 @@ mod tests {
|
||||
.json()
|
||||
.await
|
||||
.expect("json");
|
||||
assert_eq!(roots.len(), 2, "the two seeded movie roots: {roots:?}");
|
||||
assert_eq!(roots.len(), 4, "the seeded movie and TV roots: {roots:?}");
|
||||
assert_eq!(roots[0]["audience"], "main");
|
||||
assert_eq!(roots[0]["policy_name"], "Movies — main");
|
||||
assert_eq!(roots[1]["audience"], "kids");
|
||||
assert!(roots[1]["path"]
|
||||
.as_str()
|
||||
.is_some_and(|p| p.contains("kids")));
|
||||
assert_eq!(roots[2]["kind"], "tv");
|
||||
assert_eq!(roots[2]["policy_name"], "TV — main");
|
||||
assert_eq!(roots[3]["kind"], "tv");
|
||||
assert_eq!(roots[3]["policy_name"], "TV — kids");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,7 +806,7 @@ mod tests {
|
||||
let classified = classify(
|
||||
release,
|
||||
&policy,
|
||||
&MovieOverrides::default(),
|
||||
&TitleOverrides::default(),
|
||||
&Language::Other("en".into()),
|
||||
)
|
||||
.expect("classified release");
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::{collections::BTreeMap, path::PathBuf, time::SystemTime};
|
||||
pub mod lang;
|
||||
pub mod policy;
|
||||
pub mod score;
|
||||
pub mod tracking;
|
||||
|
||||
pub use arr_parse::NameClaims as ParsedRelease;
|
||||
pub use score::{Score, ScoreWeights};
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
use crate::{Episode, Season, Series};
|
||||
|
||||
/// A season returned by metadata refresh, classified against persisted seasons.
|
||||
#[derive(Debug)]
|
||||
pub struct RefreshedSeason {
|
||||
pub season: Season,
|
||||
pub episodes: Vec<Episode>,
|
||||
pub is_new: bool,
|
||||
}
|
||||
|
||||
/// Applies a series' tracking rule to newly revealed seasons.
|
||||
///
|
||||
/// Existing seasons keep their tracking rule and leaf-level intent unchanged.
|
||||
/// Season zero is treated like every other newly revealed season.
|
||||
pub fn apply_auto_track(series: &Series, seasons: &mut [RefreshedSeason]) {
|
||||
if !series.auto_track {
|
||||
return;
|
||||
}
|
||||
|
||||
for refreshed in seasons.iter_mut().filter(|season| season.is_new) {
|
||||
refreshed.season.tracked = true;
|
||||
for episode in &mut refreshed.episodes {
|
||||
episode.wanted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::SystemTime;
|
||||
|
||||
use super::{apply_auto_track, RefreshedSeason};
|
||||
use crate::{
|
||||
Episode, EpisodeId, Language, MediaState, RootId, Season, SeasonId, Series, SeriesId,
|
||||
TitleOverrides,
|
||||
};
|
||||
|
||||
fn series(auto_track: bool) -> Series {
|
||||
Series {
|
||||
id: SeriesId(1),
|
||||
tmdb_id: 82_728,
|
||||
title: "Bluey".into(),
|
||||
year: 2018,
|
||||
original_language: Language::Other("en".into()),
|
||||
root_id: RootId(1),
|
||||
auto_track,
|
||||
overrides: TitleOverrides::default(),
|
||||
upstream_ended: false,
|
||||
blocked: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn episode(season: i64, number: u16, wanted: bool) -> Episode {
|
||||
Episode {
|
||||
id: EpisodeId(season * 100 + i64::from(number)),
|
||||
season_id: SeasonId(season),
|
||||
number,
|
||||
title: format!("Episode {number}"),
|
||||
air_date: Some(SystemTime::UNIX_EPOCH),
|
||||
wanted,
|
||||
state: MediaState::Missing,
|
||||
search_attempts: 0,
|
||||
last_searched_at: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn refreshed_season(number: u16, is_new: bool, wanted: &[bool]) -> RefreshedSeason {
|
||||
let id = i64::from(number);
|
||||
RefreshedSeason {
|
||||
season: Season {
|
||||
id: SeasonId(id),
|
||||
series_id: SeriesId(1),
|
||||
number,
|
||||
tracked: false,
|
||||
},
|
||||
episodes: wanted
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, wanted)| {
|
||||
episode(
|
||||
id,
|
||||
u16::try_from(index + 1).expect("episode number fits"),
|
||||
*wanted,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
is_new,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_track_marks_only_new_seasons_and_their_episodes() {
|
||||
let mut refresh = [
|
||||
refreshed_season(2, false, &[false, false]),
|
||||
refreshed_season(3, true, &[false, false]),
|
||||
];
|
||||
|
||||
apply_auto_track(&series(true), &mut refresh);
|
||||
|
||||
assert!(!refresh[0].season.tracked);
|
||||
assert!(refresh[0].episodes.iter().all(|episode| !episode.wanted));
|
||||
assert!(refresh[1].season.tracked);
|
||||
assert!(refresh[1].episodes.iter().all(|episode| episode.wanted));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn untracked_series_keeps_manual_leaf_intent_only() {
|
||||
let mut refresh = [
|
||||
refreshed_season(2, false, &[true, true, true]),
|
||||
refreshed_season(3, true, &[false, false]),
|
||||
];
|
||||
|
||||
apply_auto_track(&series(false), &mut refresh);
|
||||
|
||||
assert!(refresh[0].episodes.iter().all(|episode| episode.wanted));
|
||||
assert!(!refresh[0].season.tracked);
|
||||
assert!(refresh[1].episodes.iter().all(|episode| !episode.wanted));
|
||||
assert!(!refresh[1].season.tracked);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn season_zero_follows_the_same_rule() {
|
||||
let mut refresh = [refreshed_season(0, true, &[false])];
|
||||
|
||||
apply_auto_track(&series(true), &mut refresh);
|
||||
|
||||
assert!(refresh[0].season.tracked);
|
||||
assert!(refresh[0].episodes[0].wanted);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user