Saturday 16 October 2010

More iTunes Statistics

I my previous post I shared an Applescript  that allows you to get some basic statistics about your iTunes Library. I've expanded on that script and created the script shown below. The initial script produced a number of lists that showed count of songs per rating, per number of plays and per number of skips. I wanted to know if the playcounts or skipcounts were related to the song's rating.  So, without further ado, here are the results that the script produced:


Number of tracks analysed: 7053


Distribution of Playcounts
cnt ----- ----* ---** --*** -**** ***** Total
0     0     3     2     78    0     0     83
1 0 23    156   3254  53    0     3486
2 0 11 130 1947 61 4 2153
3 0 6 44 512 33 4 599
4 0 0 9 150 28 8 195
5 0 2 7 85 35 15    144
6 0 0 2     45    107   18    172
7 0     0     1     26    49    11    87
8 0 0 0     9     19    10    38
9 0     0     0 6     7     13    26
10 0     0     0     11    13    6     30
11   0     0     0     3     7     2     12
12 0     0     0     1     2     3     6
13 0     0     0     2     3     0     5
14 0     0     0     1     1     0     2
15 0     0     0     0     1     1     2
16 0     0     0     0     2     0     2
17 0     0     0     0     2     0     2
18 0     0     0     0     0     0     0
19 0     0     0     1     1     0     2
20  0     0     0     0     1     1     2
21 0     0     0     0     1     1     2
22 0     0     0 0 1 1 2
23  0     0     0     0     0     0     0
24 0     0     0     0     0     0     0
25 0     0     0     0     0     0     0
26 0     0     0     0     0     0     0
27 0     0     0     0     0     0     0
28 0     0     0     0     0     0     0
29 0     0     0     0     0     0     0
30 0     0     0     0     0     1     1
cnt   ----- ----* ---** --*** -**** ***** Total
Total 0     45    351   6131  427   99    7053


Distribution of Skipcounts
cnt ----- ----* ---** --*** -**** ***** Total
0 0 45 337   6076 413  96 6967
1     0     13    55    14    3     85
2 0 0 1 0 0 0 1
cnt ----- ----* ---** --*** -**** ***** Total
Total 0     45    351   6131 427   99    7053


Time taken talking with iTunes: 1s
Time taken analysing the data : 12s


Looking at the data, we see that at low playcounts the distribution tends towards the (my default) three-star rating. Songs with higher playcounts tend to have a higher rating aswell, but at the same time the distribution curve seems to flatten a bit.

For the skipcounts I wasn't expecting anything, since I've been re-setting the skipcounts periodically. In the future though, I expect to see a similar shift towards lower ratings. However, iTunes only counts a skip if you skip the song within the first, say, 10 seconds. If you skip it later the song doesn't get counted as played, but it also doesn't get counted as skipped.

If you like the script below and use it, I'd appreciate it if you could post the results here in the comments of this article.


-- Initialise variables/constants
set sep to tab
-- set sep to ","

set flgActTunes to false

set ptrPlays to 0
set cntPlays to 0
set cntPlaysMax to 0
set lstPlays to {}

set ptrSkips to 0
set cntSkips to 0
set cntSkipsMax to 0
set lstSkips to {}

set lstRates to {"-----", "----*", "---**", "--***", "-****", "*****", "Total"}
set lstRateCnt to {0, 0, 0, 0, 0, 0, 0}

set timings to {}

-- ** Fetch data from iTunes
set stime to (current date) --t1 start
-- Let's see if iTunes is running or not
tell application "System Events"
if (get name of every process) contains "iTunes" then set flgActTunes to true
end tell -- System Events

-- Interrogate iTunes to find out the information we will be needing
tell application "iTunes"
set {lstRatings, lstPlaycounts, lstSkipcounts, lstArtists} to {rating, played count, skipped count, artist} of the second playlist's tracks
-- If we started up iTunes for this, let's be nice and clean up after us
if flgActTunes = false then quit
end tell -- iTunes
set end of timings to ((current date) - stime) --t1 end

-- ** Analyse data
set stime to (current date) --t2 start
tell me
-- determine maxima
repeat with i from 1 to (count of (items in lstRatings))
set cntPlays to item i of lstPlaycounts
set cntSkips to item i of lstSkipcounts
-- find out the maximum playcount 
if cntPlays > cntPlaysMax then set cntPlaysMax to cntPlays
-- find out the maximum skipcount
if cntSkips > cntSkipsMax then set cntSkipsMax to cntSkips
end repeat
end tell

