sweeper 0.1 → 0.2
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/Manifest +1 -0
- data/README +22 -8
- data/TODO +3 -0
- data/bin/sweeper +13 -7
- data/lib/sweeper.rb +117 -28
- data/sweeper.gemspec +7 -6
- data/test/integration/sweeper_test.rb +16 -5
- data/vendor/lastfm.fpclient.beta2.OSX-intel/lastfmfpclient +0 -0
- data/vendor/lastfm.fpclient.beta2.OSX-intel/libcurl.dylib +0 -0
- data/vendor/lastfm.fpclient.beta2.OSX-intel/libmad.dylib +0 -0
- data/vendor/lastfm.fpclient.beta2.OSX-intel/libsamplerate.dylib +0 -0
- data/vendor/lastfm.fpclient.beta2.OSX-intel/libtag.dylib +0 -0
- data/vendor/lastfm.fpclient.beta2.linux-32/lastfmfpclient +0 -0
- metadata +13 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
data/README
CHANGED
@@ -3,7 +3,7 @@ Automatically tag your music collection with metadata from Last.fm.
|
|
3
3
|
|
4
4
|
== License
|
5
5
|
|
6
|
-
Copyright 2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Unlinked portions copyright 2008 Last.fm Ltd., used by permission, and licensed under the
|
6
|
+
Copyright 2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Unlinked portions copyright 2008 Last.fm Ltd., used by permission, and licensed under the GPL 2.
|
7
7
|
|
8
8
|
The public certificate for the gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem].
|
9
9
|
|
@@ -11,15 +11,27 @@ If you use this software, please {make a donation}[http://blog.evanweaver.com/do
|
|
11
11
|
|
12
12
|
== Features
|
13
13
|
|
14
|
-
*
|
15
|
-
*
|
14
|
+
* faster than MusicBrainz
|
15
|
+
* better results than MusicBrainz
|
16
|
+
* smart genre tagging
|
16
17
|
|
17
|
-
|
18
|
+
<b>WARNING: This is beta software. Backup your music collection first.</b>
|
19
|
+
|
20
|
+
== Requirements
|
21
|
+
|
22
|
+
* Linux, Intel OS X, or Windows
|
23
|
+
* Ruby and Rubygems
|
24
|
+
* id3lib (Linux and OS X only)
|
25
|
+
* some mp3 files
|
18
26
|
|
19
|
-
|
27
|
+
== Installation
|
28
|
+
|
29
|
+
Just install the gem:
|
20
30
|
sudo gem install sweeper
|
21
31
|
|
22
|
-
|
32
|
+
== Usage
|
33
|
+
|
34
|
+
Change to the directory of mp3s you want to tag and run:
|
23
35
|
sweeper
|
24
36
|
|
25
37
|
That's all.
|
@@ -31,8 +43,10 @@ Sweeper takes a few command line options:
|
|
31
43
|
-d, --dir Directory to search (defaults to current).
|
32
44
|
-r, --recursive Recurse directories.
|
33
45
|
--dry-run Do a dry run (no files will be changed).
|
34
|
-
-f, --force Overwrite existing tags.
|
35
|
-
|
46
|
+
-f, --force Overwrite all existing tags.
|
47
|
+
-g, --genre Add genre and genre comments.
|
48
|
+
-e, --force-genre Add genre and genre comments, overwriting e
|
49
|
+
|
36
50
|
== Reporting problems
|
37
51
|
|
38
52
|
The support forum is here[http://rubyforge.org/forum/forum.php?forum_id=23599].
|
data/TODO
ADDED
data/bin/sweeper
CHANGED
@@ -19,7 +19,7 @@ Choice.options do
|
|
19
19
|
desc 'Recurse directories.'
|
20
20
|
end
|
21
21
|
|
22
|
-
option :dry do
|
22
|
+
option :"dry-run" do
|
23
23
|
long '--dry-run'
|
24
24
|
desc 'Do a dry run (no files will be changed).'
|
25
25
|
end
|
@@ -27,14 +27,20 @@ Choice.options do
|
|
27
27
|
option :force do
|
28
28
|
short '-f'
|
29
29
|
long '--force'
|
30
|
-
desc 'Overwrite existing tags.'
|
30
|
+
desc 'Overwrite all existing tags.'
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
option :genre do
|
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
|
38
44
|
end
|
39
45
|
|
40
46
|
Sweeper.new(Choice.choices).run
|
data/lib/sweeper.rb
CHANGED
@@ -3,31 +3,59 @@ require 'rubygems'
|
|
3
3
|
require 'id3lib'
|
4
4
|
require 'xsd/mapping'
|
5
5
|
require 'activesupport'
|
6
|
+
require 'open-uri'
|
7
|
+
require 'uri'
|
8
|
+
require 'amatch'
|
6
9
|
|
7
10
|
class ID3Lib::Tag
|
8
|
-
|
9
|
-
|
11
|
+
def url
|
12
|
+
f = frame(:WORS)
|
13
|
+
f ? f[:url] : nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def url=(s)
|
17
|
+
remove_frame(:WORS)
|
18
|
+
self << {:id => :WORS, :url => s} if s.any?
|
19
|
+
end
|
10
20
|
end
|
11
21
|
|
12
22
|
class Sweeper
|
13
23
|
|
14
24
|
class Problem < RuntimeError; end
|
15
25
|
|
16
|
-
|
26
|
+
BASIC_KEYS = ['artist', 'title', 'url']
|
27
|
+
GENRE_KEYS = ['genre', 'comment']
|
28
|
+
GENRES = ID3Lib::Info::Genres.sort
|
29
|
+
GENRE_COUNT = 7
|
30
|
+
DEFAULT_GENRE = {'genre' => 'Other', 'comment' => 'other'}
|
17
31
|
|
18
32
|
attr_reader :options
|
19
33
|
|
20
34
|
def initialize(options = {})
|
35
|
+
options['genre'] ||= options['force-genre']
|
21
36
|
@dir = File.expand_path(options['dir'] || Dir.pwd)
|
22
37
|
@options = options
|
23
38
|
end
|
24
39
|
|
25
|
-
def run
|
26
|
-
@
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
def run
|
41
|
+
@read = 0
|
42
|
+
@updated = 0
|
43
|
+
@failed = 0
|
44
|
+
|
45
|
+
Kernel.at_exit do
|
46
|
+
if @read == 0
|
47
|
+
puts "No files found. Maybe you meant --recursive?"
|
48
|
+
exec "#{$0} --help"
|
49
|
+
else
|
50
|
+
puts "Read: #{@read}\nUpdated: #{@updated}\nFailed: #{@failed}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
begin
|
55
|
+
recurse(@dir)
|
56
|
+
rescue Object => e
|
57
|
+
puts "Unknown error: #{e.inspect}"
|
58
|
+
ENV['DEBUG'] ? raise : exit
|
31
59
|
end
|
32
60
|
end
|
33
61
|
|
@@ -38,19 +66,21 @@ class Sweeper
|
|
38
66
|
if File.directory? filename and options['recursive']
|
39
67
|
recurse(filename)
|
40
68
|
elsif File.extname(filename) == ".mp3"
|
41
|
-
@
|
69
|
+
@read += 1
|
42
70
|
tries = 0
|
43
71
|
begin
|
44
|
-
current = read(filename)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
72
|
+
current = read(filename)
|
73
|
+
updated = lookup(filename, current)
|
74
|
+
|
75
|
+
if updated != current
|
76
|
+
write(filename, updated)
|
77
|
+
@updated += 1
|
50
78
|
end
|
79
|
+
|
51
80
|
rescue Problem => e
|
52
81
|
tries += 1 and retry if tries < 2
|
53
|
-
puts "Skipped #{filename}: #{e.message}"
|
82
|
+
puts "Skipped #{File.basename(filename)}: #{e.message}"
|
83
|
+
@failed += 1
|
54
84
|
end
|
55
85
|
end
|
56
86
|
end
|
@@ -58,44 +88,103 @@ class Sweeper
|
|
58
88
|
|
59
89
|
def read(filename)
|
60
90
|
tags = {}
|
61
|
-
|
91
|
+
|
92
|
+
song = ID3Lib::Tag.new(filename, ID3Lib::V2)
|
93
|
+
if song.empty?
|
94
|
+
song = ID3Lib::Tag.new(filename, ID3Lib::V1)
|
95
|
+
end
|
62
96
|
|
63
|
-
|
97
|
+
(BASIC_KEYS + GENRE_KEYS).each do |key|
|
64
98
|
tags[key] = song.send(key) if !song.send(key).blank?
|
65
99
|
end
|
100
|
+
|
66
101
|
tags
|
67
102
|
end
|
68
103
|
|
69
|
-
def lookup(filename)
|
104
|
+
def lookup(filename, tags = {})
|
105
|
+
updated = {}
|
106
|
+
if options['force'] or
|
107
|
+
(BASIC_KEYS - tags.keys).any?
|
108
|
+
updated.merge!(lookup_basic(filename))
|
109
|
+
end
|
110
|
+
if options['genre'] and
|
111
|
+
(options['force'] or options['force-genre'] or (GENRE_KEYS - tags.keys).any?)
|
112
|
+
updated.merge!(lookup_genre(updated.merge(tags)))
|
113
|
+
end
|
114
|
+
|
115
|
+
if options['force']
|
116
|
+
tags.merge!(updated)
|
117
|
+
elsif options['force-genre']
|
118
|
+
tags.merge!(updated.slice('genre', 'comment'))
|
119
|
+
end
|
120
|
+
|
121
|
+
updated.merge(tags)
|
122
|
+
end
|
123
|
+
|
124
|
+
def lookup_basic(filename)
|
70
125
|
Dir.chdir File.dirname(binary) do
|
71
|
-
response = silence { `./#{File.basename(binary)} #{filename}` }
|
126
|
+
response = silence { `./#{File.basename(binary)} #{filename.inspect}` }
|
72
127
|
object = begin
|
73
128
|
XSD::Mapping.xml2obj(response)
|
74
129
|
rescue REXML::ParseException
|
75
|
-
raise Problem, "
|
130
|
+
raise Problem, "Server sent invalid response."
|
76
131
|
end
|
77
|
-
raise Problem, "
|
132
|
+
raise Problem, "Fingerprint failed or not found." unless object
|
78
133
|
|
79
134
|
tags = {}
|
80
135
|
song = Array(object.track).first
|
81
136
|
|
82
|
-
|
137
|
+
BASIC_KEYS.each do |key|
|
83
138
|
tags[key] = song.send(key) if song.respond_to? key
|
84
139
|
end
|
85
140
|
tags
|
86
141
|
end
|
87
142
|
end
|
88
143
|
|
144
|
+
def lookup_genre(tags)
|
145
|
+
return DEFAULT_GENRE if tags['artist'].blank?
|
146
|
+
|
147
|
+
response = begin
|
148
|
+
open("http://ws.audioscrobbler.com/1.0/artist/#{URI.encode(tags['artist'])}/toptags.xml").read
|
149
|
+
rescue OpenURI::HTTPError
|
150
|
+
return DEFAULT_GENRE
|
151
|
+
end
|
152
|
+
|
153
|
+
object = XSD::Mapping.xml2obj(response)
|
154
|
+
return DEFAULT_GENRE if !object.respond_to? :tag
|
155
|
+
|
156
|
+
genres = Array(object.tag)[0..(GENRE_COUNT - 1)].map(&:name)
|
157
|
+
return DEFAULT_GENRE if !genres.any?
|
158
|
+
|
159
|
+
primary = nil
|
160
|
+
genres.each do |this|
|
161
|
+
match_results = Amatch::Levenshtein.new(this).similar(GENRES)
|
162
|
+
max = match_results.max
|
163
|
+
match = GENRES[match_results.index(max)]
|
164
|
+
|
165
|
+
if ['Rock', 'Pop', 'Rap'].include? match
|
166
|
+
# Penalize useless genres
|
167
|
+
max = max / 3.0
|
168
|
+
end
|
169
|
+
|
170
|
+
if !primary or primary.first < max
|
171
|
+
primary = [max, match]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
{'genre' => primary.last, 'comment' => genres.join(" ")}
|
176
|
+
end
|
177
|
+
|
89
178
|
def write(filename, tags)
|
90
179
|
return if tags.empty?
|
91
|
-
puts filename
|
180
|
+
puts File.basename(filename)
|
92
181
|
|
93
|
-
file = ID3Lib::Tag.new(filename)
|
182
|
+
file = ID3Lib::Tag.new(filename, ID3Lib::V2)
|
94
183
|
tags.each do |key, value|
|
95
184
|
file.send("#{key}=", value)
|
96
|
-
puts " #{value}"
|
185
|
+
puts " #{key.capitalize}: #{value}"
|
97
186
|
end
|
98
|
-
file.update! unless options['dry']
|
187
|
+
file.update! unless options['dry-run']
|
99
188
|
end
|
100
189
|
|
101
190
|
def binary
|
data/sweeper.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Sweeper-0.
|
2
|
+
# Gem::Specification for Sweeper-0.2
|
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.
|
7
|
+
s.version = "0.2"
|
8
8
|
|
9
9
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
10
|
|
@@ -16,19 +16,20 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.email = %q{}
|
17
17
|
s.executables = ["sweeper"]
|
18
18
|
s.extensions = ["ext/extconf.rb"]
|
19
|
-
s.extra_rdoc_files = ["CHANGELOG", "lib/sweeper.rb", "LICENSE", "README"]
|
20
|
-
s.files = ["bin/sweeper", "CHANGELOG", "ext/extconf.rb", "ext/Makefile", "lib/sweeper.rb", "LICENSE", "Manifest", "README", "test/integration/sweeper_test.rb", "vendor/lastfm.fpclient.beta2.linux-32/lastfmfpclient", "vendor/lastfm.fpclient.beta2.linux-32/readme.txt", "vendor/lastfm.fpclient.beta2.OSX-intel/lastfmfpclient", "vendor/lastfm.fpclient.beta2.OSX-intel/libcurl.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libmad.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libsamplerate.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libtag.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/readme.txt", "vendor/lastfm.fpclient.beta2.win32/lastfmfpclient.exe", "vendor/lastfm.fpclient.beta2.win32/libcurl.dll", "vendor/lastfm.fpclient.beta2.win32/libfftw3f-3.dll", "vendor/lastfm.fpclient.beta2.win32/Microsoft.VC80.CRT.manifest", "vendor/lastfm.fpclient.beta2.win32/msvcm80.dll", "vendor/lastfm.fpclient.beta2.win32/msvcp80.dll", "vendor/lastfm.fpclient.beta2.win32/msvcr80.dll", "vendor/lastfm.fpclient.beta2.win32/taglib.dll", "vendor/lastfm.fpclient.beta2.win32/zlib1.dll", "sweeper.gemspec"]
|
19
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/sweeper.rb", "LICENSE", "README", "TODO"]
|
20
|
+
s.files = ["bin/sweeper", "CHANGELOG", "ext/extconf.rb", "ext/Makefile", "lib/sweeper.rb", "LICENSE", "Manifest", "README", "test/integration/sweeper_test.rb", "TODO", "vendor/lastfm.fpclient.beta2.linux-32/lastfmfpclient", "vendor/lastfm.fpclient.beta2.linux-32/readme.txt", "vendor/lastfm.fpclient.beta2.OSX-intel/lastfmfpclient", "vendor/lastfm.fpclient.beta2.OSX-intel/libcurl.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libmad.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libsamplerate.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/libtag.dylib", "vendor/lastfm.fpclient.beta2.OSX-intel/readme.txt", "vendor/lastfm.fpclient.beta2.win32/lastfmfpclient.exe", "vendor/lastfm.fpclient.beta2.win32/libcurl.dll", "vendor/lastfm.fpclient.beta2.win32/libfftw3f-3.dll", "vendor/lastfm.fpclient.beta2.win32/Microsoft.VC80.CRT.manifest", "vendor/lastfm.fpclient.beta2.win32/msvcm80.dll", "vendor/lastfm.fpclient.beta2.win32/msvcp80.dll", "vendor/lastfm.fpclient.beta2.win32/msvcr80.dll", "vendor/lastfm.fpclient.beta2.win32/taglib.dll", "vendor/lastfm.fpclient.beta2.win32/zlib1.dll", "sweeper.gemspec"]
|
21
21
|
s.has_rdoc = true
|
22
22
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/sweeper/}
|
23
23
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sweeper", "--main", "README"]
|
24
24
|
s.require_paths = ["lib", "ext"]
|
25
25
|
s.rubyforge_project = %q{fauna}
|
26
|
-
s.rubygems_version = %q{1.0
|
26
|
+
s.rubygems_version = %q{1.1.0}
|
27
27
|
s.summary = %q{Automatically tag your music collection with metadata from Last.fm.}
|
28
28
|
s.test_files = ["test/integration/sweeper_test.rb"]
|
29
29
|
|
30
30
|
s.add_dependency(%q<id3lib-ruby>, [">= 0"])
|
31
31
|
s.add_dependency(%q<choice>, [">= 0"])
|
32
|
+
s.add_dependency(%q<amatch>, [">= 0"])
|
32
33
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
33
34
|
end
|
34
35
|
|
@@ -43,7 +44,7 @@ end
|
|
43
44
|
# p.summary = "Automatically tag your music collection with metadata from Last.fm."
|
44
45
|
# p.url = "http://blog.evanweaver.com/files/doc/fauna/sweeper/"
|
45
46
|
# p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
|
46
|
-
# p.dependencies = ['id3lib-ruby', 'choice', 'activesupport']
|
47
|
+
# p.dependencies = ['id3lib-ruby', 'choice', 'amatch', 'activesupport']
|
47
48
|
# p.clean_pattern = ['doc', 'pkg', 'test/integration/songs']
|
48
49
|
# p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'TODO', 'lib/*']
|
49
50
|
# end
|
@@ -11,25 +11,36 @@ class SweeperTest < Test::Unit::TestCase
|
|
11
11
|
@found_many = "#{@dir}/1_001.mp3"
|
12
12
|
@found_one = "#{@dir}/1_010.mp3"
|
13
13
|
@not_found = "#{@dir}/1_003.mp3"
|
14
|
-
@s = Sweeper.new('dir' => @dir)
|
14
|
+
@s = Sweeper.new('dir' => @dir, 'genre' => true)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def test_lookup_basic
|
18
18
|
assert_equal(
|
19
19
|
{"artist"=>"Photon Band",
|
20
20
|
"title"=>"To Sing For You",
|
21
21
|
"url"=>"http://www.last.fm/music/Photon+Band/_/To+Sing+For+You"},
|
22
|
-
@s.
|
22
|
+
@s.lookup_basic(@found_many))
|
23
23
|
assert_equal(
|
24
24
|
{"artist"=>"Various Artists - Vagabond Productions",
|
25
25
|
"title"=>"Sugar Man - Tom Heyman",
|
26
26
|
"url"=> "http://www.last.fm/music/Various+Artists+-+Vagabond+Productions/_/Sugar+Man+-+Tom+Heyman"},
|
27
|
-
@s.
|
27
|
+
@s.lookup_basic(@found_one))
|
28
28
|
assert_raises(Sweeper::Problem) do
|
29
|
-
@s.
|
29
|
+
@s.lookup_basic(@not_found)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def test_lookup_genre
|
34
|
+
assert_equal(
|
35
|
+
{"genre"=>"Psychadelic", "comment"=>"rock psychedelic mod Philly"},
|
36
|
+
@s.lookup_genre(@s.lookup_basic(@found_many))
|
37
|
+
)
|
38
|
+
assert_equal(
|
39
|
+
Sweeper::DEFAULT_GENRE,
|
40
|
+
@s.lookup_genre({})
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
33
44
|
def test_read
|
34
45
|
assert_equal({},
|
35
46
|
@s.read(@found_many))
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sweeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Weaver
|
@@ -51,6 +51,15 @@ dependencies:
|
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: "0"
|
53
53
|
version:
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: amatch
|
56
|
+
version_requirement:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
54
63
|
- !ruby/object:Gem::Dependency
|
55
64
|
name: activesupport
|
56
65
|
version_requirement:
|
@@ -71,6 +80,7 @@ extra_rdoc_files:
|
|
71
80
|
- lib/sweeper.rb
|
72
81
|
- LICENSE
|
73
82
|
- README
|
83
|
+
- TODO
|
74
84
|
files:
|
75
85
|
- bin/sweeper
|
76
86
|
- CHANGELOG
|
@@ -81,6 +91,7 @@ files:
|
|
81
91
|
- Manifest
|
82
92
|
- README
|
83
93
|
- test/integration/sweeper_test.rb
|
94
|
+
- TODO
|
84
95
|
- vendor/lastfm.fpclient.beta2.linux-32/lastfmfpclient
|
85
96
|
- vendor/lastfm.fpclient.beta2.linux-32/readme.txt
|
86
97
|
- vendor/lastfm.fpclient.beta2.OSX-intel/lastfmfpclient
|
@@ -127,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
138
|
requirements: []
|
128
139
|
|
129
140
|
rubyforge_project: fauna
|
130
|
-
rubygems_version: 1.0
|
141
|
+
rubygems_version: 1.1.0
|
131
142
|
signing_key:
|
132
143
|
specification_version: 2
|
133
144
|
summary: Automatically tag your music collection with metadata from Last.fm.
|
metadata.gz.sig
CHANGED
Binary file
|