mp3renamer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.svnignore +4 -0
- data/History.txt +4 -0
- data/Manifest.txt +0 -0
- data/README.txt +48 -0
- data/Rakefile +30 -0
- data/bin/mp3renamer.rb +174 -0
- data/lib/mp3/album.rb +114 -0
- data/lib/mp3/disc.rb +96 -0
- data/lib/mp3/renamer.rb +113 -0
- data/lib/mp3/track.rb +101 -0
- data/lib/mp3renamer.rb +49 -0
- data/lib/utils/formatter.rb +58 -0
- data/lib/utils/parser.rb +34 -0
- data/spec/mp3renamer_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +300 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/test/test_mp3renamer.rb +0 -0
- metadata +92 -0
data/.svnignore
ADDED
data/History.txt
ADDED
data/Manifest.txt
ADDED
File without changes
|
data/README.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
mp3renamer
|
2
|
+
by FIXME (your name)
|
3
|
+
FIXME (url)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
FIXME (describe your package)
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* FIXME (list of features or problems)
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
FIXME (code sample of usage)
|
16
|
+
|
17
|
+
== REQUIREMENTS:
|
18
|
+
|
19
|
+
* FIXME (list of requirements)
|
20
|
+
|
21
|
+
== INSTALL:
|
22
|
+
|
23
|
+
* FIXME (sudo gem install, anything else)
|
24
|
+
|
25
|
+
== LICENSE:
|
26
|
+
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2008 FIXME (different license?)
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
'Software'), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
45
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
46
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
47
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
48
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
Bones.setup
|
8
|
+
rescue LoadError
|
9
|
+
begin
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
rescue LoadError
|
12
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ensure_in_path 'lib'
|
17
|
+
require 'mp3renamer'
|
18
|
+
|
19
|
+
task :default => 'spec:run'
|
20
|
+
|
21
|
+
PROJ.name = 'mp3renamer'
|
22
|
+
PROJ.authors = 'FIXME (who is writing this software)'
|
23
|
+
PROJ.email = 'FIXME (your e-mail)'
|
24
|
+
PROJ.url = 'FIXME (project homepage)'
|
25
|
+
PROJ.version = Mp3renamer::VERSION
|
26
|
+
PROJ.rubyforge.name = 'mp3renamer'
|
27
|
+
|
28
|
+
PROJ.spec.opts << '--color'
|
29
|
+
|
30
|
+
# EOF
|
data/bin/mp3renamer.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
#!C:\ruby\bin\ruby.exe
|
2
|
+
|
3
|
+
require File.expand_path(
|
4
|
+
File.join(File.dirname(__FILE__), %w[.. lib mp3renamer]))
|
5
|
+
require 'rubygems'
|
6
|
+
require 'cooloptions'
|
7
|
+
require 'mp3info'
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
$:.unshift(File.join(File.dirname($0), 'lib'))
|
11
|
+
$:.unshift(File.join(File.dirname($0), '..', 'lib'))
|
12
|
+
$:.unshift("./lib/")
|
13
|
+
|
14
|
+
require 'mp3/album'
|
15
|
+
require 'mp3/disc'
|
16
|
+
require 'mp3/renamer'
|
17
|
+
require 'mp3/track'
|
18
|
+
|
19
|
+
#
|
20
|
+
# constants
|
21
|
+
#
|
22
|
+
CURRENT_DIR = 'base name of the CURRENT directory'
|
23
|
+
PARENT_DIR = 'base name of the PARENT directory'
|
24
|
+
|
25
|
+
#
|
26
|
+
# globals
|
27
|
+
#
|
28
|
+
temp_dir = File::expand_path(ENV['TEMP'] || File::SEPARATOR)
|
29
|
+
puts "Temporary directory is \"#{temp_dir}\"" if $DEBUG
|
30
|
+
|
31
|
+
source_dir = Dir::pwd
|
32
|
+
puts "Source directory is \"#{source_dir}\"" if $DEBUG
|
33
|
+
|
34
|
+
target_dir = File.join(temp_dir, 'renamed_mp3_files')
|
35
|
+
puts "Target directory is \"#{target_dir}\"" if $DEBUG
|
36
|
+
|
37
|
+
album_artist = PARENT_DIR
|
38
|
+
album_title = CURRENT_DIR
|
39
|
+
album_year = Time::new.year.to_s
|
40
|
+
puts "Current Year is \"#{album_year}\"" if $DEBUG
|
41
|
+
|
42
|
+
puts ''
|
43
|
+
|
44
|
+
options = CoolOptions.parse!('[options] SOURCE-DIRECTORY') do |cooloptions|
|
45
|
+
|
46
|
+
cooloptions.desc ' '
|
47
|
+
cooloptions.desc 'This program takes an MP3 audiobook and renames the subdirs and files using a consistent naming convention.'
|
48
|
+
cooloptions.desc 'It also updates the ID3v1 and ID3v2 tags for artist, album, track number, track title, genre, and year.'
|
49
|
+
cooloptions.desc ' '
|
50
|
+
|
51
|
+
cooloptions.desc ' '
|
52
|
+
cooloptions.desc 'NOTES'
|
53
|
+
cooloptions.desc ' '
|
54
|
+
cooloptions.desc '(1) The following source directory structure is assumed for this program:'
|
55
|
+
cooloptions.desc ' '
|
56
|
+
cooloptions.desc ' <artist>'
|
57
|
+
cooloptions.desc ' |'
|
58
|
+
cooloptions.desc ' `--- <album> <==== this is the SOURCE-DIRECTORY command line parameter.'
|
59
|
+
cooloptions.desc ' |'
|
60
|
+
cooloptions.desc ' +--- <disc 1>'
|
61
|
+
cooloptions.desc ' | |'
|
62
|
+
cooloptions.desc ' | +--- <disc 1 track 1>.mp3'
|
63
|
+
cooloptions.desc ' | +--- <disc 1 track 2>.mp3'
|
64
|
+
cooloptions.desc ' | | ...'
|
65
|
+
cooloptions.desc ' | `--- <disc 1 track N1>.mp3'
|
66
|
+
cooloptions.desc ' |'
|
67
|
+
cooloptions.desc ' +--- <disc 2>'
|
68
|
+
cooloptions.desc ' | |'
|
69
|
+
cooloptions.desc ' | +--- <disc 2 track 1>.mp3'
|
70
|
+
cooloptions.desc ' | +--- <disc 2 track 2>.mp3'
|
71
|
+
cooloptions.desc ' | | ...'
|
72
|
+
cooloptions.desc ' | `--- <disc 2 track N1>.mp3'
|
73
|
+
cooloptions.desc ' |'
|
74
|
+
cooloptions.desc ' | ...'
|
75
|
+
cooloptions.desc ' |'
|
76
|
+
cooloptions.desc ' `--- <disc M>'
|
77
|
+
cooloptions.desc ' |'
|
78
|
+
cooloptions.desc ' +--- <disc M track 1>.mp3'
|
79
|
+
cooloptions.desc ' +--- <disc M track 2>.mp3'
|
80
|
+
cooloptions.desc ' | ...'
|
81
|
+
cooloptions.desc ' `--- <disc M track NM>.mp3'
|
82
|
+
cooloptions.desc ' '
|
83
|
+
cooloptions.desc ' '
|
84
|
+
cooloptions.desc '(2) The following output directory structure will be created:'
|
85
|
+
cooloptions.desc ' '
|
86
|
+
cooloptions.desc ' <output-directory> <==== this is value of the --output command line parameter.'
|
87
|
+
cooloptions.desc ' |'
|
88
|
+
cooloptions.desc ' `--- <artist>'
|
89
|
+
cooloptions.desc ' |'
|
90
|
+
cooloptions.desc ' `--- <album>'
|
91
|
+
cooloptions.desc ' |'
|
92
|
+
cooloptions.desc ' +--- <album> [D01.MM]'
|
93
|
+
cooloptions.desc ' | |'
|
94
|
+
cooloptions.desc ' | +--- D01.MM-T01.N1.mp3'
|
95
|
+
cooloptions.desc ' | +--- D01.MM-T02.N1.mp3'
|
96
|
+
cooloptions.desc ' | | ...'
|
97
|
+
cooloptions.desc ' | `--- D01.MM-TN1.N1.mp3'
|
98
|
+
cooloptions.desc ' |'
|
99
|
+
cooloptions.desc ' +--- <album> [D02.MM]'
|
100
|
+
cooloptions.desc ' | |'
|
101
|
+
cooloptions.desc ' | +--- D02.MM-T01.N2.mp3'
|
102
|
+
cooloptions.desc ' | +--- D02.MM-T02.N2.mp3'
|
103
|
+
cooloptions.desc ' | | ...'
|
104
|
+
cooloptions.desc ' | `--- D02.MM-TN2.N2.mp3'
|
105
|
+
cooloptions.desc ' |'
|
106
|
+
cooloptions.desc ' | ...'
|
107
|
+
cooloptions.desc ' |'
|
108
|
+
cooloptions.desc ' `--- <album> [DMM.MM]'
|
109
|
+
cooloptions.desc ' |'
|
110
|
+
cooloptions.desc ' +--- DMM.MM-T01.NN.mp3'
|
111
|
+
cooloptions.desc ' +--- DMM.MM-T02.NN.mp3'
|
112
|
+
cooloptions.desc ' | ...'
|
113
|
+
cooloptions.desc ' `--- DMM.MM-TNN.NN.mp3'
|
114
|
+
cooloptions.desc ' '
|
115
|
+
cooloptions.desc ' '
|
116
|
+
|
117
|
+
cooloptions.desc ' '
|
118
|
+
cooloptions.desc 'OPTIONS'
|
119
|
+
cooloptions.desc ' '
|
120
|
+
|
121
|
+
cooloptions.on 'output DIRECTORY' , 'Directory into which the renamed files will be written.', target_dir
|
122
|
+
cooloptions.desc ' '
|
123
|
+
|
124
|
+
cooloptions.on 'artist ARTIST-NAME', 'Name of the album\'s artist.', album_artist
|
125
|
+
cooloptions.desc ' '
|
126
|
+
cooloptions.on 'title ALBUM-TITLE' , 'Title of the album.', album_title
|
127
|
+
cooloptions.desc ' '
|
128
|
+
cooloptions.on 'year RELEASE-YEAR' , 'Year of the album\'s release.', album_year
|
129
|
+
cooloptions.desc ' '
|
130
|
+
|
131
|
+
cooloptions.on 'copy-files' , 'Copy files from source directory into output directory.', true
|
132
|
+
cooloptions.desc ' '
|
133
|
+
cooloptions.on 'update-id3v(1)-tags', 'Update ID3v1 tags for artist, album, track number, track title, genre, and year.', true
|
134
|
+
cooloptions.desc ' '
|
135
|
+
cooloptions.on 'update-id3v(2)-tags', 'Update ID3v2 tags for artist, album, track number, track title, genre, and year.', true
|
136
|
+
|
137
|
+
cooloptions.after do |result|
|
138
|
+
if result.year !~ /^(\d\d\d\d)$/
|
139
|
+
cooloptions.error("\nERROR: Invalid year: \"#{result.year}\"\n\n")
|
140
|
+
else
|
141
|
+
album_year = result.year
|
142
|
+
end
|
143
|
+
|
144
|
+
target_dir = result.output
|
145
|
+
album_artist = (result.artist != PARENT_DIR) ? result.artist : nil
|
146
|
+
album_title = (result.title != CURRENT_DIR) ? result.title : nil
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
if $DEBUG
|
152
|
+
puts "Source directory is \"#{source_dir}\""
|
153
|
+
puts "Target directory is \"#{target_dir}\""
|
154
|
+
puts "Album artist is \"#{album_artist}\""
|
155
|
+
puts "Album title is \"#{album_title}\""
|
156
|
+
puts "Album year is \"#{album_year}\""
|
157
|
+
end
|
158
|
+
|
159
|
+
if ARGV.size == 0
|
160
|
+
ARGV << '.'
|
161
|
+
end
|
162
|
+
|
163
|
+
ARGV.each do |src_dir|
|
164
|
+
renamer = Mp3::Renamer.new
|
165
|
+
renamer.album_artist = album_artist if defined? album_artist
|
166
|
+
renamer.album_title = album_title if defined? album_title
|
167
|
+
renamer.album_year = album_year
|
168
|
+
|
169
|
+
renamer.read_album(src_dir)
|
170
|
+
renamer.rename_tracks
|
171
|
+
renamer.write_album(target_dir)
|
172
|
+
renamer.update_id3_tags(target_dir)
|
173
|
+
end
|
174
|
+
puts ''
|
data/lib/mp3/album.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'mp3/disc'
|
2
|
+
require 'utils/parser'
|
3
|
+
|
4
|
+
class Mp3
|
5
|
+
|
6
|
+
#
|
7
|
+
# This class presents an album, consisting of one of more physical media
|
8
|
+
# (LPs, CDs, tapes), each of which is referred to as a disc.
|
9
|
+
#
|
10
|
+
# An instance of this class holds:
|
11
|
+
# * the name of the album's artist;
|
12
|
+
# * the title of the album;
|
13
|
+
# * year of release;
|
14
|
+
# * and an array of Disc instances, each of which describes
|
15
|
+
# just one of the aforementioned physical media making up the album.
|
16
|
+
#
|
17
|
+
class Album
|
18
|
+
|
19
|
+
attr_accessor :album_artist
|
20
|
+
attr_accessor :album_title
|
21
|
+
attr_accessor :album_year
|
22
|
+
attr_reader :discs
|
23
|
+
|
24
|
+
#
|
25
|
+
# The constructor takes a hash of symbols and their corresponding values. Valid symbols are:
|
26
|
+
# * <b>:artist</b> => the name(s) of the artist(s) responsible for the album;
|
27
|
+
# * <b>:title</b> => the title of the album;
|
28
|
+
# * <b>:year</b> => the year of release.
|
29
|
+
#
|
30
|
+
# If the <b>:artist</b> and/or <b>:title</b> symbols are not specified, they are derived from the grandparent and parent
|
31
|
+
# directories, respectively.
|
32
|
+
#
|
33
|
+
def initialize(*args)
|
34
|
+
@discs = []
|
35
|
+
parse_args(nil, args)
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# This method is used to add a Disc instance to the [current] album instance.
|
40
|
+
# Assumptions
|
41
|
+
# * The order in which discs are appended _is_ the disc play order.
|
42
|
+
#
|
43
|
+
def add(item)
|
44
|
+
if item.class.name == Disc.name
|
45
|
+
@discs << item
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# This method is used to rename the album and all of its contained discs to a consistent format.
|
52
|
+
#
|
53
|
+
# Right now:
|
54
|
+
# * the <i>album level</i> album title is left unchanged;
|
55
|
+
# * the <i>disc level</i> album titles are set to "D<i>disc-number</i>.<i>number-of-discs</i>" for all of the
|
56
|
+
# discs in the album;
|
57
|
+
# * the <i>track level</i> album titles are also set to "D<i>disc-number</i>.<i>number-of-discs</i>" for all of the
|
58
|
+
# discs in the album;
|
59
|
+
# * the tracks are renamed recursively (see the Track class for details).
|
60
|
+
#
|
61
|
+
def rename
|
62
|
+
$track_number = 0
|
63
|
+
@discs.each do |disc|
|
64
|
+
printf("Renaming disc %02d : ", disc.disc_number); $stdout.flush
|
65
|
+
|
66
|
+
disc.album_artist = @album_artist
|
67
|
+
disc.album_title = @album_title
|
68
|
+
disc.album_year = @album_year
|
69
|
+
disc.rename(discs.size)
|
70
|
+
|
71
|
+
print "\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def write(dst_dir)
|
76
|
+
here = Dir.pwd
|
77
|
+
Dir.chdir dst_dir
|
78
|
+
@discs.each do |disc|
|
79
|
+
printf("Copying disc %02d : ", disc.disc_number); $stdout.flush
|
80
|
+
disc.write
|
81
|
+
puts ""
|
82
|
+
end
|
83
|
+
Dir.chdir here
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_id3_tags(dst_dir)
|
87
|
+
here = Dir.pwd
|
88
|
+
Dir.chdir dst_dir
|
89
|
+
@discs.each do |disc|
|
90
|
+
print "Updating ID3 tags for disc #{disc.disc_number}"; $stdout.flush
|
91
|
+
disc.update_id3_tags
|
92
|
+
puts ""
|
93
|
+
end
|
94
|
+
Dir.chdir here
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
include Utils::Parser
|
100
|
+
|
101
|
+
def parse_string(name, value)
|
102
|
+
puts "album: parse_string(\"#{name}\", \"#{value}\")" if $DEBUG
|
103
|
+
|
104
|
+
if name.to_s == 'artist'; @album_artist = value
|
105
|
+
elsif name.to_s == 'title' ; @album_title = value
|
106
|
+
elsif name.to_s == 'year' ; @album_year = value
|
107
|
+
else
|
108
|
+
puts "Unknown keyword: \"#{name}\""
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end # Album
|
113
|
+
|
114
|
+
end # Mp3
|
data/lib/mp3/disc.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'mp3/track'
|
2
|
+
require 'utils/parser'
|
3
|
+
require 'utils/formatter'
|
4
|
+
|
5
|
+
class Mp3
|
6
|
+
|
7
|
+
class Disc
|
8
|
+
|
9
|
+
attr_accessor :disc_number
|
10
|
+
attr_accessor :disc_title
|
11
|
+
attr_accessor :album_artist
|
12
|
+
attr_accessor :album_title
|
13
|
+
attr_accessor :album_year
|
14
|
+
attr_reader :tracks
|
15
|
+
attr_accessor :separator
|
16
|
+
attr_accessor :prefix
|
17
|
+
attr_accessor :suffix
|
18
|
+
|
19
|
+
def initialize(*args)
|
20
|
+
@disc_title = ''
|
21
|
+
@tracks = []
|
22
|
+
@separator = '.'
|
23
|
+
@prefix = 'D'
|
24
|
+
@suffix = ''
|
25
|
+
parse_args(nil, args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def add(item)
|
29
|
+
if item.class.name == Track.name
|
30
|
+
@tracks << item
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def rename(number_of_discs)
|
36
|
+
|
37
|
+
@disc_title = format(@prefix, @separator, @suffix, @disc_number, number_of_discs)
|
38
|
+
|
39
|
+
tracks.each do |track|
|
40
|
+
track.album_artist = @album_artist
|
41
|
+
track.album_title = @album_title
|
42
|
+
track.album_year = @album_year
|
43
|
+
track.rename(@disc_title, tracks.size)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_id3_tags
|
49
|
+
disc_subdir = "#{@album_title} [#{@disc_title}]"
|
50
|
+
|
51
|
+
here = Dir.pwd
|
52
|
+
Dir.chdir disc_subdir
|
53
|
+
|
54
|
+
@tracks.each do |track|
|
55
|
+
track.update_id3_tags
|
56
|
+
end
|
57
|
+
|
58
|
+
Dir.chdir here
|
59
|
+
end
|
60
|
+
|
61
|
+
def write
|
62
|
+
disc_subdir = "#{@album_title} [#{@disc_title}]"
|
63
|
+
if $DEBUG
|
64
|
+
print "\n\talbum title = #{@album_title}"
|
65
|
+
print "\n\tdisc title = #{@disc_title}"
|
66
|
+
print "\n\tdisc subdir = #{disc_subdir}"
|
67
|
+
end
|
68
|
+
File.makedirs(disc_subdir)
|
69
|
+
|
70
|
+
here = Dir.pwd
|
71
|
+
Dir.chdir disc_subdir
|
72
|
+
|
73
|
+
@tracks.each do |track|
|
74
|
+
track.write
|
75
|
+
end
|
76
|
+
|
77
|
+
Dir.chdir here
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
include Utils::Formatter
|
83
|
+
include Utils::Parser
|
84
|
+
|
85
|
+
def parse_string(name, value)
|
86
|
+
puts "album: parse_string(\"#{name}\", \"#{value}\")" if $DEBUG
|
87
|
+
|
88
|
+
if name.to_s == 'number'; @disc_number = value
|
89
|
+
else
|
90
|
+
puts "Unknown keyword: \"#{name}\""
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end # Disc
|
95
|
+
|
96
|
+
end # Mp3
|
data/lib/mp3/renamer.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'find'
|
3
|
+
require 'ftools'
|
4
|
+
|
5
|
+
require 'mp3/disc'
|
6
|
+
require 'utils/parser'
|
7
|
+
|
8
|
+
class Mp3
|
9
|
+
|
10
|
+
class Renamer
|
11
|
+
|
12
|
+
attr_accessor :album_artist
|
13
|
+
attr_accessor :album_title
|
14
|
+
attr_accessor :album_year
|
15
|
+
attr_accessor :album
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
@album_artist = nil
|
19
|
+
@album_title = nil
|
20
|
+
@album_year = nil
|
21
|
+
end # initialize
|
22
|
+
|
23
|
+
def read_album(src_dir)
|
24
|
+
here = Dir.pwd
|
25
|
+
|
26
|
+
Dir.chdir src_dir
|
27
|
+
|
28
|
+
puts "you are here: \"#{Dir.pwd}\"" if $DEBUG
|
29
|
+
|
30
|
+
@album_artist ||= File.basename(File.expand_path('..'))
|
31
|
+
@album_title ||= File.basename(File.expand_path('.'))
|
32
|
+
@album_year ||= '2008'
|
33
|
+
|
34
|
+
@album = Mp3::Album.new(:artist => @album_artist, :title => @album_title, :year => @album_year)
|
35
|
+
|
36
|
+
disc_number = 0
|
37
|
+
Dir['*'].sort.each do |e|
|
38
|
+
next if not File.directory?(e)
|
39
|
+
puts "\t#{e}" if $DEBUG
|
40
|
+
disc_number += 1
|
41
|
+
disc = Mp3::Disc::new(:number => disc_number)
|
42
|
+
here2 = Dir.pwd
|
43
|
+
Dir.chdir e
|
44
|
+
track_number = 0
|
45
|
+
Dir['*'].sort.each do |t|
|
46
|
+
if t =~ /\.((mp3)|(mp4)|(aac))$/
|
47
|
+
track_number += 1
|
48
|
+
track = Mp3::Track::new(:number => track_number, :file => t, :path => File.expand_path(t))
|
49
|
+
end
|
50
|
+
#puts "\t\t#{t}"
|
51
|
+
disc.add(track)
|
52
|
+
end
|
53
|
+
Dir.chdir here2
|
54
|
+
@album.add(disc)
|
55
|
+
end
|
56
|
+
Dir.chdir here
|
57
|
+
|
58
|
+
puts "Album artist : #{@album.album_artist}"
|
59
|
+
puts "Album title : #{@album.album_title}"
|
60
|
+
puts "Album year : #{@album.album_year}"
|
61
|
+
puts "Number of disc(s) : #{@album.discs.size}"
|
62
|
+
|
63
|
+
#pp(album) if $DEBUG
|
64
|
+
end # read
|
65
|
+
|
66
|
+
def rename_tracks
|
67
|
+
@album.rename
|
68
|
+
end # read
|
69
|
+
|
70
|
+
def update_id3_tags(dst_dir)
|
71
|
+
dst_dir = File.join(dst_dir, @album.album_artist, @album.album_title)
|
72
|
+
@album.update_id3_tags(dst_dir)
|
73
|
+
end
|
74
|
+
|
75
|
+
def write_album(dst_dir)
|
76
|
+
#
|
77
|
+
# (1) create the output directory (if necessary)
|
78
|
+
# (2) create the individual disc subdirs
|
79
|
+
# (3) copy the track files per disc subdir
|
80
|
+
#
|
81
|
+
dst_dir = File.join(dst_dir, @album.album_artist, @album.album_title)
|
82
|
+
if File.exists?(dst_dir)
|
83
|
+
FileUtils.remove_dir(dst_dir, true)
|
84
|
+
puts "Deleted output dir: #{dst_dir}"
|
85
|
+
end
|
86
|
+
puts "Created output dir: #{dst_dir}"
|
87
|
+
File.makedirs(dst_dir)
|
88
|
+
|
89
|
+
here = Dir.pwd
|
90
|
+
Dir.chdir dst_dir
|
91
|
+
@album.write(dst_dir)
|
92
|
+
Dir.chdir here
|
93
|
+
end # read
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
include Utils::Parser
|
98
|
+
|
99
|
+
def parse_string(name, value)
|
100
|
+
puts "Rename: parse_string(\"#{name}\", \"#{value}\")" if $DEBUG
|
101
|
+
|
102
|
+
puts "Unknown keyword: \"#{name}\""
|
103
|
+
end # parse_string
|
104
|
+
|
105
|
+
def purge_dir_subtree(root)
|
106
|
+
Find.find(root) do |item|
|
107
|
+
puts "found: #{item}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end # Renamer
|
112
|
+
|
113
|
+
end # Mp3
|
data/lib/mp3/track.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'mp3info'
|
2
|
+
|
3
|
+
require 'utils/parser'
|
4
|
+
require 'utils/formatter'
|
5
|
+
|
6
|
+
class Mp3
|
7
|
+
|
8
|
+
class Track
|
9
|
+
|
10
|
+
attr_accessor :track_number
|
11
|
+
attr_accessor :track_title
|
12
|
+
attr_accessor :album_artist
|
13
|
+
attr_accessor :album_title
|
14
|
+
attr_accessor :album_year
|
15
|
+
attr_accessor :file
|
16
|
+
attr_accessor :path
|
17
|
+
attr_accessor :separator
|
18
|
+
attr_accessor :prefix
|
19
|
+
attr_accessor :suffix
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
@track_title = ''
|
23
|
+
@separator = '.'
|
24
|
+
@prefix = 'T'
|
25
|
+
@suffix = ''
|
26
|
+
parse_args(nil, args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rename(disc_title, number_of_tracks)
|
30
|
+
print '.'; $stdout.flush
|
31
|
+
|
32
|
+
@track_title = disc_title + '-' + format(@prefix, @separator, @suffix, @track_number, number_of_tracks)
|
33
|
+
|
34
|
+
#print @track_title + "/"; $stdout.flush
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_id3_tags
|
39
|
+
print '.'; $stdout.flush
|
40
|
+
track_filename = "#{@track_title}.mp3"
|
41
|
+
$track_number += 1
|
42
|
+
if $DEBUG
|
43
|
+
print "\n\ttrack source file = #{@path}"
|
44
|
+
print "\n\ttrack filename = #{track_filename}"
|
45
|
+
print "\n\t@track number = #{@track_number}"
|
46
|
+
print "\n\t$track number = #{$track_number}"
|
47
|
+
end
|
48
|
+
Mp3Info.open(track_filename) do |mp3|
|
49
|
+
#
|
50
|
+
# ID3v1 tags
|
51
|
+
#
|
52
|
+
mp3.tag.tracknum = $track_number # @track_number.to_i
|
53
|
+
mp3.tag.title = @track_title
|
54
|
+
mp3.tag.artist = @album_artist
|
55
|
+
mp3.tag.album = @album_title
|
56
|
+
mp3.tag.year = @album_year
|
57
|
+
mp3.tag.genre_s = 'speech'
|
58
|
+
mp3.tag.comments = "Renamed on #{Time.now}"
|
59
|
+
|
60
|
+
#
|
61
|
+
# ID3v2 tags
|
62
|
+
#
|
63
|
+
mp3.tag2.TRK = $track_number # @track_number.to_i
|
64
|
+
mp3.tag2.TT2 = @track_title
|
65
|
+
mp3.tag2.TP2 = @album_artist
|
66
|
+
mp3.tag2.TAL = @album_title
|
67
|
+
mp3.tag2.TYE = @album_year
|
68
|
+
mp3.tag2.TCO = mp3.tag.genre_s
|
69
|
+
mp3.tag2.COM = mp3.tag.comments
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def write
|
74
|
+
print '.'; $stdout.flush
|
75
|
+
track_filename = "#{@track_title}.mp3"
|
76
|
+
if $DEBUG
|
77
|
+
print "\n\ttrack source file = #{@path}"
|
78
|
+
print "\n\ttrack filename = #{track_filename}"
|
79
|
+
end
|
80
|
+
File.copy(@path, track_filename, false)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
include Utils::Formatter
|
86
|
+
include Utils::Parser
|
87
|
+
|
88
|
+
def parse_string(track_title, value)
|
89
|
+
puts "album: parse_string(\"#{track_title}\", \"#{value}\")" if $DEBUG
|
90
|
+
|
91
|
+
if track_title.to_s == 'number'; @track_number = value
|
92
|
+
elsif track_title.to_s == 'file' ; @file = value
|
93
|
+
elsif track_title.to_s == 'path' ; @path = value
|
94
|
+
else
|
95
|
+
puts "Unknown keyword: \"#{track_title}\""
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end # Track
|
100
|
+
|
101
|
+
end # Mp3
|