' 
' This is a script to generate various statistics for your iTunes library.
' On average, it would take about 1 minute to run for every 1,000 songs. 
' It was created by Scott Yanoff (yanoff-NOSPAM@yahoo.com). Copyright 2011. 
' (Remove the "-NOSPAM" to successfully contact me) 
' Great scripting help can be found at: http://blogs.technet.com/b/heyscriptingguy/archive/2010/11/21/icame-ipod-iscripted-scripting-itunes.aspx
' 
' Update history: 
' 12-24-2008    Created this script
' 12-30-2008    Added the RightPad function for right-alignment of text
'               Added enumeration to the lists
'               Enhanced the information by artist to include average plays per artist 
'               Added message at start of execution so user knows the script is running
'               File that is generated is now automatically launched at the end
'               Added percentages to some of the statistics
' 01-01-2009    Corrected filename to include leading zero in month and day
'               Added total song time and total played time
' 01-03-2009    Corrected display of count of least-recently played tracks 
' 01-07-2009    Added average track duration, average play count per track
' 01-08-2009    Removed longest songs listing, it was too hard to sort by time for little value
'               Added play counts by hour of the day
' 01-10-2009    Limited the Top Genres list to 20 instead of displaying entire list
'               Most-played album listing now only shows albums with > 7 songs
' 01-11-2009    Limited the Artists list to 100 instead of displaying entire list
' 01-19-2009    Increased top albums display, corrected leading zero in seconds in average track duration
' 02-04-2009    Added count of unique artists
' 02-25-2009    Added artist name to all song lists
'               Now limits list of years to top 30 years, and numbers them
'               Now numbers genres and allows for more space for them
' 03-20-2009    Changed Tracks by Year to be Tracks by Decade
' 01-04-2010    Increased number of top albums, made min. # of songs on an album a variable
'               Minor cosmetic changes to the output
' 01-23-2010    Added total song play count for the top albums
' 09-20-2010    Added the run date to the file
' 11-30-2010    Now prints a count of the number of unique songs played in the last week, month, quarter, and year
'               Now prints a count of the number of unique songs never played
' 12-03-2010    Now writes historical data to iTunesStats.csv for import into spreadsheet for historical/trending analysis.
' 07-22-2011		Reformatted plays-by-hour and improved the speed of processing that data 
'               Added bit rate (quality) analysis of tracks
'								Added file type analysis of tracks
'								Added plays-by-rating, plays-by-decade, and plays-by-genre
' 09-18-2011		Added top most-skipped tracks
' 11-05-2011		Now displays count of tracks missing genre or year
'
Const SORT_BY_NUMBER     = 1
Const SORT_BY_NUMBER_ASC = 2
Const SORT_BY_STRING     = 3

Dim songCount, playCount, intDisplayTopSongs, intDisplayTopAlbums, totalTime, songAndArtist
Dim totalPlayedTime, playedHour, intDisplayTopGenres, i, intDisplayTopArtists, intDisplayTopYears, intDisplayTopKinds
songCount            = 0 
playCount            = 0

' The following are constants that can be changed to affect the output. 
' These constants control how many items appear in the various lists that are output.
intDisplayTopSongs   = 100
intDisplayTopAlbums  = 51
intDisplayTopGenres  = 20
intDisplayTopKinds	 = 20
intDisplayTopSkips   = 20
intDisplayTopArtists = 100
intDisplayTopYears   = 30
intMinSongsOnAlbum   = 7

Dim objApp, objLibrary, colTracks, intCount, strFileName, strSong, strArtist, strAlbum, strYear, strDataFileName, objDataFile
Dim dictAlbums, dictArtistsSongs, dictRatingsSongs, dictPlaysByRating, dictGenreSongs, dictYearSongs, dictPlaysByHour, dictPlaysByYear, dictPlaysByGenre
Dim dictPlayedCounts, dimSkips, dictPlayedDates, dictArtistPlaycounts, dictAlbumPlaycounts, dictAlbumTotalPlaycount, dictBitRates, dictKinds
Dim intSongsPlayedLastWeek, intSongsPlayedLastMonth, intSongsPlayedLastQuarter, intSongsPlayedLastYear, intSongsNeverPlayed
Dim LAST_WEEK, LAST_MONTH, LAST_QUARTER, LAST_YEAR
Set dictAlbums = CreateObject("Scripting.Dictionary") 
Set dictArtistsSongs = CreateObject("Scripting.Dictionary") 
Set dictRatingsSongs = CreateObject("Scripting.Dictionary") 
Set dictPlaysByRating = CreateObject("Scripting.Dictionary") 
Set dictGenreSongs = CreateObject("Scripting.Dictionary") 
Set dictPlaysByGenre = CreateObject("Scripting.Dictionary") 
Set dictYearSongs = CreateObject("Scripting.Dictionary") 
Set dictPlaysByYear = CreateObject("Scripting.Dictionary") 
Set dictPlaysByHour = CreateObject("Scripting.Dictionary")
Set dictPlayedCounts = CreateObject("Scripting.Dictionary") 
Set dictSkips = CreateObject("Scripting.Dictionary") 
Set dictPlayedDates = CreateObject("Scripting.Dictionary")  
Set dictArtistPlaycounts = CreateObject("Scripting.Dictionary") 
Set dictAlbumPlaycounts = CreateObject("Scripting.Dictionary") 
Set dictAlbumTotalPlaycount = CreateObject("Scripting.Dictionary")
Set dictBitRates = CreateObject("Scripting.Dictionary")
Set dictKinds = CreateObject("Scripting.Dictionary")

