Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Well, this took me a good few hours to find! Be prepared, it's not as simple as just using <code>MPMediaQuery</code>.</p> <h2>Overview</h2> <p>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 <code>ITUNESADVISORY</code>. This tag can take 3 values:</p> <blockquote> <p>0 - No advisory information</p> <p>1 - Explicit</p> <p>2 - Clean</p> </blockquote> <p>This is what we're looking for, but how do we access it. The <code>MediaPlayer</code> 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 <code>AVFoundation</code> framework as well.</p> <h2>How-to</h2> <p>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:</p> <ol> <li><p>I needed to get a hold of a <code>MPMediaItem</code> containing the file I want to inspect. I did this using <code>MPMediaPickerController</code>, presenting it, and retrieved the selected media items through its delegate method:</p> <pre><code>- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection { // Do whatever is appropriate in your case to extract the media items MPMediaItem* item = [mediaItemCollection.items objectAtIndex:...]; .... } </code></pre></li> <li><p>Once I have my <code>MPMediaItem</code>, I need to get the equivalent <code>AVAsset</code> so I can work with the <code>AVFoundation</code> framework. To do this, I can use the URL path from the media item to create the asset.</p> <pre><code>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]; .... </code></pre></li> <li><p>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.</p> <pre><code>NSArray* metadata = [asset metadataForFormat:AVMetadataFormatiTunesMetadata]; </code></pre></li> <li><p>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 <code>1920233063</code>.</p> <p>To get the correct metadata item, we need to perform a filter on the metadata array, as so:</p> <pre><code>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; }]; </code></pre></li> <li><p>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. (<strong>Remember:</strong> It's entirely possible the media file doesn't include an advisory tag, so we have to check whether the index exists or not)</p> <pre><code>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; } } </code></pre></li> </ol> <h2>Conclusion</h2> <p>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.</p> <p>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.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload