1pub mod lyrics;
2pub mod audio;
3pub mod error;
4pub use error::*;
5
6pub use imagesize;
7use std::io::{ErrorKind, SeekFrom};
8use symphonia::core::io::MediaSource;
9#[derive(Debug, PartialEq, Eq, Clone, Copy)]
10pub enum MusicFmt {
11 M4a,
12 Mp3,
13 Flac,
14 Ogg,
15}
16
17pub struct AudioReader {
18 pos: usize,
19 buf: Vec<u8>,
20}
21impl MediaSource for AudioReader {
22 fn is_seekable(&self) -> bool {
23 true
24 }
25
26 fn byte_len(&self) -> Option<u64> {
27 Some(self.buf.len() as u64)
28 }
29}
30unsafe impl Send for AudioReader {}
31unsafe impl Sync for AudioReader {}
32impl AudioReader {
33 pub fn new(buf: Vec<u8>) -> AudioReader {
34 Self { pos: 0, buf }
35 }
36}
37impl std::io::Seek for AudioReader {
38 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
39 match pos {
40 SeekFrom::Current(i) => {
41 let pos = i as usize + self.pos;
42 if self.buf.len() > pos {
43 self.pos = pos;
44 Ok(self.pos as u64)
45 } else {
46 Err(std::io::Error::new(
47 ErrorKind::InvalidInput,
48 "Invalid position",
49 ))
50 }
51 }
52 SeekFrom::End(e) => {
53 if self.buf.len() >= e as usize {
54 self.pos = self.buf.len() - e as usize;
55 Ok(self.pos as u64)
56 } else {
57 Err(std::io::Error::new(
58 ErrorKind::InvalidInput,
59 "Invalid position",
60 ))
61 }
62 }
63 SeekFrom::Start(s) => {
64 if self.buf.len() >= s as usize {
65 self.pos = s as usize;
66 Ok(self.pos as u64)
67 } else {
68 Err(std::io::Error::new(
69 ErrorKind::InvalidInput,
70 "Invalid position",
71 ))
72 }
73 }
74 }
75 }
76}
77impl std::io::Read for AudioReader {
78 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
79 let pos = self.pos;
80 for i in self.pos..self.buf.len() {
81 if i - pos >= buf.len() {
82 break;
83 }
84 buf[i - pos] = self.buf[i];
85 self.pos = i + 1;
86 }
87 Ok(self.pos - pos)
88 }
89}