' Initialize some of the counters:
intSongsPlayedLastWeek    = 0
intSongsPlayedLastMonth   = 0
intSongsPlayedLastQuarter = 0
intSongsPlayedLastYear    = 0
intSongsNeverPlayed       = 0
LAST_WEEK                 = Now()-7
LAST_MONTH                = Now()-30
LAST_QUARTER              = Now()-90
LAST_YEAR                 = Now()-365

strFileName = "iTunesStats." & DatePart("yyyy",Now()) & Right("0" & Month(Now()),2) & Right("0" & Day(Now()),2) & ".txt" 
strDataFileName = "iTunesStats.csv"
Wscript.Echo "iTunes Stats v2.19 by Scott Yanoff" & chr(13) & chr(13) & "iTunes Stats will take a few minutes to run. When it is done, it will show you the stats in a file called " & strFileName & VbCrLf & VbCrLf & "Look for iTunesStats on Facebook!"

' Initialize the dictPlaysByHour object so that every hour has an entry:
 For i = 0 to 23
  dictPlaysByHour.Add i,0
 Next

' Initialize the dictBitRates object so that the ranges we track have an entry:
 dictBitRates.Add "Excellent",0
 dictBitRates.Add "High",0
 dictBitRates.Add "Good",0
 dictBitRates.Add "Low",0

' This function can be used to add spaces to the end of some text
Function Pad(ByRef Text, ByVal Length)
  Pad = Left(Text & Space(Length), Length)
End Function

' This function can be used to add spaces to the beginning of some text
Function RightPad(ByRef Text, ByVal Length) 
  RightPad = Right(Space(Length) & Text, Length) 
End Function 


 ' Description:
 '   Sorts a dictionary by either key or item
 ' Parameters:
 '   objDict - the dictionary to sort
 '   sortField - the field to sort (1=key, 2=item)
 '   sortBy - (1=sort by number, 2=sory by number ascending, 3=sort by string)
 ' Returns:
 '   A dictionary sorted by sortField
 '
Function SortDictionary(objDict, sortField, sortBy)

    ' declare constants
    Const dictKey  = 1
    Const dictItem = 2

    ' declare our variables
    Dim strDict()
    Dim objKey
    Dim strKey, strItem
    Dim X,Y,Z

    ' get the dictionary count
    Z = objDict.Count

    ' we need more than one item to warrant sorting
    If Z > 1 Then
      ' create an array to store dictionary information:
      ReDim strDict(Z,2)
      X = 0
      ' populate the string array:
      For Each objKey In objDict
          strDict(X,dictKey)  = objKey
          strDict(X,dictItem) = objDict(objKey)
          X = X + 1
      Next

      ' perform a a shell sort of the string array:
      For X = 0 To (Z - 2)
        For Y = X To (Z - 1)
         
          Select case sortBy
           case SORT_BY_NUMBER
            If strDict(X,sortField) < strDict(Y,sortField) Then
              strKey  = strDict(X,dictKey)
              strItem = strDict(X,dictItem)
              strDict(X,dictKey)  = strDict(Y,dictKey)
              strDict(X,dictItem) = strDict(Y,dictItem)
              strDict(Y,dictKey)  = strKey
              strDict(Y,dictItem) = strItem
            End If
            
           case SORT_BY_NUMBER_ASC
            If strDict(X,sortField) > strDict(Y,sortField) Then
              strKey  = strDict(X,dictKey)
              strItem = strDict(X,dictItem)
              strDict(X,dictKey)  = strDict(Y,dictKey)
              strDict(X,dictItem) = strDict(Y,dictItem)
              strDict(Y,dictKey)  = strKey
              strDict(Y,dictItem) = strItem
            End If
                                
           case SORT_BY_STRING
            If StrComp(strDict(X,sortField),strDict(Y,sortField),vbTextCompare) > 0 Then
              strKey  = strDict(X,dictKey)
              strItem = strDict(X,dictItem)
              strDict(X,dictKey)  = strDict(Y,dictKey)
              strDict(X,dictItem) = strDict(Y,dictItem)
              strDict(Y,dictKey)  = strKey
              strDict(Y,dictItem) = strItem
            End If

          End Select
        Next
      Next

      ' erase the contents of the dictionary object
      objDict.RemoveAll

      ' repopulate the dictionary with the sorted information
      For X = 0 To (Z - 1)
        objDict.Add strDict(X,dictKey), strDict(X,dictItem)
      Next

    End If
  End Function

