Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions src/mp4/ilst/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,33 +216,44 @@ pub enum AtomData {
}

/// The parental advisory rating
///
/// See also:
/// <https://docs.mp3tag.de/mapping/#itunesadvisory>
/// <https://exiftool.org/TagNames/QuickTime.html>
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AdvisoryRating {
/// A rating of 0
/// *Inoffensive*/*None* (0)
Inoffensive,
/// A rating of 2
Clean,
/// A rating of (1 || > 2)
/// *Explicit* (1 or 4)
///
/// In the past Apple used the value 4 for explicit content
/// that has later been replaced by 1. Both values are considered
/// as valid when reading but only the newer value 1 is written.
Explicit,
/// *Clean*/*Edited* (2)
Clean,
}

impl AdvisoryRating {
/// Returns the rating as it appears in the `rtng` atom
pub fn as_u8(&self) -> u8 {
match self {
AdvisoryRating::Inoffensive => 0,
AdvisoryRating::Explicit => 1,
AdvisoryRating::Clean => 2,
AdvisoryRating::Explicit => 4,
}
}
}

impl From<u8> for AdvisoryRating {
fn from(input: u8) -> Self {
impl TryFrom<u8> for AdvisoryRating {
type Error = u8;

fn try_from(input: u8) -> Result<Self, Self::Error> {
match input {
0 => Self::Inoffensive,
2 => Self::Clean,
_ => Self::Explicit,
0 => Ok(Self::Inoffensive),
1 | 4 => Ok(Self::Explicit),
2 => Ok(Self::Clean),
value => Err(value),
}
}
}
20 changes: 9 additions & 11 deletions src/mp4/ilst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,15 @@ impl Ilst {

/// Returns the parental advisory rating according to the `rtng` atom
pub fn advisory_rating(&self) -> Option<AdvisoryRating> {
if let Some(atom) = self.atom(&ADVISORY_RATING) {
let rating = match atom.data().next() {
Some(AtomData::SignedInteger(si)) => *si as u8,
Some(AtomData::Unknown { data: c, .. }) if !c.is_empty() => c[0],
_ => return None,
};

return Some(AdvisoryRating::from(rating));
}

None
self.atom(&ADVISORY_RATING)
.into_iter()
.flat_map(Atom::data)
.filter_map(|data| match data {
AtomData::SignedInteger(si) => u8::try_from(*si).ok(),
AtomData::Unknown { data, .. } => data.first().copied(),
_ => None,
})
.find_map(|rating| AdvisoryRating::try_from(rating).ok())
}

/// Sets the advisory rating
Expand Down