youtube_dl_parser/reader/
output_reader.rs

1use duct::ReaderHandle;
2use std::collections::VecDeque;
3use std::io::{BufReader, Read};
4
5use crate::state::output_state::OutputState;
6
7/// Raw output reader
8pub struct OutputReader {
9    stdout_reader: BufReader<ReaderHandle>,
10    failed: bool,
11    finished: bool,
12    buffer_capacity: usize,
13    line_queue: VecDeque<String>,
14}
15
16impl OutputReader {
17    /// Creates a raw output reader based on the given reader handle
18    pub fn new(child_stdout: ReaderHandle) -> Self {
19        let stdout_reader = BufReader::new(child_stdout);
20        let buffer_capacity = stdout_reader.capacity();
21        let line_queue = VecDeque::new();
22        Self {
23            stdout_reader,
24            failed: false,
25            finished: false,
26            buffer_capacity,
27            line_queue,
28        }
29    }
30}
31
32impl Iterator for OutputReader {
33    type Item = OutputState;
34
35    fn next(&mut self) -> Option<Self::Item> {
36        if self.failed || self.finished {
37            return None;
38        }
39
40        if !self.line_queue.is_empty() {
41            let Some(next_output) = self.line_queue.pop_front() else {
42                self.failed=true;
43                return Some(OutputState::Error("Failed to read an output".to_owned()));
44            };
45            return Some(OutputState::Outputting(next_output));
46        }
47
48        let mut output = vec![0; self.buffer_capacity];
49
50        let read_size = match self.stdout_reader.read(&mut output) {
51            Ok(read_size) => read_size,
52            Err(err) => {
53                self.failed = true;
54                return Some(OutputState::Error(err.to_string()));
55            }
56        };
57
58        if read_size == 0 {
59            self.finished = true;
60            return Some(OutputState::Finished);
61        }
62
63        output.truncate(read_size);
64
65        let mut output = String::from_utf8_lossy(output.as_slice()).to_string();
66
67        output = output.replace(['\n'], "");
68
69        if !output.contains('\x0D') {
70            return Some(OutputState::Outputting(output));
71        }
72
73        let mut output = output
74            .split('\x0D')
75            .skip(1)
76            .map(|str| str.to_owned())
77            .collect::<VecDeque<_>>();
78
79        let Some(that_one) = output.pop_front() else {
80            self.failed=true;
81            return Some(OutputState::Error("Failed to read an output".to_owned()));
82        };
83
84        if output.is_empty() {
85            Some(OutputState::Outputting(that_one))
86        } else {
87            self.line_queue = output;
88            Some(OutputState::Outputting(that_one))
89        }
90    }
91}