Set objApp = CreateObject("iTunes.Application") 
Set objLibrary = objApp.LibraryPlaylist 
Set colTracks = objLibrary.Tracks 

' Use these 2 lines for testing across a small part of the collection INSTEAD of the For Each below
'For i = 1 to 500
'Set objTrack = colTracks.Item(i)
For Each objTrack in colTracks 
 Dim song, album, artist, rating, genre, year, bitrate, kind, playedCount, playedDate, albumAndArtist, trackTime, trackTimeInSeconds, dateAdded, skips
 song    = objTrack.Name 
 album   = objTrack.Album 
 artist  = objTrack.Artist 
 rating  = objTrack.Rating 
 genre   = objTrack.Genre 
 year    = objTrack.Year
 kind		 = objTrack.KindAsString
 bitrate = objTrack.BitRate
 dateAdded = objTrack.DateAdded
 playedDate = objTrack.PlayedDate 
 playedCount = objTrack.PlayedCount 
 trackTime = objTrack.Time

 ' Calculate the total times:
 if isDate(trackTime) Then
  trackTimeInSeconds = (Hour(trackTime) * 60) + Minute(trackTime)
  totalTime = totalTime + trackTimeInSeconds 
  totalPlayedTime = totalPlayedTime + (trackTimeInSeconds * playedCount)
 end if
   
 ' Track the number of songs per artist: 
 if dictArtistsSongs.exists(artist) = true then 
  dictArtistsSongs(artist) = dictArtistsSongs(artist) + 1 
 else 
  dictArtistsSongs.Add artist,1 
 end if 

 ' Track the number of songs per rating:
 select case rating
  case 0
    rating = "None"
  case 20
    rating = "*"
  case 40
    rating = "**"
  case 60
    rating = "***"
  case 80
    rating = "****"
  case 100
    rating = "*****"
  case else
    rating = "None"
 end select
  
 if dictRatingsSongs.exists(rating) = true then 
  dictRatingsSongs(rating) = dictRatingsSongs(rating) + 1 
 else 
  dictRatingsSongs.Add rating,1 
 end if 
  
 ' Track the number of plays by rating:
 if dictPlaysByRating.exists(rating) = true then 
  dictPlaysByRating(rating) = dictPlaysByRating(rating) + playedCount 
 else 
  dictPlaysByRating.Add rating,playedCount 
 end if 

 ' Track the number of songs per genre: 
 if dictGenreSongs.exists(genre) = true then 
  dictGenreSongs(genre) = dictGenreSongs(genre) + 1 
 else 
  dictGenreSongs.Add genre,1 
 end if 

 ' Track the number of plays by genre:
 if dictPlaysByGenre.exists(genre) = true then 
  dictPlaysByGenre(genre) = dictPlaysByGenre(genre) + playedCount 
 else 
  dictPlaysByGenre.Add genre,playedCount 
 end if 

 ' Track the number of songs per year: 
 year = Left(year, 3) + "0s"
 if dictYearSongs.exists(year) = true then 
   dictYearSongs(year) = dictYearSongs(year) + 1 
 else 
   dictYearSongs.Add year,1 
 end if 

 ' Track the number of plays by decade:
 if dictPlaysByYear.exists(year) = true then 
  dictPlaysByYear(year) = dictPlaysByYear(year) + playedCount 
 else 
  dictPlaysByYear.Add year,playedCount 
 end if 

 ' Track the number of songs per kind: 
 if dictKinds.exists(kind) = true then 
  dictKinds(kind) = dictKinds(kind) + 1 
 else 
  dictKinds.Add kind,1 
 end if 

 ' Track the number of unique albums by combining album and artist name 
 ' This will ensure that albums such as "Greatest Hits" are tracked 
 ' individually by artist. We can also use this to track the song count
 ' per album, which will be used for the overall album play count later.
 albumAndArtist = album & "    (" & artist & ")" 
 if dictAlbums.exists(albumAndArtist) = true then 
  dictAlbums(albumAndArtist) = dictAlbums(albumAndArtist) + 1 
 else 
  dictAlbums.Add albumAndArtist,1 
 end if 

 ' Track the album play counts by storing lowest song play count per album:
 if dictAlbumPlaycounts.exists(albumAndArtist) = true then 
  if dictAlbumPlaycounts(albumAndArtist) > playedCount Then
   dictAlbumPlaycounts(albumAndArtist) = playedCount
  end if
 else 
  dictAlbumPlaycounts.Add albumAndArtist,playedCount 
 end if

' Track songs that have not been played:
if (playedCount = 0) then
 intSongsNeverPlayed = intSongsNeverPlayed + 1
end if

' Track the frequency with which songs are played:
If DateDiff("d", playedDate, LAST_YEAR) <= 1 Then
 intSongsPlayedLastYear = intSongsPlayedLastYear + 1
end if

If DateDiff("d", playedDate, LAST_QUARTER) <= 1 Then
 intSongsPlayedLastQuarter = intSongsPlayedLastQuarter + 1