tell me
repeat with j from 1 to (count of (items in lstRates))
set end of lstPlays to {}
set end of lstSkips to {}
end repeat
-- prepare lists for the playcount histogram and skipcount histogram
repeat with i from 0 to cntPlaysMax
repeat with j from 1 to (count of (items in lstRates))
set end of (item j of lstPlays) to 0
end repeat
end repeat
repeat with i from 0 to cntSkipsMax
repeat with j from 1 to (count of (items in lstRates))
set end of (item j of lstSkips) to 0
end repeat
end repeat
-- fill the list
repeat with i from 1 to (count of (items in lstRatings))
set Rval to item i of lstRatings
set cntPlays to (item i of lstPlaycounts) + 1
set cntSkips to (item i of lstSkipcounts) + 1
-- create a histogram of the ratings. Half-stars get counted as full.
if Rval < 1 then
set j to 1
else if Rval < 21 then
set j to 2
else if Rval < 41 then
set j to 3
else if Rval < 61 then
set j to 4
else if Rval < 81 then
set j to 5
else
set j to 6
end if
set item cntPlays of (item j of lstPlays) to (item cntPlays of (item j of lstPlays)) + 1
set item cntSkips of (item j of lstSkips) to (item cntSkips of (item j of lstSkips)) + 1
-- counting totals
set k to (count of (items in lstRates))
set item cntPlays of (item k of lstPlays) to (item cntPlays of (item k of lstPlays)) + 1
set item cntSkips of (item k of lstSkips) to (item cntSkips of (item k of lstSkips)) + 1
end repeat
end tell
set end of timings to ((current date) - stime) --t2 end


-- output the data to a file on the desktop
tell me
-- make a header
set headerText to "cnt"
repeat with i from 1 to (count of lstRates)
set headerText to headerText & sep & (item i of lstRates)
end repeat
write_data("Number of tracks analysed: " & (count of (items in lstRatings)))
write_data("")
-- Statistics of playcount vs Rating
write_data("Distribution of Playcounts")
write_data(headerText)
repeat with j from 1 to (count of (item 1 of lstPlays))
set lineText to (j - 1 as string)
repeat with i from 1 to (count of lstRates)
set lineText to lineText & sep & (item j of (item i of lstPlays))
end repeat
write_data(lineText)
end repeat
write_data(headerText)
-- Totals for each rating
repeat with i from 1 to (count of lstRates)
repeat with j from 1 to (count of (item 1 of lstPlays))
set (item i of lstRateCnt) to (item i of lstRateCnt) + (item j of (item i of lstPlays))
end repeat
end repeat
set lineText to "Total"
repeat with i from 1 to (count of lstRateCnt)
set lineText to lineText & sep & (item i of lstRateCnt)
end repeat
write_data(lineText)
write_data("")
-- Statistics of skipcount vs Rating
write_data("Distribution of Skipcounts")
write_data(headerText)
repeat with j from 1 to (count of (item 1 of lstSkips))
set lineText to (j - 1 as string)
repeat with i from 1 to (count of lstRates)
set lineText to lineText & sep & (item j of (item i of lstSkips))
end repeat
write_data(lineText)
end repeat
write_data(headerText)
-- Totals for each rating
set lstRateCnt to {0, 0, 0, 0, 0, 0, 0}
repeat with i from 1 to (count of lstRates)
repeat with j from 1 to (count of (item 1 of lstSkips))
set (item i of lstRateCnt) to (item i of lstRateCnt) + (item j of (item i of lstSkips))
end repeat
end repeat
set lineText to "Total"
repeat with i from 1 to (count of lstRateCnt)
set lineText to lineText & sep & (item i of lstRateCnt)
end repeat
write_data(lineText)
write_data("")
write_data(("Time taken talking with iTunes: " & (item 1 of timings) as string) & "s")
write_data(("Time taken analysing the data : " & (item 2 of timings) as string) & "s")
end tell

say "iTunes statistics ready"
return

on write_data(this_text)
set myName to name of (info for (path to me))
set the theLog to ((path to desktop) as text) & myName & " Log.txt"
try
open for access file theLog with write permission
write (this_text & return) to file theLog starting at eof
close access file theLog
on error
try
close access file theLog
end try
end try
end write_data