1use crate::{Error, Result};
6use id3::frame::Picture as Id3Picture;
7use id3::frame::Timestamp as Id3Timestamp;
8use metaflac::block::Picture as FlacPicture;
9use mp4ameta::Img as Mp4Picture;
10use mp4ameta::ImgFmt as Mp4ImageFmt;
11use opusmeta::picture::Picture as OpusPicture;
12use std::str::FromStr;
13
14#[derive(Clone, Debug, Default)]
16pub struct Album {
17 pub title: Option<String>,
18 pub artist: Option<String>,
19 pub cover: Option<Picture>,
20}
21
22#[derive(Clone, Debug)]
24pub struct Picture {
25 pub data: Vec<u8>,
26 pub mime_type: String,
27}
28
29impl From<Id3Picture> for Picture {
30 fn from(value: Id3Picture) -> Self {
31 Self {
32 data: value.data,
33 mime_type: value.mime_type,
34 }
35 }
36}
37
38impl From<FlacPicture> for Picture {
39 fn from(value: FlacPicture) -> Self {
40 Self {
41 data: value.data,
42 mime_type: value.mime_type,
43 }
44 }
45}
46
47impl From<Mp4Picture<&[u8]>> for Picture {
48 fn from(value: Mp4Picture<&[u8]>) -> Self {
49 Self {
50 data: value.data.to_vec(),
51 mime_type: match value.fmt {
52 Mp4ImageFmt::Bmp => "image/bmp".into(),
53 Mp4ImageFmt::Jpeg => "image/jpeg".into(),
54 Mp4ImageFmt::Png => "image/png".into(),
55 },
56 }
57 }
58}
59
60impl TryFrom<Picture> for Mp4Picture<Vec<u8>> {
61 type Error = Error;
62
63 fn try_from(value: Picture) -> Result<Self> {
64 let image_fmt = match value.mime_type.as_str() {
65 "image/bmp" => Ok(Mp4ImageFmt::Bmp),
66 "image/jpeg" => Ok(Mp4ImageFmt::Jpeg),
67 "image/png" => Ok(Mp4ImageFmt::Png),
68 _ => Err(Error::InvalidImageFormat),
69 }?;
70
71 Ok(Self {
72 fmt: image_fmt,
73 data: value.data,
74 })
75 }
76}
77
78impl From<OpusPicture> for Picture {
79 fn from(value: OpusPicture) -> Self {
80 Self {
81 data: value.data,
82 mime_type: value.mime_type,
83 }
84 }
85}
86
87impl From<Picture> for OpusPicture {
88 fn from(value: Picture) -> Self {
89 let mut picture = OpusPicture::new();
90 picture.mime_type = value.mime_type;
91 picture.data = value.data;
92
93 picture
94 }
95}
96
97impl std::fmt::Display for Picture {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(
100 f,
101 "Picture data ({}, {} bytes)",
102 self.mime_type,
103 self.data.len()
104 )
105 }
106}
107
108#[derive(Clone, Copy, Debug, Default)]
110pub struct Timestamp {
111 pub year: i32,
112 pub month: Option<u8>,
113 pub day: Option<u8>,
114 pub hour: Option<u8>,
115 pub minute: Option<u8>,
116 pub second: Option<u8>,
117}
118
119impl From<Id3Timestamp> for Timestamp {
120 fn from(value: Id3Timestamp) -> Self {
121 Self {
122 year: value.year,
123 month: value.month,
124 day: value.day,
125 hour: value.hour,
126 minute: value.minute,
127 second: value.second,
128 }
129 }
130}
131
132impl From<Timestamp> for Id3Timestamp {
133 fn from(value: Timestamp) -> Self {
134 Self {
135 year: value.year,
136 month: value.month,
137 day: value.day,
138 hour: value.hour,
139 minute: value.minute,
140 second: value.second,
141 }
142 }
143}
144
145impl FromStr for Timestamp {
146 type Err = Error;
147
148 fn from_str(s: &str) -> Result<Self> {
149 Ok(Id3Timestamp::from_str(s)
150 .map_err(|_| Error::TimestampParseError)?
151 .into())
152 }
153}
154
155impl std::fmt::Display for Timestamp {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 write!(f, "{}", Id3Timestamp::from(*self))
158 }
159}