end if

If DateDiff("d", playedDate, LAST_MONTH) <= 1 Then
 intSongsPlayedLastMonth = intSongsPlayedLastMonth + 1
end if

If DateDiff("d", playedDate, LAST_WEEK) <= 1 Then
 intSongsPlayedLastWeek = intSongsPlayedLastWeek + 1
end if

 songAndArtist = song & "    (" & artist & ")" 

 ' Track the song counts:
 if dictPlayedCounts.exists(songAndArtist) = false then
  dictPlayedCounts.Add songAndArtist,playedCount
 end if 
 playCount = playCount + playedCount
 
 ' Track the song skip counts (but ignore streams such as radio stations which do not have skip counts):
 if InStr(kind,"stream") <= 0 then
  skips = objTrack.SkippedCount 
  if dictSkips.exists(songAndArtist) = false then
   dictSkips.Add songAndArtist,skips
  end if 
 end if

 ' Track the song counts by album: 
 if dictAlbumTotalPlaycount.exists(albumAndArtist) = true then 
  dictAlbumTotalPlaycount(albumAndArtist) = dictAlbumTotalPlaycount(albumAndArtist) + playedCount 
 else 
  dictAlbumTotalPlaycount.Add albumAndArtist,playedCount 
 end if 

 ' Track the song counts by artist: 
 if dictArtistPlaycounts.exists(artist) = true then 
  dictArtistPlaycounts(artist) = dictArtistPlaycounts(artist) + playedCount 
 else 
  dictArtistPlaycounts.Add artist,playedCount 
 end if 
 
 ' Track the song played dates: 
 if dictPlayedDates.exists(songAndArtist) = false then
  dictPlayedDates.Add songAndArtist,playedDate
 end if 

 ' Track the song bit rates: 
 If bitrate < 128 Then
   dictBitRates("Low") = dictBitRates("Low") + 1
 ElseIf bitrate > 127 & bitrate < 192 then
   dictBitRates("Good") = dictBitRates("Good") + 1
 ElseIf bitrate > 191 & bitrate < 256 then
   dictBitRates("High") = dictBitRates("High") + 1
 Else
   dictBitRates("Excellent") = dictBitRates("Excellent") + 1
 End If

 ' Track the plays by hour of the day: 
 playedHour = datePart("h",playedDate)
 dictPlaysByHour(playedHour) = dictPlaysByHour(playedHour) + playedCount 
 
 songCount = songCount + 1 
Next 


' Create the File System Object:
Set objFSO     = CreateObject("Scripting.FileSystemObject")
Set objFSOData = CreateObject("Scripting.FileSystemObject")

' ForAppending = 8 ForReading = 1, ForWriting = 2
Set objTextFile = objFSO.OpenTextFile(strFileName, 2, True)
Set objDataFile = objFSOData.OpenTextFile(strDataFileName, 8, True)
Set objDataFile = objFSOData.GetFile(strDataFileName)

' If creating the historical data file for the first time, create the header row for the data:

If objDataFile.Size < 1 Then
   Set objDataFile = objFSOData.OpenTextFile(strDataFileName, 8, True)
   objDataFile.WriteLine("Reporting Date,Unique Tracks,Tracks Played,Avg Play Per Track,Unique Albums,Unique Artists,Unplayed Songs,Avg Track Length,# of Genres,Top Genre,Top Decade,Most-Played Song,Most-Played Album,Most-Played Artist,")
   Wscript.Echo "iTunesStats has created a file to store historical data called " & strDataFileName & ". This can be imported into Excel for historical analysis/trending."
End If 

' Reset the data file object in case it was already opened
Set objDataFile = Nothing
Set objDataFile = objFSOData.OpenTextFile(strDataFileName, 8, True)


' Writes information to the files:
objTextFile.WriteLine("Report Date: " & Now())
objDataFile.Write(Now() & ",")
objTextFile.WriteLine()
objTextFile.WriteLine(Pad("Number of unique tracks: ",30) & RightPad(FormatNumber(songCount,0),8))
objTextFile.WriteLine(Pad("Number of tracks played: ",30) & RightPad(FormatNumber(playCount,0),8))
objTextFile.WriteLine(Pad("Average play count per track: ",30) & RightPad(FormatNumber(playCount / songCount,1),8))
objTextFile.WriteLine(Pad("Number of unique albums: ",30) & RightPad(FormatNumber(dictAlbums.Count,0),8))
objTextFile.WriteLine(Pad("Number of unique artists: ",30) & RightPad(FormatNumber(dictArtistsSongs.Count,0),8))

' Write the same data to the historical data file:
objDataFile.Write(songCount & ",")
objDataFile.Write(playCount & ",")
objDataFile.Write(FormatNumber(playCount / songCount,1) & ",")
objDataFile.Write(dictAlbums.Count & ",")
objDataFile.Write(dictArtistsSongs.Count & ",")
objDataFile.Write(intSongsNeverPlayed & ",")

