-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtitle_recognizer.rs
125 lines (103 loc) · 3.3 KB
/
title_recognizer.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::cell::RefCell;
use std::str::FromStr;
use anitomy::{Anitomy, ElementCategory, Elements};
use log::debug;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Title {
pub title: String,
pub season_number: i32,
pub episode_number: i32,
}
impl Title {
pub fn new(title: String, season_number: i32, episode_number: i32) -> Self {
Self {
title,
season_number,
episode_number,
}
}
}
trait Recognizer: Send + Sync {
fn recognize(&mut self, title: Option<&str>, filename: Option<&str>) -> Option<Title>;
}
#[derive(Default)]
pub struct TitleRecognizer {
recognizers: Vec<Box<dyn Recognizer>>,
}
impl TitleRecognizer {
pub fn new() -> Self {
let recognizers: Vec<Box<dyn Recognizer>> = vec![
Box::new(AniCliRecognizer::new()),
Box::new(AnitomyRecognizer::new()),
];
Self { recognizers }
}
pub fn recognize(&mut self, title: Option<&str>, filename: Option<&str>) -> Option<Title> {
self.recognizers
.iter_mut()
.find_map(|x| x.recognize(title, filename))
}
}
#[derive(Default)]
struct AnitomyRecognizer;
thread_local! {
static ANITOMY: RefCell<Anitomy> = RefCell::new(Anitomy::new());
}
impl AnitomyRecognizer {
pub fn new() -> Self {
Default::default()
}
fn elements_to_title(elements: &Elements) -> Option<Title> {
debug!("Found path elements: {:?}", elements);
let title = elements.get(ElementCategory::AnimeTitle)?.to_owned();
let episode_number: i32 = elements
.get(ElementCategory::EpisodeNumber)
.unwrap_or("1")
.parse()
.ok()?;
if episode_number < 1 {
return None;
}
let season_number: i32 = elements
.get(ElementCategory::AnimeSeason)
.unwrap_or("1")
.parse()
.ok()?;
Some(Title::new(title, season_number, episode_number))
}
}
impl Recognizer for AnitomyRecognizer {
fn recognize(&mut self, _title: Option<&str>, filename: Option<&str>) -> Option<Title> {
if let Some(filename) = filename {
ANITOMY.with(|anitomy| match anitomy.borrow_mut().parse(filename) {
Ok(ref elements) => Self::elements_to_title(elements),
Err(_elements) => None,
})
} else {
None
}
}
}
#[derive(Default)]
struct AniCliRecognizer;
impl AniCliRecognizer {
pub fn new() -> Self {
Default::default()
}
}
impl Recognizer for AniCliRecognizer {
fn recognize(&mut self, title: Option<&str>, _filename: Option<&str>) -> Option<Title> {
if let Some(title) = title {
if title.starts_with("ani-cli: ") {
let (title, episode_number_str) = title.split_once(" ep ")?;
let episode_number = i32::from_str(episode_number_str).ok()?;
return Some(Title::new(title.to_owned(), 1, episode_number));
} else if title.contains(" Episode ") {
let (title, episode_number_str) = title.split_once(" Episode ")?;
let episode_number = i32::from_str(episode_number_str).ok()?;
return Some(Title::new(title.to_owned(), 1, episode_number));
}
}
None
}
}