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