mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 14:44:22 +00:00
Finally separate VorbisTag::read_from_path from the other tags
Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
This commit is contained in:
parent
48e6182e3a
commit
b072f0b0e5
8 changed files with 141 additions and 94 deletions
|
@ -4,13 +4,13 @@ use crate::{
|
|||
impl_tag, traits::ReadPath, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture,
|
||||
Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
pub use ape::Tag as ApeInnerTag;
|
||||
use filepath::FilePath;
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
impl ReadPath for ApeInnerTag {
|
||||
fn from_path<P>(path: P, _tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
Self: Sized,
|
||||
|
@ -21,6 +21,16 @@ impl ReadPath for ApeInnerTag {
|
|||
|
||||
impl_tag!(ApeTag, ApeInnerTag, TagType::Ape);
|
||||
|
||||
impl ApeTag {
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self(ApeInnerTag::from_path(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ApeTag> for AnyTag<'a> {
|
||||
fn from(inp: &'a ApeTag) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -4,12 +4,14 @@ use crate::{
|
|||
impl_tag, traits::ReadPath, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Error,
|
||||
MimeType, Picture, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
use std::{convert::TryInto, fs::File, path::Path};
|
||||
|
||||
pub use id3::Tag as Id3v2InnerTag;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
impl ReadPath for Id3v2InnerTag {
|
||||
fn from_path<P>(path: P, _tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
Self: Sized,
|
||||
|
@ -20,6 +22,16 @@ impl ReadPath for Id3v2InnerTag {
|
|||
|
||||
impl_tag!(Id3v2Tag, Id3v2InnerTag, TagType::Id3v2);
|
||||
|
||||
impl Id3v2Tag {
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self(Id3v2InnerTag::from_path(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Id3v2Tag> for AnyTag<'a> {
|
||||
fn from(inp: &'a Id3v2Tag) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -4,12 +4,13 @@ use crate::{
|
|||
impl_tag, traits::ReadPath, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Error,
|
||||
MimeType, Picture, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
pub use mp4ameta::{FourCC, Tag as Mp4InnerTag};
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
impl ReadPath for Mp4InnerTag {
|
||||
fn from_path<P>(path: P, _tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
Self: Sized,
|
||||
|
@ -20,6 +21,16 @@ impl ReadPath for Mp4InnerTag {
|
|||
|
||||
impl_tag!(Mp4Tag, Mp4InnerTag, TagType::Mp4);
|
||||
|
||||
impl Mp4Tag {
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self(Mp4InnerTag::from_path(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Mp4Tag> for AnyTag<'a> {
|
||||
fn from(inp: &'a Mp4Tag) -> Self {
|
||||
let title = inp.title();
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
#![cfg(feature = "vorbis")]
|
||||
|
||||
use crate::{
|
||||
components::logic, impl_tag, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture,
|
||||
Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
collections::HashMap,
|
||||
fs::File,
|
||||
fs::OpenOptions,
|
||||
io::Write,
|
||||
io::{Cursor, Seek, SeekFrom},
|
||||
path::Path,
|
||||
components::logic, impl_tag, tag::VorbisFormat, Album, AnyTag, AudioTag, AudioTagEdit,
|
||||
AudioTagWrite, Picture, Result, TagType, ToAny, ToAnyTag,
|
||||
};
|
||||
|
||||
use std::borrow::BorrowMut;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
|
||||
const START_SIGNATURE: [u8; 7] = [3, 118, 111, 114, 98, 105, 115];
|
||||
const END_BYTE: u8 = 1;
|
||||
|
||||
struct VorbisInnerTag {
|
||||
tag_type: Option<TagType>,
|
||||
format: Option<VorbisFormat>,
|
||||
vendor: String,
|
||||
comments: HashMap<String, String>,
|
||||
}
|
||||
|
@ -26,7 +23,7 @@ struct VorbisInnerTag {
|
|||
impl Default for VorbisInnerTag {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tag_type: None,
|
||||
format: None,
|
||||
vendor: "".to_string(),
|
||||
comments: std::collections::HashMap::default(),
|
||||
}
|
||||
|
@ -59,63 +56,71 @@ impl VorbisInnerTag {
|
|||
self.comments = comments;
|
||||
}
|
||||
|
||||
fn from_path<P>(path: P, tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P, format: VorbisFormat) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
if let Some(tag_type) = tag_type {
|
||||
match tag_type {
|
||||
TagType::Ogg => {
|
||||
let headers =
|
||||
lewton::inside_ogg::OggStreamReader::new(File::open(path)?).unwrap();
|
||||
match format {
|
||||
VorbisFormat::Ogg => {
|
||||
let headers = lewton::inside_ogg::OggStreamReader::new(File::open(path)?).unwrap();
|
||||
|
||||
let vendor = headers.comment_hdr.vendor;
|
||||
let vendor = headers.comment_hdr.vendor;
|
||||
|
||||
let comments: HashMap<String, String> =
|
||||
headers.comment_hdr.comment_list.into_iter().collect();
|
||||
let comments: HashMap<String, String> =
|
||||
headers.comment_hdr.comment_list.into_iter().collect();
|
||||
|
||||
Ok(Self {
|
||||
tag_type: Some(tag_type),
|
||||
vendor,
|
||||
comments,
|
||||
})
|
||||
},
|
||||
TagType::Opus => {
|
||||
let headers = opus_headers::parse_from_path(path)?;
|
||||
let vendor = headers.comments.vendor;
|
||||
Ok(Self {
|
||||
format: Some(format),
|
||||
vendor,
|
||||
comments,
|
||||
})
|
||||
},
|
||||
VorbisFormat::Opus => {
|
||||
let headers = opus_headers::parse_from_path(path)?;
|
||||
let vendor = headers.comments.vendor;
|
||||
|
||||
Ok(Self {
|
||||
tag_type: Some(tag_type),
|
||||
vendor,
|
||||
comments: headers.comments.user_comments,
|
||||
})
|
||||
},
|
||||
TagType::Flac => {
|
||||
let headers = metaflac::Tag::read_from_path(path)?;
|
||||
let comments = headers.vorbis_comments().unwrap();
|
||||
let mut comment_collection = Vec::new();
|
||||
Ok(Self {
|
||||
format: Some(format),
|
||||
vendor,
|
||||
comments: headers.comments.user_comments,
|
||||
})
|
||||
},
|
||||
VorbisFormat::Flac => {
|
||||
let headers = metaflac::Tag::read_from_path(path)?;
|
||||
let comments = headers.vorbis_comments().unwrap();
|
||||
let mut comment_collection = Vec::new();
|
||||
|
||||
for (k, v) in comments.comments.clone() {
|
||||
for e in v {
|
||||
comment_collection.push((k.clone(), e.clone()))
|
||||
}
|
||||
for (k, v) in comments.comments.clone() {
|
||||
for e in v {
|
||||
comment_collection.push((k.clone(), e.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
tag_type: Some(tag_type),
|
||||
vendor: comments.vendor_string.clone(),
|
||||
comments: comment_collection.into_iter().collect(),
|
||||
})
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
Ok(Self {
|
||||
format: Some(format),
|
||||
vendor: comments.vendor_string.clone(),
|
||||
comments: comment_collection.into_iter().collect(),
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_tag!(VorbisTag, VorbisInnerTag, TagType::Ogg);
|
||||
impl_tag!(
|
||||
VorbisTag,
|
||||
VorbisInnerTag,
|
||||
TagType::Vorbis(VorbisFormat::Ogg)
|
||||
);
|
||||
|
||||
impl VorbisTag {
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P, format: VorbisFormat) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self(VorbisInnerTag::from_path(path, format)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<AnyTag<'a>> for VorbisTag {
|
||||
fn from(inp: AnyTag<'a>) -> Self {
|
||||
|
@ -196,7 +201,7 @@ impl From<metaflac::Tag> for VorbisTag {
|
|||
};
|
||||
|
||||
tag.0 = VorbisInnerTag {
|
||||
tag_type: Some(TagType::Flac),
|
||||
format: Some(VorbisFormat::Flac),
|
||||
vendor,
|
||||
comments,
|
||||
};
|
||||
|
@ -396,9 +401,9 @@ impl AudioTagEdit for VorbisTag {
|
|||
|
||||
impl AudioTagWrite for VorbisTag {
|
||||
fn write_to(&self, file: &mut File) -> Result<()> {
|
||||
if let Some(tag_type) = self.0.tag_type.clone() {
|
||||
match tag_type {
|
||||
TagType::Ogg => {
|
||||
if let Some(format) = self.0.format.clone() {
|
||||
match format {
|
||||
VorbisFormat::Ogg => {
|
||||
let vendor = self.0.vendor.clone();
|
||||
let vendor_bytes = vendor.as_bytes();
|
||||
|
||||
|
@ -442,16 +447,14 @@ impl AudioTagWrite for VorbisTag {
|
|||
file.set_len(0)?;
|
||||
file.write_all(&data)?;
|
||||
},
|
||||
TagType::Flac => {
|
||||
VorbisFormat::Flac => {
|
||||
let mut flac_tag: metaflac::Tag = self.into();
|
||||
|
||||
flac_tag.write_to(file)?;
|
||||
},
|
||||
TagType::Opus => {
|
||||
VorbisFormat::Opus => {
|
||||
todo!()
|
||||
},
|
||||
TagType::Mp4 => {},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ struct WavInnerTag {
|
|||
}
|
||||
|
||||
impl ReadPath for WavInnerTag {
|
||||
fn from_path<P>(path: P, _tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
Self: Sized,
|
||||
|
@ -32,6 +32,8 @@ impl Default for WavInnerTag {
|
|||
}
|
||||
}
|
||||
|
||||
impl_tag!(WavTag, WavInnerTag, TagType::Wav);
|
||||
|
||||
impl<'a> From<AnyTag<'a>> for WavTag {
|
||||
fn from(inp: AnyTag<'a>) -> Self {
|
||||
let mut tag = WavTag::default();
|
||||
|
@ -84,7 +86,15 @@ impl<'a> From<&'a WavTag> for AnyTag<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl_tag!(WavTag, WavInnerTag, TagType::Wav);
|
||||
impl WavTag {
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self(WavInnerTag::from_path(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl WavTag {
|
||||
fn get_value(&self, key: &str) -> Option<&str> {
|
||||
|
|
|
@ -15,13 +15,6 @@ macro_rules! impl_tag {
|
|||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_from_path<P>(path: P, tag_type: Option<TagType>) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(Self($inner::from_path(path, tag_type)?))
|
||||
}
|
||||
}
|
||||
|
||||
use std::any::Any;
|
||||
|
|
32
src/tag.rs
32
src/tag.rs
|
@ -38,15 +38,15 @@ impl Tag {
|
|||
.unwrap_or(&TagType::try_from_ext(extension_str)?)
|
||||
{
|
||||
#[cfg(feature = "ape")]
|
||||
TagType::Ape => Ok(Box::new(ApeTag::read_from_path(path, None)?)),
|
||||
TagType::Ape => Ok(Box::new(ApeTag::read_from_path(path)?)),
|
||||
#[cfg(feature = "mp3")]
|
||||
TagType::Id3v2 => Ok(Box::new(Id3v2Tag::read_from_path(path, None)?)),
|
||||
TagType::Id3v2 => Ok(Box::new(Id3v2Tag::read_from_path(path)?)),
|
||||
#[cfg(feature = "mp4")]
|
||||
TagType::Mp4 => Ok(Box::new(Mp4Tag::read_from_path(path, None)?)),
|
||||
TagType::Mp4 => Ok(Box::new(Mp4Tag::read_from_path(path)?)),
|
||||
#[cfg(feature = "wav")]
|
||||
TagType::Wav => Ok(Box::new(WavTag::read_from_path(path, None)?)),
|
||||
#[cfg(feature = "vorbis")] // TODO: this isn't ideal, make this better somehow
|
||||
id => Ok(Box::new(VorbisTag::read_from_path(path, Some(id.clone()))?)),
|
||||
TagType::Wav => Ok(Box::new(WavTag::read_from_path(path)?)),
|
||||
#[cfg(feature = "vorbis")]
|
||||
TagType::Vorbis(format) => Ok(Box::new(VorbisTag::read_from_path(path, format.clone())?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,17 @@ pub enum TagType {
|
|||
#[cfg(feature = "mp4")]
|
||||
/// Common file extensions: `.mp4, .m4a, .m4p, .m4b, .m4r, .m4v`
|
||||
Mp4,
|
||||
#[cfg(feature = "vorbis")]
|
||||
/// Represents multiple formats, see [`VorbisFormat`] for extensions.
|
||||
Vorbis(VorbisFormat),
|
||||
#[cfg(feature = "wav")]
|
||||
/// Common file extensions: `.wav, .wave`
|
||||
Wav,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg(feature = "vorbis")]
|
||||
pub enum VorbisFormat {
|
||||
#[cfg(feature = "vorbis")]
|
||||
/// Common file extensions: `.ogg, .oga`
|
||||
Ogg,
|
||||
|
@ -72,9 +83,6 @@ pub enum TagType {
|
|||
#[cfg(feature = "vorbis")]
|
||||
/// Common file extensions: `.flac`
|
||||
Flac,
|
||||
#[cfg(feature = "wav")]
|
||||
/// Common file extensions: `.wav, .wave`
|
||||
Wav,
|
||||
}
|
||||
|
||||
impl TagType {
|
||||
|
@ -85,11 +93,11 @@ impl TagType {
|
|||
#[cfg(feature = "mp3")]
|
||||
"mp3" => Ok(Self::Id3v2),
|
||||
#[cfg(feature = "vorbis")]
|
||||
"opus" => Ok(Self::Opus),
|
||||
"opus" => Ok(Self::Vorbis(VorbisFormat::Opus)),
|
||||
#[cfg(feature = "vorbis")]
|
||||
"flac" => Ok(Self::Flac),
|
||||
"flac" => Ok(Self::Vorbis(VorbisFormat::Flac)),
|
||||
#[cfg(feature = "vorbis")]
|
||||
"ogg" | "oga" => Ok(Self::Ogg),
|
||||
"ogg" | "oga" => Ok(Self::Vorbis(VorbisFormat::Ogg)),
|
||||
#[cfg(feature = "mp4")]
|
||||
"m4a" | "m4b" | "m4p" | "m4v" | "isom" | "mp4" => Ok(Self::Mp4),
|
||||
#[cfg(feature = "wav")]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::WavTag;
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use crate::{components::tags::*, Album, AnyTag, Picture, Result, TagType};
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
pub trait AudioTag: AudioTagEdit + AudioTagWrite + ToAnyTag {}
|
||||
|
@ -114,7 +114,7 @@ pub trait ToAnyTag: ToAny {
|
|||
#[cfg(feature = "mp4")]
|
||||
TagType::Mp4 => Box::new(Mp4Tag::from(self.to_anytag())),
|
||||
#[cfg(feature = "vorbis")]
|
||||
TagType::Ogg | TagType::Opus | TagType::Flac => Box::new(VorbisTag::from(self.to_anytag())),
|
||||
TagType::Vorbis(_) => Box::new(VorbisTag::from(self.to_anytag())),
|
||||
#[cfg(feature = "wav")]
|
||||
TagType::Wav => Box::new(WavTag::from(self.to_anytag())),
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ pub trait ToAny {
|
|||
}
|
||||
|
||||
pub trait ReadPath {
|
||||
fn from_path<P>(path: P, _tag_type: Option<TagType>) -> Result<Self>
|
||||
fn from_path<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
Self: Sized;
|
||||
|
|
Loading…
Reference in a new issue