Created
January 27, 2010 07:05
-
-
Save mattly/287619 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # based on something zenspider wrote. I hacked to add: | |
| # 1. tracks that don't have ratings | |
| # 2. take the number of tracks into account for the album's score (note to self: should instead take into account the length) | |
| # 3. take an 'age' argument to only show stuff added in the last x weeks, f.e.: itunes-popular 12 52 shows the top twelve albums from the last fifty-two weeks | |
| # changes 26 Jan 10 | |
| # - | |
| #!/usr/bin/env ruby | |
| require 'time' | |
| class Album < Array | |
| def age | |
| @age ||= map { |track| track.age }.max | |
| end | |
| def score | |
| @score ||= total / Math.log(age) | |
| end | |
| def total | |
| inject(0.0) do |total_score, track| | |
| total_score + track.score | |
| end / size | |
| end | |
| def self.parse(file, age) | |
| today = Time.now | |
| d = {} | |
| library = Hash.new { |h,k| h[k] = Album.new } | |
| IO.foreach(File.expand_path(file)) do |line| | |
| if line =~ /<dict/ | |
| d.clear | |
| elsif line =~ /<key>(Name|Artist|Album|Date Added|Play Count)<\/key><.*?>(.*)<\/.*?>/ then | |
| key = $1.downcase.split.first | |
| val = $2 | |
| val = val.sub(/T.*/,'') if key == :date | |
| d[key.intern] = val | |
| elsif line =~ /<\/dict>/ && d.size == 5 | |
| # if we don't have all the keys, don't bother with this track or if it's some random /dict | |
| key = "#{d[:album]} by #{d[:artist]}" | |
| track_age = ((today - Time.parse(d[:date])) / 86400.0).to_i | |
| next if age && ((track_age / 7) > age.to_i) | |
| library[key] << Track.new(track_age, d[:play].to_i) | |
| end | |
| end | |
| library | |
| end | |
| end | |
| Track = Struct.new(:age, :count) | |
| class Track | |
| def score | |
| # rating * count.to_f | |
| count.to_f | |
| end | |
| end | |
| max = (ARGV.shift || 10).to_i | |
| age = ARGV.shift || nil # in weeks | |
| file = ARGV.shift || "~/Music/iTunes/iTunes Music Library.xml" | |
| library = Album.parse(file, age) | |
| top = library.sort_by { |h,k| -k.score }[0...max] | |
| top.each_with_index do |(artist_album, album), c| | |
| puts "%-3d = (%4d tot, %5.2f adj, %4i days): %s" % [c+1, album.total, album.score, album.age, artist_album] | |
| album.each do |t| | |
| puts " #{t.age} days old, #{t.count} count, #{t.rating} rating = #{t.score}" | |
| end if $DEBUG | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment