imp3 0.1.1 → 0.1.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/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
|