SouthernYankee65
SouthernYankee65

Reputation: 1269

ITunes Library Framework in Swift 5.2

I have searched everywhere and I am unable to find a swifty example of how to use the Apple ITunesLibraryFramework. I have been trying to figure out how to use this Framework in Swift 5.2.

I want to get information directly from the Music library rather than having to rely on a XML library export file.

I have the below code in my playground and it prints nothing legible. How would I access the fields for playlists and mediaItems and be able to read them in human readable form?

I have installed the framework in the project. This is my project playground code:

import Foundation
import iTunesLibrary

var library:ITLibrary

do {
    let library = try ITLibrary(apiVersion: "1.1")
    let mediaItems = library.allMediaItems
    let playlists = library.allPlaylists
    print("Media Folder Location - \(String(describing: library.mediaFolderLocation))")
    print("\nPlaylists - \(playlists)")
    print("\nTracks - \(mediaItems)")
} catch let error as NSError {
    print(error)
}

This is the ITLibrary.m file that I imported the header:

#import <Foundation/Foundation.h>
#import <iTunesLibrary/iTunesLibrary.h>

When I run the above code in the project playground all I get is a bunch of binary data for both playlists and mediaItems. All I want to do is iterate over the data and collect information from the library for use in my program. It's probably something easy, but I haven't found it yet.

EDIT: - After using @Vincent's answer I ran into another problem with the following code:

import Foundation
import iTunesLibrary

let library = try ITLibrary(apiVersion: "1.1")
typealias tracks = [NSNumber:TrackInfo]
var trackInfo = TrackInfo()

struct TrackInfo {
    var title = ""
    var artist = ""
    var album = ""
    var totalTime = 0
    var year = 0
    var persistentID = ""
    var location:URL!
}

let songs = library.allMediaItems
let playlists = library.allPlaylists

for playlist in playlists {
    if playlist.name.lowercased().contains("test-") {
        print("New Playlist---------------\nName: \(playlist.name)")
        for song in playlist.items {
            trackInfo.title = song.title
            print("\n\nNew Track-----------------\nTitle: \(trackInfo.title)")
            if song.artist?.name != nil {
                trackInfo.artist = song.artist?.name as! String
            }
            print("Artist: \(trackInfo.artist)")
            trackInfo.album = song.album.title!
            print("Albumn Name: \(trackInfo.album)")
            trackInfo.totalTime = song.totalTime
            print("Total Time: \(trackInfo.totalTime)")
            trackInfo.year = song.year
            print("Year: \(trackInfo.year)")
            trackInfo.location = song.location!
            print("Location: \(trackInfo.location!)")
            var persistentID = song.persistentID
            tracks.updateValue(song.persistentID, trackInfo)
        }
    }
}

The issue I'm having is getting the tracks info into the trackInfo dictionary. I'm trying to use the track persistentID (NSNumber) as the key for the dictionary, which I have declared. For some reason it isn't allowing me to use it.

Upvotes: 1

Views: 711

Answers (1)

vincent
vincent

Reputation: 267

Here's how you can have it print each playlist and track:

Each ITLibPlaylist or ITLibMediaItem object contains many information about each playlist/media item. To get only the name/title of each, you will have to iterate through the results to retrieve them.

For this example below, the name of each playlist's name is printed.

    print("\nPlaylists -")
    for playlist in playlists {
        print(playlist.name)
    }

Which will print (for example):

Playlists -
Library
Music

For this example below, the name of each track's name is printed.

    print("\nTracks -")
    for mediaItem in mediaItems {
        print(mediaItem.title)
    }

Which will print (for example):

Tracks -
Ev'ry Time We Say Goodbye
My Favorite Things
But Not for Me
Summertime

Edit: Here's the secondary solution to the secondary problem:

First things first, a dictionary should be initialised, instead of using typealias.

typealias only makes an alias for a pre existing type, like

typealias NumberWithAlotOfDecimals = Double
let a: NumberWithAlotOfDecimals = 10.1
let b: Double = 10.1

both will a and b are Double, as NumberWithAlotOfDecimals is just an alias for Double.

Here's how to initialise:

//typealias tracks = [NSNumber:TrackInfo] // not this
var tracks = [NSNumber:TrackInfo]() // but this

Secondly, nullable objects should be properly handled

            if let artistName = song.artist?.name {
                trackInfo.artist = artistName
            }

and

            if let title = song.album.title {
                trackInfo.album = title
            }
            if let location = song.location {
                trackInfo.location = location
                print("Location: \(location)")
            }

instead of

            if song.artist?.name != nil {
                trackInfo.artist = song.artist?.name as! String
            }

Please do not use ! to force unwrap nullable objects as that will cause runtime crashes when the object is nil.

Lastly, this is the way to store key value into dictionary in Swift.

            let persistentID = song.persistentID
            //tracks.updateValue(song.persistentID, trackInfo) // not this
            tracks[persistentID] = trackInfo // this 

Upvotes: 1

Related Questions