mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 06:34:18 +00:00
Update tags
Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
This commit is contained in:
parent
730ce2ff6a
commit
0a7b327c03
5 changed files with 124 additions and 98 deletions
|
@ -11,7 +11,7 @@ use crate::types::picture::APE_PICTYPES;
|
||||||
use ape::Item;
|
use ape::Item;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
#[impl_tag(ApeInnerTag, TagType::Ape)]
|
#[impl_tag(ApeInnerTag, TagType::Ape)]
|
||||||
pub struct ApeTag;
|
pub struct ApeTag;
|
||||||
|
@ -19,12 +19,12 @@ pub struct ApeTag;
|
||||||
impl ApeTag {
|
impl ApeTag {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::missing_errors_doc)]
|
#[allow(clippy::missing_errors_doc)]
|
||||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
pub fn read_from<R>(reader: &mut R) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: ape::read_from_path(&path)?,
|
inner: ape::read_from(reader)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None, // TODO
|
duration: None, // TODO
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,20 +2,18 @@
|
||||||
|
|
||||||
use crate::tag::Id3Format;
|
use crate::tag::Id3Format;
|
||||||
use crate::{
|
use crate::{
|
||||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Error, MimeType, Picture, Result,
|
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, MimeType, Picture,
|
||||||
TagType, ToAny, ToAnyTag,
|
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||||
};
|
};
|
||||||
use lofty_attr::impl_tag;
|
use lofty_attr::impl_tag;
|
||||||
|
|
||||||
pub use id3::Tag as Id3v2InnerTag;
|
pub use id3::Tag as Id3v2InnerTag;
|
||||||
|
|
||||||
use crate::types::picture::PictureType;
|
|
||||||
use filepath::FilePath;
|
use filepath::FilePath;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[impl_tag(Id3v2InnerTag, TagType::Id3v2(Id3Format::Default))]
|
#[impl_tag(Id3v2InnerTag, TagType::Id3v2(Id3Format::Default))]
|
||||||
pub struct Id3v2Tag;
|
pub struct Id3v2Tag;
|
||||||
|
@ -23,23 +21,23 @@ pub struct Id3v2Tag;
|
||||||
impl Id3v2Tag {
|
impl Id3v2Tag {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::missing_errors_doc)]
|
#[allow(clippy::missing_errors_doc)]
|
||||||
pub fn read_from_path<P>(path: P, format: &Id3Format) -> Result<Self>
|
pub fn read_from<R>(reader: &mut R, format: &Id3Format) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
match format {
|
match format {
|
||||||
Id3Format::Default => Ok(Self {
|
Id3Format::Default => Ok(Self {
|
||||||
inner: Id3v2InnerTag::read_from_path(&path)?,
|
inner: Id3v2InnerTag::read_from(reader)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: Some(mp3_duration::from_path(&path)?),
|
duration: None, // TODO
|
||||||
}),
|
}),
|
||||||
Id3Format::Riff => Ok(Self {
|
Id3Format::Riff => Ok(Self {
|
||||||
inner: Id3v2InnerTag::read_from_wav(&path)?,
|
inner: Id3v2InnerTag::read_from_wav_reader(reader)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None,
|
duration: None,
|
||||||
}),
|
}),
|
||||||
Id3Format::Form => Ok(Self {
|
Id3Format::Form => Ok(Self {
|
||||||
inner: Id3v2InnerTag::read_from_aiff(&path)?,
|
inner: Id3v2InnerTag::read_from_aiff_reader(reader)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None,
|
duration: None,
|
||||||
}),
|
}),
|
||||||
|
@ -48,7 +46,8 @@ impl Id3v2Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::TryFrom<id3::frame::Picture> for Picture {
|
impl std::convert::TryFrom<id3::frame::Picture> for Picture {
|
||||||
type Error = Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: id3::frame::Picture) -> Result<Self> {
|
fn try_from(inp: id3::frame::Picture) -> Result<Self> {
|
||||||
let id3::frame::Picture {
|
let id3::frame::Picture {
|
||||||
ref mime_type,
|
ref mime_type,
|
||||||
|
@ -75,7 +74,8 @@ impl std::convert::TryFrom<id3::frame::Picture> for Picture {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Picture> for id3::frame::Picture {
|
impl TryFrom<Picture> for id3::frame::Picture {
|
||||||
type Error = Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: Picture) -> Result<Self> {
|
fn try_from(inp: Picture) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
mime_type: String::from(inp.mime_type),
|
mime_type: String::from(inp.mime_type),
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
#![cfg(feature = "format-mp4")]
|
#![cfg(feature = "format-mp4")]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Error, MimeType, Picture, Result,
|
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, MimeType, Picture,
|
||||||
TagType, ToAny, ToAnyTag,
|
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||||
};
|
};
|
||||||
use lofty_attr::impl_tag;
|
use lofty_attr::impl_tag;
|
||||||
|
|
||||||
pub use mp4ameta::{Fourcc, Tag as Mp4InnerTag};
|
pub use mp4ameta::{Fourcc, Tag as Mp4InnerTag};
|
||||||
|
|
||||||
use crate::types::picture::PictureType;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
#[impl_tag(Mp4InnerTag, TagType::Mp4)]
|
#[impl_tag(Mp4InnerTag, TagType::Mp4)]
|
||||||
pub struct Mp4Tag {}
|
pub struct Mp4Tag {}
|
||||||
|
@ -19,12 +18,12 @@ pub struct Mp4Tag {}
|
||||||
impl Mp4Tag {
|
impl Mp4Tag {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::missing_errors_doc)]
|
#[allow(clippy::missing_errors_doc)]
|
||||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
pub fn read_from<R>(reader: &mut R) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: Mp4InnerTag::read_from_path(path)?,
|
inner: Mp4InnerTag::read_from(reader)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None,
|
duration: None,
|
||||||
})
|
})
|
||||||
|
@ -32,7 +31,8 @@ impl Mp4Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::TryFrom<mp4ameta::Data> for Picture {
|
impl std::convert::TryFrom<mp4ameta::Data> for Picture {
|
||||||
type Error = Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: mp4ameta::Data) -> Result<Self> {
|
fn try_from(inp: mp4ameta::Data) -> Result<Self> {
|
||||||
Ok(match inp {
|
Ok(match inp {
|
||||||
mp4ameta::Data::Png(data) => Self {
|
mp4ameta::Data::Png(data) => Self {
|
||||||
|
@ -53,7 +53,7 @@ impl std::convert::TryFrom<mp4ameta::Data> for Picture {
|
||||||
description: None,
|
description: None,
|
||||||
data: Cow::from(data),
|
data: Cow::from(data),
|
||||||
},
|
},
|
||||||
_ => return Err(Error::NotAPicture),
|
_ => return Err(LoftyError::NotAPicture),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![cfg(feature = "format-riff")]
|
#![cfg(feature = "format-riff")]
|
||||||
|
|
||||||
use crate::components::logic;
|
use crate::components::logic::riff;
|
||||||
use crate::{
|
use crate::{
|
||||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture, Result, TagType, ToAny, ToAnyTag,
|
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture, Result, TagType, ToAny, ToAnyTag,
|
||||||
};
|
};
|
||||||
|
@ -9,7 +9,7 @@ use lofty_attr::impl_tag;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
struct RiffInnerTag {
|
struct RiffInnerTag {
|
||||||
data: Option<HashMap<String, String>>,
|
data: Option<HashMap<String, String>>,
|
||||||
|
@ -29,13 +29,13 @@ pub struct RiffTag;
|
||||||
impl RiffTag {
|
impl RiffTag {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::missing_errors_doc)]
|
#[allow(clippy::missing_errors_doc)]
|
||||||
pub fn read_from_path<P>(path: P) -> Result<Self>
|
pub fn read_from<R>(reader: &mut R) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: RiffInnerTag {
|
inner: RiffInnerTag {
|
||||||
data: logic::read::wav(File::open(path)?)?,
|
data: riff::read_from(reader)?,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None,
|
duration: None,
|
||||||
|
@ -235,7 +235,7 @@ impl AudioTagEdit for RiffTag {
|
||||||
impl AudioTagWrite for RiffTag {
|
impl AudioTagWrite for RiffTag {
|
||||||
fn write_to(&self, file: &mut File) -> Result<()> {
|
fn write_to(&self, file: &mut File) -> Result<()> {
|
||||||
if let Some(data) = self.inner.data.clone() {
|
if let Some(data) = self.inner.data.clone() {
|
||||||
crate::components::logic::write::riff(file, data)?;
|
riff::write_to(file, data)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4,26 +4,29 @@
|
||||||
feature = "format-flac"
|
feature = "format-flac"
|
||||||
))]
|
))]
|
||||||
|
|
||||||
use crate::components::logic::write::vorbis_generic;
|
use crate::components::logic::constants::{
|
||||||
use crate::{
|
OPUSHEAD, OPUSTAGS, VORBIS_COMMENT_HEAD, VORBIS_IDENT_HEAD,
|
||||||
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Error, Picture, PictureType, Result,
|
|
||||||
TagType, ToAny, ToAnyTag, VorbisFormat,
|
|
||||||
};
|
};
|
||||||
|
use crate::components::logic::{flac, ogg_generic};
|
||||||
|
use crate::{
|
||||||
|
Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, LoftyError, OggFormat, Picture,
|
||||||
|
PictureType, Result, TagType, ToAny, ToAnyTag,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "format-opus")]
|
||||||
|
use crate::components::logic::ogg_generic::OGGTags;
|
||||||
|
|
||||||
use lofty_attr::impl_tag;
|
use lofty_attr::impl_tag;
|
||||||
|
|
||||||
use lewton::inside_ogg::OggStreamReader;
|
use lewton::inside_ogg::OggStreamReader;
|
||||||
use opus_headers::OpusHeaders;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
pub const VORBIS: [u8; 7] = [3, 118, 111, 114, 98, 105, 115];
|
|
||||||
const OPUSTAGS: [u8; 8] = [79, 112, 117, 115, 84, 97, 103, 115];
|
|
||||||
|
|
||||||
struct VorbisInnerTag {
|
struct VorbisInnerTag {
|
||||||
format: Option<VorbisFormat>,
|
format: Option<OggFormat>,
|
||||||
vendor: String,
|
vendor: String,
|
||||||
comments: HashMap<String, String>,
|
comments: HashMap<String, String>,
|
||||||
pictures: Option<Cow<'static, [Picture]>>,
|
pictures: Option<Cow<'static, [Picture]>>,
|
||||||
|
@ -66,25 +69,25 @@ impl VorbisInnerTag {
|
||||||
self.comments = comments;
|
self.comments = comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_path<P>(path: P, format: &VorbisFormat) -> Result<Self>
|
fn read_from<R>(reader: &mut R, format: &OggFormat) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
match format {
|
match format {
|
||||||
VorbisFormat::Ogg => {
|
OggFormat::Vorbis => {
|
||||||
let tag = lewton::inside_ogg::OggStreamReader::new(File::open(path)?)?;
|
let tag = ogg_generic::read_from(reader, &VORBIS_IDENT_HEAD, &VORBIS_COMMENT_HEAD)?;
|
||||||
let vorbis_tag: VorbisTag = tag.try_into()?;
|
let vorbis_tag: VorbisTag = tag.try_into()?;
|
||||||
|
|
||||||
Ok(vorbis_tag.inner)
|
Ok(vorbis_tag.inner)
|
||||||
},
|
},
|
||||||
VorbisFormat::Opus => {
|
OggFormat::Opus => {
|
||||||
let tag = opus_headers::parse_from_path(path)?;
|
let tag = ogg_generic::read_from(reader, &OPUSHEAD, &OPUSTAGS)?;
|
||||||
let vorbis_tag: VorbisTag = tag.try_into()?;
|
let vorbis_tag: VorbisTag = tag.try_into()?;
|
||||||
|
|
||||||
Ok(vorbis_tag.inner)
|
Ok(vorbis_tag.inner)
|
||||||
},
|
},
|
||||||
VorbisFormat::Flac => {
|
OggFormat::Flac => {
|
||||||
let tag = metaflac::Tag::read_from_path(path)?;
|
let tag = metaflac::Tag::read_from(reader)?;
|
||||||
let vorbis_tag: VorbisTag = tag.try_into()?;
|
let vorbis_tag: VorbisTag = tag.try_into()?;
|
||||||
|
|
||||||
Ok(vorbis_tag.inner)
|
Ok(vorbis_tag.inner)
|
||||||
|
@ -93,12 +96,12 @@ impl VorbisInnerTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[impl_tag(VorbisInnerTag, TagType::Vorbis(VorbisFormat::Ogg))]
|
#[impl_tag(VorbisInnerTag, TagType::Ogg(OggFormat::Vorbis))]
|
||||||
pub struct VorbisTag;
|
pub struct VorbisTag;
|
||||||
|
|
||||||
#[cfg(feature = "format-vorbis")]
|
#[cfg(feature = "format-vorbis")]
|
||||||
impl TryFrom<lewton::inside_ogg::OggStreamReader<File>> for VorbisTag {
|
impl TryFrom<lewton::inside_ogg::OggStreamReader<File>> for VorbisTag {
|
||||||
type Error = crate::Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: OggStreamReader<File>) -> Result<Self> {
|
fn try_from(inp: OggStreamReader<File>) -> Result<Self> {
|
||||||
let mut tag = Self::default();
|
let mut tag = Self::default();
|
||||||
|
@ -118,7 +121,7 @@ impl TryFrom<lewton::inside_ogg::OggStreamReader<File>> for VorbisTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
tag.inner = VorbisInnerTag {
|
tag.inner = VorbisInnerTag {
|
||||||
format: Some(VorbisFormat::Ogg),
|
format: Some(OggFormat::Vorbis),
|
||||||
vendor: inp.comment_hdr.vendor,
|
vendor: inp.comment_hdr.vendor,
|
||||||
comments: comments.into_iter().collect(),
|
comments: comments.into_iter().collect(),
|
||||||
pictures: if pictures.is_empty() {
|
pictures: if pictures.is_empty() {
|
||||||
|
@ -133,28 +136,34 @@ impl TryFrom<lewton::inside_ogg::OggStreamReader<File>> for VorbisTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "format-opus")]
|
#[cfg(feature = "format-opus")]
|
||||||
impl TryFrom<opus_headers::OpusHeaders> for VorbisTag {
|
impl TryFrom<OGGTags> for VorbisTag {
|
||||||
type Error = crate::Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: OpusHeaders) -> Result<Self> {
|
fn try_from(inp: OGGTags) -> Result<Self> {
|
||||||
let mut tag = Self::default();
|
let mut tag = Self::default();
|
||||||
|
|
||||||
let mut comments = inp.comments.user_comments;
|
let read_pictures = inp.1;
|
||||||
|
let comments = inp.2;
|
||||||
|
|
||||||
// TODO: opus_headers doesn't store all keys
|
let mut pictures = Vec::new();
|
||||||
let mut pictures = None;
|
|
||||||
|
|
||||||
if let Some(data) = comments.remove("METADATA_BLOCK_PICTURE") {
|
if !read_pictures.is_empty() {
|
||||||
if let Ok(pic) = Picture::from_apic_bytes(&data.as_bytes()) {
|
for pic in read_pictures {
|
||||||
pictures = Some(Cow::from(vec![pic]))
|
if let Ok(pic) = Picture::from_apic_bytes(&pic.as_bytes()) {
|
||||||
|
pictures.push(pic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tag.inner = VorbisInnerTag {
|
tag.inner = VorbisInnerTag {
|
||||||
format: Some(VorbisFormat::Opus),
|
format: Some(inp.3),
|
||||||
vendor: inp.comments.vendor,
|
vendor: inp.0,
|
||||||
comments,
|
comments: comments.into_iter().collect(),
|
||||||
pictures,
|
pictures: if pictures.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Cow::from(pictures))
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(tag)
|
Ok(tag)
|
||||||
|
@ -163,7 +172,7 @@ impl TryFrom<opus_headers::OpusHeaders> for VorbisTag {
|
||||||
|
|
||||||
#[cfg(feature = "format-flac")]
|
#[cfg(feature = "format-flac")]
|
||||||
impl TryFrom<metaflac::Tag> for VorbisTag {
|
impl TryFrom<metaflac::Tag> for VorbisTag {
|
||||||
type Error = crate::Error;
|
type Error = LoftyError;
|
||||||
|
|
||||||
fn try_from(inp: metaflac::Tag) -> Result<Self> {
|
fn try_from(inp: metaflac::Tag) -> Result<Self> {
|
||||||
let mut tag = Self::default();
|
let mut tag = Self::default();
|
||||||
|
@ -194,7 +203,7 @@ impl TryFrom<metaflac::Tag> for VorbisTag {
|
||||||
comment_collection.into_iter().collect();
|
comment_collection.into_iter().collect();
|
||||||
|
|
||||||
tag.inner = VorbisInnerTag {
|
tag.inner = VorbisInnerTag {
|
||||||
format: Some(VorbisFormat::Flac),
|
format: Some(OggFormat::Flac),
|
||||||
vendor: comments.vendor_string,
|
vendor: comments.vendor_string,
|
||||||
comments: comment_collection,
|
comments: comment_collection,
|
||||||
pictures: Some(Cow::from(pictures)),
|
pictures: Some(Cow::from(pictures)),
|
||||||
|
@ -203,19 +212,19 @@ impl TryFrom<metaflac::Tag> for VorbisTag {
|
||||||
return Ok(tag);
|
return Ok(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::InvalidData)
|
Err(LoftyError::InvalidData("Flac file contains invalid data"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VorbisTag {
|
impl VorbisTag {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::missing_errors_doc)]
|
#[allow(clippy::missing_errors_doc)]
|
||||||
pub fn read_from_path<P>(path: P, format: &VorbisFormat) -> Result<Self>
|
pub fn read_from<R>(reader: &mut R, format: &OggFormat) -> Result<Self>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: VorbisInnerTag::from_path(path, &format)?,
|
inner: VorbisInnerTag::read_from(reader, format)?,
|
||||||
#[cfg(feature = "duration")]
|
#[cfg(feature = "duration")]
|
||||||
duration: None,
|
duration: None,
|
||||||
})
|
})
|
||||||
|
@ -314,10 +323,10 @@ impl AudioTagEdit for VorbisTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_front_cover(&mut self, cover: Picture) {
|
fn set_front_cover(&mut self, cover: Picture) {
|
||||||
|
if let Some(pic) = create_cover(&cover) {
|
||||||
self.remove_front_cover();
|
self.remove_front_cover();
|
||||||
|
self.inner.pictures = Some(replace_pic(pic, &self.inner.pictures))
|
||||||
let pictures = create_cover(&cover, &self.inner.pictures);
|
}
|
||||||
self.inner.pictures = pictures
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_front_cover(&mut self) {
|
fn remove_front_cover(&mut self) {
|
||||||
|
@ -333,10 +342,10 @@ impl AudioTagEdit for VorbisTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_back_cover(&mut self, cover: Picture) {
|
fn set_back_cover(&mut self, cover: Picture) {
|
||||||
self.remove_front_cover();
|
if let Some(pic) = create_cover(&cover) {
|
||||||
|
self.remove_back_cover();
|
||||||
let pictures = create_cover(&cover, &self.inner.pictures);
|
self.inner.pictures = Some(replace_pic(pic, &self.inner.pictures))
|
||||||
self.inner.pictures = pictures
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_back_cover(&mut self) {
|
fn remove_back_cover(&mut self) {
|
||||||
|
@ -425,39 +434,56 @@ fn get_cover(p_type: PictureType, pictures: &Option<Cow<'static, [Picture]>>) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_cover(
|
fn create_cover(cover: &Picture) -> Option<Picture> {
|
||||||
cover: &Picture,
|
|
||||||
pictures: &Option<Cow<'static, [Picture]>>,
|
|
||||||
) -> Option<Cow<'static, [Picture]>> {
|
|
||||||
if cover.pic_type == PictureType::CoverFront || cover.pic_type == PictureType::CoverBack {
|
if cover.pic_type == PictureType::CoverFront || cover.pic_type == PictureType::CoverBack {
|
||||||
if let Ok(pic) = Picture::from_apic_bytes(&cover.as_apic_bytes()) {
|
if let Ok(pic) = Picture::from_apic_bytes(&cover.as_apic_bytes()) {
|
||||||
if let Some(pictures) = pictures {
|
return Some(pic);
|
||||||
let mut pictures = pictures.to_vec();
|
|
||||||
pictures.retain(|p| p.pic_type != PictureType::CoverBack);
|
|
||||||
|
|
||||||
pictures.push(pic);
|
|
||||||
return Some(Cow::from(pictures));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(Cow::from(vec![pic]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replace_pic(
|
||||||
|
pic: Picture,
|
||||||
|
pictures: &Option<Cow<'static, [Picture]>>,
|
||||||
|
) -> Cow<'static, [Picture]> {
|
||||||
|
if let Some(pictures) = pictures {
|
||||||
|
let mut pictures = pictures.to_vec();
|
||||||
|
pictures.retain(|p| p.pic_type != pic.pic_type);
|
||||||
|
|
||||||
|
pictures.push(pic);
|
||||||
|
|
||||||
|
Cow::from(pictures)
|
||||||
|
} else {
|
||||||
|
Cow::from(vec![pic])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AudioTagWrite for VorbisTag {
|
impl AudioTagWrite for VorbisTag {
|
||||||
fn write_to(&self, file: &mut File) -> Result<()> {
|
fn write_to(&self, file: &mut File) -> Result<()> {
|
||||||
if let Some(format) = self.inner.format.clone() {
|
if let Some(format) = self.inner.format.clone() {
|
||||||
match format {
|
match format {
|
||||||
VorbisFormat::Ogg => {
|
OggFormat::Vorbis => {
|
||||||
vorbis_generic(file, &VORBIS, &self.inner.vendor, &self.inner.comments)?;
|
ogg_generic::create_pages(
|
||||||
|
file,
|
||||||
|
&VORBIS_COMMENT_HEAD,
|
||||||
|
&self.inner.vendor,
|
||||||
|
&self.inner.comments,
|
||||||
|
&self.inner.pictures,
|
||||||
|
)?;
|
||||||
},
|
},
|
||||||
VorbisFormat::Opus => {
|
OggFormat::Opus => {
|
||||||
vorbis_generic(file, &OPUSTAGS, &self.inner.vendor, &self.inner.comments)?;
|
ogg_generic::create_pages(
|
||||||
|
file,
|
||||||
|
&OPUSTAGS,
|
||||||
|
&self.inner.vendor,
|
||||||
|
&self.inner.comments,
|
||||||
|
&self.inner.pictures,
|
||||||
|
)?;
|
||||||
},
|
},
|
||||||
VorbisFormat::Flac => {
|
OggFormat::Flac => {
|
||||||
crate::components::logic::write::flac(
|
flac::write_to(
|
||||||
file,
|
file,
|
||||||
&self.inner.vendor,
|
&self.inner.vendor,
|
||||||
&self.inner.comments,
|
&self.inner.comments,
|
||||||
|
|
Loading…
Reference in a new issue