Add ID3v2 tag flags and restrictions

This commit is contained in:
Serial 2021-08-24 21:56:46 -04:00
parent c5a1af5ccd
commit 0c41b3e15e
3 changed files with 127 additions and 8 deletions

View file

@ -0,0 +1,80 @@
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
/// Restrictions on the tag size
pub enum TagSizeRestrictions {
/// No more than 128 frames and 1 MB total tag size
S_128F_1M,
/// No more than 64 frames and 128 KB total tag size
S_64F_128K,
/// No more than 32 frames and 40 KB total tag size
S_32F_40K,
/// No more than 32 frames and 4 KB total tag size
S_32F_4K,
}
impl Default for TagSizeRestrictions {
fn default() -> Self {
Self::S_128F_1M
}
}
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
/// Restrictions on text field sizes
pub enum TextSizeRestrictions {
/// No size restrictions
None,
/// No longer than 1024 characters
C_1024,
/// No longer than 128 characters
C_128,
/// No longer than 30 characters
C_30,
}
impl Default for TextSizeRestrictions {
fn default() -> Self {
Self::None
}
}
#[derive(Clone, Copy)]
#[allow(non_camel_case_types)]
/// Restrictions on all image sizes
pub enum ImageSizeRestrictions {
/// No size restrictions
None,
/// All images are 256x256 or smaller
P_256,
/// All images are 64x64 or smaller
P_64,
/// All images are **exactly** 64x64
P_64_64,
}
impl Default for ImageSizeRestrictions {
fn default() -> Self {
Self::None
}
}
#[derive(Default, Clone, Copy)]
/// Restrictions on the content of an ID3v2 tag
pub struct TagRestrictions {
/// Restriction on the size of the tag. See [`TagSizeRestrictions`]
pub size: TagSizeRestrictions,
/// Text encoding restrictions
///
/// `false` - No restrictions
/// `true` - Strings are only encoded with [`TextEncoding::Latin1`](crate::TextEncoding::Latin1) or [`TextEncoding::UTF8`](crate::TextEncoding::UTF8)
pub text_encoding: bool,
/// Restrictions on all text field sizes. See [`TextSizeRestrictions`]
pub text_fields_size: TextSizeRestrictions,
/// Image encoding restrictions
///
/// `false` - No restrictions
/// `true` - Images can only be `PNG` or `JPEG`
pub image_encoding: bool,
/// Restrictions on all image sizes. See [`ImageSizeRestrictions`]
pub image_size: ImageSizeRestrictions,
}

View file

