iOS - Getting [Explicit] and [Clean] tags from Media in Objective-C
Asked Answered
M

1

7

When I view my purchased music in iTunes songs that are explicit are shown with a red explicit box next to them in the list of songs. I.e. the explicit tag you see when purchasing the song is passed through to the iTunes library. Also the same is done for songs itunes tagged as clean. I'd really like to be able to identify any songs that are explicit in my ios app but I can't find any resources on whether the tag is passed through to the ios devices with the other song information (MPMediaItemProperty) and if so how to get it (I've searched endlessly!) Some songs include "[Explicit] at the end of their title, but this is only the case with some songs, not all. Does anyone know if the tag is present and readable from Objective-C code?

Majuscule answered 3/11, 2012 at 10:16 Comment(0)
H
8

Well, this took me a good few hours to find! Be prepared, it's not as simple as just using MPMediaQuery.

Overview

The data you need isn't easily accessible via the standard channels (i.e There is no pre-defined key in the MediaPlayer or AVFoundation frameworks to access this metadata). It is available via most ID3 tag editors, under the name ITUNESADVISORY. This tag can take 3 values:

0 - No advisory information

1 - Explicit

2 - Clean

This is what we're looking for, but how do we access it. The MediaPlayer framework is fairly high level, which means that we are limited in what data we can access/use. In order to look more deeply at a media file, we need to use AVFoundation framework as well.

How-to

I don't know what exact workflow you're using, but I hope you can adapt this to your needs. In order to determine whether a media file is explicit/clean or otherwise, I did as follows:

  1. I needed to get a hold of a MPMediaItem containing the file I want to inspect. I did this using MPMediaPickerController, presenting it, and retrieved the selected media items through its delegate method:

    - (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
        // Do whatever is appropriate in your case to extract the media items
        MPMediaItem* item = [mediaItemCollection.items objectAtIndex:...];
        ....
    }
    
  2. Once I have my MPMediaItem, I need to get the equivalent AVAsset so I can work with the AVFoundation framework. To do this, I can use the URL path from the media item to create the asset.

    MPMediaItem* item = ...;
    NSURL* path = [item valueForProperty:MPMediaItemPropertyAssetURL];
    
    // We have to check if a path exists, because a media item may not be present on the device. Blame iTunes Match.
    if (path) {
        AVAsset* asset = [AVAsset assetWithURL:path];
        ....
    
  3. Once we have our asset, we need to get the metadata from it. From experimentation, this is iTunes metadata. As such, lets extract it from our asset.

    NSArray* metadata = [asset metadataForFormat:AVMetadataFormatiTunesMetadata];
    
  4. This is where the fun, undocumented work begins. We now have to find the correct metadata item for what we want. As the advisory key is not declared as a constant in any of Apple's documentation, after a lot of trial and error, I've found it to be 1920233063.

    To get the correct metadata item, we need to perform a filter on the metadata array, as so:

    NSUInteger advisoryIndex = [metadata indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[AVMetadataItem class]]) {
            AVMetadataItem* metaItem = (AVMetadataItem*)obj;
            NSNumber* advisoryKeyTest = @(1920233063);
    
            if ([metaItem.key isEqual:advisoryKeyTest]) {
                *stop = YES;
                return YES;
            }
            return NO;
        }
        return NO;
    }];
    
  5. Once we've done that, then we need to determine what it is. This is relatively simple, and can be adapted to your own needs. I've just written a simple switch statement that says what type the song/media is. (Remember: It's entirely possible the media file doesn't include an advisory tag, so we have to check whether the index exists or not)

    if (advisoryIndex != NSNotFound) {
        AVMetadataItem* metaItem = [metadata objectAtIndex:advisoryIndex];
    
        NSInteger advisoryValue = [metaItem.numberValue integerValue];
        switch (advisoryValue) {
            case 0:
                NSLog(@"%@", @"Unspecified");
                break;
            case 1:
                NSLog(@"%@", @"Explicit");
                break;
            case 2:
                NSLog(@"%@", @"Clean");
                break;
            default:
                NSLog(@"%@", @"Unexpected Value");
                break;
        }
    }
    

Conclusion

And there you have it, a way to determine whether a song is clean or explicit, or neither. Because this is using a static number to find the advisory data, and is not linked to any constant defined in Apple's headers, I can not guarantee that this will work for all iOS versions in the past, present and future. I have tested this on iOS 6, and it seemed to be ok. Your milage may vary.

It's a shame Apple don't provide this functionality out of the box (even if they just provided the Advisory Key). This functionality could be placed within a Category, if you so desire.

Holpen answered 3/11, 2012 at 16:59 Comment(7)
Wow, thank you so much for solving this. I think you must be the only person to have found this out as in all my searching I couldn't find anyone who'd done it. Much appreciated!Majuscule
Took a lot of digging around, and sacrificing some of my music to make them clean/explicit(!), but I'm glad I was able to help :)Holpen
@Adam Are you using iTunes Match, or re-encoding the music for the device when syncing?Holpen
I implemented this today and unfortunately I'm finding it isn't a complete solution as several of my library explicit songs don't have that key, some only have iTunNORM and iTunSMPB keys. I guess this might mean the explicit information simply isn't there reliably for all tracks which is real shame.Majuscule
I guess it might be that the explicit tag is actually within the value of the iTunNORM or iTunSMPB key in some alternative way for songs that use them instead of the numerically named keys such as 1920233063 - not an area I have any knowledge on though unfortunately.Majuscule
If you crack open the song in something like MP3Tag (Windows only, but works in Crossover), does it include the ITUNESADVISORY tag? I wouldn't write this off yet, it may be a case that AVFoundation didn't load that key yet (for performance reasons, it loads only some metadata, it may have missed the Advisory ones). Will investigate when I can, this is an interesting project for myself!Holpen
I'm not using iTunes match. I have a mix of tracks, some from imported MP3's, some ripped from CD using iTunes and the rest purchased through iTunes. However I would only expect to be able to get the explicit warning for tunes purchased through iTunes and these are the tracks I was testing with.Majuscule

© 2022 - 2024 — McMap. All rights reserved.