2 Replies
      Latest reply on Feb 5, 2019 9:56 AM by Claude31
      ComboDrums Level 1 Level 1 (0 points)

        Hi,

         

        I'm looking for a way to get all the iTunes artists and their albums in a tree (like the playlists in iTunes which I get like it).

         

        I tried an algo where I get all the media items filtered by mediaKind == .kindSong sorted by artist and after that, I "while" loop in all the media items count (about 36 000 for me (iTunes user for 15 years )) to filter them by artist name and after that by album title so each time, I increase the i + the count of the results to go to the next artist and then next album for each artist.

         

        It is working but it is very slow. I think it is because of the array filter function of the media items list which loop into all the array (right ?) to find the criteria. But as I sorted it just before to start the loop, it could be faster to stop it as soon as the artist name is not the same than the previous (or something like that...).

         

        Here is the 2 main func I use :

        static func getArtistsTree(theITTracks: [ITLibMediaItem], theLenght: Int) -> [Artist] {
            var theArtists: [Artist] = [Artist]() // just a custon obj to record the artists
            let theArtistNames = getAllArtistNames(theITTracks: theITTracks).sorted()
            for theArtistName in theArtistNames {
                let theArtistResults = theITTracks.filter({$0.artist?.name?.lowercased() == theArtistName.lowercased()}).sorted(by: {self.sortITTrack(ITTrack1: $0, ITTrack2: $1, kind: ITSortKind.album)})
                print("V&G_Project___theArtistResult.count : ", theArtistResults.count)
                var i: Int = 0
                while i < theArtistResults.count {
                    let theArtistTrack = theArtistResults[i]
                    if let theAlbumTitle = theArtistTrack.album.title {
                        let theAlbumResults = theArtistResults.filter({$0.album.title?.lowercased() == theAlbumTitle.lowercased()})
                        print("V&G_Project___name : ", theArtistTrack.artist?.name, " - ", theAlbumTitle, "theAlbumResults.count : " + String(theAlbumResults.count))
                        var j: Int = 0
                        while j < theAlbumResults.count {
                            let theAlbum = theAlbumResults[j]
                            let theTracksResults = theAlbumResults.filter({$0.album.title?.lowercased() == theAlbumTitle.lowercased()})
                            j += 1
                        }
                        i += theAlbumResults.count
                    } else {
                        i += 1
                    }
                }
                print("V&G_Project___--------------- : ")
            }
            
            return theArtists
        }
        
        static func getAllArtistNames(theITTracks: [ITLibMediaItem]) -> [String] {
            var theArtistsList: [String] = [String]()
            for theITTrack in theITTracks {
                let theArtistName = theITTrack.artist?.name
                var theToto: String = "unknown"
                if let theArtistName = theArtistName {
                    theToto = theArtistName
                }
                let theIndex = theArtistsList.index(of: theToto)
                print("V&G_Project___getAllArtistNames : ", theIndex)
                if theIndex == nil {
                    theArtistsList.append(theToto)
                }
                
            }
            return theArtistsList
        }
        
        do {
            let lib = try ITLibrary(apiVersion: "1.0")
            let theITTracks = lib.allMediaItems.filter({$0.mediaKind == .kindSong})
            let theArtistsTree = iTunesModel.getArtistsTree(theITTracks: theITTracks, theLenght: theITTracks.count)    
        } catch let error {
            print("V&G_Project___<#name#> : ", error)
        }

        I can use only one func to save one loop but even with one, everything works fine but the algorythm is very slooooww and I need to improve it.

         

        Any idea ?

         

        Thx.

        • Re: [ITLib] Get a tree of artists / albums (Mac OS Swift app)
          eskimo Apple Staff Apple Staff (11,955 points)

          On line 3 you build a list of artist names and then on line 4 you iterate that list and on line 5 you filter the tracks to find the tracks for that artist.  But you’ve already gone through the list of tracks on line 3, so you can accumulate the info you need at that point.  For example, in the code below I walk the list of tracks building a dictionary that maps the artist name to a list of their tracks.

          struct Track {
              var id: Int
              var artist: String
          }
          
          let tracks = [
              Track(id: 1, artist: "a"),
              Track(id: 2, artist: "b"),
              Track(id: 3, artist: "c"),
              Track(id: 4, artist: "a"),
              Track(id: 5, artist: "a"),
              Track(id: 6, artist: "a"),
              Track(id: 7, artist: "b"),
          ]
          let tracksByArtist = Dictionary(grouping: tracks, by: { $0.artist })
          for (artist, tracks) in tracksByArtist {
              print(artist, tracks.map { $0.id })
          }
          // prints:
          //
          // a [1, 4, 5, 6]
          // b [2, 7]
          // c [3]

          There’s probably a bunch of other things you can improve here, but let’s stack with this.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

          • Re: [ITLib] Get a tree of artists / albums (Mac OS Swift app)
            Claude31 Level 8 Level 8 (6,555 points)

            There is something I don't understand in your code:

             

            Line 2, you create an empty array

             

                var theArtists: [Artist] = [Artist]() // just a custon obj to record the artists

             

            You return the array on line 27

             

                return theArtists 

             

            But it was never modified in between.

             

            So either it is useless, or your code cannot work.

            Did I miss something ?