@ -22,7 +22,7 @@ macro_rules! first_key {
// Keys should appear in order of popularity.
macro_rules! item_keys {
(ALLOWED_UNKNOWN => [$($unknown_tag_type:pat),+]; $($variant:ident => [$($($tag_type:pat)|* => $($key:tt)|+),+]),+) => {
#[derive(PartialEq)]
#[derive(PartialEq, Clone)]
#[allow(missing_docs)]
#[non_exhaustive]
/// A generic representation of a tag's key
@ -44,7 +44,7 @@ macro_rules! item_keys {
///
/// NOTE: If used with ID3v2, this will only check against the ID3v2.4 keys.
/// If you wish to use a V2 or V3 key, see [`upgrade_v2`](crate::id3::upgrade_v2) and [`upgrade_v3`](crate::id3::upgrade_v3)
pub const fn from_key(tag_type: &TagType, key: &str) -> Option<Self> {
pub fn from_key(tag_type: &TagType, key: &str) -> Option<Self> {
match tag_type {
$(
$(
@ -62,7 +62,7 @@ macro_rules! item_keys {
///
/// NOTE: Since all ID3v2 tags are upgraded to [`Id3v2Version::V4`](crate::id3::Id3v2Version), the
/// version provided does not matter. They cannot be downgraded.
pub const fn map_key(&self, tag_type: &TagType) -> Option<&str> {
pub fn map_key(&self, tag_type: &TagType) -> Option<&str> {
match (tag_type, self) {
$(
$(

View file

@ -1,5 +1,6 @@
use super::item::ItemKey;
use super::picture::{Picture, PictureType};
use crate::logic::id3::v2::restrictions::TagRestrictions;
use crate::logic::id3::v2::Id3v2Version;
#[cfg(feature = "quick_tag_accessors")]
@ -13,7 +14,7 @@ macro_rules! common_items {
$(
#[doc = "Gets the " $name]
pub fn $name(&self) -> Option<&str> {
if let Some(ItemValue::Text(txt)) = self.get_item_ref(&ItemKey::$item_key).map(|i| i.value()) {
if let Some(ItemValue::Text(txt)) = self.get_item_ref(&ItemKey::$item_key).map(TagItem::value) {
return Some(&*txt)
}
@ -35,6 +36,7 @@ macro_rules! common_items {
}
}
#[derive(Clone)]
#[allow(clippy::struct_excessive_bools)]
/// **(ID3v2/APEv2 ONLY)** Various flags to describe the content of an item
///
@ -93,6 +95,7 @@ impl Default for TagItemFlags {
}
}
#[derive(Clone)]
/// Represents a tag item (key/value)
pub struct TagItem {
item_key: ItemKey,
@ -149,11 +152,12 @@ impl TagItem {
&self.flags
}
pub(crate) fn re_map(self, tag_type: &TagType) -> Option<Self> {
self.item_key.map_key(tag_type).is_some().then(|| self)
pub(crate) fn re_map(&self, tag_type: &TagType) -> Option<()> {
self.item_key.map_key(tag_type).is_some().then(|| ())
}
}
#[derive(Clone)]
/// Represents a tag item's value
///
/// NOTES:
@ -166,10 +170,43 @@ pub enum ItemValue {
Text(String),
/// **(APE/ID3v2 ONLY)** Any UTF-8 encoded locator of external information
Locator(String),
/// **(APE ONLY)** Binary information, most likely a picture
/// **(APE/ID3v2 ONLY)** Binary information
///
/// In the case of ID3v2, this is the type of a [`Id3v2Frame::EncapsulatedObject`](crate::id3::Id3v2Frame::EncapsulatedObject) **and** any unknown frame.
///
/// For APEv2, no uses of this item type are documented, there's no telling what it could be.
Binary(Vec<u8>),
/// **(ID3v2 ONLY)** The content of a synchronized text frame, see [`SynchronizedText`](crate::id3::SynchronizedText)
SynchronizedText(Vec<(u32, String)>),
}
#[derive(Default, Copy, Clone)]
#[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`]
pub unsynchronisation: bool,
/// Whether or not the header is followed by an extended header
pub extended_header: bool,
/// Indicates if the tag is in an experimental stage
pub experimental: bool,
/// Indicates that the tag includes a footer
pub footer: bool,
/// Whether or not to include a CRC-32 in the extended header
///
/// NOTE: This **requires** `extended_header` to be set. Otherwise, it will be ignored.
///
/// This is calculated if the tag is written
pub crc: bool,
/// Restrictions on the tag
///
/// NOTE: This **requires** `extended_header` to be set. Otherwise, it will be ignored.
///
/// In addition to being setting this flag, all restrictions must be provided. See [`TagRestrictions`]
pub restrictions: (bool, TagRestrictions),
}
#[derive(Clone)]
/// Represents a parsed tag
///
/// NOTE: Items and pictures are separated
@ -177,6 +214,7 @@ pub struct Tag {
tag_type: TagType,
pictures: Vec<Picture>,
items: Vec<TagItem>,
flags: TagFlags,
}
impl IntoIterator for Tag {
@ -222,6 +260,7 @@ impl Tag {
tag_type,
pictures: vec![],
items: vec![],
flags: TagFlags::default()
}
}
}
@ -299,7 +338,7 @@ impl Tag {
/// When dealing with ID3v2, it may be necessary to use [`insert_item_unchecked`](Tag::insert_item_unchecked).
/// See [`id3`](crate::id3) for an explanation.
pub fn insert_item(&mut self, item: TagItem) -> bool {
if let Some(item) = item.re_map(&self.tag_type) {
if item.re_map(&self.tag_type).is_some() {
self.insert_item_unchecked(item);
return true;
}