imp3 0.1.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/.document +5 -0
- data/.gitignore +23 -0
- data/LICENSE +20 -0
- data/README.rdoc +129 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/imp3 +63 -0
- data/lib/imp3/cli.rb +208 -0
- data/lib/imp3.rb +5 -0
- data/test/helper.rb +11 -0
- data/test/test_normalization.rb +16 -0
- metadata +116 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Víctor Martínez
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
== DESCRIPTION
|
2
|
+
|
3
|
+
iMp3 is an application for batch processing and fixing common issues when dealing with a large iTunes library
|
4
|
+
|
5
|
+
== REQUIREMENTS
|
6
|
+
|
7
|
+
* Mac OS X 10.6
|
8
|
+
* iTunes 9
|
9
|
+
|
10
|
+
== INSTALL
|
11
|
+
|
12
|
+
sudo gem install imp3
|
13
|
+
|
14
|
+
== SYNOPSIS
|
15
|
+
|
16
|
+
Application for batch processing and fixing common issues when dealing with a large iTunes library
|
17
|
+
|
18
|
+
Commands:
|
19
|
+
fix genres Tags all tracks genres using last.fm
|
20
|
+
fix misspelled-artists Fixes misspelled artist names
|
21
|
+
help Display global or [command] help documentation.
|
22
|
+
stats genres Lists all genres tagged in iTunes
|
23
|
+
|
24
|
+
Global Options:
|
25
|
+
-h, --help Display help documentation
|
26
|
+
-v, --version Display version information
|
27
|
+
-t, --trace Display backtrace when an error occurs
|
28
|
+
|
29
|
+
== FEATURES
|
30
|
+
|
31
|
+
$ imp3 genres fetch
|
32
|
+
53% |=============............| Tagging track 911DA9F96A9D7003 with genre 'sludge'
|
33
|
+
|
34
|
+
$ imp3 artists misspelled
|
35
|
+
Misspelled artist name scan complete.
|
36
|
+
|
37
|
+
What is the correct artist name for L'Antietam
|
38
|
+
1. L'Antietam
|
39
|
+
2. L'antietam
|
40
|
+
3. (Skip)
|
41
|
+
? 1
|
42
|
+
Tagging track 851744AFF27C75D1 with artist name 'L'Antietam'
|
43
|
+
|
44
|
+
177 artists.
|
45
|
+
1479 tracks.
|
46
|
+
1 tracks tagged.
|
47
|
+
0 requests.
|
48
|
+
0 errors.
|
49
|
+
|
50
|
+
$ imp3 genres ignore-add singer-songwriter
|
51
|
+
Genre 'singer-songwriter' added to ignore list
|
52
|
+
|
53
|
+
$ imp3 genres ignore-list
|
54
|
+
+-------------------+
|
55
|
+
| Genre |
|
56
|
+
+-------------------+
|
57
|
+
| singer-songwriter |
|
58
|
+
| polish |
|
59
|
+
| swedish |
|
60
|
+
+-------------------+
|
61
|
+
|
62
|
+
$ imp3 genres list
|
63
|
+
+-------------------+--------+
|
64
|
+
| Genre | Tracks |
|
65
|
+
+-------------------+--------+
|
66
|
+
| screamo | 398 |
|
67
|
+
| post-rock | 252 |
|
68
|
+
| hardcore | 116 |
|
69
|
+
| post-hardcore | 81 |
|
70
|
+
| sludge | 72 |
|
71
|
+
| indie | 67 |
|
72
|
+
| rock | 58 |
|
73
|
+
| math-rock | 44 |
|
74
|
+
| thrashcore | 38 |
|
75
|
+
| emo | 36 |
|
76
|
+
| electronic | 33 |
|
77
|
+
| crust | 32 |
|
78
|
+
| mathcore | 29 |
|
79
|
+
| post-metal | 26 |
|
80
|
+
| metalcore | 23 |
|
81
|
+
| punk | 21 |
|
82
|
+
| grindcore | 21 |
|
83
|
+
| crustcore | 15 |
|
84
|
+
| ska | 11 |
|
85
|
+
| indie-rock | 11 |
|
86
|
+
| deathcore | 10 |
|
87
|
+
| black-metal | 9 |
|
88
|
+
| experimental | 8 |
|
89
|
+
| ambient | 7 |
|
90
|
+
| emo-violence | 6 |
|
91
|
+
| death-metal | 5 |
|
92
|
+
| pop-punk | 5 |
|
93
|
+
| swedish | 3 |
|
94
|
+
| psychedelic | 3 |
|
95
|
+
| pop | 2 |
|
96
|
+
| polish | 2 |
|
97
|
+
| punk-rock | 1 |
|
98
|
+
| acoustic | 1 |
|
99
|
+
| post-punk | 1 |
|
100
|
+
+-------------------+--------+
|
101
|
+
|
102
|
+
== TODO
|
103
|
+
|
104
|
+
* Issue solver: Misspelled album names
|
105
|
+
* Issue solver: Lower-cased track names
|
106
|
+
* Issue solver: Same artist, different genre
|
107
|
+
* Issue solver: Fetch missing album art using images.google.com
|
108
|
+
* Issue solver: Duplicate tracks
|
109
|
+
* Issue solver: Remove sort artist (I personally hate this feature)
|
110
|
+
* Switch to only process current iTunes selection
|
111
|
+
* Switch to skip/force already processed tracks
|
112
|
+
* Cache last.fm requests
|
113
|
+
* Windows support through Win32OLE
|
114
|
+
* (your feature request here)
|
115
|
+
* ...
|
116
|
+
|
117
|
+
== Note on Patches/Pull Requests
|
118
|
+
|
119
|
+
* Fork the project.
|
120
|
+
* Make your feature addition or bug fix.
|
121
|
+
* Add tests for it. This is important so I don't break it in a
|
122
|
+
future version unintentionally.
|
123
|
+
* Commit, do not mess with rakefile, version, or history.
|
124
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
125
|
+
* Send me a pull request. Bonus points for topic branches.
|
126
|
+
|
127
|
+
== LICENSE
|
128
|
+
|
129
|
+
Copyright (c) 2010 Víctor Martínez. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'lib/imp3'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = "imp3"
|
9
|
+
gem.summary = %Q{Application for batch processing and fixing common issues when dealing with a large iTunes library}
|
10
|
+
gem.description = %Q{An application for batch processing and fixing common issues when dealing with a large iTunes library}
|
11
|
+
gem.email = "knoopx@gmail.com"
|
12
|
+
gem.homepage = "http://github.com/knoopx/imp3"
|
13
|
+
gem.authors = ["Víctor Martínez"]
|
14
|
+
gem.add_dependency('commander', '~> 4.0.2')
|
15
|
+
gem.add_dependency('terminal-table', '~> 1.4.2')
|
16
|
+
gem.add_dependency('nokogiri', '~> 1.4.1')
|
17
|
+
gem.add_dependency('pbosetti-rubyosa', '~> 0.5.3')
|
18
|
+
gem.add_dependency('friendly_id', '~> 2.3.3')
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
29
|
+
test.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'rcov/rcovtask'
|
34
|
+
Rcov::RcovTask.new do |test|
|
35
|
+
test.libs << 'test'
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
rescue LoadError
|
40
|
+
task :rcov do
|
41
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
task :test => :check_dependencies
|
46
|
+
|
47
|
+
task :default => :test
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "imp3 #{IMP3::VERSION}"
|
53
|
+
rdoc.rdoc_files.include('README.rdoc')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
data/bin/imp3
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require "lib/imp3"
|
8
|
+
require 'commander/import'
|
9
|
+
|
10
|
+
program :name, 'imp3'
|
11
|
+
program :version, IMP3::VERSION
|
12
|
+
program :description, 'Application for batch processing and fixing common issues when dealing with a large iTunes library'
|
13
|
+
program :help_formatter, :compact
|
14
|
+
|
15
|
+
default_command :help
|
16
|
+
|
17
|
+
command "genres list" do |c|
|
18
|
+
c.syntax = 'genres list'
|
19
|
+
c.description = 'Lists all genres tagged in iTunes'
|
20
|
+
c.when_called do |args, options|
|
21
|
+
IMP3::CLI.new.genres_list
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
command "genres fetch" do |c|
|
26
|
+
c.syntax = 'genres fetch'
|
27
|
+
c.description = 'Fetch and tag track genres from last.fm top tag'
|
28
|
+
c.when_called do |args, options|
|
29
|
+
IMP3::CLI.new.genres_tag
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
command "genres ignore-add" do |c|
|
34
|
+
c.syntax = 'genres ignore-add GENRE'
|
35
|
+
c.description = 'Ignore specified genre so is no longer used and the next one is taken for tagging tracks'
|
36
|
+
c.when_called do |args, options|
|
37
|
+
IMP3::CLI.new.genres_ignore_add(args.first)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
command "genres ignore-del" do |c|
|
42
|
+
c.syntax = 'genres ignore-del GENRE'
|
43
|
+
c.description = 'Ignore specified genre so is no longer used and the next one is taken for tagging tracks'
|
44
|
+
c.when_called do |args, options|
|
45
|
+
IMP3::CLI.new.genres_ignore_del(args.first)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
command "genres ignore-list" do |c|
|
50
|
+
c.syntax = 'genres ignore-list'
|
51
|
+
c.description = 'Lists all ignored genres'
|
52
|
+
c.when_called do |args, options|
|
53
|
+
IMP3::CLI.new.genres_ignore_list
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
command "artists misspelled" do |c|
|
58
|
+
c.syntax = 'artists misspelled'
|
59
|
+
c.description = 'Fix misspelled artist names'
|
60
|
+
c.when_called do |args, options|
|
61
|
+
IMP3::CLI.new.artists_misspelled
|
62
|
+
end
|
63
|
+
end
|
data/lib/imp3/cli.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'terminal-table/import'
|
5
|
+
require 'active_support'
|
6
|
+
require 'friendly_id/slug_string'
|
7
|
+
require 'rbosa'
|
8
|
+
require 'pp'
|
9
|
+
require 'commander/user_interaction'
|
10
|
+
|
11
|
+
OSA.utf8_strings = true
|
12
|
+
|
13
|
+
class IMP3::CLI
|
14
|
+
CONFIG_FILE = File.expand_path(File.join("~", ".imp3"))
|
15
|
+
|
16
|
+
def genres_tag
|
17
|
+
artist_genres = {}
|
18
|
+
tagged, requests, errors = 0, 0, 0
|
19
|
+
|
20
|
+
progress_bar tracks do |track, bar|
|
21
|
+
normalized_artist_name = track.artist.normalize
|
22
|
+
|
23
|
+
begin
|
24
|
+
unless artist_genres.has_key?(normalized_artist_name)
|
25
|
+
requests += 1
|
26
|
+
bar.refresh(:title => "Quering last.fm for '#{track.artist}'")
|
27
|
+
tags = Nokogiri(open("http://ws.audioscrobbler.com/1.0/artist/#{URI.escape(CGI.escape(track.artist))}/toptags.xml")).search("//toptags/tag/name").map{|t| t.text.normalize }.uniq
|
28
|
+
tags = tags - config[:ignore_genres] if config[:ignore_genres]
|
29
|
+
artist_genres[normalized_artist_name] = tags.first
|
30
|
+
end
|
31
|
+
rescue => e
|
32
|
+
errors += 1
|
33
|
+
bar.refresh(:title => e)
|
34
|
+
artist_genres[normalized_artist_name] = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
if (artist_genres.has_key?(normalized_artist_name) and not artist_genres[normalized_artist_name].nil?)
|
38
|
+
tagged += 1
|
39
|
+
bar.increment(:title => "Tagging track #{track.persistent_id} with genre '#{artist_genres[normalized_artist_name]}'")
|
40
|
+
track.genre = ""
|
41
|
+
track.genre = artist_genres[normalized_artist_name]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
summary(:tracks_tagged => tagged, :requests => requests, :errors => errors)
|
46
|
+
end
|
47
|
+
|
48
|
+
def genres_list
|
49
|
+
genres = {}
|
50
|
+
tracks.each do |track|
|
51
|
+
genres[track.genre] ||= 0
|
52
|
+
genres[track.genre] += 1
|
53
|
+
end
|
54
|
+
|
55
|
+
genre_table = table do |t|
|
56
|
+
t.headings = 'Genre', 'Tracks'
|
57
|
+
genres.sort{|a, b| b[1] <=> a[1]}.each do |g, c|
|
58
|
+
t << [g, c]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
puts genre_table
|
63
|
+
summary
|
64
|
+
end
|
65
|
+
|
66
|
+
def genres_ignore_add(genre)
|
67
|
+
raise "Please specify a genre" unless genre
|
68
|
+
genre.strip!
|
69
|
+
config[:ignore_genres] ||= []
|
70
|
+
config[:ignore_genres] << genre unless config[:ignore_genres].include?(genre)
|
71
|
+
save_config
|
72
|
+
puts "Genre '#{genre}' added to ignore list"
|
73
|
+
end
|
74
|
+
|
75
|
+
def genres_ignore_del(genre)
|
76
|
+
raise "Please specify a genre" unless genre
|
77
|
+
genre.strip!
|
78
|
+
config[:ignore_genres].delete(genre) if config[:ignore_genres].include?(genre)
|
79
|
+
save_config
|
80
|
+
puts "Genre '#{genre}' deleted from ignore list"
|
81
|
+
end
|
82
|
+
|
83
|
+
def genres_ignore_list
|
84
|
+
if config[:ignore_genres].any?
|
85
|
+
genre_table = table do |t|
|
86
|
+
t.headings = 'Genre'
|
87
|
+
config[:ignore_genres].each do |g|
|
88
|
+
t << [g]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
puts genre_table
|
92
|
+
else
|
93
|
+
puts "No ignored genres."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def artists_misspelled
|
98
|
+
artist_choices = {}
|
99
|
+
tagged = 0
|
100
|
+
|
101
|
+
progress_bar artists, :complete_message => "Misspelled artist name scan complete." do |artist, bar|
|
102
|
+
bar.increment :title => "Scanning artist '#{artist}'"
|
103
|
+
normalized_artist_name = artist.normalized_without_words
|
104
|
+
artist_choices[normalized_artist_name] ||= []
|
105
|
+
artist_choices[normalized_artist_name] << artist.strip unless artist_choices[normalized_artist_name].include?(artist)
|
106
|
+
end
|
107
|
+
|
108
|
+
artist_names = {}
|
109
|
+
tracks.each do |track|
|
110
|
+
normalized_artist_name = track.artist.normalized_without_words
|
111
|
+
unless artist_names.has_key?(normalized_artist_name)
|
112
|
+
if artist_choices[normalized_artist_name] && artist_choices[normalized_artist_name].size > 1
|
113
|
+
puts
|
114
|
+
artist_name = choose("What is the correct artist name for #{track.artist}", *(artist_choices[normalized_artist_name] << :"(Skip)"))
|
115
|
+
artist_names[normalized_artist_name] = artist_name
|
116
|
+
else
|
117
|
+
artist_names[normalized_artist_name] = track.artist
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
unless artist_names[normalized_artist_name].eql?(:"(Skip)") or track.artist.eql?(artist_names[normalized_artist_name])
|
122
|
+
tagged += 1
|
123
|
+
puts "Tagging track #{track.persistent_id} with artist name '#{artist_names[normalized_artist_name]}'"
|
124
|
+
track.artist = ""
|
125
|
+
track.artist = artist_names[normalized_artist_name]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
summary :tracks_tagged => tagged
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
def itunes
|
135
|
+
@itunes ||= OSA.app('iTunes')
|
136
|
+
end
|
137
|
+
|
138
|
+
def library
|
139
|
+
@library ||= itunes.sources.find {|s| s.kind == OSA::ITunes::ESRC::LIBRARY }.playlists[0]
|
140
|
+
end
|
141
|
+
|
142
|
+
def tracks
|
143
|
+
@tracks ||= library.tracks
|
144
|
+
end
|
145
|
+
|
146
|
+
def artists
|
147
|
+
@artists ||= tracks.map{|t| t.artist}.uniq.sort
|
148
|
+
end
|
149
|
+
|
150
|
+
def config
|
151
|
+
return @config if @config
|
152
|
+
if File.exist?(CONFIG_FILE)
|
153
|
+
begin
|
154
|
+
@config = YAML.load_file(CONFIG_FILE)
|
155
|
+
rescue
|
156
|
+
raise "Unable to read config file #{CONFIG_FILE}"
|
157
|
+
end
|
158
|
+
else
|
159
|
+
@config = { :ignore_genres => [] }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def save_config
|
164
|
+
File.new(CONFIG_FILE, "w+").write(config.to_yaml)
|
165
|
+
end
|
166
|
+
|
167
|
+
def summary(opts = {})
|
168
|
+
puts
|
169
|
+
puts "#{opts[:artist] || tracks.map{|t| t.artist}.uniq.size} artists."
|
170
|
+
puts "#{opts[:tracks] || tracks.size} tracks."
|
171
|
+
puts "#{opts[:tracks_tagged] || 0} tracks tagged."
|
172
|
+
puts "#{opts[:requests] || 0} requests."
|
173
|
+
puts "#{opts[:errors] || 0} errors."
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class String
|
178
|
+
STRIP_WORDS = %w(the a of in)
|
179
|
+
|
180
|
+
def strip_meaningless_words
|
181
|
+
string = self
|
182
|
+
STRIP_WORDS.each do |w|
|
183
|
+
string = string.gsub(/\b#{w}\b/i, '')
|
184
|
+
end
|
185
|
+
string.strip
|
186
|
+
end
|
187
|
+
|
188
|
+
def normalized_without_words
|
189
|
+
self.strip_meaningless_words.normalize
|
190
|
+
end
|
191
|
+
|
192
|
+
def normalize
|
193
|
+
FriendlyId::SlugString.new(self).normalize!.approximate_ascii!.to_s
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def progress_bar arr, options = {:format => ":percent_complete% |:progress_bar| :title"}, &block
|
198
|
+
bar = ProgressBar.new arr.size, options
|
199
|
+
bar.show
|
200
|
+
arr.each { |v| yield(v, bar) }
|
201
|
+
end
|
202
|
+
|
203
|
+
class Commander::UI::ProgressBar
|
204
|
+
def refresh(tokens)
|
205
|
+
@tokens.merge! tokens if tokens.is_a? Hash
|
206
|
+
show
|
207
|
+
end
|
208
|
+
end
|
data/lib/imp3.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestNormalization < Test::Unit::TestCase
|
4
|
+
def test_normalization
|
5
|
+
fixtures = {
|
6
|
+
"the fall of troy" => "fall-troy",
|
7
|
+
"The Fall of Troy" => "fall-troy",
|
8
|
+
"Daïtro" => "daitro",
|
9
|
+
"té" => "te"
|
10
|
+
}
|
11
|
+
|
12
|
+
fixtures.each do |string, expected|
|
13
|
+
assert_equal expected, string.normalized_without_words
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: imp3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "V\xC3\xADctor Mart\xC3\xADnez"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-14 00:00:00 +01:00
|
13
|
+
default_executable: imp3
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: commander
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 4.0.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: terminal-table
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.4.2
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: nokogiri
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.4.1
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: pbosetti-rubyosa
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.5.3
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: friendly_id
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.3.3
|
64
|
+
version:
|
65
|
+
description: An application for batch processing and fixing common issues when dealing with a large iTunes library
|
66
|
+
email: knoopx@gmail.com
|
67
|
+
executables:
|
68
|
+
- imp3
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files:
|
72
|
+
- LICENSE
|
73
|
+
- README.rdoc
|
74
|
+
files:
|
75
|
+
- .document
|
76
|
+
- .gitignore
|
77
|
+
- LICENSE
|
78
|
+
- README.rdoc
|
79
|
+
- Rakefile
|
80
|
+
- VERSION
|
81
|
+
- bin/imp3
|
82
|
+
- lib/imp3.rb
|
83
|
+
- lib/imp3/cli.rb
|
84
|
+
- test/helper.rb
|
85
|
+
- test/test_normalization.rb
|
86
|
+
has_rdoc: true
|
87
|
+
homepage: http://github.com/knoopx/imp3
|
88
|
+
licenses: []
|
89
|
+
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options:
|
92
|
+
- --charset=UTF-8
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: "0"
|
100
|
+
version:
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: "0"
|
106
|
+
version:
|
107
|
+
requirements: []
|
108
|
+
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.3.5
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: Application for batch processing and fixing common issues when dealing with a large iTunes library
|
114
|
+
test_files:
|
115
|
+
- test/helper.rb
|
116
|
+
- test/test_normalization.rb
|