feat(core): add movie domain types (#47)
This commit was merged in pull request #47.
This commit is contained in:
+284
-8
@@ -1,14 +1,290 @@
|
||||
//! arr-core — domain types, policy engine, scoring. See DESIGN.md §4 and §5.
|
||||
//! Pure domain types shared by the arr crates.
|
||||
//!
|
||||
//! This crate must never depend on `axum`, `sqlx` or `reqwest`. It holds the
|
||||
//! logic that is tested constantly and it has to stay fast to compile.
|
||||
//! This crate must never depend on `axum`, `sqlx` or `reqwest`.
|
||||
|
||||
use std::{collections::BTreeMap, path::PathBuf, time::SystemTime};
|
||||
|
||||
macro_rules! id_type {
|
||||
($name:ident) => {
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct $name(pub i64);
|
||||
};
|
||||
}
|
||||
|
||||
id_type!(RootId);
|
||||
id_type!(PolicyId);
|
||||
id_type!(MovieId);
|
||||
id_type!(MediaFileId);
|
||||
id_type!(ReleaseId);
|
||||
id_type!(GrabId);
|
||||
id_type!(OwnerId);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Audience {
|
||||
Main,
|
||||
Kids,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Root {
|
||||
pub id: RootId,
|
||||
pub audience: Audience,
|
||||
pub path: PathBuf,
|
||||
pub policy_id: PolicyId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Language {
|
||||
PortuguesePortugal,
|
||||
PortugueseBrazil,
|
||||
PortugueseUnverified,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Resolution {
|
||||
R2160p,
|
||||
R1080p,
|
||||
R720p,
|
||||
Other(u16),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Source {
|
||||
Remux,
|
||||
BluRay,
|
||||
WebDl,
|
||||
WebRip,
|
||||
Hdtv,
|
||||
Telesync,
|
||||
Cam,
|
||||
Screener,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct DolbyVisionProfile {
|
||||
pub profile: u8,
|
||||
pub compatibility_id: Option<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum HdrFormat {
|
||||
Sdr,
|
||||
Hdr10,
|
||||
Hdr10Plus,
|
||||
Hlg,
|
||||
DolbyVision(DolbyVisionProfile),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum HdrClaim {
|
||||
Hdr10,
|
||||
Hdr10Plus,
|
||||
Hlg,
|
||||
DolbyVision,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum RequiredAudio {
|
||||
OriginalLanguage,
|
||||
AnyOf(Vec<Language>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct HdrRules {
|
||||
pub rejected_dolby_vision_profiles: Vec<DolbyVisionProfile>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct SizeBand {
|
||||
pub floor_bytes: u64,
|
||||
pub target_bytes: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Policy {
|
||||
pub id: PolicyId,
|
||||
pub name: String,
|
||||
pub required_audio: RequiredAudio,
|
||||
pub dub_blacklist: Vec<Language>,
|
||||
pub hdr_rules: HdrRules,
|
||||
pub size_bands: BTreeMap<Resolution, SizeBand>,
|
||||
pub resolution_preference: Vec<Resolution>,
|
||||
pub source_weights: BTreeMap<Source, i32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct MovieOverrides {
|
||||
pub only_4k: bool,
|
||||
pub allow_english_audio: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum MovieState {
|
||||
Missing,
|
||||
Downloading,
|
||||
Available,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Movie {
|
||||
pub id: MovieId,
|
||||
pub tmdb_id: u64,
|
||||
pub title: String,
|
||||
pub year: u16,
|
||||
pub original_language: Language,
|
||||
pub root_id: RootId,
|
||||
pub wanted: bool,
|
||||
pub overrides: MovieOverrides,
|
||||
pub state: MovieState,
|
||||
pub blocked: bool,
|
||||
pub search_attempts: u32,
|
||||
pub last_searched_at: Option<SystemTime>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AudioTrack {
|
||||
pub language: Language,
|
||||
pub title: Option<String>,
|
||||
pub handler_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SubtitleTrack {
|
||||
pub language: Language,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ProbedMedia {
|
||||
pub resolution: Resolution,
|
||||
pub source: Option<Source>,
|
||||
pub hdr: HdrFormat,
|
||||
pub audio_tracks: Vec<AudioTrack>,
|
||||
pub subtitle_tracks: Vec<SubtitleTrack>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Rule {
|
||||
RequiredAudio,
|
||||
DubBlacklist(Language),
|
||||
DolbyVisionProfile(DolbyVisionProfile),
|
||||
Resolution(Resolution),
|
||||
Source(Source),
|
||||
Size,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Verdict {
|
||||
Eligible,
|
||||
Waived(Rule),
|
||||
Rejected(Rule),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct MediaFile {
|
||||
pub id: MediaFileId,
|
||||
pub movie_id: MovieId,
|
||||
pub path: PathBuf,
|
||||
pub size: u64,
|
||||
pub probed: ProbedMedia,
|
||||
pub waiver: Option<Rule>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ParsedRelease {
|
||||
pub resolution: Option<Resolution>,
|
||||
pub source: Option<Source>,
|
||||
pub hdr: Vec<HdrClaim>,
|
||||
pub audio_languages: Vec<Language>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Release {
|
||||
pub id: ReleaseId,
|
||||
pub indexer_id: i64,
|
||||
pub guid: String,
|
||||
pub name: String,
|
||||
pub size: u64,
|
||||
pub seeders: u32,
|
||||
pub publish_date: SystemTime,
|
||||
pub download_url: String,
|
||||
pub parsed: ParsedRelease,
|
||||
pub score: i64,
|
||||
pub verdict: Verdict,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum GrabState {
|
||||
Downloading,
|
||||
Downloaded,
|
||||
Imported,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Grab {
|
||||
pub id: GrabId,
|
||||
pub release_id: ReleaseId,
|
||||
pub movie_id: MovieId,
|
||||
pub infohash: String,
|
||||
pub state: GrabState,
|
||||
pub grabbed_at: SystemTime,
|
||||
pub imported_at: Option<SystemTime>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct BlacklistEntry {
|
||||
pub infohash: String,
|
||||
pub normalised_name: String,
|
||||
pub reason: String,
|
||||
pub created_at: SystemTime,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Owner {
|
||||
pub id: OwnerId,
|
||||
pub name: String,
|
||||
pub ntfy_topic: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct MovieOwner {
|
||||
pub movie_id: MovieId,
|
||||
pub owner_id: OwnerId,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// Placeholder so the test gate is meaningful on an empty workspace —
|
||||
/// `cargo nextest` fails a run with zero tests, and relaxing that would
|
||||
/// let a broken filter go green later. Replaced by real tests in the
|
||||
/// domain-types and policy-engine issues.
|
||||
use super::{DolbyVisionProfile, HdrFormat, Language, Rule, Verdict};
|
||||
|
||||
#[test]
|
||||
fn workspace_builds_and_tests_run() {}
|
||||
fn portuguese_variants_are_distinct() {
|
||||
assert_ne!(Language::PortuguesePortugal, Language::PortugueseBrazil);
|
||||
assert_ne!(Language::PortugueseBrazil, Language::PortugueseUnverified);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dolby_vision_profile_is_preserved() {
|
||||
assert_ne!(
|
||||
HdrFormat::DolbyVision(DolbyVisionProfile {
|
||||
profile: 8,
|
||||
compatibility_id: Some(1),
|
||||
}),
|
||||
HdrFormat::DolbyVision(DolbyVisionProfile {
|
||||
profile: 8,
|
||||
compatibility_id: Some(2),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_eligible_verdicts_name_the_rule() {
|
||||
let rule = Rule::DolbyVisionProfile(DolbyVisionProfile {
|
||||
profile: 5,
|
||||
compatibility_id: None,
|
||||
});
|
||||
assert_eq!(Verdict::Rejected(rule.clone()), Verdict::Rejected(rule));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user