objTextFile.WriteLine()
objTextFile.WriteLine(Pad("Number of unique songs played in the last week: ",51) & RightPad(FormatNumber(intSongsPlayedLastWeek,0),8) & "(" & FormatPercent(intSongsPlayedLastWeek / songCount, 0) & ")")
objTextFile.WriteLine(Pad("Number of unique songs played in the last month: ",51) & RightPad(FormatNumber(intSongsPlayedLastMonth,0),8) & "(" & FormatPercent(intSongsPlayedLastMonth / songCount, 0) & ")")
objTextFile.WriteLine(Pad("Number of unique songs played in the last quarter: ",51) & RightPad(FormatNumber(intSongsPlayedLastQuarter,0),8) & "(" & FormatPercent(intSongsPlayedLastQuarter / songCount, 0) & ")")
objTextFile.WriteLine(Pad("Number of unique songs played in the last year: ",51) & RightPad(FormatNumber(intSongsPlayedLastYear,0),8) & "(" & FormatPercent(intSongsPlayedLastYear / songCount, 0) & ")")
objTextFile.WriteLine(Pad("Number of unique songs never played: ",51) & RightPad(FormatNumber(intSongsNeverPlayed,0),8) & "(" & FormatPercent(intSongsNeverPlayed / songCount, 0) & ")")
objTextFile.WriteLine()

' Calculate and print various duration information:
Dim intDays, intHours, intMinutes, intSeconds, averageDuration

averageDuration = totalTime \ songCount
intMinutes = averageDuration \ 60
intSeconds = averageDuration Mod 60
objTextFile.WriteLine("Average track length: " & intMinutes & ":" & Right("0" & intSeconds,2))
objDataFile.Write(intMinutes & ":" & Right("0" & intSeconds,2) & ",")

intDays = totalTime \ 86400
intHours = (totalTime Mod 86400) \ 3600
intMinutes = (totalTime Mod 3600) \ 60
intSeconds = totalTime Mod 60
objTextFile.WriteLine("Total duration of all tracks: " & intDays & " days, " & intHours & " hours, " & intMinutes & " minutes, " & intSeconds & " seconds")

intDays = totalPlayedTime \ 86400
intHours = (totalPlayedTime Mod 86400) \ 3600
intMinutes = (totalPlayedTime Mod 3600) \ 60
intSeconds = totalPlayedTime Mod 60
objTextFile.WriteLine("Total played time of all tracks played: " & intDays & " days, " & intHours & " hours, " & intMinutes & " minutes, " & intSeconds & " seconds")
objTextFile.WriteLine()

if Int(intDisplayTopSongs) > Int(songCount) Then
 intDisplayTopSongs = songCount
End If

if Int(intDisplayTopAlbums) > Int(dictAlbums.Count) Then
 intDisplayTopAlbums = dictAlbums.Count
End If

if Int(intDisplayTopGenres) > Int(dictGenreSongs.Count) Then
 intDisplayTopGenres = dictGenreSongs.Count
End If

if Int(intDisplayTopKinds) > Int(dictKinds.Count) Then
 intDisplayTopKinds = dictKinds.Count
End If

if Int(intDisplayTopArtists) > Int(dictArtistPlaycounts.Count) Then
 intDisplayTopArtists = dictArtistPlaycounts.Count
End If

if Int(intDisplayTopYears) > Int(dictYearSongs.Count) Then
 intDisplayTopYears = dictYearSongs.Count
End If

' Print the rating information:
objTextFile.WriteLine("Total number of unique ratings: " & dictRatingsSongs.Count)
objTextFile.WriteLine("Rating:         Number of Tracks:		Plays by Rating:")
objTextFile.WriteLine("-------------------------------------------------------")
Dim strRating 
SortDictionary dictRatingsSongs,1,SORT_BY_STRING
strRating = dictRatingsSongs.keys 
intCount = dictRatingsSongs.Items 
for i = 0 To dictRatingsSongs.Count - 1
  objTextFile.WriteLine(Pad(strRating(i),12) & RightPad(FormatNumber(intCount(i),0),8) & " (" & RightPad(FormatPercent((intCount(i) / songCount),1),6) & ")"_
  & RightPad(FormatNumber(dictPlaysByRating(strRating(i)),0),15) & " (" & RightPad(FormatPercent((dictPlaysByRating(strRating(i)) / playCount),1),6) & ")")
next 
objTextFile.WriteLine()

' Print the genre information:
objDataFile.Write(dictGenreSongs.Count & ",")
objTextFile.WriteLine("Total number of unique genres: " & dictGenreSongs.Count)
objTextFile.WriteLine("Genre:                              Number of Tracks:		Plays by Genre:")
objTextFile.WriteLine("------------------------------------------------------------------------")
Dim strGenre 
SortDictionary dictGenreSongs,2,SORT_BY_NUMBER
strGenre = dictGenreSongs.keys 
intCount = dictGenreSongs.Items 
for i = 0 To intDisplayTopGenres - 1
  If (strGenre(i) <> "") Then
    objTextFile.WriteLine(RightPad(i+1,3) & ". " & Pad(strGenre(i),30) & RightPad(FormatNumber(intCount(i),0),8) & " (" & RightPad(FormatPercent((intCount(i) / songCount),1),6) & ")"_
  & RightPad(FormatNumber(dictPlaysByGenre(strGenre(i)),0),10) & " (" & RightPad(FormatPercent((dictPlaysByGenre(strGenre(i)) / playCount),1),6) & ")")
  End If
