mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2025-03-04 23:07:20 +00:00
Leave GEOB/SYLT parsing up to the user, fix docs
This commit is contained in:
parent
ffba428c98
commit
556aaea287
7 changed files with 29 additions and 40 deletions
|
@ -141,6 +141,9 @@ pub use crate::types::{
|
|||
#[cfg(any(feature = "id3v2", feature = "ape"))]
|
||||
pub use crate::types::item::TagItemFlags;
|
||||
|
||||
#[cfg(feature = "id3v2")]
|
||||
pub use crate::types::tag::TagFlags;
|
||||
|
||||
mod types;
|
||||
|
||||
/// Various concrete file types, used when inference is unnecessary
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::error::Result;
|
||||
use crate::logic::id3::v2::util::encapsulated_object::GeneralEncapsulatedObject;
|
||||
use crate::logic::id3::v2::util::sync_text::SynchronizedText;
|
||||
use crate::logic::id3::v2::util::text_utils::decode_text;
|
||||
use crate::logic::id3::v2::{Id3v2Frame, Id3v2Version, LanguageSpecificFrame, TextEncoding};
|
||||
use crate::types::picture::Picture;
|
||||
|
@ -28,19 +26,15 @@ pub(crate) fn parse_content(
|
|||
"WXXX" => FrameContent::Item(parse_user_defined(content, true)?),
|
||||
"COMM" | "USLT" => FrameContent::Item(parse_text_language(id, content)?),
|
||||
"SYLT" => FrameContent::Item({
|
||||
let sync_text = SynchronizedText::parse(content)?;
|
||||
|
||||
TagItem::new(
|
||||
ItemKey::Id3v2Specific(Id3v2Frame::SyncText(sync_text.information)),
|
||||
ItemValue::SynchronizedText(sync_text.content),
|
||||
ItemKey::Id3v2Specific(Id3v2Frame::SyncText),
|
||||
ItemValue::Binary(content.to_vec()),
|
||||
)
|
||||
}),
|
||||
"GEOB" => FrameContent::Item({
|
||||
let geob = GeneralEncapsulatedObject::parse(content)?;
|
||||
|
||||
TagItem::new(
|
||||
ItemKey::Id3v2Specific(Id3v2Frame::EncapsulatedObject(geob.information)),
|
||||
ItemValue::Binary(geob.data),
|
||||
ItemKey::Id3v2Specific(Id3v2Frame::EncapsulatedObject),
|
||||
ItemValue::Binary(content.to_vec()),
|
||||
)
|
||||
}),
|
||||
_ if id.starts_with('T') => FrameContent::Item(parse_text(id, content)?),
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::logic::id3::decode_u32;
|
||||
use crate::logic::id3::v2::util::encapsulated_object::GEOBInformation;
|
||||
use crate::logic::id3::v2::util::sync_text::SyncTextInformation;
|
||||
use crate::Result;
|
||||
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
@ -97,12 +95,12 @@ pub enum Id3v2Frame {
|
|||
UserURL(TextEncoding, String),
|
||||
/// Represents a "SYLT" frame
|
||||
///
|
||||
/// Due to the amount of information needed, it is contained in a separate struct, [`SyncTextInformation`]
|
||||
SyncText(SyncTextInformation),
|
||||
/// Nothing is required here, the entire frame is stored as [`ItemValue::Binary`](crate::ItemValue::Binary). For parsing see [`SynchronizedText::parse`](crate::id3::SynchronizedText::parse)
|
||||
SyncText,
|
||||
/// Represents a "GEOB" frame
|
||||
///
|
||||
/// Due to the amount of information needed, it is contained in a separate struct, [`GEOBInformation`]
|
||||
EncapsulatedObject(GEOBInformation),
|
||||
/// Nothing is required here, the entire frame is stored as [`ItemValue::Binary`](crate::ItemValue::Binary). For parsing see [`GeneralEncapsulatedObject::parse`](crate::id3::GeneralEncapsulatedObject::parse)
|
||||
EncapsulatedObject,
|
||||
/// When an ID3v2.2 key couldn't be upgraded
|
||||
///
|
||||
/// This **will not** be written. It is up to the user to upgrade and store the key as [`ItemKey::Unknown`](crate::ItemKey::Unknown).
|
||||
|
|
|
@ -13,8 +13,8 @@ pub struct GEOBInformation {
|
|||
pub mime_type: Option<String>,
|
||||
/// The file's name
|
||||
pub file_name: Option<String>,
|
||||
/// A description of the content
|
||||
pub description: String,
|
||||
/// A unique content descriptor
|
||||
pub descriptor: String,
|
||||
}
|
||||
|
||||
/// Allows for encapsulation of any file type inside an ID3v2 tag
|
||||
|
@ -45,7 +45,7 @@ impl GeneralEncapsulatedObject {
|
|||
|
||||
let mime_type = decode_text(&mut cursor, TextEncoding::Latin1, true)?;
|
||||
let file_name = decode_text(&mut cursor, encoding, true)?;
|
||||
let description = decode_text(&mut cursor, encoding, true)?.unwrap_or_else(String::new);
|
||||
let descriptor = decode_text(&mut cursor, encoding, true)?.unwrap_or_else(String::new);
|
||||
|
||||
let mut data = Vec::new();
|
||||
cursor.read_to_end(&mut data)?;
|
||||
|
@ -55,7 +55,7 @@ impl GeneralEncapsulatedObject {
|
|||
encoding,
|
||||
mime_type,
|
||||
file_name,
|
||||
description,
|
||||
descriptor,
|
||||
},
|
||||
data,
|
||||
})
|
||||
|
|
|
@ -194,10 +194,8 @@ fn build_ilst(tag: &Tag) -> Result<Vec<u8>> {
|
|||
.iter()
|
||||
.filter_map(|i| {
|
||||
let key = i.key().map_key(&TagType::Mp4Atom).unwrap();
|
||||
let valid_value = std::mem::discriminant(&ItemValue::SynchronizedText(Vec::new()))
|
||||
!= std::mem::discriminant(i.value())
|
||||
&& std::mem::discriminant(&ItemValue::Binary(Vec::new()))
|
||||
!= std::mem::discriminant(i.value());
|
||||
let valid_value = std::mem::discriminant(&ItemValue::Binary(Vec::new()))
|
||||
!= std::mem::discriminant(i.value());
|
||||
|
||||
((key.chars().count() == 4 || key.starts_with("----")) && valid_value)
|
||||
.then(|| (key, i.value()))
|
||||
|
|
|
@ -427,11 +427,8 @@ item_keys!(
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
/// Represents a tag item's value
|
||||
///
|
||||
/// NOTES:
|
||||
///
|
||||
/// * The [Locator][ItemValue::Locator] variant is only applicable to APE and ID3v2 tags.
|
||||
/// * The [Binary][ItemValue::Binary] variant is only applicable to APE tags.
|
||||
/// * Attempting to write either to another file/tag type will **not** error, they will just be ignored.
|
||||
/// NOTE: The [Locator][crate::ItemValue::Locator] and [Binary][crate::ItemValue::Binary] variants are only applicable to ID3v2, APEv2, and MP4 ilst tags.
|
||||
/// Attempting to write either to another file/tag type will **not** error, they will just be ignored.
|
||||
pub enum ItemValue {
|
||||
/// Any UTF-8 encoded text
|
||||
Text(String),
|
||||
|
@ -439,9 +436,10 @@ pub enum ItemValue {
|
|||
Locator(String),
|
||||
/// **(APE/ID3v2/MP4 ONLY)** Binary information
|
||||
///
|
||||
/// In the case of ID3v2, this is the type of a [`Id3v2Frame::EncapsulatedObject`](crate::id3::Id3v2Frame::EncapsulatedObject) **and** any unknown frame.
|
||||
/// In the case of ID3v2, this is the type of a [`Id3v2Frame::EncapsulatedObject`](crate::id3::Id3v2Frame::EncapsulatedObject),
|
||||
/// [`Id3v2Frame::SyncText`](crate::id3::Id3v2Frame::SyncText), and any unknown frame.
|
||||
///
|
||||
/// For APEv2, no uses of this item type are documented, there's no telling what it could be.
|
||||
/// For APEv2 and MP4, the only use is for unknown items.
|
||||
Binary(Vec<u8>),
|
||||
/// Any 32 bit unsigned integer
|
||||
///
|
||||
|
@ -459,9 +457,6 @@ pub enum ItemValue {
|
|||
///
|
||||
/// There are no common [`ItemKey`]s that use this
|
||||
Int64(i64),
|
||||
#[cfg(feature = "id3v2")]
|
||||
/// **(ID3v2 ONLY)** The content of a synchronized text frame, see [`SynchronizedText`](crate::id3::SynchronizedText)
|
||||
SynchronizedText(Vec<(u32, String)>),
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "id3v2", feature = "ape"))]
|
||||
|
@ -533,7 +528,7 @@ impl TagItem {
|
|||
///
|
||||
/// * This will check for validity based on the [`TagType`].
|
||||
/// * If the [`ItemKey`] does not map to a key in the target format, `None` will be returned.
|
||||
/// * It is pointless to do this if you plan on using [`Tag::insert_item`], as it does validity checks itself.
|
||||
/// * It is pointless to do this if you plan on using [`Tag::insert_item`](crate::Tag::insert_item), as it does validity checks itself.
|
||||
pub fn new_checked(
|
||||
tag_type: &TagType,
|
||||
item_key: ItemKey,
|
||||
|
|
|
@ -45,7 +45,7 @@ macro_rules! common_items {
|
|||
#[allow(clippy::struct_excessive_bools)]
|
||||
/// **(ID3v2 ONLY)** Flags that apply to the entire tag
|
||||
pub struct TagFlags {
|
||||
/// Whether or not all frames are unsynchronised. See [`TagItemFlags::unsynchronization`]
|
||||
/// Whether or not all frames are unsynchronised. See [`TagItemFlags::unsynchronisation`](crate::TagItemFlags::unsynchronisation)
|
||||
pub unsynchronisation: bool,
|
||||
/// Whether or not the header is followed by an extended header
|
||||
pub extended_header: bool,
|
||||
|
@ -160,6 +160,7 @@ impl Tag {
|
|||
self.items.len() as u32
|
||||
}
|
||||
|
||||
#[cfg(feature = "id3v2")]
|
||||
/// Returns the [`TagFlags`]
|
||||
pub fn flags(&self) -> &TagFlags {
|
||||
&self.flags
|
||||
|
@ -206,7 +207,7 @@ impl Tag {
|
|||
///
|
||||
/// NOTES:
|
||||
///
|
||||
/// * This **will** respect [`TagItemFlags::read_only`]
|
||||
/// * This **will** respect [`TagItemFlags::read_only`](crate::TagItemFlags::read_only)
|
||||
/// * This **will** verify an [`ItemKey`] mapping exists for the target [`TagType`]
|
||||
///
|
||||
/// # Warning
|
||||
|
@ -226,7 +227,7 @@ impl Tag {
|
|||
///
|
||||
/// Notes:
|
||||
///
|
||||
/// * This **will not** respect [`TagItemFlags::read_only`]
|
||||
/// * This **will not** respect [`TagItemFlags::read_only`](crate::TagItemFlags::read_only)
|
||||
/// * This **will not** verify an [`ItemKey`] mapping exists
|
||||
/// * This **will not** allow writing item keys that are out of spec (keys are verified before writing)
|
||||
///
|
||||
|
@ -244,8 +245,8 @@ impl Tag {
|
|||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * A [`FileType`] couldn't be determined from the File
|
||||
/// * Attempting to write a tag to a format that does not support it. See [`FileType::supports_tag_type`]
|
||||
/// * A [`FileType`](crate::FileType) couldn't be determined from the File
|
||||
/// * Attempting to write a tag to a format that does not support it. See [`FileType::supports_tag_type`](crate::FileType::supports_tag_type)
|
||||
pub fn save_to(&self, file: &mut File) -> Result<()> {
|
||||
match Probe::new().file_type(file) {
|
||||
Some(file_type) => {
|
||||
|
|
Loading…
Add table
Reference in a new issue