1use crate::artist_credit::{get_credit_string, ArtistCredit, ArtistCreditParser};
2use crate::parser::{Parser, ParserError};
3use crate::reader::XmlReader;
4use crate::shared::Image;
5use crate::util::get_attr_id;
6use crate::video::{Video, VideoParser};
7use log::debug;
8use quick_xml::events::Event;
9use std::fmt;
10use std::mem::take;
11
12#[derive(Clone, Debug, Default)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Master {
15 pub id: u32,
16 pub title: String,
17 pub main_release: i32,
18 pub year: i32,
19 pub notes: Option<String>,
20 pub genres: Vec<String>,
21 pub styles: Vec<String>,
22 pub data_quality: String,
23 pub artists: Vec<ArtistCredit>,
24 pub images: Vec<Image>,
25 pub videos: Vec<Video>,
26}
27
28impl fmt::Display for Master {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 let artist_credit = get_credit_string(&self.artists);
31 write!(f, "{} - {}", artist_credit, self.title)
32 }
33}
34
35pub struct MastersReader {
36 buf: Vec<u8>,
37 reader: XmlReader,
38 parser: MasterParser,
39}
40
41impl MastersReader {
42 pub fn new(reader: XmlReader, buf: Vec<u8>) -> Self {
43 Self {
44 buf,
45 reader,
46 parser: MasterParser::new(),
47 }
48 }
49}
50
51impl Iterator for MastersReader {
52 type Item = Master;
53 fn next(&mut self) -> Option<Self::Item> {
54 loop {
55 match self.reader.read_event_into(&mut self.buf).unwrap() {
56 Event::Eof => {
57 return None;
58 }
59 ev => self.parser.process(ev).unwrap(),
60 };
61 if self.parser.item_ready {
62 return Some(self.parser.take());
63 }
64 self.buf.clear();
65 }
66 }
67}
68
69#[derive(Debug, Default)]
70enum ParserState {
71 #[default]
72 Master,
73 MainRelease,
74 Artists,
75 Title,
76 DataQuality,
77 Notes,
78 Images,
79 Styles,
80 Genres,
81 Year,
82 Videos,
83}
84
85#[derive(Debug, Default)]
86pub struct MasterParser {
87 state: ParserState,
88 current_item: Master,
89 artist_parser: ArtistCreditParser,
90 videos_parser: VideoParser,
91 item_ready: bool,
92}
93
94impl Parser for MasterParser {
95 type Item = Master;
96 fn new() -> Self {
97 Self::default()
98 }
99
100 fn take(&mut self) -> Master {
101 self.item_ready = false;
102 take(&mut self.current_item)
103 }
104
105 fn process(&mut self, ev: Event) -> Result<(), ParserError> {
106 self.state = match self.state {
107 ParserState::Master => match ev {
108 Event::Start(e) if e.local_name().as_ref() == b"master" => {
109 self.current_item.id = get_attr_id(e);
110 debug!("Began parsing Master {}", self.current_item.id);
111 ParserState::Master
112 }
113
114 Event::Start(e) => match e.local_name().as_ref() {
115 b"main_release" => ParserState::MainRelease,
116 b"title" => ParserState::Title,
117 b"artists" => ParserState::Artists,
118 b"data_quality" => ParserState::DataQuality,
119 b"images" => ParserState::Images,
120 b"styles" => ParserState::Styles,
121 b"genres" => ParserState::Genres,
122 b"notes" => ParserState::Notes,
123 b"year" => ParserState::Year,
124 b"videos" => ParserState::Videos,
125 _ => ParserState::Master,
126 },
127
128 Event::End(e) if e.local_name().as_ref() == b"master" => {
129 self.item_ready = true;
130 ParserState::Master
131 }
132
133 _ => ParserState::Master,
134 },
135
136 ParserState::MainRelease => match ev {
137 Event::Text(e) => {
138 self.current_item.main_release = e.unescape()?.parse()?;
139 ParserState::MainRelease
140 }
141 _ => ParserState::Master,
142 },
143
144 ParserState::Artists => match ev {
145 Event::End(e) if e.local_name().as_ref() == b"artists" => ParserState::Master,
146
147 ev => {
148 self.artist_parser.process(ev)?;
149 if self.artist_parser.item_ready {
150 self.current_item.artists.push(self.artist_parser.take());
151 }
152 ParserState::Artists
153 }
154 },
155
156 ParserState::Title => match ev {
157 Event::Text(e) => {
158 self.current_item.title = e.unescape()?.to_string();
159 ParserState::Title
160 }
161 _ => ParserState::Master,
162 },
163
164 ParserState::DataQuality => match ev {
165 Event::Text(e) => {
166 self.current_item.data_quality = e.unescape()?.to_string();
167 ParserState::DataQuality
168 }
169 _ => ParserState::Master,
170 },
171
172 ParserState::Images => match ev {
173 Event::Empty(e) if e.local_name().as_ref() == b"image" => {
174 let image = Image::from_event(e);
175 self.current_item.images.push(image);
176 ParserState::Images
177 }
178 Event::End(e) if e.local_name().as_ref() == b"images" => ParserState::Master,
179
180 _ => ParserState::Images,
181 },
182
183 ParserState::Genres => match ev {
184 Event::End(e) if e.local_name().as_ref() == b"genres" => ParserState::Master,
185
186 Event::Text(e) => {
187 self.current_item.genres.push(e.unescape()?.to_string());
188 ParserState::Genres
189 }
190 _ => ParserState::Genres,
191 },
192
193 ParserState::Styles => match ev {
194 Event::End(e) if e.local_name().as_ref() == b"styles" => ParserState::Master,
195
196 Event::Text(e) => {
197 self.current_item.styles.push(e.unescape()?.to_string());
198 ParserState::Styles
199 }
200 _ => ParserState::Styles,
201 },
202
203 ParserState::Notes => match ev {
204 Event::Text(e) => {
205 self.current_item.notes = Some(e.unescape()?.to_string());
206 ParserState::Notes
207 }
208 _ => ParserState::Master,
209 },
210
211 ParserState::Year => match ev {
212 Event::Text(e) => {
213 self.current_item.year = e.unescape()?.parse()?;
214 ParserState::Year
215 }
216 _ => ParserState::Master,
217 },
218
219 ParserState::Videos => match ev {
220 Event::End(e) if e.local_name().as_ref() == b"videos" => ParserState::Master,
221
222 ev => {
223 self.videos_parser.process(ev)?;
224 if self.videos_parser.item_ready {
225 self.current_item.videos.push(self.videos_parser.take());
226 }
227 ParserState::Videos
228 }
229 },
230 };
231
232 Ok(())
233 }
234}