mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-14 22:52:32 +00:00
Restructure project
This commit is contained in:
parent
e61f63e63b
commit
8f2f7ba484
91 changed files with 390 additions and 421 deletions
|
@ -1,21 +1,32 @@
|
||||||
|
//! APE specific items
|
||||||
|
//!
|
||||||
|
//! ## File notes
|
||||||
|
//!
|
||||||
|
//! It is possible for an `APE` file to contain an `ID3v2` tag. For the sake of data preservation,
|
||||||
|
//! this tag will be read, but **cannot** be written. The only tags allowed by spec are `APEv1/2` and
|
||||||
|
//! `ID3v1`.
|
||||||
mod constants;
|
mod constants;
|
||||||
pub(crate) mod properties;
|
mod properties;
|
||||||
pub(crate) mod read;
|
mod read;
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
pub(crate) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub use crate::ape::properties::ApeProperties;
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
|
pub use {
|
||||||
|
crate::types::picture::APE_PICTURE_TYPES,
|
||||||
|
tag::{ape_tag::ApeTag, item::ApeItem},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::logic::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::tag_methods;
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
use properties::ApeProperties;
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
use tag::ape_tag::ApeTag;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
|
@ -2,13 +2,13 @@ use super::constants::APE_PREAMBLE;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use super::tag::{ape_tag::ApeTag, read::read_ape_tag};
|
use super::tag::{ape_tag::ApeTag, read::read_ape_tag};
|
||||||
use super::{ApeFile, ApeProperties};
|
use super::{ApeFile, ApeProperties};
|
||||||
|
use crate::ape::tag::read_ape_header;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ape::tag::read_ape_header;
|
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::logic::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::{read::parse_id3v2, tag::Id3v2Tag};
|
use crate::id3::v2::{read::parse_id3v2, tag::Id3v2Tag};
|
||||||
use crate::logic::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
|
use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::ape::tag::item::{ApeItem, ApeItemRef};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::ape::tag::item::{ApeItem, ApeItemRef};
|
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
use crate::types::tag::{Accessor, Tag, TagType};
|
use crate::types::tag::{Accessor, Tag, TagType};
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ impl From<Tag> for ApeTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) struct ApeTagRef<'a> {
|
pub(crate) struct ApeTagRef<'a> {
|
||||||
pub(crate) read_only: bool,
|
pub(crate) read_only: bool,
|
||||||
pub(super) items: Box<dyn Iterator<Item = ApeItemRef<'a>> + 'a>,
|
pub(super) items: Box<dyn Iterator<Item = ApeItemRef<'a>> + 'a>,
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ mod tests {
|
||||||
use crate::ape::{ApeItem, ApeTag};
|
use crate::ape::{ApeItem, ApeTag};
|
||||||
use crate::{ItemValue, Tag, TagType};
|
use crate::{ItemValue, Tag, TagType};
|
||||||
|
|
||||||
use crate::logic::ape::tag::read_ape_header;
|
use crate::ape::tag::read_ape_header;
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -300,7 +300,7 @@ mod tests {
|
||||||
let mut reader = Cursor::new(tag);
|
let mut reader = Cursor::new(tag);
|
||||||
|
|
||||||
let header = read_ape_header(&mut reader, false).unwrap();
|
let header = read_ape_header(&mut reader, false).unwrap();
|
||||||
let parsed_tag = crate::logic::ape::tag::read::read_ape_tag(&mut reader, header).unwrap();
|
let parsed_tag = crate::ape::tag::read::read_ape_tag(&mut reader, header).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_tag.items().len(), parsed_tag.items().len());
|
assert_eq!(expected_tag.items().len(), parsed_tag.items().len());
|
||||||
|
|
||||||
|
@ -321,11 +321,11 @@ mod tests {
|
||||||
let mut reader = Cursor::new(tag_bytes);
|
let mut reader = Cursor::new(tag_bytes);
|
||||||
|
|
||||||
let header = read_ape_header(&mut reader, false).unwrap();
|
let header = read_ape_header(&mut reader, false).unwrap();
|
||||||
let ape = crate::logic::ape::tag::read::read_ape_tag(&mut reader, header).unwrap();
|
let ape = crate::ape::tag::read::read_ape_tag(&mut reader, header).unwrap();
|
||||||
|
|
||||||
let tag: Tag = ape.into();
|
let tag: Tag = ape.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, true, true);
|
crate::tag_utils::test_utils::verify_tag(&tag, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -337,7 +337,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::Ape);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::Ape);
|
||||||
|
|
||||||
let ape_tag: ApeTag = tag.into();
|
let ape_tag: ApeTag = tag.into();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::ape::constants::INVALID_KEYS;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ape::constants::INVALID_KEYS;
|
|
||||||
use crate::types::item::{ItemValue, ItemValueRef, TagItem};
|
use crate::types::item::{ItemValue, ItemValueRef, TagItem};
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ impl TryFrom<TagItem> for ApeItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) struct ApeItemRef<'a> {
|
pub(crate) struct ApeItemRef<'a> {
|
||||||
pub read_only: bool,
|
pub read_only: bool,
|
||||||
pub key: &'a str,
|
pub key: &'a str,
|
||||||
pub value: ItemValueRef<'a>,
|
pub value: ItemValueRef<'a>,
|
|
@ -3,9 +3,9 @@ pub(crate) mod ape_tag;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
pub(crate) mod item;
|
pub(crate) mod item;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
pub(in crate::logic) mod read;
|
pub(crate) mod read;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
pub(in crate::logic) mod write;
|
mod write;
|
||||||
|
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{ape_tag::ApeTag, item::ApeItem, ApeHeader};
|
use super::{ape_tag::ApeTag, item::ApeItem, ApeHeader};
|
||||||
|
use crate::ape::constants::INVALID_KEYS;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ape::constants::INVALID_KEYS;
|
|
||||||
use crate::types::item::ItemValue;
|
use crate::types::item::ItemValue;
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
|
@ -1,8 +1,8 @@
|
||||||
use super::read::read_ape_tag;
|
use super::read::read_ape_tag;
|
||||||
|
use crate::ape::constants::APE_PREAMBLE;
|
||||||
|
use crate::ape::tag::ape_tag::ApeTagRef;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ape::constants::APE_PREAMBLE;
|
use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
|
||||||
use crate::logic::ape::tag::ape_tag::ApeTagRef;
|
|
||||||
use crate::logic::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
|
|
||||||
use crate::probe::Probe;
|
use crate::probe::Probe;
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
use crate::types::item::ItemValueRef;
|
use crate::types::item::ItemValueRef;
|
||||||
|
@ -10,11 +10,11 @@ use crate::types::item::ItemValueRef;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use crate::logic::ape::tag::read_ape_header;
|
use crate::ape::tag::read_ape_header;
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
#[allow(clippy::shadow_unrelated)]
|
#[allow(clippy::shadow_unrelated)]
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &mut ApeTagRef) -> Result<()> {
|
pub(crate) fn write_to(data: &mut File, tag: &mut ApeTagRef) -> Result<()> {
|
||||||
let probe = Probe::new(data).guess_file_type()?;
|
let probe = Probe::new(data).guess_file_type()?;
|
||||||
|
|
||||||
match probe.file_type() {
|
match probe.file_type() {
|
|
@ -1,15 +1,15 @@
|
||||||
use crate::error::{LoftyError, Result};
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use crate::logic::ape::tag::ape_tag::ApeTagRef;
|
use crate::ape::tag::ape_tag::ApeTagRef;
|
||||||
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::logic::id3::v1::tag::Id3v1TagRef;
|
use crate::id3::v1::tag::Id3v1TagRef;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &Tag) -> Result<()> {
|
pub(crate) fn write_to(data: &mut File, tag: &Tag) -> Result<()> {
|
||||||
match tag.tag_type() {
|
match tag.tag_type() {
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
TagType::Ape => Into::<ApeTagRef>::into(tag).write_to(data),
|
TagType::Ape => Into::<ApeTagRef>::into(tag).write_to(data),
|
|
@ -1,7 +1,8 @@
|
||||||
use ogg_pager::PageError;
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
/// Result of tag operations
|
use ogg_pager::PageError;
|
||||||
|
|
||||||
|
/// Alias for `Result<T, LoftyError>`
|
||||||
pub type Result<T> = std::result::Result<T, LoftyError>;
|
pub type Result<T> = std::result::Result<T, LoftyError>;
|
||||||
|
|
||||||
/// Errors that could occur within Lofty
|
/// Errors that could occur within Lofty
|
||||||
|
@ -21,7 +22,7 @@ pub enum LoftyError {
|
||||||
|
|
||||||
// Picture related errors
|
// Picture related errors
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
/// Arises when an invalid picture format is parsed. Only applicable to [`Id3v2Version::V2`](crate::logic::id3::v2::Id3v2Version)
|
/// Arises when an invalid picture format is parsed. Only applicable to [`Id3v2Version::V2`](crate::id3::v2::Id3v2Version)
|
||||||
BadPictureFormat(String),
|
BadPictureFormat(String),
|
||||||
/// Provided an invalid picture
|
/// Provided an invalid picture
|
||||||
NotAPicture,
|
NotAPicture,
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
//! ID3 specific items
|
||||||
|
//!
|
||||||
|
//! ID3 does things differently than other tags, making working with them a little more effort than other formats.
|
||||||
|
//! Check the other modules for important notes and/or warnings.
|
||||||
|
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
pub(crate) mod v1;
|
pub mod v1;
|
||||||
pub(crate) mod v2;
|
pub mod v2;
|
||||||
|
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use v2::{read_id3v2_header, Id3v2Header};
|
use v2::{read_id3v2_header, Id3v2Header};
|
||||||
|
@ -37,10 +42,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
pub(in crate::logic) fn find_id3v1<R>(
|
pub(crate) fn find_id3v1<R>(data: &mut R, read: bool) -> Result<(bool, Option<v1::tag::Id3v1Tag>)>
|
||||||
data: &mut R,
|
|
||||||
read: bool,
|
|
||||||
) -> Result<(bool, Option<v1::tag::Id3v1Tag>)>
|
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
|
@ -74,7 +76,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "id3v1"))]
|
#[cfg(not(feature = "id3v1"))]
|
||||||
pub(in crate::logic) fn find_id3v1<R>(data: &mut R, _read: bool) -> Result<(bool, Option<()>)>
|
pub(in crate::tag_utils) fn find_id3v1<R>(data: &mut R, _read: bool) -> Result<(bool, Option<()>)>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
23
src/id3/v1/mod.rs
Normal file
23
src/id3/v1/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//! ID3v1 items
|
||||||
|
//!
|
||||||
|
//! # ID3v1 notes
|
||||||
|
//!
|
||||||
|
//! See also: [Id3v1Tag]
|
||||||
|
//!
|
||||||
|
//! ## Genres
|
||||||
|
//!
|
||||||
|
//! ID3v1 stores the genre in a single byte ranging from 0 to 192 (inclusive).
|
||||||
|
//! All possible genres have been stored in the [`GENRES`] constant.
|
||||||
|
//!
|
||||||
|
//! ## Track Numbers
|
||||||
|
//!
|
||||||
|
//! ID3v1 stores the track number in a non-zero byte.
|
||||||
|
//! A track number of 0 will be treated as an empty field.
|
||||||
|
//! Additionally, there is no track total field.
|
||||||
|
pub(crate) mod constants;
|
||||||
|
pub(crate) mod read;
|
||||||
|
pub(crate) mod tag;
|
||||||
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub use crate::id3::v1::constants::GENRES;
|
||||||
|
pub use crate::id3::v1::tag::Id3v1Tag;
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::id3::v1::constants::GENRES;
|
use crate::id3::v1::constants::GENRES;
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
use crate::types::tag::{Accessor, Tag, TagType};
|
use crate::types::tag::{Accessor, Tag, TagType};
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ impl From<Tag> for Id3v1Tag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) struct Id3v1TagRef<'a> {
|
pub(crate) struct Id3v1TagRef<'a> {
|
||||||
pub title: Option<&'a str>,
|
pub title: Option<&'a str>,
|
||||||
pub artist: Option<&'a str>,
|
pub artist: Option<&'a str>,
|
||||||
pub album: Option<&'a str>,
|
pub album: Option<&'a str>,
|
||||||
|
@ -263,7 +263,7 @@ mod tests {
|
||||||
.read_exact(&mut tag)
|
.read_exact(&mut tag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let parsed_tag = crate::logic::id3::v1::read::parse_id3v1(tag);
|
let parsed_tag = crate::id3::v1::read::parse_id3v1(tag);
|
||||||
|
|
||||||
assert_eq!(expected_tag, parsed_tag);
|
assert_eq!(expected_tag, parsed_tag);
|
||||||
}
|
}
|
||||||
|
@ -276,16 +276,16 @@ mod tests {
|
||||||
.read_exact(&mut tag_bytes)
|
.read_exact(&mut tag_bytes)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let id3v1 = crate::logic::id3::v1::read::parse_id3v1(tag_bytes);
|
let id3v1 = crate::id3::v1::read::parse_id3v1(tag_bytes);
|
||||||
|
|
||||||
let tag: Tag = id3v1.into();
|
let tag: Tag = id3v1.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, true, true);
|
crate::tag_utils::test_utils::verify_tag(&tag, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_to_id3v1() {
|
fn tag_to_id3v1() {
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::Id3v1);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::Id3v1);
|
||||||
|
|
||||||
let id3v1_tag: Id3v1Tag = tag.into();
|
let id3v1_tag: Id3v1Tag = tag.into();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::tag::Id3v1TagRef;
|
use super::tag::Id3v1TagRef;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::find_id3v1;
|
use crate::id3::find_id3v1;
|
||||||
use crate::probe::Probe;
|
use crate::probe::Probe;
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use byteorder::WriteBytesExt;
|
use byteorder::WriteBytesExt;
|
||||||
|
|
||||||
#[allow(clippy::shadow_unrelated)]
|
#[allow(clippy::shadow_unrelated)]
|
||||||
pub(in crate::logic) fn write_id3v1(writer: &mut File, tag: &Id3v1TagRef) -> Result<()> {
|
pub(crate) fn write_id3v1(writer: &mut File, tag: &Id3v1TagRef) -> Result<()> {
|
||||||
let probe = Probe::new(writer).guess_file_type()?;
|
let probe = Probe::new(writer).guess_file_type()?;
|
||||||
|
|
||||||
match probe.file_type() {
|
match probe.file_type() {
|
|
@ -1,14 +1,14 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::frame::{EncodedTextFrame, FrameValue, LanguageFrame};
|
use crate::id3::v2::frame::{EncodedTextFrame, FrameValue, LanguageFrame};
|
||||||
use crate::logic::id3::v2::util::text_utils::{decode_text, TextEncoding};
|
use crate::id3::v2::util::text_utils::{decode_text, TextEncoding};
|
||||||
use crate::logic::id3::v2::Id3v2Version;
|
use crate::id3::v2::Id3v2Version;
|
||||||
use crate::types::picture::Picture;
|
use crate::types::picture::Picture;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
|
||||||
pub(crate) fn parse_content(
|
pub(super) fn parse_content(
|
||||||
content: &mut &[u8],
|
content: &mut &[u8],
|
||||||
id: &str,
|
id: &str,
|
||||||
version: Id3v2Version,
|
version: Id3v2Version,
|
|
@ -1,7 +1,7 @@
|
||||||
use super::FrameFlags;
|
use super::FrameFlags;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
use crate::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
|
||||||
use crate::id3::v2::FrameID;
|
use crate::id3::v2::FrameID;
|
||||||
use crate::logic::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
|
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ where
|
||||||
let id_str = std::str::from_utf8(&frame_header[..4]).map_err(|_| LoftyError::BadFrameID)?;
|
let id_str = std::str::from_utf8(&frame_header[..4]).map_err(|_| LoftyError::BadFrameID)?;
|
||||||
|
|
||||||
let (id, size) = if synchsafe {
|
let (id, size) = if synchsafe {
|
||||||
let size = crate::logic::id3::v2::unsynch_u32(u32::from_be_bytes([
|
let size = crate::id3::v2::unsynch_u32(u32::from_be_bytes([
|
||||||
frame_header[4],
|
frame_header[4],
|
||||||
frame_header[5],
|
frame_header[5],
|
||||||
frame_header[6],
|
frame_header[6],
|
|
@ -1,11 +1,11 @@
|
||||||
pub(in crate::logic::id3::v2) mod content;
|
mod content;
|
||||||
mod header;
|
mod header;
|
||||||
pub(in crate::logic::id3::v2) mod read;
|
pub(super) mod read;
|
||||||
|
|
||||||
use super::util::text_utils::TextEncoding;
|
use super::util::text_utils::TextEncoding;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::util::text_utils::encode_text;
|
use crate::id3::v2::util::text_utils::encode_text;
|
||||||
use crate::logic::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
|
use crate::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
use crate::types::picture::Picture;
|
use crate::types::picture::Picture;
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
|
@ -1,9 +1,9 @@
|
||||||
use super::header::{parse_header, parse_v2_header};
|
use super::header::{parse_header, parse_v2_header};
|
||||||
use super::Frame;
|
use super::Frame;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
use crate::id3::v2::frame::content::parse_content;
|
||||||
use crate::id3::v2::FrameValue;
|
use crate::id3::v2::FrameValue;
|
||||||
use crate::logic::id3::v2::frame::content::parse_content;
|
use crate::id3::v2::Id3v2Version;
|
||||||
use crate::logic::id3::v2::Id3v2Version;
|
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ impl Frame {
|
||||||
reader.read_exact(&mut content)?;
|
reader.read_exact(&mut content)?;
|
||||||
|
|
||||||
if flags.unsynchronisation {
|
if flags.unsynchronisation {
|
||||||
content = crate::logic::id3::v2::util::unsynch_content(content.as_slice())?;
|
content = crate::id3::v2::util::unsynch_content(content.as_slice())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.compression {
|
if flags.compression {
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::util::text_utils::{decode_text, encode_text, TextEncoding};
|
use crate::id3::v2::util::text_utils::{decode_text, encode_text, TextEncoding};
|
||||||
|
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
|
|
4
src/id3/v2/items/mod.rs
Normal file
4
src/id3/v2/items/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub(super) mod encapsulated_object;
|
||||||
|
#[cfg(feature = "id3v2_restrictions")]
|
||||||
|
pub(super) mod restrictions;
|
||||||
|
pub(super) mod sync_text;
|
|
@ -3,8 +3,8 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::util::text_utils;
|
use crate::id3::v2::util::text_utils;
|
||||||
use crate::logic::id3::v2::util::text_utils::{
|
use crate::id3::v2::util::text_utils::{
|
||||||
decode_text, encode_text, read_to_terminator, utf16_decode, TextEncoding,
|
decode_text, encode_text, read_to_terminator, utf16_decode, TextEncoding,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,20 +1,48 @@
|
||||||
pub(crate) mod flags;
|
//! ID3v2 items and utilities
|
||||||
|
//!
|
||||||
|
//! ## Important notes
|
||||||
|
//!
|
||||||
|
//! See:
|
||||||
|
//!
|
||||||
|
//! * [Id3v2Tag]
|
||||||
|
//! * [Frame]
|
||||||
|
mod flags;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(crate) mod frame;
|
mod frame;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(crate) mod items;
|
mod items;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(crate) mod read;
|
pub(crate) mod read;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
pub use frame::{EncodedTextFrame, Frame, FrameFlags, FrameID, FrameValue, LanguageFrame};
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
pub use items::{
|
||||||
|
encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject},
|
||||||
|
sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
pub use tag::Id3v2Tag;
|
||||||
|
pub use util::text_utils::TextEncoding;
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
pub use util::upgrade::{upgrade_v2, upgrade_v3};
|
||||||
|
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
pub use flags::Id3v2TagFlags;
|
||||||
|
#[cfg(not(feature = "id3v2"))]
|
||||||
|
use flags::Id3v2TagFlags;
|
||||||
|
|
||||||
|
#[cfg(feature = "id3v2_restrictions")]
|
||||||
|
pub use crate::id3::v2::items::restrictions::*;
|
||||||
|
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
#[cfg(feature = "id3v2_restrictions")]
|
||||||
use crate::logic::id3::v2::items::restrictions::TagRestrictions;
|
use crate::id3::v2::items::restrictions::TagRestrictions;
|
||||||
use flags::Id3v2TagFlags;
|
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::frame::{Frame, FrameID, FrameValue};
|
||||||
use super::util::text_utils::TextEncoding;
|
use super::util::text_utils::TextEncoding;
|
||||||
use super::Id3v2Version;
|
use super::Id3v2Version;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::id3::v2::frame::FrameRef;
|
use crate::id3::v2::frame::FrameRef;
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
use crate::types::tag::{Accessor, Tag, TagType};
|
use crate::types::tag::{Accessor, Tag, TagType};
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ pub(crate) struct Id3v2TagRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Id3v2TagRef<'a> {
|
impl<'a> Id3v2TagRef<'a> {
|
||||||
pub(in crate::logic) fn write_to(&mut self, file: &mut File) -> Result<()> {
|
pub(crate) fn write_to(&mut self, file: &mut File) -> Result<()> {
|
||||||
super::write::write_id3v2(file, self)
|
super::write::write_id3v2(file, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ mod tests {
|
||||||
use crate::id3::v2::{Frame, FrameFlags, FrameValue, Id3v2Tag, LanguageFrame, TextEncoding};
|
use crate::id3::v2::{Frame, FrameFlags, FrameValue, Id3v2Tag, LanguageFrame, TextEncoding};
|
||||||
use crate::{Tag, TagType};
|
use crate::{Tag, TagType};
|
||||||
|
|
||||||
use crate::logic::id3::v2::read_id3v2_header;
|
use crate::id3::v2::read_id3v2_header;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -439,7 +439,7 @@ mod tests {
|
||||||
let mut reader = std::io::Cursor::new(&tag[..]);
|
let mut reader = std::io::Cursor::new(&tag[..]);
|
||||||
|
|
||||||
let header = read_id3v2_header(&mut reader).unwrap();
|
let header = read_id3v2_header(&mut reader).unwrap();
|
||||||
let parsed_tag = crate::logic::id3::v2::read::parse_id3v2(&mut reader, header).unwrap();
|
let parsed_tag = crate::id3::v2::read::parse_id3v2(&mut reader, header).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_tag, parsed_tag);
|
assert_eq!(expected_tag, parsed_tag);
|
||||||
}
|
}
|
||||||
|
@ -456,11 +456,11 @@ mod tests {
|
||||||
let mut reader = std::io::Cursor::new(&tag_bytes[..]);
|
let mut reader = std::io::Cursor::new(&tag_bytes[..]);
|
||||||
|
|
||||||
let header = read_id3v2_header(&mut reader).unwrap();
|
let header = read_id3v2_header(&mut reader).unwrap();
|
||||||
let id3v2 = crate::logic::id3::v2::read::parse_id3v2(&mut reader, header).unwrap();
|
let id3v2 = crate::id3::v2::read::parse_id3v2(&mut reader, header).unwrap();
|
||||||
|
|
||||||
let tag: Tag = id3v2.into();
|
let tag: Tag = id3v2.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, true, true);
|
crate::tag_utils::test_utils::verify_tag(&tag, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -481,7 +481,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::Id3v2);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::Id3v2);
|
||||||
|
|
||||||
let id3v2_tag: Id3v2Tag = tag.into();
|
let id3v2_tag: Id3v2Tag = tag.into();
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub(crate) mod upgrade;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
pub(crate) fn unsynch_content(content: &[u8]) -> Result<Vec<u8>> {
|
pub(in crate::id3::v2) fn unsynch_content(content: &[u8]) -> Result<Vec<u8>> {
|
||||||
let mut unsynch_content = Vec::new();
|
let mut unsynch_content = Vec::new();
|
||||||
|
|
||||||
let mut discard = false;
|
let mut discard = false;
|
|
@ -1,23 +1,39 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
macro_rules! gen_upgrades {
|
macro_rules! gen_upgrades {
|
||||||
(V2 => [$($($v2_key:tt)|* => $id3v24_from_v2:tt),+]; V3 => [$($($v3_key:tt)|* => $id3v24_from_v3:tt),+]) => {
|
(V2 => [$($($v2_key:literal)|* => $id3v24_from_v2:literal),+]; V3 => [$($($v3_key:literal)|* => $id3v24_from_v3:literal),+]) => {
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref V2KEYS: HashMap<&'static str, &'static str> = {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
map.insert($v2_key, $id3v24_from_v2);
|
||||||
|
)+
|
||||||
|
)+
|
||||||
|
map
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref V3KEYS: HashMap<&'static str, &'static str> = {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
$(
|
||||||
|
$(
|
||||||
|
map.insert($v3_key, $id3v24_from_v3);
|
||||||
|
)+
|
||||||
|
)+
|
||||||
|
map
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Upgrade an ID3v2.2 key to an ID3v2.4 key
|
/// Upgrade an ID3v2.2 key to an ID3v2.4 key
|
||||||
pub fn upgrade_v2(key: &str) -> Option<&'static str> {
|
pub fn upgrade_v2(key: &str) -> Option<&'static str> {
|
||||||
match key {
|
V2KEYS.get(key).map(|s| *s)
|
||||||
$(
|
|
||||||
$($v2_key)|* => Some($id3v24_from_v2),
|
|
||||||
)+
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upgrade an ID3v2.3 key to an ID3v2.4 key
|
/// Upgrade an ID3v2.3 key to an ID3v2.4 key
|
||||||
pub fn upgrade_v3(key: &str) -> Option<&'static str> {
|
pub fn upgrade_v3(key: &str) -> Option<&'static str> {
|
||||||
match key {
|
V3KEYS.get(key).map(|s| *s)
|
||||||
$(
|
|
||||||
$($v3_key)|* => Some($id3v24_from_v3),
|
|
||||||
)+
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use byteorder::{ByteOrder, WriteBytesExt};
|
use byteorder::{ByteOrder, WriteBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic::id3::v2) fn write_to_chunk_file<B>(data: &mut File, tag: &[u8]) -> Result<()>
|
pub(in crate::id3::v2) fn write_to_chunk_file<B>(data: &mut File, tag: &[u8]) -> Result<()>
|
||||||
where
|
where
|
||||||
B: ByteOrder,
|
B: ByteOrder,
|
||||||
{
|
{
|
|
@ -1,13 +1,13 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
use crate::id3::v2::frame::{FrameFlags, FrameRef, FrameValueRef};
|
||||||
|
use crate::id3::v2::synch_u32;
|
||||||
use crate::id3::v2::Id3v2Version;
|
use crate::id3::v2::Id3v2Version;
|
||||||
use crate::logic::id3::v2::frame::{FrameFlags, FrameRef, FrameValueRef};
|
|
||||||
use crate::logic::id3::v2::synch_u32;
|
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic::id3::v2) fn create_items<'a, W>(
|
pub(in crate::id3::v2) fn create_items<'a, W>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
frames: &mut dyn Iterator<Item = FrameRef<'a>>,
|
frames: &mut dyn Iterator<Item = FrameRef<'a>>,
|
||||||
) -> Result<()>
|
) -> Result<()>
|
|
@ -3,8 +3,8 @@ mod frame;
|
||||||
|
|
||||||
use super::Id3v2TagFlags;
|
use super::Id3v2TagFlags;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::tag::Id3v2TagRef;
|
use crate::id3::v2::tag::Id3v2TagRef;
|
||||||
use crate::logic::id3::{find_id3v2, v2::synch_u32};
|
use crate::id3::{find_id3v2, v2::synch_u32};
|
||||||
use crate::probe::Probe;
|
use crate::probe::Probe;
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use byteorder::{BigEndian, ByteOrder, LittleEndian, WriteBytesExt};
|
use byteorder::{BigEndian, ByteOrder, LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
#[allow(clippy::shadow_unrelated)]
|
#[allow(clippy::shadow_unrelated)]
|
||||||
pub(in crate::logic) fn write_id3v2(data: &mut File, tag: &mut Id3v2TagRef) -> Result<()> {
|
pub(crate) fn write_id3v2(data: &mut File, tag: &mut Id3v2TagRef) -> Result<()> {
|
||||||
let probe = Probe::new(data).guess_file_type()?;
|
let probe = Probe::new(data).guess_file_type()?;
|
||||||
|
|
||||||
match probe.file_type() {
|
match probe.file_type() {
|
||||||
|
@ -48,10 +48,7 @@ pub(in crate::logic) fn write_id3v2(data: &mut File, tag: &mut Id3v2TagRef) -> R
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats such as WAV and AIFF store the ID3v2 tag in an 'ID3 ' chunk rather than at the beginning of the file
|
// Formats such as WAV and AIFF store the ID3v2 tag in an 'ID3 ' chunk rather than at the beginning of the file
|
||||||
pub(in crate::logic) fn write_id3v2_to_chunk_file<B>(
|
fn write_id3v2_to_chunk_file<B>(data: &mut File, tag: &mut Id3v2TagRef) -> Result<()>
|
||||||
data: &mut File,
|
|
||||||
tag: &mut Id3v2TagRef,
|
|
||||||
) -> Result<()>
|
|
||||||
where
|
where
|
||||||
B: ByteOrder,
|
B: ByteOrder,
|
||||||
{
|
{
|
|
@ -2,12 +2,12 @@ mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
#[cfg(feature = "aiff_text_chunks")]
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::tag_methods;
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
|
@ -3,15 +3,15 @@ use super::tag::AiffTextChunks;
|
||||||
use super::AiffFile;
|
use super::AiffFile;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
use byteorder::BigEndian;
|
use byteorder::BigEndian;
|
||||||
|
|
||||||
pub(in crate::logic::iff) fn verify_aiff<R>(data: &mut R) -> Result<()>
|
pub(in crate::iff) fn verify_aiff<R>(data: &mut R) -> Result<()>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) fn read_from<R>(data: &mut R, read_properties: bool) -> Result<AiffFile>
|
pub(crate) fn read_from<R>(data: &mut R, read_properties: bool) -> Result<AiffFile>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
use crate::types::tag::{Accessor, Tag, TagType};
|
use crate::types::tag::{Accessor, Tag, TagType};
|
||||||
|
|
||||||
|
@ -146,12 +146,12 @@ impl<'a> Into<AiffTextChunksRef<'a>> for &'a Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AiffTextChunksRef<'a> {
|
impl<'a> AiffTextChunksRef<'a> {
|
||||||
pub(in crate::logic) fn write_to(&self, file: &mut File) -> Result<()> {
|
pub(crate) fn write_to(&self, file: &mut File) -> Result<()> {
|
||||||
write_to(file, self)
|
write_to(file, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &AiffTextChunksRef) -> Result<()> {
|
pub(crate) fn write_to(data: &mut File, tag: &AiffTextChunksRef) -> Result<()> {
|
||||||
fn write_chunk(writer: &mut Vec<u8>, key: &str, value: Option<&str>) {
|
fn write_chunk(writer: &mut Vec<u8>, key: &str, value: Option<&str>) {
|
||||||
if let Some(val) = value {
|
if let Some(val) = value {
|
||||||
if let Ok(len) = u32::try_from(val.len()) {
|
if let Ok(len) = u32::try_from(val.len()) {
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2TagRef;
|
use crate::id3::v2::tag::Id3v2TagRef;
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
#[cfg(feature = "aiff_text_chunks")]
|
||||||
use crate::logic::iff::aiff::tag::AiffTextChunksRef;
|
use crate::iff::aiff::tag::AiffTextChunksRef;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::read::parse_id3v2;
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::logic::id3::v2::read_id3v2_header;
|
use crate::id3::v2::read_id3v2_header;
|
||||||
use byteorder::{ByteOrder, ReadBytesExt};
|
use byteorder::{ByteOrder, ReadBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic) struct Chunks<B>
|
pub(crate) struct Chunks<B>
|
||||||
where
|
where
|
||||||
B: ByteOrder,
|
B: ByteOrder,
|
||||||
{
|
{
|
13
src/iff/mod.rs
Normal file
13
src/iff/mod.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//! WAV/AIFF specific items
|
||||||
|
pub(crate) mod aiff;
|
||||||
|
pub(crate) mod chunk;
|
||||||
|
pub(crate) mod wav;
|
||||||
|
|
||||||
|
pub use crate::iff::aiff::AiffFile;
|
||||||
|
pub use crate::iff::wav::WavFile;
|
||||||
|
|
||||||
|
#[cfg(feature = "aiff_text_chunks")]
|
||||||
|
pub use crate::iff::aiff::tag::AiffTextChunks;
|
||||||
|
#[cfg(feature = "riff_info_list")]
|
||||||
|
pub use crate::iff::wav::tag::RiffInfoList;
|
||||||
|
pub use wav::{WavFormat, WavProperties};
|
|
@ -1,17 +1,18 @@
|
||||||
pub(crate) mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
#[cfg(feature = "riff_info_list")]
|
#[cfg(feature = "riff_info_list")]
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub use crate::iff::wav::properties::{WavFormat, WavProperties};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::tag_methods;
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
use properties::WavProperties;
|
|
||||||
#[cfg(feature = "riff_info_list")]
|
#[cfg(feature = "riff_info_list")]
|
||||||
use tag::RiffInfoList;
|
use tag::RiffInfoList;
|
||||||
|
|
|
@ -4,14 +4,14 @@ use super::tag::RiffInfoList;
|
||||||
use super::WavFile;
|
use super::WavFile;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic::iff) fn verify_wav<T>(data: &mut T) -> Result<()>
|
pub(in crate::iff) fn verify_wav<T>(data: &mut T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) fn read_from<R>(data: &mut R, read_properties: bool) -> Result<WavFile>
|
pub(crate) fn read_from<R>(data: &mut R, read_properties: bool) -> Result<WavFile>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
|
@ -1,5 +1,5 @@
|
||||||
pub(in crate::logic::iff::wav) mod read;
|
pub(super) mod read;
|
||||||
pub(in crate::logic::iff::wav) mod write;
|
mod write;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
|
@ -243,12 +243,12 @@ mod tests {
|
||||||
|
|
||||||
let tag: Tag = riff_info.into();
|
let tag: Tag = riff_info.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, true, false);
|
crate::tag_utils::test_utils::verify_tag(&tag, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_to_riff_info() {
|
fn tag_to_riff_info() {
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::RiffInfo);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::RiffInfo);
|
||||||
|
|
||||||
let riff_info: RiffInfoList = tag.into();
|
let riff_info: RiffInfoList = tag.into();
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use super::RiffInfoList;
|
use super::RiffInfoList;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
use byteorder::LittleEndian;
|
use byteorder::LittleEndian;
|
||||||
|
|
||||||
pub(in crate::logic::iff::wav) fn parse_riff_info<R>(
|
pub(in crate::iff::wav) fn parse_riff_info<R>(
|
||||||
data: &mut R,
|
data: &mut R,
|
||||||
end: u64,
|
end: u64,
|
||||||
tag: &mut RiffInfoList,
|
tag: &mut RiffInfoList,
|
|
@ -1,14 +1,14 @@
|
||||||
use super::RiffInfoListRef;
|
use super::RiffInfoListRef;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
use crate::logic::iff::wav::read::verify_wav;
|
use crate::iff::wav::read::verify_wav;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic::iff::wav) fn write_riff_info(
|
pub(in crate::iff::wav) fn write_riff_info(
|
||||||
data: &mut File,
|
data: &mut File,
|
||||||
tag: &mut RiffInfoListRef,
|
tag: &mut RiffInfoListRef,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2TagRef;
|
use crate::id3::v2::tag::Id3v2TagRef;
|
||||||
#[cfg(feature = "riff_info_list")]
|
#[cfg(feature = "riff_info_list")]
|
||||||
use crate::logic::iff::wav::tag::RiffInfoListRef;
|
use crate::iff::wav::tag::RiffInfoListRef;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
138
src/lib.rs
138
src/lib.rs
|
@ -150,9 +150,15 @@
|
||||||
clippy::single_match_else
|
clippy::single_match_else
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
pub mod ape;
|
||||||
mod error;
|
mod error;
|
||||||
pub(crate) mod logic;
|
pub mod id3;
|
||||||
|
pub mod iff;
|
||||||
|
pub mod mp3;
|
||||||
|
pub mod mp4;
|
||||||
|
pub mod ogg;
|
||||||
mod probe;
|
mod probe;
|
||||||
|
pub(crate) mod tag_utils;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use crate::error::{LoftyError, Result};
|
pub use crate::error::{LoftyError, Result};
|
||||||
|
@ -174,133 +180,3 @@ pub use crate::types::picture::{MimeType, Picture, PictureType};
|
||||||
pub use crate::types::picture::PictureInformation;
|
pub use crate::types::picture::PictureInformation;
|
||||||
|
|
||||||
pub use probe::{read_from, read_from_path};
|
pub use probe::{read_from, read_from_path};
|
||||||
|
|
||||||
#[cfg(any(feature = "id3v1", feature = "id3v2"))]
|
|
||||||
pub mod id3 {
|
|
||||||
//! ID3 specific items
|
|
||||||
//!
|
|
||||||
//! ID3 does things differently than other tags, making working with them a little more effort than other formats.
|
|
||||||
//! Check the other modules for important notes and/or warnings.
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub mod v2 {
|
|
||||||
//! ID3v2 items and utilities
|
|
||||||
//!
|
|
||||||
//! ## Important notes
|
|
||||||
//!
|
|
||||||
//! See:
|
|
||||||
//!
|
|
||||||
//! * [Id3v2Tag]
|
|
||||||
//! * [Frame]
|
|
||||||
|
|
||||||
pub use {
|
|
||||||
crate::logic::id3::v2::flags::Id3v2TagFlags,
|
|
||||||
crate::logic::id3::v2::frame::{
|
|
||||||
EncodedTextFrame, Frame, FrameFlags, FrameID, FrameValue, LanguageFrame,
|
|
||||||
},
|
|
||||||
crate::logic::id3::v2::items::encapsulated_object::{
|
|
||||||
GEOBInformation, GeneralEncapsulatedObject,
|
|
||||||
},
|
|
||||||
crate::logic::id3::v2::items::sync_text::{
|
|
||||||
SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat,
|
|
||||||
},
|
|
||||||
crate::logic::id3::v2::tag::Id3v2Tag,
|
|
||||||
crate::logic::id3::v2::util::text_utils::TextEncoding,
|
|
||||||
crate::logic::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3},
|
|
||||||
crate::logic::id3::v2::Id3v2Version,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
pub use crate::logic::id3::v2::items::restrictions::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v1")]
|
|
||||||
pub mod v1 {
|
|
||||||
//! ID3v1 items
|
|
||||||
//!
|
|
||||||
//! # ID3v1 notes
|
|
||||||
//!
|
|
||||||
//! See also: [Id3v1Tag]
|
|
||||||
//!
|
|
||||||
//! ## Genres
|
|
||||||
//!
|
|
||||||
//! ID3v1 stores the genre in a single byte ranging from 0 to 192 (inclusive).
|
|
||||||
//! All possible genres have been stored in the [`GENRES`] constant.
|
|
||||||
//!
|
|
||||||
//! ## Track Numbers
|
|
||||||
//!
|
|
||||||
//! ID3v1 stores the track number in a non-zero byte.
|
|
||||||
//! A track number of 0 will be treated as an empty field.
|
|
||||||
//! Additionally, there is no track total field.
|
|
||||||
pub use crate::logic::id3::v1::constants::GENRES;
|
|
||||||
pub use crate::logic::id3::v1::tag::Id3v1Tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod ape {
|
|
||||||
//! APE specific items
|
|
||||||
//!
|
|
||||||
//! ## File notes
|
|
||||||
//!
|
|
||||||
//! It is possible for an `APE` file to contain an `ID3v2` tag. For the sake of data preservation,
|
|
||||||
//! this tag will be read, but **cannot** be written. The only tags allowed by spec are `APEv1/2` and
|
|
||||||
//! `ID3v1`.
|
|
||||||
pub use crate::logic::ape::{properties::ApeProperties, ApeFile};
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub use crate::{
|
|
||||||
logic::ape::tag::{ape_tag::ApeTag, item::ApeItem},
|
|
||||||
types::picture::APE_PICTURE_TYPES,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod mp3 {
|
|
||||||
//! MP3 specific items
|
|
||||||
pub use crate::logic::mp3::header::{ChannelMode, Layer, MpegVersion};
|
|
||||||
pub use crate::logic::mp3::{properties::Mp3Properties, Mp3File};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod mp4 {
|
|
||||||
//! MP4 specific items
|
|
||||||
//!
|
|
||||||
//! ## File notes
|
|
||||||
//!
|
|
||||||
//! The only supported tag format is [`Ilst`].
|
|
||||||
#[cfg(feature = "mp4_ilst")]
|
|
||||||
pub use crate::logic::mp4::{
|
|
||||||
ilst::{
|
|
||||||
atom::{Atom, AtomData},
|
|
||||||
Ilst,
|
|
||||||
},
|
|
||||||
AtomIdent,
|
|
||||||
};
|
|
||||||
pub use crate::logic::mp4::{
|
|
||||||
properties::{Mp4Codec, Mp4Properties},
|
|
||||||
Mp4File,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod ogg {
|
|
||||||
//! OPUS/FLAC/Vorbis specific items
|
|
||||||
//!
|
|
||||||
//! ## File notes
|
|
||||||
//!
|
|
||||||
//! The only supported tag format is [`VorbisComments`]
|
|
||||||
pub use crate::logic::ogg::flac::FlacFile;
|
|
||||||
pub use crate::logic::ogg::opus::{properties::OpusProperties, OpusFile};
|
|
||||||
#[cfg(feature = "vorbis_comments")]
|
|
||||||
pub use crate::logic::ogg::tag::VorbisComments;
|
|
||||||
pub use crate::logic::ogg::vorbis::{properties::VorbisProperties, VorbisFile};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod iff {
|
|
||||||
//! WAV/AIFF specific items
|
|
||||||
pub use crate::logic::iff::aiff::AiffFile;
|
|
||||||
pub use crate::logic::iff::wav::WavFile;
|
|
||||||
|
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
|
||||||
pub use crate::logic::iff::aiff::tag::AiffTextChunks;
|
|
||||||
#[cfg(feature = "riff_info_list")]
|
|
||||||
pub use crate::logic::iff::wav::tag::RiffInfoList;
|
|
||||||
|
|
||||||
pub use crate::logic::iff::wav::properties::{WavFormat, WavProperties};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
pub(crate) mod constants;
|
|
||||||
pub(in crate::logic) mod read;
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(in crate::logic) mod write;
|
|
|
@ -1,4 +0,0 @@
|
||||||
pub(crate) mod encapsulated_object;
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
pub(crate) mod restrictions;
|
|
||||||
pub(crate) mod sync_text;
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub(crate) mod aiff;
|
|
||||||
pub(in crate::logic) mod chunk;
|
|
||||||
pub(crate) mod wav;
|
|
|
@ -1,21 +1,24 @@
|
||||||
|
//! MP3 specific items
|
||||||
mod constants;
|
mod constants;
|
||||||
pub(crate) mod header;
|
pub(crate) mod header;
|
||||||
pub(crate) mod properties;
|
mod properties;
|
||||||
pub(crate) mod read;
|
mod read;
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub use header::{ChannelMode, Layer, MpegVersion};
|
||||||
|
pub use properties::Mp3Properties;
|
||||||
|
|
||||||
use crate::error::Result;
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use crate::logic::ape::tag::ape_tag::ApeTag;
|
use crate::ape::tag::ape_tag::ApeTag;
|
||||||
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::logic::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::logic::tag_methods;
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
use properties::Mp3Properties;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use super::header::{verify_frame_sync, Header, XingHeader};
|
use super::header::{verify_frame_sync, Header, XingHeader};
|
||||||
use super::{Mp3File, Mp3Properties};
|
use super::{Mp3File, Mp3Properties};
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
|
use crate::ape::tag::ape_tag::ApeTag;
|
||||||
|
use crate::ape::tag::read_ape_header;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
#[cfg(feature = "id3v1")]
|
||||||
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
|
#[cfg(feature = "id3v2")]
|
||||||
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
|
use crate::id3::v2::read_id3v2_header;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::Id3v2Tag;
|
use crate::id3::v2::Id3v2Tag;
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
use crate::logic::ape::tag::ape_tag::ApeTag;
|
|
||||||
use crate::logic::ape::tag::read_ape_header;
|
|
||||||
#[cfg(feature = "id3v1")]
|
|
||||||
use crate::logic::id3::v1::tag::Id3v1Tag;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::logic::id3::v2::read::parse_id3v2;
|
|
||||||
use crate::logic::id3::v2::read_id3v2_header;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ where
|
||||||
|
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
{
|
{
|
||||||
id3v1_tag = Some(crate::logic::id3::v1::read::parse_id3v1(id3v1_read));
|
id3v1_tag = Some(crate::id3::v1::read::parse_id3v1(id3v1_read));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -105,9 +105,7 @@ where
|
||||||
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
{
|
{
|
||||||
ape_tag = Some(crate::logic::ape::tag::read::read_ape_tag(
|
ape_tag = Some(crate::ape::tag::read::read_ape_tag(data, ape_header)?);
|
||||||
data, ape_header,
|
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::error::{LoftyError, Result};
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use crate::logic::ape::tag::ape_tag::ApeTagRef;
|
use crate::ape::tag::ape_tag::ApeTagRef;
|
||||||
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::logic::id3::v1::tag::Id3v1TagRef;
|
use crate::id3::v1::tag::Id3v1TagRef;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::logic::id3::v2::tag::Id3v2TagRef;
|
use crate::id3::v2::tag::Id3v2TagRef;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::logic::mp4::AtomIdent;
|
use crate::mp4::AtomIdent;
|
||||||
use crate::types::picture::Picture;
|
use crate::types::picture::Picture;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
|
@ -1,6 +1,6 @@
|
||||||
pub(crate) mod atom;
|
pub(super) mod atom;
|
||||||
pub(in crate::logic::mp4) mod read;
|
pub(super) mod read;
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
use super::AtomIdent;
|
use super::AtomIdent;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
@ -221,7 +221,7 @@ pub(crate) struct IlstRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IlstRef<'a> {
|
impl<'a> IlstRef<'a> {
|
||||||
pub(in crate::logic) fn write_to(&mut self, file: &mut File) -> Result<()> {
|
pub(crate) fn write_to(&mut self, file: &mut File) -> Result<()> {
|
||||||
write::write_to(file, self)
|
write::write_to(file, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ mod tests {
|
||||||
|
|
||||||
let tag: Tag = ilst.into();
|
let tag: Tag = ilst.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, false, true);
|
crate::tag_utils::test_utils::verify_tag(&tag, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -368,7 +368,7 @@ mod tests {
|
||||||
assert_eq!(atom.data(), &data);
|
assert_eq!(atom.data(), &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::Mp4Ilst);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::Mp4Ilst);
|
||||||
|
|
||||||
let ilst: Ilst = tag.into();
|
let ilst: Ilst = tag.into();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::{Atom, AtomData, AtomIdent, Ilst};
|
use super::{Atom, AtomData, AtomIdent, Ilst};
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::id3::v2::util::text_utils::utf16_decode;
|
use crate::id3::v2::util::text_utils::utf16_decode;
|
||||||
use crate::logic::mp4::atom_info::AtomInfo;
|
use crate::mp4::atom_info::AtomInfo;
|
||||||
use crate::logic::mp4::read::skip_unneeded;
|
use crate::mp4::read::skip_unneeded;
|
||||||
use crate::types::picture::{MimeType, Picture, PictureType};
|
use crate::types::picture::{MimeType, Picture, PictureType};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
|
@ -1,9 +1,9 @@
|
||||||
use super::{AtomDataRef, IlstRef};
|
use super::{AtomDataRef, IlstRef};
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::mp4::ilst::{AtomIdentRef, AtomRef};
|
use crate::mp4::ilst::{AtomIdentRef, AtomRef};
|
||||||
use crate::logic::mp4::moov::Moov;
|
use crate::mp4::moov::Moov;
|
||||||
use crate::logic::mp4::read::nested_atom;
|
use crate::mp4::read::nested_atom;
|
||||||
use crate::logic::mp4::read::verify_mp4;
|
use crate::mp4::read::verify_mp4;
|
||||||
use crate::types::picture::MimeType;
|
use crate::types::picture::MimeType;
|
||||||
use crate::types::picture::Picture;
|
use crate::types::picture::Picture;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &mut IlstRef) -> Result<()> {
|
pub(in crate) fn write_to(data: &mut File, tag: &mut IlstRef) -> Result<()> {
|
||||||
verify_mp4(data)?;
|
verify_mp4(data)?;
|
||||||
|
|
||||||
let moov = Moov::find(data)?;
|
let moov = Moov::find(data)?;
|
|
@ -1,19 +1,29 @@
|
||||||
|
//! MP4 specific items
|
||||||
|
//!
|
||||||
|
//! ## File notes
|
||||||
|
//!
|
||||||
|
//! The only supported tag format is [`Ilst`].
|
||||||
mod atom_info;
|
mod atom_info;
|
||||||
#[cfg(feature = "mp4_ilst")]
|
#[cfg(feature = "mp4_ilst")]
|
||||||
pub(crate) mod ilst;
|
pub(crate) mod ilst;
|
||||||
mod moov;
|
mod moov;
|
||||||
pub(crate) mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
mod trak;
|
mod trak;
|
||||||
|
|
||||||
use crate::logic::tag_methods;
|
pub use crate::mp4::properties::{Mp4Codec, Mp4Properties};
|
||||||
|
#[cfg(feature = "mp4_ilst")]
|
||||||
|
pub use crate::mp4::{
|
||||||
|
atom_info::AtomIdent,
|
||||||
|
ilst::{
|
||||||
|
atom::{Atom, AtomData},
|
||||||
|
Ilst,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::{FileProperties, Result, TagType};
|
use crate::{FileProperties, Result, TagType};
|
||||||
#[cfg(feature = "mp4_ilst")]
|
|
||||||
pub use atom_info::AtomIdent;
|
|
||||||
#[cfg(feature = "mp4_ilst")]
|
|
||||||
use ilst::Ilst;
|
|
||||||
use properties::Mp4Properties;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::error::{LoftyError, Result};
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
pub(in crate::logic::mp4) fn verify_mp4<R>(data: &mut R) -> Result<String>
|
pub(in crate::mp4) fn verify_mp4<R>(data: &mut R) -> Result<String>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
|
@ -15,7 +15,7 @@ pub(super) struct Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub(in crate::logic::ogg) fn read<R>(data: &mut R) -> Result<Self>
|
pub(in crate::ogg) fn read<R>(data: &mut R) -> Result<Self>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
|
@ -2,12 +2,12 @@ mod block;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
pub(in crate::logic) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use super::tag::VorbisComments;
|
use super::tag::VorbisComments;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::tag_methods;
|
use crate::tag_utils::tag_methods;
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
|
@ -2,7 +2,7 @@ use super::block::Block;
|
||||||
use super::FlacFile;
|
use super::FlacFile;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use crate::logic::ogg::{read::read_comments, tag::VorbisComments};
|
use crate::ogg::{read::read_comments, tag::VorbisComments};
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use crate::types::picture::Picture;
|
use crate::types::picture::Picture;
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
|
@ -1,8 +1,8 @@
|
||||||
use super::block::Block;
|
use super::block::Block;
|
||||||
use super::read::verify_flac;
|
use super::read::verify_flac;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ogg::tag::VorbisCommentsRef;
|
use crate::ogg::tag::VorbisCommentsRef;
|
||||||
use crate::logic::ogg::write::create_comments;
|
use crate::ogg::write::create_comments;
|
||||||
use crate::types::picture::{Picture, PictureInformation};
|
use crate::types::picture::{Picture, PictureInformation};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -10,7 +10,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &mut VorbisCommentsRef) -> Result<()> {
|
pub(in crate) fn write_to(data: &mut File, tag: &mut VorbisCommentsRef) -> Result<()> {
|
||||||
let stream_info = verify_flac(data)?;
|
let stream_info = verify_flac(data)?;
|
||||||
let stream_info_end = stream_info.end as usize;
|
let stream_info_end = stream_info.end as usize;
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
|
//! OPUS/FLAC/Vorbis specific items
|
||||||
|
//!
|
||||||
|
//! ## File notes
|
||||||
|
//!
|
||||||
|
//! The only supported tag format is [`VorbisComments`]
|
||||||
pub(crate) mod constants;
|
pub(crate) mod constants;
|
||||||
pub(crate) mod read;
|
|
||||||
#[cfg(feature = "vorbis_comments")]
|
|
||||||
pub(crate) mod write;
|
|
||||||
|
|
||||||
pub(crate) mod flac;
|
pub(crate) mod flac;
|
||||||
pub(crate) mod opus;
|
pub(crate) mod opus;
|
||||||
|
pub(crate) mod read;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
pub(crate) mod vorbis;
|
pub(crate) mod vorbis;
|
||||||
|
#[cfg(feature = "vorbis_comments")]
|
||||||
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub use crate::ogg::flac::FlacFile;
|
||||||
|
pub use crate::ogg::opus::{properties::OpusProperties, OpusFile};
|
||||||
|
#[cfg(feature = "vorbis_comments")]
|
||||||
|
pub use crate::ogg::tag::VorbisComments;
|
||||||
|
pub use crate::ogg::vorbis::{properties::VorbisProperties, VorbisFile};
|
||||||
|
|
||||||
use crate::{LoftyError, Result};
|
use crate::{LoftyError, Result};
|
||||||
|
|
||||||
|
@ -16,7 +26,7 @@ use std::io::{Read, Seek};
|
||||||
use ogg_pager::Page;
|
use ogg_pager::Page;
|
||||||
|
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
pub fn page_from_packet(packet: &mut [u8]) -> Result<Vec<Page>> {
|
pub(self) fn page_from_packet(packet: &mut [u8]) -> Result<Vec<Page>> {
|
||||||
let mut pages: Vec<Page> = Vec::new();
|
let mut pages: Vec<Page> = Vec::new();
|
||||||
|
|
||||||
let reader = &mut &packet[..];
|
let reader = &mut &packet[..];
|
|
@ -1,4 +1,4 @@
|
||||||
pub(crate) mod properties;
|
pub(super) mod properties;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
pub(super) mod write;
|
pub(super) mod write;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use super::find_last_page;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use super::tag::VorbisComments;
|
use super::tag::VorbisComments;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::ogg::constants::{OPUSHEAD, OPUSTAGS};
|
use crate::ogg::constants::{OPUSHEAD, OPUSTAGS};
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
|
@ -82,10 +82,7 @@ impl OpusProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic::ogg) fn read_properties<R>(
|
pub(in crate::ogg) fn read_properties<R>(data: &mut R, first_page: &Page) -> Result<OpusProperties>
|
||||||
data: &mut R,
|
|
||||||
first_page: &Page,
|
|
||||||
) -> Result<OpusProperties>
|
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
|
@ -5,7 +5,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use ogg_pager::Page;
|
use ogg_pager::Page;
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(
|
pub(crate) fn write_to(
|
||||||
data: &mut File,
|
data: &mut File,
|
||||||
writer: &mut Vec<u8>,
|
writer: &mut Vec<u8>,
|
||||||
ser: u32,
|
ser: u32,
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ogg::constants::{OPUSHEAD, VORBIS_IDENT_HEAD};
|
use crate::ogg::constants::{OPUSHEAD, VORBIS_IDENT_HEAD};
|
||||||
use crate::probe::Probe;
|
use crate::probe::Probe;
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
use crate::types::item::{ItemKey, ItemValue, TagItem};
|
||||||
|
@ -253,7 +253,7 @@ mod tests {
|
||||||
let mut reader = std::io::Cursor::new(&tag[..]);
|
let mut reader = std::io::Cursor::new(&tag[..]);
|
||||||
let mut parsed_tag = VorbisComments::default();
|
let mut parsed_tag = VorbisComments::default();
|
||||||
|
|
||||||
crate::logic::ogg::read::read_comments(&mut reader, &mut parsed_tag).unwrap();
|
crate::ogg::read::read_comments(&mut reader, &mut parsed_tag).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_tag, parsed_tag);
|
assert_eq!(expected_tag, parsed_tag);
|
||||||
}
|
}
|
||||||
|
@ -269,16 +269,16 @@ mod tests {
|
||||||
let mut reader = std::io::Cursor::new(&tag_bytes[..]);
|
let mut reader = std::io::Cursor::new(&tag_bytes[..]);
|
||||||
let mut vorbis_comments = VorbisComments::default();
|
let mut vorbis_comments = VorbisComments::default();
|
||||||
|
|
||||||
crate::logic::ogg::read::read_comments(&mut reader, &mut vorbis_comments).unwrap();
|
crate::ogg::read::read_comments(&mut reader, &mut vorbis_comments).unwrap();
|
||||||
|
|
||||||
let tag: Tag = vorbis_comments.into();
|
let tag: Tag = vorbis_comments.into();
|
||||||
|
|
||||||
crate::logic::test_utils::verify_tag(&tag, true, true);
|
crate::tag_utils::test_utils::verify_tag(&tag, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_to_vorbis_comments() {
|
fn tag_to_vorbis_comments() {
|
||||||
let tag = crate::logic::test_utils::create_tag(TagType::VorbisComments);
|
let tag = crate::tag_utils::test_utils::create_tag(TagType::VorbisComments);
|
||||||
|
|
||||||
let vorbis_comments: VorbisComments = tag.into();
|
let vorbis_comments: VorbisComments = tag.into();
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
pub(crate) mod properties;
|
pub(super) mod properties;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
pub(in crate::logic::ogg) mod write;
|
pub(in crate::ogg) mod write;
|
||||||
|
|
||||||
use super::find_last_page;
|
use super::find_last_page;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use super::tag::VorbisComments;
|
use super::tag::VorbisComments;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::logic::ogg::constants::{VORBIS_COMMENT_HEAD, VORBIS_IDENT_HEAD};
|
use crate::ogg::constants::{VORBIS_COMMENT_HEAD, VORBIS_IDENT_HEAD};
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
|
@ -106,7 +106,7 @@ impl VorbisProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic::ogg) fn read_properties<R>(
|
pub(in crate::ogg) fn read_properties<R>(
|
||||||
data: &mut R,
|
data: &mut R,
|
||||||
first_page: &Page,
|
first_page: &Page,
|
||||||
) -> Result<VorbisProperties>
|
) -> Result<VorbisProperties>
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ogg::constants::VORBIS_SETUP_HEAD;
|
use crate::ogg::constants::VORBIS_SETUP_HEAD;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
|
@ -7,7 +7,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use ogg_pager::Page;
|
use ogg_pager::Page;
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(
|
pub(crate) fn write_to(
|
||||||
data: &mut File,
|
data: &mut File,
|
||||||
writer: &mut Vec<u8>,
|
writer: &mut Vec<u8>,
|
||||||
first_md_content: Vec<u8>,
|
first_md_content: Vec<u8>,
|
|
@ -1,8 +1,8 @@
|
||||||
use super::{page_from_packet, verify_signature};
|
use super::{page_from_packet, verify_signature};
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ogg::constants::OPUSTAGS;
|
use crate::ogg::constants::OPUSTAGS;
|
||||||
use crate::logic::ogg::constants::VORBIS_COMMENT_HEAD;
|
use crate::ogg::constants::VORBIS_COMMENT_HEAD;
|
||||||
use crate::logic::ogg::tag::VorbisCommentsRef;
|
use crate::ogg::tag::VorbisCommentsRef;
|
||||||
use crate::types::picture::PictureInformation;
|
use crate::types::picture::PictureInformation;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
||||||
|
@ -13,8 +13,9 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use ogg_pager::Page;
|
use ogg_pager::Page;
|
||||||
|
|
||||||
pub(in crate::logic) fn write_to(data: &mut File, tag: &Tag, sig: &[u8]) -> Result<()> {
|
pub(in crate) fn write_to(data: &mut File, tag: &Tag, sig: &[u8]) -> Result<()> {
|
||||||
match tag.tag_type() {
|
match tag.tag_type() {
|
||||||
|
#[cfg(feature = "vorbis_comments")]
|
||||||
TagType::VorbisComments => write(data, &mut Into::<VorbisCommentsRef>::into(tag), sig),
|
TagType::VorbisComments => write(data, &mut Into::<VorbisCommentsRef>::into(tag), sig),
|
||||||
_ => Err(LoftyError::UnsupportedTag),
|
_ => Err(LoftyError::UnsupportedTag),
|
||||||
}
|
}
|
18
src/probe.rs
18
src/probe.rs
|
@ -1,13 +1,13 @@
|
||||||
|
use crate::ape::ApeFile;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::logic::ape::ApeFile;
|
use crate::iff::aiff::AiffFile;
|
||||||
use crate::logic::iff::aiff::AiffFile;
|
use crate::iff::wav::WavFile;
|
||||||
use crate::logic::iff::wav::WavFile;
|
use crate::mp3::header::verify_frame_sync;
|
||||||
use crate::logic::mp3::header::verify_frame_sync;
|
use crate::mp3::Mp3File;
|
||||||
use crate::logic::mp3::Mp3File;
|
use crate::mp4::Mp4File;
|
||||||
use crate::logic::mp4::Mp4File;
|
use crate::ogg::flac::FlacFile;
|
||||||
use crate::logic::ogg::flac::FlacFile;
|
use crate::ogg::opus::OpusFile;
|
||||||
use crate::logic::ogg::opus::OpusFile;
|
use crate::ogg::vorbis::VorbisFile;
|
||||||
use crate::logic::ogg::vorbis::VorbisFile;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
|
@ -1,48 +1,45 @@
|
||||||
pub(crate) mod ape;
|
|
||||||
pub(crate) mod id3;
|
|
||||||
pub(crate) mod iff;
|
|
||||||
pub(crate) mod mp3;
|
|
||||||
pub(crate) mod mp4;
|
|
||||||
pub(crate) mod ogg;
|
|
||||||
|
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::types::file::FileType;
|
|
||||||
use crate::types::tag::Tag;
|
|
||||||
#[cfg(feature = "mp4_ilst")]
|
#[cfg(feature = "mp4_ilst")]
|
||||||
use mp4::ilst::IlstRef;
|
use crate::mp4::ilst::IlstRef;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use ogg::{
|
use crate::ogg::{
|
||||||
constants::{OPUSTAGS, VORBIS_COMMENT_HEAD},
|
constants::{OPUSTAGS, VORBIS_COMMENT_HEAD},
|
||||||
tag::VorbisCommentsRef,
|
tag::VorbisCommentsRef,
|
||||||
};
|
};
|
||||||
|
use crate::types::file::FileType;
|
||||||
|
use crate::types::tag::Tag;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
pub(crate) fn write_tag(tag: &Tag, file: &mut File, file_type: FileType) -> Result<()> {
|
pub(crate) fn write_tag(tag: &Tag, file: &mut File, file_type: FileType) -> Result<()> {
|
||||||
match file_type {
|
match file_type {
|
||||||
FileType::AIFF => iff::aiff::write::write_to(file, tag),
|
FileType::AIFF => crate::iff::aiff::write::write_to(file, tag),
|
||||||
FileType::APE => ape::write::write_to(file, tag),
|
FileType::APE => crate::ape::write::write_to(file, tag),
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
FileType::FLAC => ogg::flac::write::write_to(file, &mut Into::<VorbisCommentsRef>::into(tag)),
|
FileType::FLAC => {
|
||||||
FileType::MP3 => mp3::write::write_to(file, tag),
|
crate::ogg::flac::write::write_to(file, &mut Into::<VorbisCommentsRef>::into(tag))
|
||||||
|
},
|
||||||
|
FileType::MP3 => crate::mp3::write::write_to(file, tag),
|
||||||
#[cfg(feature = "mp4_ilst")]
|
#[cfg(feature = "mp4_ilst")]
|
||||||
FileType::MP4 => mp4::ilst::write::write_to(file, &mut Into::<IlstRef>::into(tag)),
|
FileType::MP4 => crate::mp4::ilst::write::write_to(file, &mut Into::<IlstRef>::into(tag)),
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
FileType::Opus => ogg::write::write_to(file, tag, OPUSTAGS),
|
FileType::Opus => crate::ogg::write::write_to(file, tag, OPUSTAGS),
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
FileType::Vorbis => ogg::write::write_to(file, tag, VORBIS_COMMENT_HEAD),
|
FileType::Vorbis => crate::ogg::write::write_to(file, tag, VORBIS_COMMENT_HEAD),
|
||||||
FileType::WAV => iff::wav::write::write_to(file, tag),
|
FileType::WAV => crate::iff::wav::write::write_to(file, tag),
|
||||||
_ => Err(LoftyError::UnsupportedTag),
|
_ => Err(LoftyError::UnsupportedTag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! tag_methods {
|
macro_rules! tag_methods {
|
||||||
($(
|
(
|
||||||
|
$(
|
||||||
$(#[$attr:meta])?;
|
$(#[$attr:meta])?;
|
||||||
$display_name:tt,
|
$display_name:tt,
|
||||||
$name:ident,
|
$name:ident,
|
||||||
$ty:ty);*
|
$ty:ty
|
||||||
|
);*
|
||||||
) => {
|
) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
$(
|
$(
|
||||||
|
@ -68,11 +65,11 @@ macro_rules! tag_methods {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) use tag_methods;
|
pub(crate) use tag_methods;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
// Used for tag conversion tests
|
// Used for tag conversion tests
|
||||||
mod test_utils {
|
pub(crate) mod test_utils {
|
||||||
use crate::{ItemKey, Tag, TagType};
|
use crate::{ItemKey, Tag, TagType};
|
||||||
|
|
||||||
pub(crate) fn create_tag(tag_type: TagType) -> Tag {
|
pub(crate) fn create_tag(tag_type: TagType) -> Tag {
|
|
@ -283,7 +283,7 @@ impl FileType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_buffer_inner(buf: &[u8]) -> Result<(Option<Self>, u32)> {
|
pub(crate) fn from_buffer_inner(buf: &[u8]) -> Result<(Option<Self>, u32)> {
|
||||||
use crate::logic::id3::v2::unsynch_u32;
|
use crate::id3::v2::unsynch_u32;
|
||||||
|
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Err(LoftyError::EmptyFile);
|
return Err(LoftyError::EmptyFile);
|
||||||
|
@ -306,7 +306,7 @@ impl FileType {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quick_type_guess(buf: &[u8]) -> Option<Self> {
|
fn quick_type_guess(buf: &[u8]) -> Option<Self> {
|
||||||
use crate::logic::mp3::header::verify_frame_sync;
|
use crate::mp3::header::verify_frame_sync;
|
||||||
|
|
||||||
match buf.first().unwrap() {
|
match buf.first().unwrap() {
|
||||||
77 if buf.starts_with(b"MAC") => Some(Self::APE),
|
77 if buf.starts_with(b"MAC") => Some(Self::APE),
|
||||||
|
|
|
@ -610,7 +610,7 @@ impl TagItem {
|
||||||
pub(crate) fn re_map(&self, tag_type: TagType) -> Option<()> {
|
pub(crate) fn re_map(&self, tag_type: TagType) -> Option<()> {
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
if tag_type == TagType::Id3v1 {
|
if tag_type == TagType::Id3v1 {
|
||||||
use crate::logic::id3::v1::constants::VALID_ITEMKEYS;
|
use crate::id3::v1::constants::VALID_ITEMKEYS;
|
||||||
|
|
||||||
return VALID_ITEMKEYS.contains(&self.item_key).then(|| ());
|
return VALID_ITEMKEYS.contains(&self.item_key).then(|| ());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{LoftyError, Result};
|
use crate::{LoftyError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use {crate::logic::id3::v2::util::text_utils::TextEncoding, crate::logic::id3::v2::Id3v2Version};
|
use {crate::id3::v2::util::text_utils::TextEncoding, crate::id3::v2::Id3v2Version};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
#[cfg(any(feature = "vorbis_comments", feature = "ape", feature = "id3v2"))]
|
#[cfg(any(feature = "vorbis_comments", feature = "ape", feature = "id3v2"))]
|
||||||
|
@ -587,13 +587,9 @@ impl Picture {
|
||||||
data.write_u8(self.pic_type.as_u8())?;
|
data.write_u8(self.pic_type.as_u8())?;
|
||||||
|
|
||||||
match &self.description {
|
match &self.description {
|
||||||
Some(description) => {
|
Some(description) => data.write_all(
|
||||||
data.write_all(&*crate::logic::id3::v2::util::text_utils::encode_text(
|
&*crate::id3::v2::util::text_utils::encode_text(description, text_encoding, true),
|
||||||
description,
|
)?,
|
||||||
text_encoding,
|
|
||||||
true,
|
|
||||||
))?
|
|
||||||
},
|
|
||||||
None => data.write_u8(0)?,
|
None => data.write_u8(0)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,18 +639,14 @@ impl Picture {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(crate::logic::id3::v2::util::text_utils::decode_text(
|
(crate::id3::v2::util::text_utils::decode_text(&mut cursor, TextEncoding::UTF8, true)?)
|
||||||
&mut cursor,
|
|
||||||
TextEncoding::UTF8,
|
|
||||||
true,
|
|
||||||
)?)
|
|
||||||
.map_or(MimeType::None, |mime_type| MimeType::from_str(&*mime_type))
|
.map_or(MimeType::None, |mime_type| MimeType::from_str(&*mime_type))
|
||||||
};
|
};
|
||||||
|
|
||||||
let picture_type = PictureType::from_u8(cursor.read_u8()?);
|
let picture_type = PictureType::from_u8(cursor.read_u8()?);
|
||||||
|
|
||||||
let description =
|
let description =
|
||||||
crate::logic::id3::v2::util::text_utils::decode_text(&mut cursor, encoding, true)?
|
crate::id3::v2::util::text_utils::decode_text(&mut cursor, encoding, true)?
|
||||||
.map(Cow::from);
|
.map(Cow::from);
|
||||||
|
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
|
|
|
@ -289,7 +289,7 @@ impl Tag {
|
||||||
match probe.file_type() {
|
match probe.file_type() {
|
||||||
Some(file_type) => {
|
Some(file_type) => {
|
||||||
if file_type.supports_tag_type(self.tag_type()) {
|
if file_type.supports_tag_type(self.tag_type()) {
|
||||||
crate::logic::write_tag(self, probe.into_inner(), file_type)
|
crate::tag_utils::write_tag(self, probe.into_inner(), file_type)
|
||||||
} else {
|
} else {
|
||||||
Err(LoftyError::UnsupportedTag)
|
Err(LoftyError::UnsupportedTag)
|
||||||
}
|
}
|
||||||
|
@ -354,7 +354,7 @@ impl TagType {
|
||||||
if file_type.supports_tag_type(self) {
|
if file_type.supports_tag_type(self) {
|
||||||
let file = probe.into_inner();
|
let file = probe.into_inner();
|
||||||
|
|
||||||
return crate::logic::write_tag(&Tag::new(*self), file, file_type).is_ok();
|
return crate::tag_utils::write_tag(&Tag::new(*self), file, file_type).is_ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue