sweeper 0.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
 - data/CHANGELOG +2 -0
 - data/README +43 -15
 - data/TODO +1 -2
 - data/bin/sweeper +3 -9
 - data/lib/sweeper.rb +73 -25
 - data/sweeper.gemspec +2 -2
 - data/test/integration/sweeper_test.rb +1 -1
 - metadata +1 -1
 - metadata.gz.sig +0 -0
 
    
        data.tar.gz.sig
    CHANGED
    
    | 
         Binary file 
     | 
    
        data/CHANGELOG
    CHANGED
    
    
    
        data/README
    CHANGED
    
    | 
         @@ -24,29 +24,57 @@ If you use this software, please {make a donation}[http://blog.evanweaver.com/do 
     | 
|
| 
       24 
24 
     | 
    
         
             
            * id3lib (Linux and OS X only)
         
     | 
| 
       25 
25 
     | 
    
         
             
            * some mp3 files
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
            ==  
     | 
| 
      
 27 
     | 
    
         
            +
            == Usage
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 29 
     | 
    
         
            +
            First, install the gem:
         
     | 
| 
       30 
30 
     | 
    
         
             
              sudo gem install sweeper
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
            Now, change to the directory of mp3s you want to tag and run:
         
     | 
| 
      
 33 
     | 
    
         
            +
              sweeper --genre --recursive
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            Your mp3s will be updated with missing artist, genre, and trackname information, and a list of all tagged genres will be added to the <tt>comment</tt> field, for use in smart playlists.
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            == Demo
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            Unknown song before sweeping:
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              $ id3info 1_001.mp3 
         
     | 
| 
      
 42 
     | 
    
         
            +
              *** Tag information for 1_001.mp3
         
     | 
| 
      
 43 
     | 
    
         
            +
              *** mp3 info
         
     | 
| 
      
 44 
     | 
    
         
            +
              MPEG1/layer III
         
     | 
| 
      
 45 
     | 
    
         
            +
              Bitrate: 128KBps
         
     | 
| 
      
 46 
     | 
    
         
            +
              Frequency: 44KHz
         
     | 
| 
      
 47 
     | 
    
         
            +
             
         
     | 
| 
      
 48 
     | 
    
         
            +
            Same song after running <tt>sweeper ----genre</tt>:
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              $ id3info 1_001.mp3   
         
     | 
| 
      
 51 
     | 
    
         
            +
              *** Tag information for 1_001.mp3
         
     | 
| 
      
 52 
     | 
    
         
            +
              === TPE1 (Lead performer(s)/Soloist(s)): Photon Band
         
     | 
| 
      
 53 
     | 
    
         
            +
              === TIT2 (Title/songname/content description): To Sing For You
         
     | 
| 
      
 54 
     | 
    
         
            +
              === WORS (Official internet radio station homepage): http://www.last.fm/music/Ph
         
     | 
| 
      
 55 
     | 
    
         
            +
              oton+Band/_/To+Sing+For+You
         
     | 
| 
      
 56 
     | 
    
         
            +
              === TCON (Content type): Psychadelic
         
     | 
| 
      
 57 
     | 
    
         
            +
              === COMM (Comments): ()[]: rock, psychedelic, mod, Philly
         
     | 
| 
      
 58 
     | 
    
         
            +
              *** mp3 info
         
     | 
| 
      
 59 
     | 
    
         
            +
              MPEG1/layer III
         
     | 
| 
      
 60 
     | 
    
         
            +
              Bitrate: 128KBps
         
     | 
| 
      
 61 
     | 
    
         
            +
              Frequency: 44KHz
         
     | 
| 
       38 
62 
     | 
    
         | 
| 
       39 
63 
     | 
    
         
             
            == Options  
         
     | 
| 
       40 
64 
     | 
    
         | 
| 
       41 
65 
     | 
    
         
             
            Sweeper takes a few command line options:
         
     | 
| 
       42 
66 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                -d, --dir 
     | 
| 
       44 
     | 
    
         
            -
                -r, --recursive 
     | 
| 
       45 
     | 
    
         
            -
                    --dry-run 
     | 
| 
       46 
     | 
    
         
            -
                -f, --force 
     | 
| 
       47 
     | 
    
         
            -
                -g, --genre 
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
      
 67 
     | 
    
         
            +
                -d, --dir            Directory to search (defaults to current).
         
     | 
| 
      
 68 
     | 
    
         
            +
                -r, --recursive      Recurse directories.
         
     | 
| 
      
 69 
     | 
    
         
            +
                    --dry-run        Do a dry run (no files will be changed).
         
     | 
| 
      
 70 
     | 
    
         
            +
                -f, --force          Overwrite all existing tags.
         
     | 
| 
      
 71 
     | 
    
         
            +
                -g, --genre=[force]  Add genre tag and genre comments, optionally overwriting 
         
     | 
| 
      
 72 
     | 
    
         
            +
                                     existing ones.
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            == Notes
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            You will get cleaner tags if you convert your files to ID3v2 first. Sweeper reads both tag versions, but only outputs ID3v2.
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
       50 
78 
     | 
    
         
             
            == Reporting problems
         
     | 
| 
       51 
79 
     | 
    
         | 
| 
       52 
80 
     | 
    
         
             
            The support forum is here[http://rubyforge.org/forum/forum.php?forum_id=23599].
         
     | 
    
        data/TODO
    CHANGED
    
    
    
        data/bin/sweeper
    CHANGED
    
    | 
         @@ -32,15 +32,9 @@ Choice.options do 
     | 
|
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
              option :genre do
         
     | 
| 
       34 
34 
     | 
    
         
             
                short '-g'
         
     | 
| 
       35 
     | 
    
         
            -
                long '--genre'
         
     | 
| 
       36 
     | 
    
         
            -
                desc "Add genre and genre comments."
         
     | 
| 
       37 
     | 
    
         
            -
              end
         
     | 
| 
       38 
     | 
    
         
            -
              
         
     | 
| 
       39 
     | 
    
         
            -
              option :"force-genre" do
         
     | 
| 
       40 
     | 
    
         
            -
                short '-e'
         
     | 
| 
       41 
     | 
    
         
            -
                long '--force-genre'
         
     | 
| 
       42 
     | 
    
         
            -
                desc "Add genre and genre comments, overwriting existing ones."
         
     | 
| 
       43 
     | 
    
         
            -
              end    
         
     | 
| 
      
 35 
     | 
    
         
            +
                long '--genre=[force]'
         
     | 
| 
      
 36 
     | 
    
         
            +
                desc "Add genre tag and genre comments, optionally overwriting existing ones."
         
     | 
| 
      
 37 
     | 
    
         
            +
              end  
         
     | 
| 
       44 
38 
     | 
    
         
             
            end
         
     | 
| 
       45 
39 
     | 
    
         | 
| 
       46 
40 
     | 
    
         
             
            Sweeper.new(Choice.choices).run
         
     | 
    
        data/lib/sweeper.rb
    CHANGED
    
    | 
         @@ -25,18 +25,20 @@ class Sweeper 
     | 
|
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
              BASIC_KEYS = ['artist', 'title', 'url']
         
     | 
| 
       27 
27 
     | 
    
         
             
              GENRE_KEYS = ['genre', 'comment']
         
     | 
| 
       28 
     | 
    
         
            -
               
     | 
| 
       29 
     | 
    
         
            -
               
     | 
| 
      
 28 
     | 
    
         
            +
              ALBUM_KEYS = ['album', 'track']
         
     | 
| 
      
 29 
     | 
    
         
            +
              GENRES = ID3Lib::Info::Genres
         
     | 
| 
      
 30 
     | 
    
         
            +
              GENRE_COUNT = 10
         
     | 
| 
       30 
31 
     | 
    
         
             
              DEFAULT_GENRE = {'genre' => 'Other', 'comment' => 'other'}
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
       32 
33 
     | 
    
         
             
              attr_reader :options
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
              # Instantiate a new Sweeper. See <tt>bin/sweeper</tt> for <tt>options</tt> details.
         
     | 
| 
       34 
36 
     | 
    
         
             
              def initialize(options = {})
         
     | 
| 
       35 
     | 
    
         
            -
                options['genre'] ||= options['force-genre']
         
     | 
| 
       36 
37 
     | 
    
         
             
                @dir = File.expand_path(options['dir'] || Dir.pwd)
         
     | 
| 
       37 
38 
     | 
    
         
             
                @options = options
         
     | 
| 
       38 
39 
     | 
    
         
             
              end
         
     | 
| 
       39 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
              # Run the Sweeper according to the <tt>options</tt>.
         
     | 
| 
       40 
42 
     | 
    
         
             
              def run      
         
     | 
| 
       41 
43 
     | 
    
         
             
                @read = 0
         
     | 
| 
       42 
44 
     | 
    
         
             
                @updated = 0
         
     | 
| 
         @@ -44,7 +46,7 @@ class Sweeper 
     | 
|
| 
       44 
46 
     | 
    
         | 
| 
       45 
47 
     | 
    
         
             
                Kernel.at_exit do
         
     | 
| 
       46 
48 
     | 
    
         
             
                  if @read == 0
         
     | 
| 
       47 
     | 
    
         
            -
                    puts "No files found. Maybe you meant --recursive?"
         
     | 
| 
      
 49 
     | 
    
         
            +
                    puts "No mp3 files found. Maybe you meant --recursive?"
         
     | 
| 
       48 
50 
     | 
    
         
             
                    exec "#{$0} --help"
         
     | 
| 
       49 
51 
     | 
    
         
             
                  else
         
     | 
| 
       50 
52 
     | 
    
         
             
                    puts "Read: #{@read}\nUpdated: #{@updated}\nFailed: #{@failed}"
         
     | 
| 
         @@ -61,75 +63,99 @@ class Sweeper 
     | 
|
| 
       61 
63 
     | 
    
         | 
| 
       62 
64 
     | 
    
         
             
              #private
         
     | 
| 
       63 
65 
     | 
    
         | 
| 
      
 66 
     | 
    
         
            +
              # Recurse one directory, reading, looking up, and writing each file, if appropriate. Accepts a directory path.
         
     | 
| 
       64 
67 
     | 
    
         
             
              def recurse(dir)
         
     | 
| 
      
 68 
     | 
    
         
            +
                # Hackishly avoid problems with metacharacters in the Dir[] string.
         
     | 
| 
      
 69 
     | 
    
         
            +
                dir = dir.gsub(/[^\s\w\.\/\\\-]/, '?')
         
     | 
| 
      
 70 
     | 
    
         
            +
                # p dir if ENV['DEBUG']
         
     | 
| 
       65 
71 
     | 
    
         
             
                Dir["#{dir}/*"].each do |filename|
         
     | 
| 
       66 
72 
     | 
    
         
             
                  if File.directory? filename and options['recursive']
         
     | 
| 
       67 
73 
     | 
    
         
             
                    recurse(filename)
         
     | 
| 
       68 
     | 
    
         
            -
                  elsif File.extname(filename)  
     | 
| 
      
 74 
     | 
    
         
            +
                  elsif File.extname(filename) =~ /\.mp3$/i
         
     | 
| 
       69 
75 
     | 
    
         
             
                    @read += 1
         
     | 
| 
       70 
76 
     | 
    
         
             
                    tries = 0
         
     | 
| 
       71 
77 
     | 
    
         
             
                    begin
         
     | 
| 
       72 
78 
     | 
    
         
             
                      current = read(filename)  
         
     | 
| 
       73 
79 
     | 
    
         
             
                      updated = lookup(filename, current)
         
     | 
| 
       74 
80 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
                      if  
     | 
| 
      
 81 
     | 
    
         
            +
                      if ENV['DEBUG']
         
     | 
| 
      
 82 
     | 
    
         
            +
                        p current, updated
         
     | 
| 
      
 83 
     | 
    
         
            +
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                      if updated != current 
         
     | 
| 
      
 86 
     | 
    
         
            +
                        # Don't bother updating identical metadata.
         
     | 
| 
       76 
87 
     | 
    
         
             
                        write(filename, updated)
         
     | 
| 
       77 
88 
     | 
    
         
             
                        @updated += 1
         
     | 
| 
      
 89 
     | 
    
         
            +
                      else
         
     | 
| 
      
 90 
     | 
    
         
            +
                        puts "Unchanged: #{File.basename(filename)}"
         
     | 
| 
       78 
91 
     | 
    
         
             
                      end
         
     | 
| 
       79 
92 
     | 
    
         | 
| 
       80 
93 
     | 
    
         
             
                    rescue Problem => e          
         
     | 
| 
       81 
94 
     | 
    
         
             
                      tries += 1 and retry if tries < 2
         
     | 
| 
       82 
     | 
    
         
            -
                      puts "Skipped #{ 
     | 
| 
      
 95 
     | 
    
         
            +
                      puts "Skipped (#{e.message}): #{File.basename(filename)}"
         
     | 
| 
       83 
96 
     | 
    
         
             
                      @failed += 1
         
     | 
| 
       84 
97 
     | 
    
         
             
                    end
         
     | 
| 
       85 
98 
     | 
    
         
             
                  end
         
     | 
| 
       86 
     | 
    
         
            -
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end  
         
     | 
| 
       87 
100 
     | 
    
         
             
              end
         
     | 
| 
       88 
101 
     | 
    
         | 
| 
      
 102 
     | 
    
         
            +
              # Read tags from an mp3 file. Returns a tag hash.
         
     | 
| 
       89 
103 
     | 
    
         
             
              def read(filename)
         
     | 
| 
       90 
104 
     | 
    
         
             
                tags = {}
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                song = ID3Lib::Tag.new(filename, ID3Lib::V2)
         
     | 
| 
       93 
     | 
    
         
            -
                if song.empty?
         
     | 
| 
       94 
     | 
    
         
            -
                  song = ID3Lib::Tag.new(filename, ID3Lib::V1)
         
     | 
| 
       95 
     | 
    
         
            -
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
                song = load(filename)
         
     | 
| 
       96 
106 
     | 
    
         | 
| 
       97 
107 
     | 
    
         
             
                (BASIC_KEYS + GENRE_KEYS).each do |key|      
         
     | 
| 
       98 
108 
     | 
    
         
             
                  tags[key] = song.send(key) if !song.send(key).blank?
         
     | 
| 
       99 
109 
     | 
    
         
             
                end
         
     | 
| 
       100 
110 
     | 
    
         | 
| 
      
 111 
     | 
    
         
            +
                # Change numeric genres into TCON strings
         
     | 
| 
      
 112 
     | 
    
         
            +
                # XXX Might not work well
         
     | 
| 
      
 113 
     | 
    
         
            +
                if tags['genre'] =~ /(\d+)/
         
     | 
| 
      
 114 
     | 
    
         
            +
                  tags['genre'] = GENRES[$1.to_i]
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
                
         
     | 
| 
       101 
117 
     | 
    
         
             
                tags
         
     | 
| 
       102 
118 
     | 
    
         
             
              end
         
     | 
| 
       103 
119 
     | 
    
         | 
| 
      
 120 
     | 
    
         
            +
              # Lookup all available remote metadata for an mp3 file. Accepts a pathname and an optional hash of existing tags. Returns a tag hash. 
         
     | 
| 
       104 
121 
     | 
    
         
             
              def lookup(filename, tags = {})
         
     | 
| 
      
 122 
     | 
    
         
            +
                tags = tags.dup
         
     | 
| 
       105 
123 
     | 
    
         
             
                updated = {}
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                # Are there any empty basic tags we need to lookup?
         
     | 
| 
       106 
126 
     | 
    
         
             
                if options['force'] or 
         
     | 
| 
       107 
127 
     | 
    
         
             
                  (BASIC_KEYS - tags.keys).any?
         
     | 
| 
       108 
128 
     | 
    
         
             
                  updated.merge!(lookup_basic(filename))
         
     | 
| 
       109 
129 
     | 
    
         
             
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                # Are there any empty genre tags we need to lookup?
         
     | 
| 
       110 
132 
     | 
    
         
             
                if options['genre'] and 
         
     | 
| 
       111 
     | 
    
         
            -
                  (options['force'] or options[' 
     | 
| 
      
 133 
     | 
    
         
            +
                  (options['force'] or options['genre'] == 'force' or (GENRE_KEYS - tags.keys).any?)
         
     | 
| 
       112 
134 
     | 
    
         
             
                  updated.merge!(lookup_genre(updated.merge(tags)))
         
     | 
| 
       113 
135 
     | 
    
         
             
                end
         
     | 
| 
       114 
136 
     | 
    
         | 
| 
       115 
137 
     | 
    
         
             
                if options['force']
         
     | 
| 
      
 138 
     | 
    
         
            +
                  # Force all remote tags.
         
     | 
| 
       116 
139 
     | 
    
         
             
                  tags.merge!(updated)      
         
     | 
| 
       117 
     | 
    
         
            -
                elsif options[' 
     | 
| 
       118 
     | 
    
         
            -
                  tags. 
     | 
| 
      
 140 
     | 
    
         
            +
                elsif options['genre'] == 'force'
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # Force remote genre tags only.
         
     | 
| 
      
 142 
     | 
    
         
            +
                  tags.merge!(updated.slice(*GENRE_KEYS))
         
     | 
| 
       119 
143 
     | 
    
         
             
                end
         
     | 
| 
       120 
144 
     | 
    
         | 
| 
      
 145 
     | 
    
         
            +
                # Merge back in existing tags.
         
     | 
| 
       121 
146 
     | 
    
         
             
                updated.merge(tags)    
         
     | 
| 
       122 
147 
     | 
    
         
             
              end
         
     | 
| 
       123 
148 
     | 
    
         | 
| 
      
 149 
     | 
    
         
            +
              # Lookup the basic metadata for an mp3 file. Accepts a pathname. Returns a tag hash.
         
     | 
| 
       124 
150 
     | 
    
         
             
              def lookup_basic(filename)
         
     | 
| 
       125 
151 
     | 
    
         
             
                Dir.chdir File.dirname(binary) do
         
     | 
| 
       126 
152 
     | 
    
         
             
                  response = silence { `./#{File.basename(binary)} #{filename.inspect}` }
         
     | 
| 
       127 
153 
     | 
    
         
             
                  object = begin
         
     | 
| 
       128 
154 
     | 
    
         
             
                    XSD::Mapping.xml2obj(response)
         
     | 
| 
       129 
155 
     | 
    
         
             
                  rescue REXML::ParseException
         
     | 
| 
       130 
     | 
    
         
            -
                    raise Problem, "Server sent invalid response 
     | 
| 
      
 156 
     | 
    
         
            +
                    raise Problem, "Server sent invalid response"
         
     | 
| 
       131 
157 
     | 
    
         
             
                  end              
         
     | 
| 
       132 
     | 
    
         
            -
                  raise Problem, "Fingerprint failed or not found 
     | 
| 
      
 158 
     | 
    
         
            +
                  raise Problem, "Fingerprint failed or not found" unless object
         
     | 
| 
       133 
159 
     | 
    
         | 
| 
       134 
160 
     | 
    
         
             
                  tags = {}
         
     | 
| 
       135 
161 
     | 
    
         
             
                  song = Array(object.track).first      
         
     | 
| 
         @@ -140,7 +166,8 @@ class Sweeper 
     | 
|
| 
       140 
166 
     | 
    
         
             
                  tags
         
     | 
| 
       141 
167 
     | 
    
         
             
                end
         
     | 
| 
       142 
168 
     | 
    
         
             
              end
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
              # Lookup the genre metadata for a set of basic metadata. Accepts a tag hash. Returns a genre tag hash.  
         
     | 
| 
       144 
171 
     | 
    
         
             
              def lookup_genre(tags)
         
     | 
| 
       145 
172 
     | 
    
         
             
                return DEFAULT_GENRE if tags['artist'].blank?
         
     | 
| 
       146 
173 
     | 
    
         | 
| 
         @@ -157,36 +184,51 @@ class Sweeper 
     | 
|
| 
       157 
184 
     | 
    
         
             
                return DEFAULT_GENRE if !genres.any?
         
     | 
| 
       158 
185 
     | 
    
         | 
| 
       159 
186 
     | 
    
         
             
                primary = nil
         
     | 
| 
       160 
     | 
    
         
            -
                genres. 
     | 
| 
      
 187 
     | 
    
         
            +
                genres.each_with_index do |this, index|
         
     | 
| 
       161 
188 
     | 
    
         
             
                  match_results = Amatch::Levenshtein.new(this).similar(GENRES)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  # Get the levenshtein best-match weight
         
     | 
| 
       162 
190 
     | 
    
         
             
                  max = match_results.max
         
     | 
| 
      
 191 
     | 
    
         
            +
                  # Reverse lookup the canonical genre
         
     | 
| 
       163 
192 
     | 
    
         
             
                  match = GENRES[match_results.index(max)]
         
     | 
| 
      
 193 
     | 
    
         
            +
                  # Bias slightly towards higher tagging counts
         
     | 
| 
      
 194 
     | 
    
         
            +
                  max += ((GENRE_COUNT - index) / GENRE_COUNT / 4.0)
         
     | 
| 
       164 
195 
     | 
    
         | 
| 
       165 
196 
     | 
    
         
             
                  if ['Rock', 'Pop', 'Rap'].include? match
         
     | 
| 
       166 
197 
     | 
    
         
             
                    # Penalize useless genres
         
     | 
| 
       167 
198 
     | 
    
         
             
                    max = max / 3.0
         
     | 
| 
       168 
199 
     | 
    
         
             
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                        
         
     | 
| 
      
 201 
     | 
    
         
            +
                  p [max, match] if ENV['DEBUG']
         
     | 
| 
       169 
202 
     | 
    
         | 
| 
       170 
203 
     | 
    
         
             
                  if !primary or primary.first < max
         
     | 
| 
       171 
204 
     | 
    
         
             
                    primary = [max, match]
         
     | 
| 
       172 
205 
     | 
    
         
             
                  end
         
     | 
| 
       173 
206 
     | 
    
         
             
                end
         
     | 
| 
       174 
207 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
                {'genre' => primary.last, 'comment' => genres.join(" ")}
         
     | 
| 
      
 208 
     | 
    
         
            +
                {'genre' => primary.last, 'comment' => genres.join(", ")}
         
     | 
| 
       176 
209 
     | 
    
         
             
              end
         
     | 
| 
       177 
210 
     | 
    
         | 
| 
      
 211 
     | 
    
         
            +
              # Write tags to an mp3 file. Accepts a pathname and a tag hash.
         
     | 
| 
       178 
212 
     | 
    
         
             
              def write(filename, tags)
         
     | 
| 
       179 
213 
     | 
    
         
             
                return if tags.empty?
         
     | 
| 
       180 
     | 
    
         
            -
                puts File.basename(filename)
         
     | 
| 
      
 214 
     | 
    
         
            +
                puts "Updated: #{File.basename(filename)}"
         
     | 
| 
      
 215 
     | 
    
         
            +
                
         
     | 
| 
      
 216 
     | 
    
         
            +
                song = load(filename)
         
     | 
| 
       181 
217 
     | 
    
         | 
| 
       182 
     | 
    
         
            -
                file = ID3Lib::Tag.new(filename, ID3Lib::V2)
         
     | 
| 
       183 
218 
     | 
    
         
             
                tags.each do |key, value|
         
     | 
| 
       184 
     | 
    
         
            -
                   
     | 
| 
      
 219 
     | 
    
         
            +
                  song.send("#{key}=", value)
         
     | 
| 
       185 
220 
     | 
    
         
             
                  puts "  #{key.capitalize}: #{value}"
         
     | 
| 
       186 
221 
     | 
    
         
             
                end
         
     | 
| 
       187 
     | 
    
         
            -
                 
     | 
| 
      
 222 
     | 
    
         
            +
                ALBUM_KEYS.each do |key|
         
     | 
| 
      
 223 
     | 
    
         
            +
                  puts "  #{key.capitalize}: #{song.send(key)}"
         
     | 
| 
      
 224 
     | 
    
         
            +
                end
         
     | 
| 
      
 225 
     | 
    
         
            +
                
         
     | 
| 
      
 226 
     | 
    
         
            +
                unless options['dry-run']
         
     | 
| 
      
 227 
     | 
    
         
            +
                  song.update!(ID3Lib::V2) 
         
     | 
| 
      
 228 
     | 
    
         
            +
                end
         
     | 
| 
       188 
229 
     | 
    
         
             
              end    
         
     | 
| 
       189 
230 
     | 
    
         | 
| 
      
 231 
     | 
    
         
            +
              # Returns the path to the fingerprinter binary for this platform.
         
     | 
| 
       190 
232 
     | 
    
         
             
              def binary
         
     | 
| 
       191 
233 
     | 
    
         
             
                @binary ||= "#{File.dirname(__FILE__)}/../vendor/" + 
         
     | 
| 
       192 
234 
     | 
    
         
             
                  case RUBY_PLATFORM
         
     | 
| 
         @@ -199,6 +241,12 @@ class Sweeper 
     | 
|
| 
       199 
241 
     | 
    
         
             
                    end
         
     | 
| 
       200 
242 
     | 
    
         
             
              end
         
     | 
| 
       201 
243 
     | 
    
         | 
| 
      
 244 
     | 
    
         
            +
              # Loads metadata for an mp3 file. Looks for which ID3 version is already populated, instead of just the existence of frames.
         
     | 
| 
      
 245 
     | 
    
         
            +
              def load(filename) 
         
     | 
| 
      
 246 
     | 
    
         
            +
                ID3Lib::Tag.new(filename, ID3Lib::V_ALL)
         
     | 
| 
      
 247 
     | 
    
         
            +
              end  
         
     | 
| 
      
 248 
     | 
    
         
            +
              
         
     | 
| 
      
 249 
     | 
    
         
            +
              # Silence STDERR and STDOUT for the duration of the block.
         
     | 
| 
       202 
250 
     | 
    
         
             
              def silence(outf = nil, errf = nil)
         
     | 
| 
       203 
251 
     | 
    
         
             
                # This method is annoying.
         
     | 
| 
       204 
252 
     | 
    
         
             
                outf, errf = Tempfile.new("stdout"), Tempfile.new("stderr")
         
     | 
    
        data/sweeper.gemspec
    CHANGED
    
    | 
         @@ -1,10 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         | 
| 
       2 
     | 
    
         
            -
            # Gem::Specification for Sweeper-0.2
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Gem::Specification for Sweeper-0.2.1
         
     | 
| 
       3 
3 
     | 
    
         
             
            # Originally generated by Echoe
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       6 
6 
     | 
    
         
             
              s.name = %q{sweeper}
         
     | 
| 
       7 
     | 
    
         
            -
              s.version = "0.2"
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version = "0.2.1"
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
              s.specification_version = 2 if s.respond_to? :specification_version=
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
         @@ -32,7 +32,7 @@ class SweeperTest < Test::Unit::TestCase 
     | 
|
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
              def test_lookup_genre
         
     | 
| 
       34 
34 
     | 
    
         
             
                assert_equal(
         
     | 
| 
       35 
     | 
    
         
            -
                   {"genre"=>"Psychadelic", "comment"=>"rock psychedelic mod Philly"},
         
     | 
| 
      
 35 
     | 
    
         
            +
                   {"genre"=>"Psychadelic", "comment"=>"rock, psychedelic, mod, Philly"},
         
     | 
| 
       36 
36 
     | 
    
         
             
                  @s.lookup_genre(@s.lookup_basic(@found_many))    
         
     | 
| 
       37 
37 
     | 
    
         
             
                )
         
     | 
| 
       38 
38 
     | 
    
         
             
                assert_equal(
         
     | 
    
        metadata
    CHANGED
    
    
    
        metadata.gz.sig
    CHANGED
    
    | 
         Binary file 
     |