Merge pull request #257 from crunchy-labs/feature/relative_sequence_number

Add flags and option to control special episode behavior (#206, #241, #246)
This commit is contained in:
ByteDream 2023-11-06 20:58:55 +00:00 committed by GitHub
commit 4d01e2a4ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 267 additions and 107 deletions

View file

@ -29,8 +29,9 @@ pub struct SingleFormat {
pub episode_id: String,
pub episode_number: String,
pub sequence_number: f32,
pub relative_episode_number: Option<u32>,
pub sequence_number: f32,
pub relative_sequence_number: Option<f32>,
pub duration: Duration,
@ -42,6 +43,7 @@ impl SingleFormat {
episode: Episode,
subtitles: Vec<Locale>,
relative_episode_number: Option<u32>,
relative_sequence_number: Option<f32>,
) -> Self {
Self {
identifier: if episode.identifier.is_empty() {
@ -73,6 +75,7 @@ impl SingleFormat {
},
sequence_number: episode.sequence_number,
relative_episode_number,
relative_sequence_number,
duration: episode.duration,
source: episode.into(),
}
@ -92,8 +95,9 @@ impl SingleFormat {
season_number: 1,
episode_id: movie.id.clone(),
episode_number: "1".to_string(),
sequence_number: 1.0,
relative_episode_number: Some(1),
sequence_number: 1.0,
relative_sequence_number: Some(1.0),
duration: movie.duration,
source: movie.into(),
}
@ -113,8 +117,9 @@ impl SingleFormat {
season_number: 1,
episode_id: music_video.id.clone(),
episode_number: "1".to_string(),
sequence_number: 1.0,
relative_episode_number: Some(1),
sequence_number: 1.0,
relative_sequence_number: Some(1.0),
duration: music_video.duration,
source: music_video.into(),
}
@ -134,8 +139,9 @@ impl SingleFormat {
season_number: 1,
episode_id: concert.id.clone(),
episode_number: "1".to_string(),
sequence_number: 1.0,
relative_episode_number: Some(1),
sequence_number: 1.0,
relative_sequence_number: Some(1.0),
duration: concert.duration,
source: concert.into(),
}
@ -328,8 +334,9 @@ pub struct Format {
pub episode_id: String,
pub episode_number: String,
pub sequence_number: f32,
pub relative_episode_number: Option<u32>,
pub sequence_number: f32,
pub relative_sequence_number: Option<f32>,
}
impl Format {
@ -363,8 +370,9 @@ impl Format {
season_number: first_format.season_number,
episode_id: first_format.episode_id,
episode_number: first_format.episode_number,
sequence_number: first_format.sequence_number,
relative_episode_number: first_format.relative_episode_number,
sequence_number: first_format.sequence_number,
relative_sequence_number: first_format.relative_sequence_number,
}
}
@ -400,9 +408,28 @@ impl Format {
)
.replace(
"{relative_episode_number}",
&sanitize(
self.relative_episode_number.unwrap_or_default().to_string(),
true,
&format!(
"{:0>2}",
sanitize(
self.relative_episode_number.unwrap_or_default().to_string(),
true,
)
),
)
.replace(
"{sequence_number}",
&format!("{:0>2}", sanitize(self.sequence_number.to_string(), true)),
)
.replace(
"{relative_sequence_number}",
&format!(
"{:0>2}",
sanitize(
self.relative_sequence_number
.unwrap_or_default()
.to_string(),
true,
)
),
);
@ -446,7 +473,12 @@ impl Format {
tab_info!("FPS: {:.2}", self.fps)
}
pub fn has_relative_episodes_fmt<S: AsRef<str>>(s: S) -> bool {
return s.as_ref().contains("{relative_episode_number}");
pub fn is_special(&self) -> bool {
self.sequence_number == 0.0 || self.sequence_number.fract() != 0.0
}
pub fn has_relative_fmt<S: AsRef<str>>(s: S) -> bool {
return s.as_ref().contains("{relative_episode_number}")
|| s.as_ref().contains("{relative_sequence_number}");
}
}

View file

@ -10,8 +10,8 @@ use regex::Regex;
/// If `to_*` is [`None`] they're set to [`u32::MAX`].
#[derive(Debug, Default)]
pub struct InnerUrlFilter {
from_episode: Option<u32>,
to_episode: Option<u32>,
from_episode: Option<f32>,
to_episode: Option<f32>,
from_season: Option<u32>,
to_season: Option<u32>,
}
@ -39,10 +39,10 @@ impl UrlFilter {
})
}
pub fn is_episode_valid(&self, episode: u32, season: u32) -> bool {
pub fn is_episode_valid(&self, episode: f32, season: u32) -> bool {
self.inner.iter().any(|f| {
let from_episode = f.from_episode.unwrap_or(u32::MIN);
let to_episode = f.to_episode.unwrap_or(u32::MAX);
let from_episode = f.from_episode.unwrap_or(f32::MIN);
let to_episode = f.to_episode.unwrap_or(f32::MAX);
let from_season = f.from_season.unwrap_or(u32::MIN);
let to_season = f.to_season.unwrap_or(u32::MAX);
@ -192,3 +192,13 @@ pub fn parse_resolution(mut resolution: String) -> Result<Resolution> {
bail!("Could not find resolution")
}
}
/// Dirty implementation of [`f32::fract`] with more accuracy.
pub fn fract(input: f32) -> f32 {
if input.fract() == 0.0 {
return 0.0;
}
format!("0.{}", input.to_string().split('.').last().unwrap())
.parse::<f32>()
.unwrap()
}