next 

' Print how many tracks are missing the genre (added 11-5-2011):
If dictGenreSongs.Item("") > 0 Then
  objTextFile.WriteLine("There are " & dictGenreSongs.Item("") & " (" & RightPad(FormatPercent((dictGenreSongs.Item("") / songCount),1),6) & ")" & " tracks without a genre.")
End If

objTextFile.WriteLine()
objDataFile.Write(chr(34) & strGenre(0) & chr(34) & ",") 

' Print the kind information:
objDataFile.Write(dictKinds.Count & ",")
objTextFile.WriteLine("Total number of unique kinds of files: " & dictKinds.Count)
objTextFile.WriteLine("File Type:                          Number of Tracks:")
objTextFile.WriteLine("---------------------------------------------------------")
Dim strKind 
SortDictionary dictKinds,2,SORT_BY_NUMBER
strKind = dictKinds.keys 
intCount = dictKinds.Items 
for i = 0 To intDisplayTopKinds - 1
  objTextFile.WriteLine(RightPad(i+1,3) & ". " & Pad(strKind(i),30) & RightPad(FormatNumber(intCount(i),0),8) & " (" & FormatPercent((intCount(i) / songCount),1) & ")") 
next 
objTextFile.WriteLine()
objDataFile.Write(chr(34) & strKind(0) & chr(34) & ",")

' Print the year information:
objTextFile.WriteLine("Decade:           Number of Tracks:		Plays by Decade:")
objTextFile.WriteLine("-------------------------------------------------------")
SortDictionary dictYearSongs,2,SORT_BY_NUMBER
strYear = dictYearSongs.keys 
intCount = dictYearSongs.Items 
for i = 0 To intDisplayTopYears - 1 
  If (strYear(i) <> "00s") Then
    objTextFile.WriteLine(RightPad(i+1,3) & ". " & Pad(strYear(i),12) & RightPad(FormatNumber(intCount(i),0),8) & " (" & RightPad(FormatPercent((intCount(i) / songCount),1),6) & ")"_
 & RightPad(FormatNumber(dictPlaysByYear(strYear(i)),0),10) & " (" & RightPad(FormatPercent((dictPlaysByYear(strYear(i)) / playCount),1),6) & ")")
  End If
next 
objDataFile.Write(chr(34) & strYear(0) & chr(34) & ",")

' Print how many tracks are missing the year (added 11-5-2011):
If (dictYearSongs.Item("00s") > 0) Then
  objTextFile.WriteLine("There are " & dictYearSongs.Item("00s") & " (" & RightPad(FormatPercent((dictYearSongs.Item("00s") / songCount),1),6) & ")" & " tracks without a year.")
End If
objTextFile.WriteLine()

' Print the rating information:
objTextFile.WriteLine("Bit Rate (in kBps):   Number of Tracks:")
objTextFile.WriteLine("---------------------------------------------")
objTextFile.WriteLine("Excellent (256+ )" & RightPad(FormatNumber(dictBitRates("Excellent"),0),8) & " (" & FormatPercent((dictBitRates("Excellent") / songCount),1) & ")")
objTextFile.WriteLine("High (192 - 255) " & RightPad(FormatNumber(dictBitRates("High"),0),8) & " (" & FormatPercent((dictBitRates("High") / songCount),1) & ")")
objTextFile.WriteLine("Good (128 - 191) " & RightPad(FormatNumber(dictBitRates("Good"),0),8) & " (" & FormatPercent((dictBitRates("Good") / songCount),1) & ")")
objTextFile.WriteLine("Low (127 or less)" & RightPad(FormatNumber(dictBitRates("Low"),0),8) & " (" & FormatPercent((dictBitRates("Low") / songCount),1) & ")")
objTextFile.WriteLine()

' Print the most-played songs information:
objTextFile.WriteLine("                                     * MOST-PLAYED TRACKS *")
objTextFile.WriteLine("Song:                                                           Play Count:  Last Played:")
objTextFile.WriteLine("---------------------------------------------------------------------------------------------------")
SortDictionary dictPlayedCounts,2,SORT_BY_NUMBER
strSong = dictPlayedCounts.keys 
intCount = dictPlayedCounts.Items 

for i = 0 To intDisplayTopSongs - 1
  objTextFile.WriteLine(RightPad(i+1,3) & ".  " & Pad(strSong(i),60) & RightPad(FormatNumber(intCount(i),0),8) & RightPad(dictPlayedDates.Item(strSong(i)),24)) 
