swift3avfoundationmetadatapodcastavmetadataitem

How to get all associated data or metadata from podcast using Swift?


I'm currently using Swift 3 to create a podcast player and I am having problems accessing all the 'hidden' data (metadata) associated with a podcast file.

Specifically, in Apple's Podcast app they show 'comments' or rather a detailed description. This info is not available when using MPMediaPlayer which is how I've written my entire app so far.

I've found this post which appears to be on the right track but not specific enough for me using Swift: Getting podcast metadata from from iPodLibrary

How can I access this additional info ?

Or is there a way to implement the linked code (Obj-C) in my Swit 3 app?

EDIT:

OK, I'm inching closer to a solution. However, I am now unable to figure out how to get to a specific key in the following structure.

First here's my current code in which I send a podcast (item) to this function:

///////// key=TDS
func getMeta(_ item: MPMediaItem){
    print("")
    print("--------- GETMETA ---------")
    let url = item.value(forProperty:MPMediaItemPropertyAssetURL) as? NSURL
    let asset = AVURLAsset(url: url as! URL, options: nil)

    let formatsKey = "availableMetadataFormats"
    asset.loadValuesAsynchronously(forKeys: [formatsKey]) {
        var error: NSError? = nil
        let status = asset.statusOfValue(forKey: formatsKey, error: &error)
        if status == .loaded {
            for format in asset.availableMetadataFormats {
                let metadata = asset.metadata(forFormat: format)
                print("format:\(format)")
                print("metadata description:\(metadata.description)")
            }
        }
    }
}
/////////

Which produces this output for a given podcast:

format:org.id3
metadata description:[<AVMetadataItem: 0x174005f40, identifier=id3/TIT2, keySpace=org.id3, key class = NSTaggedPointerString, key=TIT2, commonKey=title, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=FriComedy:  The News Quiz 3rd Feb 2017>, <AVMetadataItem: 0x174006160, identifier=id3/TPE1, keySpace=org.id3, key class = NSTaggedPointerString, key=TPE1, commonKey=artist, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=BBC Radio 4>, <AVMetadataItem: 0x174006310, identifier=id3/TALB, keySpace=org.id3, key class = NSTaggedPointerString, key=TALB, commonKey=albumName, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=Friday Night Comedy from BBC Radio 4>, <AVMetadataItem: 0x174006130, identifier=id3/TCON, keySpace=org.id3, key class = NSTaggedPointerString, key=TCON, commonKey=type, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=Podcast>, <AVMetadataItem: 0x174006320, identifier=id3/USLT, keySpace=org.id3, key class = NSTaggedPointerString, key=USLT, commonKey=(null), extendedLanguageTag=   , dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
    info = "";
}, value=Susan Calman, Andy Hamilton, Katy Brand and Lloyd Langford are amongst Miles' esteemed guests for this week's round of news-wrangling.



Theresa May won a vote, Donald Trump won a vote and François Fillon might have to drop out of a vote. Orangutans can't vote but still feature in the programme.



Producer: Richard Morris

A BBC Studios Production>, <AVMetadataItem: 0x174006330, identifier=id3/COMM, keySpace=org.id3, key class = NSTaggedPointerString, key=COMM, commonKey=(null), extendedLanguageTag=en, dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
    info = "";
}, value=Susan Calman, Andy Hamilton, Katy Brand and Lloyd Langford are amongst Miles' esteemed guests for this week's round of news-wrangling.



Theresa May won a vote, Donald Trump won a vote and François Fillon might have to drop out of a vote. Orangutans can't vote but still feature in the programme.



Producer: Richard Morris

