mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2025-03-04 14:57:17 +00:00
Initial work
This commit is contained in:
parent
f7fa066698
commit
5e2d813470
10 changed files with 90 additions and 53 deletions
|
@ -29,7 +29,7 @@ base64 = "0.13.0"
|
|||
byteorder = "1.4.3"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
lofty_attr = "0.1.8"
|
||||
lofty_attr = {path = "lofty-attr"}
|
||||
|
||||
[features]
|
||||
default = ["all_tags"]
|
||||
|
|
|
@ -64,6 +64,7 @@ pub fn impl_tag(input: TokenStream) -> TokenStream {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: #inner::default(),
|
||||
properties: FileProperties::default(),
|
||||
_format: #tag_type
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +101,7 @@ pub fn impl_tag(input: TokenStream) -> TokenStream {
|
|||
fn from(inp: #inner) -> Self {
|
||||
Self {
|
||||
inner: inp,
|
||||
properties: FileProperties::default(),
|
||||
_format: #tag_type
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,23 @@ pub(crate) mod tags;
|
|||
|
||||
use std::time::Duration;
|
||||
|
||||
/// Various audio properties
|
||||
///
|
||||
/// NOTE: All fields are invalidated after any type of conversion
|
||||
pub struct FileProperties {
|
||||
duration: Duration,
|
||||
bitrate: u32,
|
||||
sample_rate: u32,
|
||||
channels: u8,
|
||||
}
|
||||
duration: Duration,
|
||||
bitrate: Option<u32>,
|
||||
sample_rate: Option<u32>,
|
||||
channels: Option<u8>,
|
||||
}
|
||||
|
||||
impl Default for FileProperties {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
duration: Duration::ZERO,
|
||||
bitrate: None,
|
||||
sample_rate: None,
|
||||
channels: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::components::logic::aiff;
|
||||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, Result, TagType, ToAny,
|
||||
ToAnyTag,
|
||||
};
|
||||
|
||||
use std::fs::File;
|
||||
|
@ -19,6 +20,7 @@ struct AiffInnerTag {
|
|||
/// Represents Aiff Text Chunks
|
||||
pub struct AiffTag {
|
||||
inner: AiffInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::AiffText)]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -38,6 +40,7 @@ impl AiffTag {
|
|||
author_id,
|
||||
copyright_id,
|
||||
},
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::AiffText,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::types::picture::{PicType, APE_PICTYPES};
|
||||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, Picture, Result, TagType,
|
||||
ToAny, ToAnyTag,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -15,6 +16,7 @@ use lofty_attr::{get_set_methods, LoftyTag};
|
|||
/// Represents an APEv2 tag
|
||||
pub struct ApeTag {
|
||||
inner: ApeInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Ape)]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -28,6 +30,7 @@ impl ApeTag {
|
|||
{
|
||||
Ok(Self {
|
||||
inner: ape::read_from(reader)?,
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::Ape,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::tag::Id3Format;
|
||||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, MimeType, Picture,
|
||||
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, LoftyError, MimeType,
|
||||
Picture, PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -17,6 +17,7 @@ use lofty_attr::LoftyTag;
|
|||
/// Represents an ID3 tag
|
||||
pub struct Id3v2Tag {
|
||||
inner: Id3v2InnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Id3v2(Id3Format::Mp3))]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -28,20 +29,17 @@ impl Id3v2Tag {
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
match format {
|
||||
Id3Format::Mp3 => Ok(Self {
|
||||
inner: Id3v2InnerTag::read_from(reader)?,
|
||||
_format: TagType::Id3v2(format),
|
||||
}),
|
||||
Id3Format::Riff => Ok(Self {
|
||||
inner: Id3v2InnerTag::read_from_wav_reader(reader)?,
|
||||
_format: TagType::Id3v2(format),
|
||||
}),
|
||||
Id3Format::Aiff => Ok(Self {
|
||||
inner: Id3v2InnerTag::read_from_aiff_reader(reader)?,
|
||||
_format: TagType::Id3v2(format),
|
||||
}),
|
||||
}
|
||||
let inner = match format {
|
||||
Id3Format::Mp3 => Id3v2InnerTag::read_from(reader)?,
|
||||
Id3Format::Riff => Id3v2InnerTag::read_from_wav_reader(reader)?,
|
||||
Id3Format::Aiff => Id3v2InnerTag::read_from_aiff_reader(reader)?,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
inner,
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::Id3v2(format),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, MimeType, Picture,
|
||||
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, LoftyError, MimeType,
|
||||
Picture, PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -14,6 +14,7 @@ pub use mp4ameta::{Fourcc, Tag as Mp4InnerTag};
|
|||
/// Represents an MPEG-4 tag
|
||||
pub struct Mp4Tag {
|
||||
inner: Mp4InnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Mp4)]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -25,8 +26,21 @@ impl Mp4Tag {
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let inner = Mp4InnerTag::read_from(reader)?;
|
||||
|
||||
let duration = inner.info.duration;
|
||||
let bitrate = inner.info.avg_bitrate;
|
||||
let channels = inner.info.channel_config.map(|cc| cc.value());
|
||||
let sample_rate = inner.info.sample_rate.map(|sr| sr.hz());
|
||||
|
||||
Ok(Self {
|
||||
inner: Mp4InnerTag::read_from(reader)?,
|
||||
inner,
|
||||
properties: FileProperties {
|
||||
duration: duration.unwrap_or_default(),
|
||||
bitrate,
|
||||
sample_rate,
|
||||
channels,
|
||||
},
|
||||
_format: TagType::Mp4,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ use crate::components::logic::ogg::constants::{OPUSHEAD, OPUSTAGS};
|
|||
#[cfg(feature = "format-vorbis")]
|
||||
use crate::components::logic::ogg::constants::{VORBIS_COMMENT_HEAD, VORBIS_IDENT_HEAD};
|
||||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, OggFormat, Picture,
|
||||
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, LoftyError, OggFormat,
|
||||
Picture, PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "format-opus", feature = "format-vorbis"))]
|
||||
|
@ -81,6 +81,7 @@ cfg_if::cfg_if! {
|
|||
/// Represents vorbis comments from multiple OGG formats
|
||||
pub struct OggTag {
|
||||
inner: OggInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Ogg(OggFormat::Opus))]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -89,6 +90,7 @@ cfg_if::cfg_if! {
|
|||
/// Represents vorbis comments from multiple OGG formats
|
||||
pub struct OggTag {
|
||||
inner: OggInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Ogg(OggFormat::Vorbis))]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -97,6 +99,7 @@ cfg_if::cfg_if! {
|
|||
/// Represents vorbis comments from multiple OGG formats
|
||||
pub struct OggTag {
|
||||
inner: OggInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::Ogg(OggFormat::Flac))]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -108,21 +111,19 @@ impl TryFrom<OGGTags> for OggTag {
|
|||
type Error = LoftyError;
|
||||
|
||||
fn try_from(inp: OGGTags) -> Result<Self> {
|
||||
let mut tag = Self::new();
|
||||
|
||||
let vendor = inp.0;
|
||||
let pictures = inp.1;
|
||||
let comments = inp.2;
|
||||
|
||||
tag._format = TagType::Ogg(inp.3);
|
||||
|
||||
tag.inner = OggInnerTag {
|
||||
vendor,
|
||||
comments,
|
||||
pictures: (!pictures.is_empty()).then(|| Cow::from(pictures)),
|
||||
};
|
||||
|
||||
Ok(tag)
|
||||
Ok(Self {
|
||||
inner: OggInnerTag {
|
||||
vendor,
|
||||
comments,
|
||||
pictures: (!pictures.is_empty()).then(|| Cow::from(pictures)),
|
||||
},
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::Ogg(inp.3),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,8 +132,6 @@ impl TryFrom<metaflac::Tag> for OggTag {
|
|||
type Error = LoftyError;
|
||||
|
||||
fn try_from(inp: metaflac::Tag) -> Result<Self> {
|
||||
let mut tag = Self::new();
|
||||
|
||||
if let Some(comments) = inp.vorbis_comments() {
|
||||
let mut user_comments = comments.comments.clone();
|
||||
|
||||
|
@ -154,15 +153,15 @@ impl TryFrom<metaflac::Tag> for OggTag {
|
|||
}
|
||||
}
|
||||
|
||||
tag._format = TagType::Ogg(OggFormat::Flac);
|
||||
|
||||
tag.inner = OggInnerTag {
|
||||
vendor: comments.vendor_string.clone(),
|
||||
comments: comment_collection,
|
||||
pictures: Some(Cow::from(pictures)),
|
||||
};
|
||||
|
||||
return Ok(tag);
|
||||
return Ok(Self {
|
||||
inner: OggInnerTag {
|
||||
vendor: comments.vendor_string.clone(),
|
||||
comments: comment_collection,
|
||||
pictures: Some(Cow::from(pictures)),
|
||||
},
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::Ogg(OggFormat::Flac),
|
||||
})
|
||||
}
|
||||
|
||||
Err(LoftyError::InvalidData(
|
||||
|
@ -180,6 +179,7 @@ impl OggTag {
|
|||
{
|
||||
Ok(Self {
|
||||
inner: OggInnerTag::read_from(reader, &format)?,
|
||||
properties: FileProperties::default(), // TODO
|
||||
_format: TagType::Ogg(format),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::components::logic::riff;
|
||||
use crate::{
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Result, TagType, ToAny, ToAnyTag,
|
||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, FileProperties, Result, TagType, ToAny,
|
||||
ToAnyTag,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -25,6 +26,7 @@ impl Default for RiffInnerTag {
|
|||
/// Represents a RIFF INFO LIST
|
||||
pub struct RiffTag {
|
||||
inner: RiffInnerTag,
|
||||
properties: FileProperties,
|
||||
#[expected(TagType::RiffInfo)]
|
||||
_format: TagType,
|
||||
}
|
||||
|
@ -40,6 +42,7 @@ impl RiffTag {
|
|||
inner: RiffInnerTag {
|
||||
data: riff::read_from(reader)?,
|
||||
},
|
||||
properties: FileProperties::default(),
|
||||
_format: TagType::RiffInfo,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ mod error;
|
|||
pub use crate::error::{LoftyError, Result};
|
||||
|
||||
mod components;
|
||||
pub use crate::components::tags::*;
|
||||
pub use crate::components::{tags::*, FileProperties};
|
||||
|
||||
mod traits;
|
||||
pub use crate::traits::{AudioTag, AudioTagEdit, AudioTagWrite, ToAny, ToAnyTag};
|
||||
|
|
Loading…
Add table
Reference in a new issue