next 
objTextFile.WriteLine()
objDataFile.Write(chr(34) & strSong(0) & chr(34) & ",")

' Print the most-skipped songs information:
objTextFile.WriteLine("                                     * MOST-SKIPPED TRACKS *")
objTextFile.WriteLine("Song:                                                           Skip Count:  Last Played:")
objTextFile.WriteLine("---------------------------------------------------------------------------------------------------")
SortDictionary dictSkips,2,SORT_BY_NUMBER
strSong = dictSkips.keys 
intCount = dictSkips.Items 

for i = 0 To intDisplayTopSkips - 1
  objTextFile.WriteLine(RightPad(i+1,3) & ".  " & Pad(strSong(i),60) & RightPad(FormatNumber(intCount(i),0),8) & RightPad(dictPlayedDates.Item(strSong(i)),24)) 
next 
objTextFile.WriteLine()
objDataFile.Write(chr(34) & strSong(0) & chr(34) & ",")

' Print the most-played songs information:
objTextFile.WriteLine("                    * MOST-PLAYED ENTIRE ALBUMS (MINIMUM " & intMinSongsOnAlbum & " SONGS PER ALBUM) *")
objTextFile.WriteLine("Album:                                                           Album Plays:  Number of Songs:  Total Song Play Count:")
objTextFile.WriteLine("-----------------------------------------------------------------------------------------------------------------------")
SortDictionary dictAlbumPlaycounts,2,SORT_BY_NUMBER
strAlbum = dictAlbumPlaycounts.keys 
intCount = dictAlbumPlaycounts.Items 
Dim songsOnAlbum, topAlbumCount, totalSongPlayCount
topAlbumCount = 1
i = 0
Do Until topAlbumCount = intDisplayTopAlbums
  songsOnAlbum = dictAlbums.Item(strAlbum(i))
  totalSongPlayCount = dictAlbumTotalPlaycount.Item(strAlbum(i))

  ' Display only albums with a specific number of songs on them:
  If songsOnAlbum >= intMinSongsOnAlbum Then
   objTextFile.WriteLine(RightPad(topAlbumCount,3) & ".  " & Pad(strAlbum(i),60) & RightPad(FormatNumber(intCount(i),0),8) & RightPad(FormatNumber(songsOnAlbum,0),12)) & RightPad(FormatNumber(totalSongPlayCount,0),28)
    topAlbumCount = topAlbumCount + 1
  End If 
  
  i = i + 1
  If topAlbumCount > dictAlbums.Count Then Exit Do
  If i = dictAlbums.Count Then Exit Do
Loop 
objTextFile.WriteLine()
objDataFile.Write(chr(34) & strAlbum(0) & chr(34) & ",")

' Print the play counts, songs, and average per artist:
objTextFile.WriteLine("                            * PLAY COUNTS / TRACKS PER ARTIST *")
objTextFile.WriteLine("Artist:                                            Play Count:    Songs:   Average:")
objTextFile.WriteLine("-----------------------------------------------------------------------------------")
SortDictionary dictArtistPlaycounts,2,SORT_BY_NUMBER
Dim avgPerArtist
strArtist = dictArtistPlaycounts.keys 
intCount = dictArtistPlaycounts.Items 
for i = 0 To intDisplayTopArtists - 1

 if dictArtistsSongs.Item(strArtist(i)) > 0 then
  avgPerArtist = intCount(i)/dictArtistsSongs.Item(strArtist(i))
 else
  avgPerArtist = 0
 end if

  objTextFile.WriteLine(RightPad(i+1,3) & ".  " & Pad(strArtist(i),45) & RightPad(FormatNumber(intCount(i),0),8) & RightPad(FormatNumber(dictArtistsSongs.Item(strArtist(i)),0),12) & RightPad(FormatNumber(avgPerArtist,1),12)) 
next 
objTextFile.WriteLine()
objDataFile.Write(chr(34) & strArtist(0) & chr(34) & ",")

