youtube_dl_parser/reader/
output_reader.rs1use duct::ReaderHandle;
2use std::collections::VecDeque;
3use std::io::{BufReader, Read};
4
5use crate::state::output_state::OutputState;
6
7pub 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 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}