A BBC Studios Production>, <AVMetadataItem: 0x174006340, identifier=id3/TCOP, keySpace=org.id3, key class = NSTaggedPointerString, key=TCOP, commonKey=copyrights, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=(c) BBC 2017>, <AVMetadataItem: 0x174006350, identifier=id3/APIC, keySpace=org.id3, key class = NSTaggedPointerString, key=APIC, commonKey=artwork, extendedLanguageTag=(null), dataType=com.apple.metadata.datatype.JPEG, time={INVALID}, duration={INVALID}, startDate=(null), extras={
    dataType = "image/jpeg";
    dataTypeNamespace = "org.iana.media-type";
    info = "";
    pictureType = "Cover (front)";
}, value length=50551>, <AVMetadataItem: 0x174006360, identifier=id3/TIT3, keySpace=org.id3, key class = NSTaggedPointerString, key=TIT3, commonKey=description, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=A satirical review of the week's news, chaired by Miles Jupp>, <AVMetadataItem: 0x174006370, identifier=id3/TYER, keySpace=org.id3, key class = NSTaggedPointerString, key=TYER, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=2017>, <AVMetadataItem: 0x174006380, identifier=id3/TDRL, keySpace=org.id3, key class = NSTaggedPointerString, key=TDRL, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=2017-02-03T18:57:00Z>, <AVMetadataItem: 0x174006390, identifier=id3/COMM, keySpace=org.id3, key class = NSTaggedPointerString, key=COMM, commonKey=(null), extendedLanguageTag=en, dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
    info = iTunPGAP;
}, value=0>, <AVMetadataItem: 0x1740063a0, identifier=id3/PCST, keySpace=org.id3, key class = NSTaggedPointerString, key=PCST, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value length=4>, <AVMetadataItem: 0x1740063b0, identifier=id3/TDES, keySpace=org.id3, key class = NSTaggedPointerString, key=TDES, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=Susan Calman, Andy Hamilton, Katy Brand and Lloyd Langford are amongst Miles' esteemed guests for this week's round of news-wrangling.



Theresa May won a vote, Donald Trump won a vote and François Fillon might have to drop out of a vote. Orangutans can't vote but still feature in the programme.



Producer: Richard Morris

A BBC Studios Production>, <AVMetadataItem: 0x1740063c0, identifier=id3/TGID, keySpace=org.id3, key class = NSTaggedPointerString, key=TGID, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=urn:bbc:podcast:p04rt97d>, <AVMetadataItem: 0x1740063d0, identifier=id3/WFED, keySpace=org.id3, key class = NSTaggedPointerString, key=WFED, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={
}, value=%00http://www.bbc.co.uk/programmes/p02pc9pj/episodes/downloads.rss%00>]

I am trying to isolate the text/value for key=TDES and/or identifier=id3/TDES


Solution

  • OK, after a lot of digging and asking questions, here is, I believe the shortest code I can manage to loop through any/all metadata from an MPMediaItem - including Podcasts. Code is Swift 3

        // Use this function to get and search through all the metadata from an MPMediaItem
                func getMeta(_ item: MPMediaItem)->String{
                    let url = item.value(forProperty:MPMediaItemPropertyAssetURL) as? NSURL
                    let asset = AVURLAsset(url: url! as URL, options: nil)
    
                    var sMetaValue: String = ""
    
                    // If you want to parse metadata based on a specific format or key space,
                    // uncomment the line below and comment the line 2 below 
                    // let metaArray = asset.metadata(forFormat: "org.id3") 
                    let metaArray = asset.metadata
                    for metadata in metaArray{
                        // Uncomment this print to see all the metadata
                        //print("----- metadata:\(metadata)")
                        let sKey = returnKeyString(metadata.identifier!)
                        // See if the returned key matches your intent
                        if (sKey == "tdes"){
                            if let sVal = metadata.stringValue{
                                sMetaValue = sVal
                            }
                        }
                    }
                }
    
        // Helper function to parse the identifier - easier than working with keys
                func returnKeyString(_ inVal: String)->String{
                    // expecting the metadata for "identifier" as input - returns key value
                    // eg "itsk/ldes" ->  "ldes"
                    // or "id3/%00WFD" etc.  -> "wfd"
                    var sFinal:String = ""
    
                    if (inVal.contains("/")){
                        sFinal = (inVal.components(separatedBy: "/")[1])
                    }
                    if sFinal.contains("%"){
                        sFinal = sFinal.components(separatedBy: "%")[1]
                        let index1 = sFinal.index(sFinal.startIndex, offsetBy: 2)
                        sFinal = sFinal.substring(from: index1)
                    }
                    return sFinal.lowercased()
                }