1use crate::parser::{Parser, ParserError};
2use crate::util::find_attr;
3use quick_xml::events::Event;
4use std::mem::take;
5
6#[derive(Clone, Debug, Default, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Video {
9 pub src: String,
10 pub duration: u32,
11 pub title: String,
12 pub description: String,
13 pub embed: bool,
14}
15
16#[derive(Debug, Default)]
17enum ParserState {
18 #[default]
19 Video,
20 Title,
21 Description,
22}
23
24#[derive(Debug, Default)]
25pub struct VideoParser {
26 state: ParserState,
27 pub current_item: Video,
28 pub item_ready: bool,
29}
30
31impl Parser for VideoParser {
32 type Item = Video;
33 fn new() -> Self {
34 Self::default()
35 }
36
37 fn take(&mut self) -> Video {
38 self.item_ready = false;
39 take(&mut self.current_item)
40 }
41 fn process(&mut self, ev: &Event) -> Result<(), ParserError> {
42 self.state = match self.state {
43 ParserState::Video => match ev {
44 Event::Start(e) => match e.local_name().as_ref() {
45 b"video" => {
46 self.current_item.src = find_attr(e, b"src")?.to_string();
47 self.current_item.duration = find_attr(e, b"duration")?.parse()?;
48 self.current_item.embed = find_attr(e, b"embed")?.parse()?;
49 ParserState::Video
50 }
51 b"title" => ParserState::Title,
52 b"description" => ParserState::Description,
53 _ => ParserState::Video,
54 },
55
56 Event::End(e) => match e.local_name().as_ref() {
57 b"video" => {
58 self.item_ready = true;
59 ParserState::Video
60 }
61 _ => ParserState::Video,
62 },
63
64 _ => ParserState::Video,
65 },
66
67 ParserState::Title => match ev {
68 Event::Text(e) => {
69 self.current_item.title = e.unescape()?.to_string();
70 ParserState::Video
71 }
72 _ => ParserState::Video,
73 },
74
75 ParserState::Description => match ev {
76 Event::Text(e) => {
77 self.current_item.description = e.unescape()?.to_string();
78 ParserState::Video
79 }
80 _ => ParserState::Video,
81 },
82 };
83 Ok(())
84 }
85}