imp3 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +36 -12
- data/VERSION +1 -1
- data/bin/imp3 +24 -11
- data/lib/imp3/cache.rb +28 -0
- data/lib/imp3/cli.rb +26 -139
- data/lib/imp3/commands/artists.rb +39 -0
- data/lib/imp3/commands/genres.rb +116 -0
- data/lib/imp3/commands.rb +8 -0
- data/lib/imp3/config.rb +33 -0
- data/lib/imp3.rb +2 -1
- metadata +6 -1
data/README.rdoc
CHANGED
@@ -13,18 +13,42 @@ iMp3 is an application for batch processing and fixing common issues when dealin
|
|
13
13
|
|
14
14
|
== SYNOPSIS
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
NAME:
|
17
|
+
|
18
|
+
imp3
|
19
|
+
|
20
|
+
DESCRIPTION:
|
21
|
+
|
22
|
+
Application for batch processing and fixing common issues when dealing with a large iTunes library
|
23
|
+
|
24
|
+
COMMANDS:
|
25
|
+
|
26
|
+
artists misspelled Fix misspelled artist names
|
27
|
+
genres fetch Fetch last.fm artist top tags and tag track genre
|
28
|
+
genres fetch-cache Lists genres present on the cache and not in the ignore list
|
29
|
+
genres ignore-add Add specified genre to ignore list so is no longer used for tagging tracks
|
30
|
+
genres ignore-del Remove specified genre from ignore list
|
31
|
+
genres ignore-list Lists all ignored genres
|
32
|
+
genres list Lists all genres tagged in iTunes
|
33
|
+
help Display global or [command] help documentation.
|
34
|
+
|
35
|
+
GLOBAL OPTIONS:
|
36
|
+
|
37
|
+
-s, --selection
|
38
|
+
Apply only to current iTunes selection
|
39
|
+
|
40
|
+
-h, --help
|
41
|
+
Display help documentation
|
42
|
+
|
43
|
+
-v, --version
|
44
|
+
Display version information
|
45
|
+
|
46
|
+
-t, --trace
|
47
|
+
Display backtrace when an error occurs
|
48
|
+
|
49
|
+
AUTHORS:
|
50
|
+
|
51
|
+
Víctor Martínez
|
28
52
|
|
29
53
|
== FEATURES
|
30
54
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/bin/imp3
CHANGED
@@ -10,39 +10,52 @@ require 'commander/import'
|
|
10
10
|
program :name, 'imp3'
|
11
11
|
program :version, IMP3::VERSION
|
12
12
|
program :description, 'Application for batch processing and fixing common issues when dealing with a large iTunes library'
|
13
|
-
program :
|
13
|
+
program :help, 'Authors', 'Víctor Martínez'
|
14
14
|
|
15
15
|
default_command :help
|
16
16
|
|
17
|
+
global_option('-s', '--selection', "Apply only to current iTunes selection") { IMP3::CLI.instance.source_origin = :selection }
|
18
|
+
|
17
19
|
command "genres list" do |c|
|
18
20
|
c.syntax = 'genres list'
|
19
21
|
c.description = 'Lists all genres tagged in iTunes'
|
20
22
|
c.when_called do |args, options|
|
21
|
-
IMP3::CLI.
|
23
|
+
IMP3::CLI.instance.genres_list_command
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
27
|
command "genres fetch" do |c|
|
26
|
-
c.syntax = 'genres fetch'
|
27
|
-
c.description = 'Fetch
|
28
|
+
c.syntax = 'genres fetch [options]'
|
29
|
+
c.description = 'Fetch last.fm artist top tags and tag track genre'
|
30
|
+
c.option '--flush-cache', 'Re-create last.fm artist tags cache'
|
31
|
+
c.when_called do |args, options|
|
32
|
+
IMP3::CLI.instance.genres_fetch_command(options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
command "genres fetch-cache" do |c|
|
37
|
+
c.syntax = 'genres fetch-cache [options]'
|
38
|
+
c.description = 'Lists genres present on the cache and not in the ignore list'
|
39
|
+
c.option '--limit VALUE', Integer, 'Limit to [VALUE] results'
|
28
40
|
c.when_called do |args, options|
|
29
|
-
|
41
|
+
options.default :limit => 25
|
42
|
+
IMP3::CLI.instance.genres_fetch_cache_command(options)
|
30
43
|
end
|
31
44
|
end
|
32
45
|
|
33
46
|
command "genres ignore-add" do |c|
|
34
47
|
c.syntax = 'genres ignore-add GENRE'
|
35
|
-
c.description = '
|
48
|
+
c.description = 'Add specified genre to ignore list so is no longer used for tagging tracks'
|
36
49
|
c.when_called do |args, options|
|
37
|
-
IMP3::CLI.
|
50
|
+
IMP3::CLI.instance.genres_ignore_add_command(args.first)
|
38
51
|
end
|
39
52
|
end
|
40
53
|
|
41
54
|
command "genres ignore-del" do |c|
|
42
55
|
c.syntax = 'genres ignore-del GENRE'
|
43
|
-
c.description = '
|
56
|
+
c.description = 'Remove specified genre from ignore list'
|
44
57
|
c.when_called do |args, options|
|
45
|
-
IMP3::CLI.
|
58
|
+
IMP3::CLI.instance.genres_ignore_del_command(args.first)
|
46
59
|
end
|
47
60
|
end
|
48
61
|
|
@@ -50,7 +63,7 @@ command "genres ignore-list" do |c|
|
|
50
63
|
c.syntax = 'genres ignore-list'
|
51
64
|
c.description = 'Lists all ignored genres'
|
52
65
|
c.when_called do |args, options|
|
53
|
-
IMP3::CLI.
|
66
|
+
IMP3::CLI.instance.genres_ignore_list_command
|
54
67
|
end
|
55
68
|
end
|
56
69
|
|
@@ -58,6 +71,6 @@ command "artists misspelled" do |c|
|
|
58
71
|
c.syntax = 'artists misspelled'
|
59
72
|
c.description = 'Fix misspelled artist names'
|
60
73
|
c.when_called do |args, options|
|
61
|
-
IMP3::CLI.
|
74
|
+
IMP3::CLI.instance.artists_misspelled_command
|
62
75
|
end
|
63
76
|
end
|
data/lib/imp3/cache.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
class IMP3::Cache
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
CACHE_FILE = File.join(IMP3::APP_DIR, "cache.yml")
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@data = {}
|
10
|
+
|
11
|
+
if File.exist?(CACHE_FILE)
|
12
|
+
begin
|
13
|
+
@data = YAML.load_file(CACHE_FILE)
|
14
|
+
rescue
|
15
|
+
raise "Unable to read cache file #{CACHE_FILE}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def artist_genres
|
21
|
+
@data[:artist_genres] ||= {}
|
22
|
+
@data[:artist_genres]
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
File.new(CACHE_FILE, "w+").write(@data.to_yaml)
|
27
|
+
end
|
28
|
+
end
|
data/lib/imp3/cli.rb
CHANGED
@@ -7,166 +7,55 @@ require 'friendly_id/slug_string'
|
|
7
7
|
require 'rbosa'
|
8
8
|
require 'pp'
|
9
9
|
require 'commander/user_interaction'
|
10
|
+
require 'singleton'
|
11
|
+
require 'lib/imp3/config'
|
12
|
+
require 'lib/imp3/cache'
|
13
|
+
require 'lib/imp3/commands.rb'
|
10
14
|
|
11
15
|
OSA.utf8_strings = true
|
12
16
|
|
13
17
|
class IMP3::CLI
|
14
|
-
|
18
|
+
include Singleton
|
19
|
+
attr_reader :config, :cache
|
20
|
+
attr_accessor :source_origin
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
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
|
22
|
+
def initialize
|
23
|
+
@source_origin = :library
|
24
|
+
@config = IMP3::Config.instance
|
25
|
+
@cache = IMP3::Cache.instance
|
95
26
|
end
|
96
27
|
|
97
|
-
|
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
|
28
|
+
include IMP3::Commands
|
131
29
|
|
132
30
|
protected
|
133
31
|
|
134
32
|
def itunes
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
def library
|
139
|
-
@library ||= itunes.sources.find {|s| s.kind == OSA::ITunes::ESRC::LIBRARY }.playlists[0]
|
33
|
+
OSA.app('iTunes') rescue raise "Can't locate iTunes! It's installed?"
|
140
34
|
end
|
141
35
|
|
142
36
|
def tracks
|
143
|
-
|
37
|
+
case source_origin
|
38
|
+
when :library
|
39
|
+
@library ||= itunes.sources.find {|s| s.kind == OSA::ITunes::ESRC::LIBRARY }.playlists[0] rescue raise "Unable to contact iTunes, please make sure it is open."
|
40
|
+
@library.tracks
|
41
|
+
when :selection
|
42
|
+
itunes.selection
|
43
|
+
else
|
44
|
+
raise "Invalid source origin: #{source_origin}"
|
45
|
+
end
|
144
46
|
end
|
145
47
|
|
146
48
|
def artists
|
147
49
|
@artists ||= tracks.map{|t| t.artist}.uniq.sort
|
148
50
|
end
|
149
51
|
|
150
|
-
def
|
151
|
-
|
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)
|
52
|
+
def create_app_dir
|
53
|
+
Dir.mkdir(APP_DIR) unless File.directory?(APP_DIR) rescue "Unable to create application directory: #{APP_DIR}"
|
165
54
|
end
|
166
55
|
|
167
56
|
def summary(opts = {})
|
168
57
|
puts
|
169
|
-
puts "#{opts[:artist] ||
|
58
|
+
puts "#{opts[:artist] || artists.size} artists."
|
170
59
|
puts "#{opts[:tracks] || tracks.size} tracks."
|
171
60
|
puts "#{opts[:tracks_tagged] || 0} tracks tagged."
|
172
61
|
puts "#{opts[:requests] || 0} requests."
|
@@ -175,11 +64,9 @@ class IMP3::CLI
|
|
175
64
|
end
|
176
65
|
|
177
66
|
class String
|
178
|
-
STRIP_WORDS = %w(the a of in)
|
179
|
-
|
180
67
|
def strip_meaningless_words
|
181
68
|
string = self
|
182
|
-
|
69
|
+
Config.instance.strip_words.each do |w|
|
183
70
|
string = string.gsub(/\b#{w}\b/i, '')
|
184
71
|
end
|
185
72
|
string.strip
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module IMP3::Commands::Artists
|
2
|
+
|
3
|
+
#
|
4
|
+
# For every artist in iTunes,
|
5
|
+
def artists_misspelled_command
|
6
|
+
artist_choices = {}
|
7
|
+
tagged = 0
|
8
|
+
|
9
|
+
progress_bar artists, :complete_message => "Misspelled artist name scan complete." do |artist, bar|
|
10
|
+
bar.increment :title => "Scanning artist '#{artist}'"
|
11
|
+
normalized_artist_name = artist.normalized_without_words
|
12
|
+
artist_choices[normalized_artist_name] ||= []
|
13
|
+
artist_choices[normalized_artist_name] << artist.strip unless artist_choices[normalized_artist_name].include?(artist)
|
14
|
+
end
|
15
|
+
|
16
|
+
artist_names = {}
|
17
|
+
tracks.each do |track|
|
18
|
+
normalized_artist_name = track.artist.normalized_without_words
|
19
|
+
unless artist_names.has_key?(normalized_artist_name)
|
20
|
+
if artist_choices[normalized_artist_name] && artist_choices[normalized_artist_name].size > 1
|
21
|
+
puts
|
22
|
+
artist_name = choose("What is the correct artist name for #{track.artist}?", *(artist_choices[normalized_artist_name] << :"(Skip)"))
|
23
|
+
artist_names[normalized_artist_name] = artist_name
|
24
|
+
else
|
25
|
+
artist_names[normalized_artist_name] = track.artist
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless artist_names[normalized_artist_name].eql?(:"(Skip)") or track.artist.eql?(artist_names[normalized_artist_name])
|
30
|
+
tagged += 1
|
31
|
+
puts "Tagging track #{track.persistent_id} with artist name '#{artist_names[normalized_artist_name]}'"
|
32
|
+
track.artist = ""
|
33
|
+
track.artist = artist_names[normalized_artist_name]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
summary :tracks_tagged => tagged
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module IMP3::Commands::Genres
|
2
|
+
def genres_fetch_command (options)
|
3
|
+
if options.flush_cache
|
4
|
+
cache.artist_genres.clear
|
5
|
+
puts "Flushing artist genres cache."
|
6
|
+
end
|
7
|
+
|
8
|
+
tagged, requests, errors = 0, 0, 0
|
9
|
+
|
10
|
+
progress_bar tracks do |track, bar|
|
11
|
+
normalized_artist_name = track.artist.normalize
|
12
|
+
begin
|
13
|
+
unless cache.artist_genres.has_key?(normalized_artist_name)
|
14
|
+
raise "Track has no artist name set" if track.artist.empty?
|
15
|
+
requests += 1
|
16
|
+
bar.refresh(:title => "Quering last.fm for '#{track.artist}'")
|
17
|
+
response = Nokogiri(open("http://ws.audioscrobbler.com/1.0/artist/#{URI.escape(CGI.escape(track.artist))}/toptags.xml"))
|
18
|
+
cache.artist_genres[normalized_artist_name] = response.search("//toptags/tag/name").map{|t| t.text.normalize }.uniq
|
19
|
+
cache.save
|
20
|
+
end
|
21
|
+
rescue => e
|
22
|
+
errors += 1
|
23
|
+
bar.refresh(:title => "Error: #{e}")
|
24
|
+
cache.artist_genres[normalized_artist_name] = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
if (cache.artist_genres.has_key?(normalized_artist_name) and not cache.artist_genres[normalized_artist_name].nil?)
|
28
|
+
genre = (cache.artist_genres[normalized_artist_name] - config.ignore_genres).first
|
29
|
+
|
30
|
+
if track.genre.eql?(genre)
|
31
|
+
bar.refresh(:title => "Skipping track #{track.persistent_id}. Genre is already '#{genre}'")
|
32
|
+
else
|
33
|
+
bar.refresh(:title => "Tagging track #{track.persistent_id} with genre '#{genre}'")
|
34
|
+
tagged += 1
|
35
|
+
track.genre = ""
|
36
|
+
track.genre = genre
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
bar.increment
|
41
|
+
end
|
42
|
+
summary(:tracks_tagged => tagged, :requests => requests, :errors => errors)
|
43
|
+
end
|
44
|
+
|
45
|
+
def genres_fetch_cache_command(options)
|
46
|
+
genres = {}
|
47
|
+
(cache.artist_genres.map{|artist, tags| tags}.flatten - config.ignore_genres).each do |tag|
|
48
|
+
genres[tag] ||= 0
|
49
|
+
genres[tag] += 1
|
50
|
+
end
|
51
|
+
|
52
|
+
genres = genres.sort{|a, b| b[1] <=> a[1]}
|
53
|
+
|
54
|
+
if genres.any?
|
55
|
+
genre_table = table do |t|
|
56
|
+
t.headings = 'Genre', 'Artist count'
|
57
|
+
genres.to_a[0..[genres.size, options.limit].min].each do |g, c|
|
58
|
+
t << [g, c]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
puts genre_table
|
62
|
+
else
|
63
|
+
puts "No genres cached yet."
|
64
|
+
end
|
65
|
+
|
66
|
+
summary
|
67
|
+
end
|
68
|
+
|
69
|
+
def genres_list_command
|
70
|
+
genres = {}
|
71
|
+
tracks.each do |track|
|
72
|
+
genres[track.genre] ||= 0
|
73
|
+
genres[track.genre] += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
genre_table = table do |t|
|
77
|
+
t.headings = 'Genre', 'Tracks'
|
78
|
+
genres.sort{|a, b| b[1] <=> a[1]}.each do |g, c|
|
79
|
+
t << [g, c]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
puts genre_table
|
84
|
+
summary
|
85
|
+
end
|
86
|
+
|
87
|
+
def genres_ignore_add_command (genre)
|
88
|
+
raise "Please specify a genre" unless genre
|
89
|
+
genre.strip!
|
90
|
+
config.ignore_genres << genre unless config.ignore_genres.include?(genre)
|
91
|
+
config.save
|
92
|
+
puts "Genre '#{genre}' added to ignore list"
|
93
|
+
end
|
94
|
+
|
95
|
+
def genres_ignore_del_command (genre)
|
96
|
+
raise "Please specify a genre" unless genre
|
97
|
+
genre.strip!
|
98
|
+
config.ignore_genres.delete(genre) if config.ignore_genres.include?(genre)
|
99
|
+
config.save
|
100
|
+
puts "Genre '#{genre}' deleted from ignore list"
|
101
|
+
end
|
102
|
+
|
103
|
+
def genres_ignore_list_command
|
104
|
+
if config.ignore_genres.any?
|
105
|
+
genre_table = table do |t|
|
106
|
+
t.headings = 'Genre'
|
107
|
+
config.ignore_genres.each do |g|
|
108
|
+
t << [g]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
puts genre_table
|
112
|
+
else
|
113
|
+
puts "No ignored genres."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/imp3/config.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
class IMP3::Config
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
CONFIG_FILE = File.join(IMP3::APP_DIR, "config.yml")
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@data = {}
|
10
|
+
|
11
|
+
if File.exist?(CONFIG_FILE)
|
12
|
+
begin
|
13
|
+
@data = YAML.load_file(CONFIG_FILE)
|
14
|
+
rescue
|
15
|
+
raise "Unable to read config file #{CONFIG_FILE}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def ignore_genres
|
21
|
+
@data[:ignore_genres] ||= {}
|
22
|
+
@data[:ignore_genres]
|
23
|
+
end
|
24
|
+
|
25
|
+
def strip_words
|
26
|
+
@data[:strip_words] ||= %w(the a of in)
|
27
|
+
@data[:strip_words]
|
28
|
+
end
|
29
|
+
|
30
|
+
def save
|
31
|
+
File.new(CONFIG_FILE, "w+").write(@data.to_yaml)
|
32
|
+
end
|
33
|
+
end
|
data/lib/imp3.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imp3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "V\xC3\xADctor Mart\xC3\xADnez"
|
@@ -80,7 +80,12 @@ files:
|
|
80
80
|
- VERSION
|
81
81
|
- bin/imp3
|
82
82
|
- lib/imp3.rb
|
83
|
+
- lib/imp3/cache.rb
|
83
84
|
- lib/imp3/cli.rb
|
85
|
+
- lib/imp3/commands.rb
|
86
|
+
- lib/imp3/commands/artists.rb
|
87
|
+
- lib/imp3/commands/genres.rb
|
88
|
+
- lib/imp3/config.rb
|
84
89
|
- test/helper.rb
|
85
90
|
- test/test_normalization.rb
|
86
91
|
has_rdoc: true
|