' Print the distribution of plays by hour:
objTextFile.WriteLine("                  * PLAY COUNT BY HOUR *")
objTextFile.WriteLine("Hour:       Play Count:          Hour:       Play Count:")
objTextFile.WriteLine("--------------------------------------------------------")
SortDictionary dictPlaysByHour,1,SORT_BY_NUMBER_ASC
playedHour = dictPlaysByHour.keys 
intCount = dictPlaysByHour.Items

 objTextFile.WriteLine(RightPad("12 AM",5) & RightPad(FormatNumber(intCount(0),0),9) & " (" & RightPad(FormatPercent((intCount(0) / playCount),1),6) & ")"_ 
  & RightPad("12 PM",15) & RightPad(FormatNumber(intCount(12),0),9) & " (" & RightPad(FormatPercent((intCount(12) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("1 AM",5) & RightPad(FormatNumber(intCount(1),0),9) & " (" & RightPad(FormatPercent((intCount(1) / playCount),1),6) & ")"_ 
  & RightPad("1 PM",15) & RightPad(FormatNumber(intCount(13),0),9) & " (" & RightPad(FormatPercent((intCount(13) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("2 AM",5) & RightPad(FormatNumber(intCount(2),0),9) & " (" & RightPad(FormatPercent((intCount(2) / playCount),1),6) & ")"_ 
  & RightPad("2 PM",15) & RightPad(FormatNumber(intCount(14),0),9) & " (" & RightPad(FormatPercent((intCount(14) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("3 AM",5) & RightPad(FormatNumber(intCount(3),0),9) & " (" & RightPad(FormatPercent((intCount(3) / playCount),1),6) & ")"_ 
  & RightPad("3 PM",15) & RightPad(FormatNumber(intCount(15),0),9) & " (" & RightPad(FormatPercent((intCount(15) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("4 AM",5) & RightPad(FormatNumber(intCount(4),0),9) & " (" & RightPad(FormatPercent((intCount(4) / playCount),1),6) & ")"_ 
  & RightPad("4 PM",15) & RightPad(FormatNumber(intCount(16),0),9) & " (" & RightPad(FormatPercent((intCount(16) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("5 AM",5) & RightPad(FormatNumber(intCount(5),0),9) & " (" & RightPad(FormatPercent((intCount(5) / playCount),1),6) & ")"_ 
  & RightPad("5 PM",15) & RightPad(FormatNumber(intCount(17),0),9) & " (" & RightPad(FormatPercent((intCount(17) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("6 AM",5) & RightPad(FormatNumber(intCount(6),0),9) & " (" & RightPad(FormatPercent((intCount(6) / playCount),1),6) & ")"_ 
  & RightPad("6 PM",15) & RightPad(FormatNumber(intCount(18),0),9) & " (" & RightPad(FormatPercent((intCount(18) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("7 AM",5) & RightPad(FormatNumber(intCount(7),0),9) & " (" & RightPad(FormatPercent((intCount(7) / playCount),1),6) & ")"_ 
  & RightPad("7 PM",15) & RightPad(FormatNumber(intCount(19),0),9) & " (" & RightPad(FormatPercent((intCount(19) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("8 AM",5) & RightPad(FormatNumber(intCount(8),0),9) & " (" & RightPad(FormatPercent((intCount(8) / playCount),1),6) & ")"_ 
  & RightPad("8 PM",15) & RightPad(FormatNumber(intCount(20),0),9) & " (" & RightPad(FormatPercent((intCount(20) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("9 AM",5) & RightPad(FormatNumber(intCount(9),0),9) & " (" & RightPad(FormatPercent((intCount(9) / playCount),1),6) & ")"_ 
  & RightPad("9 PM",15) & RightPad(FormatNumber(intCount(21),0),9) & " (" & RightPad(FormatPercent((intCount(21) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("10 AM",5) & RightPad(FormatNumber(intCount(10),0),9) & " (" & RightPad(FormatPercent((intCount(10) / playCount),1),6) & ")"_ 
  & RightPad("10 PM",15) & RightPad(FormatNumber(intCount(22),0),9) & " (" & RightPad(FormatPercent((intCount(22) / playCount),1),6) & ")") 
 objTextFile.WriteLine(RightPad("11 AM",5) & RightPad(FormatNumber(intCount(11),0),9) & " (" & RightPad(FormatPercent((intCount(11) / playCount),1),6) & ")" _
  & RightPad("11 PM",15) & RightPad(FormatNumber(intCount(23),0),9) & " (" & RightPad(FormatPercent((intCount(23) / playCount),1),6) & ")") 
 objTextFile.WriteLine()

' Print the most-recently added songs information:
objTextFile.WriteLine("                             * MOST-RECENTLY-PLAYED TRACKS *")
objTextFile.WriteLine("Song:                                                             Play Date:")
objTextFile.WriteLine("-----------------------------------------------------------------------------------------")
SortDictionary dictPlayedDates,2,SORT_BY_NUMBER
strSong = dictPlayedDates.keys 
intCount = dictPlayedDates.Items 
for i = 0 To intDisplayTopSongs - 1
  objTextFile.WriteLine(RightPad(i+1,3) & ".  " & Pad(strSong(i),60) & intCount(i)) 
next 
objTextFile.WriteLine()

' Print the most-recently added songs information:
objTextFile.WriteLine("                            * LEAST-RECENTLY-PLAYED TRACKS *")
objTextFile.WriteLine("Song:                                                             Play Date:")
objTextFile.WriteLine("-----------------------------------------------------------------------------------------")
for i = (dictPlayedDates.Count - 1) To (dictPlayedDates.Count - intDisplayTopSongs) Step -1
  objTextFile.WriteLine(RightPad(i+1,5) & ".  " & Pad(strSong(i),60) & intCount(i)) 
next 

objDataFile.WriteLine()
objTextFile.Close
objDataFile.Close

' Automatically launch the file when it is done:
Set objApp = CreateObject("WScript.Shell")
objApp.Run strFileName 

' Sort the arrays: 

WScript.Quit

