mediafile 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/music_cp +62 -50
- data/lib/mediafile/bulkmediacopy.rb +25 -10
- data/lib/mediafile/mediafile.rb +83 -72
- data/lib/mediafile/version.rb +1 -1
- data/lib/mediafile.rb +24 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 334aef8d37ba538e00245a02dc3aefafd60b4b3c
|
4
|
+
data.tar.gz: 4f8de891ef857224aced4f20d4ff9b7cb329ae7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53186aae0f9fd1b468a9f2b1fdf8dbae02017e4a59fe7897acc3bd438074b4c6bf76fae29ae872936a9fb7d5465e4d1307b6b73e21942b1c80917019e1ed0da3
|
7
|
+
data.tar.gz: 169efd96844d7d386f72834407ea8f5e4daee2708fdb939d1d2d873133981fe9eacb9c638211eded3828d5176ac7624349dc7ab30cbd980bb24632391979203a
|
data/bin/music_cp
CHANGED
@@ -4,91 +4,106 @@
|
|
4
4
|
|
5
5
|
require 'optparse'
|
6
6
|
require 'mediafile'
|
7
|
-
|
8
|
-
PROGNAME = File.basename($0)
|
7
|
+
require 'English'
|
9
8
|
|
10
9
|
def die(msg)
|
11
|
-
abort "#{
|
10
|
+
abort "#{$PROGRAM_NAME}: #{msg}"
|
12
11
|
end
|
13
12
|
|
14
|
-
kill =
|
13
|
+
kill = false
|
14
|
+
me = false
|
15
15
|
files = []
|
16
16
|
opt_files = {
|
17
17
|
flat: [],
|
18
18
|
recurse: []
|
19
19
|
}
|
20
|
-
dest =
|
20
|
+
dest = '.'
|
21
21
|
verbose = false
|
22
22
|
debug = false
|
23
23
|
progress = true
|
24
|
-
count = `grep -c '^processor' /proc/cpuinfo`.strip.to_i/2|1
|
24
|
+
count = `grep -c '^processor' /proc/cpuinfo`.strip.to_i / 2 | 1
|
25
25
|
transcode = { flac: :mp3, wav: :mp3 }
|
26
26
|
exclude_patterns = []
|
27
27
|
album_artist = nil
|
28
|
-
file_types =
|
28
|
+
file_types = '{flac,mp3,MP3,FLAC,wav,WAV,m4a,M4A}'
|
29
29
|
yes = nil
|
30
30
|
|
31
31
|
opts = OptionParser.new do |opt|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
opt.on('-f', '--file FILE|DIR', 'File or directory to copy.',
|
33
|
+
'If given a directory, will grab all files' \
|
34
|
+
'within non-recursively') do |e|
|
35
35
|
opt_files[:flat].concat e.split(',')
|
36
36
|
end
|
37
|
-
opt.on(
|
37
|
+
opt.on('-r', '--recursive DIR',
|
38
|
+
'Directory to recursively scan and copy') do |r|
|
38
39
|
opt_files[:recurse].concat r.split(',')
|
39
40
|
end
|
40
|
-
opt.on(
|
41
|
-
"
|
41
|
+
opt.on('-d', '--destination PATH', 'Where to copy file to. '\
|
42
|
+
"Default: '#{dest}'",
|
43
|
+
'Will be created if it doesn\'t exist.') do |d|
|
42
44
|
dest = d
|
43
45
|
end
|
44
|
-
opt.on(
|
45
|
-
|
46
|
+
opt.on('--transcode <from=to[,from1=to1]>',
|
47
|
+
'A comma-seperated series of name=value pairs.',
|
48
|
+
'Default is ' \
|
49
|
+
"#{transcode.to_a.map { |i| i.join('=') }.join(',')}}") do |fmt|
|
46
50
|
kill = true
|
47
|
-
transcode = Hash[
|
51
|
+
transcode = Hash[*fmt.split(',').map do |e|
|
52
|
+
e.split('=').map do |t|
|
53
|
+
t.downcase.to_sym
|
54
|
+
end
|
55
|
+
end.flatten]
|
48
56
|
end
|
49
|
-
opt.on(
|
57
|
+
opt.on('-c', '--copy', 'Turn off transcoding.') do
|
50
58
|
transcode = {}
|
51
59
|
me = true
|
52
60
|
end
|
53
|
-
opt.on(
|
61
|
+
opt.on('--[no-]progress',
|
62
|
+
"Set show progress true/false. Default is #{progress}") do |t|
|
54
63
|
progress = t
|
55
64
|
end
|
56
|
-
opt.on(
|
57
|
-
|
65
|
+
opt.on('--exclude PATTERN', '-x PATTERN', String,
|
66
|
+
'Exclude files that match the given pattern.',
|
67
|
+
'Can specify more than once, file is excluded' \
|
68
|
+
'if any pattern matches') do |p|
|
58
69
|
exclude_patterns.concat p.split(',')
|
59
70
|
end
|
60
|
-
opt.on(
|
71
|
+
opt.on('-v', '--[no-]verbose', 'Be verbose') do |v|
|
61
72
|
verbose = v
|
62
73
|
end
|
63
|
-
opt.on(
|
74
|
+
opt.on('--debug', 'Show debug output. Also enables verbose.') do
|
64
75
|
debug = true
|
65
76
|
verbose = true
|
66
77
|
end
|
67
|
-
opt.on(
|
68
|
-
|
78
|
+
opt.on('-t', '--threads NUM',
|
79
|
+
'Number of threads to spawn, useful for transcoding.',
|
80
|
+
"Default: #{count}") do |n|
|
69
81
|
count = n.to_i
|
70
82
|
end
|
71
|
-
opt.on(
|
83
|
+
opt.on('--set-aa ALBUM_ARTIST', String,
|
84
|
+
'Set the album_artist for all tracks') do |a|
|
72
85
|
album_artist = a
|
73
86
|
end
|
74
|
-
opt.on(
|
87
|
+
opt.on('-V', '--version', 'Disply the version and exit') do
|
75
88
|
puts MediaFile::VERSION
|
76
89
|
exit 0
|
77
90
|
end
|
78
|
-
opt.on(
|
79
|
-
yes =
|
91
|
+
opt.on('-y', '--yes', 'Don\'t ask before running.') do
|
92
|
+
yes = 'yes'
|
80
93
|
end
|
81
|
-
opt.on_tail(
|
94
|
+
opt.on_tail('-h', '--help', 'Show this message') do
|
82
95
|
warn opt
|
83
96
|
exit
|
84
97
|
end
|
85
98
|
begin
|
86
99
|
opt.parse!
|
87
|
-
if kill
|
88
|
-
raise OptionParser::InvalidOption.new(
|
100
|
+
if kill && me
|
101
|
+
raise OptionParser::InvalidOption.new(
|
102
|
+
'--copy and --transcode are conflicting'
|
103
|
+
), 'Argument Eror'
|
89
104
|
end
|
90
105
|
rescue OptionParser::InvalidOption
|
91
|
-
warn "#{PROGNAME}: #{
|
106
|
+
warn "#{PROGNAME}: #{$ERROR_INFO}"
|
92
107
|
die opt
|
93
108
|
end
|
94
109
|
end
|
@@ -98,7 +113,7 @@ opt_files[:flat].each do |f|
|
|
98
113
|
if File.file? f
|
99
114
|
files << f
|
100
115
|
elsif File.directory? f
|
101
|
-
files.concat Dir.glob(
|
116
|
+
files.concat Dir.glob(f + "/*.#{file_types}")
|
102
117
|
else
|
103
118
|
warn "#{f} is not a file or a directory!"
|
104
119
|
end
|
@@ -106,8 +121,8 @@ end
|
|
106
121
|
|
107
122
|
# resolve recurse dirs
|
108
123
|
opt_files[:recurse].each do |r|
|
109
|
-
if File.directory? r
|
110
|
-
files.concat Dir.glob(
|
124
|
+
if File.directory? r
|
125
|
+
files.concat Dir.glob(r + "/**/*.#{file_types}")
|
111
126
|
else
|
112
127
|
warn "#{r} is not a file or a directory!"
|
113
128
|
end
|
@@ -115,36 +130,33 @@ end
|
|
115
130
|
|
116
131
|
files = files.uniq.sort
|
117
132
|
if exclude_patterns.any?
|
118
|
-
is_a_regexp =
|
133
|
+
is_a_regexp = %r{\/?(.+?)(?:\/([imxouesn]*))?$}
|
119
134
|
pattern = Regexp.union(
|
120
|
-
exclude_patterns.map
|
135
|
+
exclude_patterns.map do |pat|
|
121
136
|
m = pat.match(is_a_regexp)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
raise "Bag pattern: '#{pat}'"
|
126
|
-
end
|
127
|
-
}.compact
|
137
|
+
raise "Bag pattern: '#{pat}'" unless m
|
138
|
+
Regexp.new(*m.captures)
|
139
|
+
end.compact
|
128
140
|
)
|
129
141
|
puts "Using exclude pattern: #{pattern}" if verbose
|
130
142
|
files.delete_if { |el| pattern.match el }
|
131
143
|
end
|
132
144
|
|
133
145
|
if files.empty?
|
134
|
-
warn
|
146
|
+
warn 'No file specified, exiting.'
|
135
147
|
warn "Perhaps you excluded too many? '#{pattern}'" if exclude_patterns.any?
|
136
148
|
warn opts
|
137
149
|
exit
|
138
150
|
end
|
139
151
|
puts "Full list of files to transfer to #{dest}:"
|
140
|
-
files.each { |l| puts "\t"+l }
|
152
|
+
files.each { |l| puts "\t" + l }
|
141
153
|
puts "#{files.count} files total"
|
142
|
-
puts
|
154
|
+
puts 'The following transcode table will be used:'
|
143
155
|
puts transcode.any? ? transcode : 'none'
|
144
|
-
puts
|
156
|
+
puts 'Do you wish to proceed? (Y/n)'
|
145
157
|
y = yes || gets
|
146
|
-
if /n/i
|
147
|
-
puts
|
158
|
+
if y =~ /n/i
|
159
|
+
puts 'User cancel.'
|
148
160
|
exit
|
149
161
|
end
|
150
162
|
puts "Begin copy to #{dest}"
|
@@ -160,4 +172,4 @@ copier = MediaFile::BulkMediaCopy.new(
|
|
160
172
|
|
161
173
|
copier.run count
|
162
174
|
|
163
|
-
puts
|
175
|
+
puts 'Complete.'
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# vim:et sw=2 ts=2
|
2
2
|
|
3
3
|
require 'mediafile'
|
4
|
-
module MediaFile;
|
4
|
+
module MediaFile;
|
5
|
+
class BulkMediaCopy
|
5
6
|
include ::MediaFile
|
6
7
|
def initialize(source,
|
7
8
|
album_artist: nil,
|
@@ -9,19 +10,23 @@ module MediaFile; class BulkMediaCopy
|
|
9
10
|
progress: false,
|
10
11
|
transcode: {},
|
11
12
|
verbose: false,
|
12
|
-
debug: false
|
13
|
-
|
13
|
+
debug: false
|
14
|
+
)
|
15
|
+
source =
|
16
|
+
case source
|
14
17
|
when String
|
15
18
|
[source]
|
16
19
|
when Array
|
17
20
|
source
|
18
21
|
else
|
19
|
-
raise "Bad value for required first arg 'source': '#{source.class}'.
|
22
|
+
raise "Bad value for required first arg 'source': '#{source.class}'. " \
|
23
|
+
'Should be String or Array.'
|
20
24
|
end
|
21
25
|
|
22
26
|
@copies = Hash.new { |h,k| h[k] = [] }
|
23
27
|
@destination_root = destination_root
|
24
28
|
@verbose = verbose
|
29
|
+
@debug = debug
|
25
30
|
@progress = progress
|
26
31
|
@album_artist = album_artist
|
27
32
|
@work = get_work(source)
|
@@ -33,6 +38,8 @@ module MediaFile; class BulkMediaCopy
|
|
33
38
|
end
|
34
39
|
|
35
40
|
def run(max=4)
|
41
|
+
start = Time.new
|
42
|
+
debug "Call run with max => '#{max}'"
|
36
43
|
puts "%#{@width + 8}s, %#{@width + 8}s,%#{@width + 8}s, %-#{@name_width}s => Destination Path" % [
|
37
44
|
"Remaining",
|
38
45
|
"Workers",
|
@@ -46,7 +53,11 @@ module MediaFile; class BulkMediaCopy
|
|
46
53
|
0
|
47
54
|
]
|
48
55
|
max > 1 ? mcopy(max) : scopy
|
49
|
-
|
56
|
+
stop = Time.new
|
57
|
+
duration = stop - start
|
58
|
+
puts "Copied #{@count} files in #{ "%d:%d:%d:%d" % duration.to_duration} " +
|
59
|
+
"(~#{(@count/duration).to_i} songs/second))."
|
60
|
+
dupes = @copies.select{ |_k,a| a.size > 1 }
|
50
61
|
if dupes.any?
|
51
62
|
puts "dupes"
|
52
63
|
require 'pp'
|
@@ -106,7 +117,7 @@ module MediaFile; class BulkMediaCopy
|
|
106
117
|
err = false
|
107
118
|
begin
|
108
119
|
mediafile.copy transcode_table: @transcode
|
109
|
-
rescue
|
120
|
+
rescue
|
110
121
|
@failed << mediafile
|
111
122
|
err = true
|
112
123
|
end
|
@@ -121,18 +132,21 @@ module MediaFile; class BulkMediaCopy
|
|
121
132
|
c = cur_perc == 100
|
122
133
|
finished = @count.to_f / @work.count * 100
|
123
134
|
f = finished == 100.0
|
124
|
-
|
125
|
-
"%#{@width}d (%4.#{f ? 0 : 1}f%%)
|
135
|
+
print "%#{@width}d (%4.1f%%), %#{@width}d (%4.#{c ? 0 : 1}f%%), " \
|
136
|
+
"%#{@width}d (%4.#{f ? 0 : 1}f%%) :: %-s\n source file => %-s\n " \
|
137
|
+
"destination => %-s\n" % [
|
126
138
|
left,
|
127
139
|
left_perc,
|
128
140
|
cur,
|
129
141
|
cur_perc,
|
130
142
|
@count,
|
131
143
|
finished,
|
132
|
-
(mediafile.
|
144
|
+
(@transcode[mediafile.type].nil? ? '*copy*' : '*transcode*'),
|
145
|
+
(mediafile.source + (err ? " **" : "") ),
|
133
146
|
mediafile.out_path(transcode_table:@transcode)
|
134
147
|
]
|
135
148
|
end
|
149
|
+
debug "#{mediafile.type} == #{@transcode[mediafile.type]}"
|
136
150
|
}
|
137
151
|
|
138
152
|
end
|
@@ -144,5 +158,6 @@ module MediaFile; class BulkMediaCopy
|
|
144
158
|
@copies[md5].count == 1
|
145
159
|
end
|
146
160
|
|
147
|
-
end
|
161
|
+
end
|
162
|
+
end
|
148
163
|
|
data/lib/mediafile/mediafile.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# vim:et sw=2 ts=2
|
2
2
|
|
3
3
|
require 'mediafile'
|
4
|
-
|
4
|
+
|
5
|
+
module MediaFile
|
6
|
+
class MediaFile
|
5
7
|
include ::MediaFile
|
6
8
|
|
7
9
|
attr_reader :source, :type, :name, :base_dir
|
@@ -37,13 +39,14 @@ module MediaFile; class MediaFile
|
|
37
39
|
destination = out_path base_dir: dest, transcode_table: transcode_table
|
38
40
|
temp_dest = tmp_path base_dir: dest, transcode_table: transcode_table
|
39
41
|
lock{
|
40
|
-
if File.
|
41
|
-
warn "File has already been transfered #{@source} => #{destination}" if @verbose
|
42
|
-
return
|
43
|
-
end
|
44
|
-
if File.exists?(temp_dest)
|
42
|
+
if File.exist?(temp_dest)
|
45
43
|
warn "File transfer is already in progress for #{@source} => #{temp_dest} => #{destination}"
|
46
44
|
warn "This shouldn't happen! Check to make sure it was really copied."
|
45
|
+
raise
|
46
|
+
#return
|
47
|
+
end
|
48
|
+
if File.exist?(destination)
|
49
|
+
warn "File has already been transfered #{@source} => #{destination}" if @verbose
|
47
50
|
return
|
48
51
|
end
|
49
52
|
FileUtils.mkdir_p File.dirname destination
|
@@ -55,11 +58,11 @@ module MediaFile; class MediaFile
|
|
55
58
|
really_copy(@source, temp_dest)
|
56
59
|
FileUtils.mv temp_dest, destination
|
57
60
|
rescue => e
|
58
|
-
FileUtils.rm temp_dest if File.
|
61
|
+
FileUtils.rm temp_dest if File.exist? temp_dest
|
59
62
|
raise e
|
60
63
|
end
|
61
64
|
ensure
|
62
|
-
FileUtils.rm temp_dest if File.
|
65
|
+
FileUtils.rm temp_dest if File.exist? temp_dest
|
63
66
|
end
|
64
67
|
|
65
68
|
def to_s
|
@@ -67,6 +70,7 @@ module MediaFile; class MediaFile
|
|
67
70
|
end
|
68
71
|
|
69
72
|
def self.tags(*args)
|
73
|
+
private
|
70
74
|
args.each do |arg|
|
71
75
|
define_method arg do
|
72
76
|
read_tags
|
@@ -75,12 +79,12 @@ module MediaFile; class MediaFile
|
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
82
|
+
private
|
83
|
+
|
78
84
|
tags :album, :artist, :album_artist,
|
79
85
|
:title, :genre, :year, :track,
|
80
86
|
:comment, :disc_number, :disc_total
|
81
87
|
|
82
|
-
private
|
83
|
-
|
84
88
|
def really_copy(src,dest)
|
85
89
|
FileUtils.cp(src, dest)
|
86
90
|
set_album_artist(dest)
|
@@ -105,37 +109,39 @@ module MediaFile; class MediaFile
|
|
105
109
|
|
106
110
|
def set_encoder(to,destination)
|
107
111
|
comment = "; Transcoded by MediaFile on #{Time.now}"
|
108
|
-
case to
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
112
|
+
encoder = case to
|
113
|
+
when :flac
|
114
|
+
%W{flac -7 -V -s -o #{destination}} +
|
115
|
+
(@artist ? ["-T", "artist=#{@artist}"] : [] ) +
|
116
|
+
(@title ? ["-T", "title=#{@title}"] : [] ) +
|
117
|
+
(@album ? ["-T", "album=#{@album}"] : [] ) +
|
118
|
+
(@track > 0 ? ["-T", "tracknumber=#{@track}"] : [] ) +
|
119
|
+
(@year ? ["-T", "date=#{@year}"] : [] ) +
|
120
|
+
(@genre ? ["-T", "genre=#{@genre}"] : [] ) +
|
121
|
+
["-T", "comment=" + @comment + comment ] +
|
122
|
+
(@album_artist ? ["-T", "albumartist=#{@album_artist}"] : [] ) +
|
123
|
+
(@disc_number ? ["-T", "discnumber=#{@disc_number}"] : [] ) +
|
124
|
+
["-"]
|
125
|
+
#raise "Please don't transcode to flac. It is broken right now"
|
126
|
+
when :mp3
|
127
|
+
%W{lame --quiet --preset extreme -h --add-id3v2 --id3v2-only} +
|
128
|
+
(@title ? ["--tt", @title] : [] ) +
|
129
|
+
(@artist ? ["--ta", @artist]: [] ) +
|
130
|
+
(@album ? ["--tl", @album] : [] ) +
|
131
|
+
(@track > 0 ? ["--tn", @track.to_s]: [] ) +
|
132
|
+
(@year ? ["--ty", @year.to_s ] : [] ) +
|
133
|
+
(@genre ? ["--tg", @genre ]: [] ) +
|
134
|
+
["--tc", @comment + comment ] +
|
135
|
+
(@album_artist ? ["--tv", "TPE2=#{@album_artist}"] : [] ) +
|
136
|
+
(@disc_number ? ["--tv", "TPOS=#{@disc_number}"] : [] ) +
|
137
|
+
["-", destination]
|
138
|
+
when :wav
|
139
|
+
%W{dd of=#{destination}}
|
140
|
+
else
|
141
|
+
raise "Unknown target '#{to}'. Cannot set encoder."
|
142
|
+
end
|
143
|
+
debug "Encoder set to '#{encoder}'"
|
144
|
+
encoder
|
139
145
|
end
|
140
146
|
|
141
147
|
def transcode(trans , destination)
|
@@ -149,7 +155,7 @@ module MediaFile; class MediaFile
|
|
149
155
|
|
150
156
|
encoder = set_encoder(to, destination)
|
151
157
|
|
152
|
-
|
158
|
+
info "Decoder: '#{decoder.join(' ')}'\nEncoder: '#{encoder.join(' ')}'"
|
153
159
|
|
154
160
|
pipes = Hash[[:encoder,:decoder].zip IO.pipe]
|
155
161
|
#readable, writeable = IO.pipe
|
@@ -166,7 +172,7 @@ module MediaFile; class MediaFile
|
|
166
172
|
sleep 0.2
|
167
173
|
tpids.delete_if do |pid|
|
168
174
|
ret = false
|
169
|
-
|
175
|
+
_p, stat = Process.wait2 pid, Process::WNOHANG
|
170
176
|
if stat
|
171
177
|
pipes[pids[pid]].close unless pipes[pids[pid]].closed?
|
172
178
|
ret = true
|
@@ -200,9 +206,10 @@ module MediaFile; class MediaFile
|
|
200
206
|
def relative_path
|
201
207
|
@relpath ||= (
|
202
208
|
read_tags
|
203
|
-
|
209
|
+
File.join(
|
204
210
|
[@album_artist, @album].map { |word|
|
205
|
-
|
211
|
+
debug word
|
212
|
+
clean_string word
|
206
213
|
}
|
207
214
|
)
|
208
215
|
)
|
@@ -212,44 +219,45 @@ module MediaFile; class MediaFile
|
|
212
219
|
# this doesn't include the extension.
|
213
220
|
@newname ||= (
|
214
221
|
read_tags
|
215
|
-
|
216
|
-
file = clean_string(
|
222
|
+
#file = clean_string(
|
217
223
|
case
|
218
224
|
when (@disc_number && (@track > 0) && @title) && !(@disc_total && @disc_total == 1)
|
219
|
-
"%1d_%02d-" % [@disc_number, @track] + @title
|
225
|
+
"%1d_%02d-" % [@disc_number, @track] + clean_string(@title)
|
220
226
|
when (@track > 0 && @title)
|
221
|
-
"%02d-" % @track + @title
|
227
|
+
"%02d-" % @track + clean_string(@title)
|
222
228
|
when @title && @title != ""
|
223
|
-
@title
|
229
|
+
clean_string(@title)
|
224
230
|
else
|
225
|
-
@name
|
231
|
+
clean_string(@name)
|
226
232
|
end
|
227
|
-
)
|
233
|
+
#)
|
228
234
|
)
|
229
235
|
end
|
230
236
|
|
231
237
|
def clean_string(my_string)
|
232
238
|
my_string ||= ""
|
233
239
|
t = my_string.gsub(
|
234
|
-
|
235
|
-
).gsub(
|
236
|
-
/\//,"_"
|
240
|
+
/\.+|\.+$/,""
|
237
241
|
).gsub(
|
238
|
-
|
242
|
+
/\/+|\s+/, '_'
|
239
243
|
).gsub(
|
240
244
|
/[,:;)\]\[('"@$^*<>?!=]/,""
|
241
|
-
).gsub(
|
242
|
-
/^[.]/,''
|
243
245
|
).gsub(
|
244
246
|
/_?[&]_?/,"_and_"
|
245
247
|
).split('_').map{ |c|
|
246
|
-
|
247
|
-
|
248
|
+
c.split('-').map{ |d|
|
249
|
+
next if d[/_/]
|
250
|
+
debug("capitalize: '#{d}'")
|
251
|
+
d.capitalize
|
252
|
+
}.join('-')
|
248
253
|
}.join('_').gsub(
|
249
|
-
|
250
|
-
).gsub(
|
251
|
-
|
254
|
+
/^[.]/, ''
|
255
|
+
).gsub(
|
256
|
+
/_+/, '_'
|
257
|
+
)
|
252
258
|
t == "" ? "UNKNOWN" : t
|
259
|
+
debug("clean_string: '#{my_string} => '#{t}'")
|
260
|
+
t
|
253
261
|
end
|
254
262
|
|
255
263
|
def tmp_file_name
|
@@ -265,12 +273,12 @@ module MediaFile; class MediaFile
|
|
265
273
|
end
|
266
274
|
|
267
275
|
def set_album_artist(file)
|
268
|
-
type = file[/(\w+)$/].downcase.to_sym
|
269
276
|
return unless @force_album_artist
|
270
|
-
case type
|
277
|
+
case @type
|
271
278
|
when :m4a
|
272
279
|
TagLib::MP4::File.open(file) do |f|
|
273
|
-
f.tag.item_list_map.insert("aART",
|
280
|
+
f.tag.item_list_map.insert("aART",
|
281
|
+
TagLib::MP4::Item.from_string_list([@force_album_artist]))
|
274
282
|
f.save
|
275
283
|
end
|
276
284
|
when :flac
|
@@ -283,7 +291,8 @@ module MediaFile; class MediaFile
|
|
283
291
|
end
|
284
292
|
when :mp3
|
285
293
|
TagLib::MPEG::File.open(file) do |f|
|
286
|
-
|
294
|
+
tag = f.id3v2_tag
|
295
|
+
if tag
|
287
296
|
frame = TagLib::ID3v2::TextIdentificationFrame.new("TPE2", TagLib::String::UTF8)
|
288
297
|
frame.text = @force_album_artist
|
289
298
|
tag.add_frame(frame)
|
@@ -306,7 +315,7 @@ module MediaFile; class MediaFile
|
|
306
315
|
f.send(method)
|
307
316
|
end
|
308
317
|
tag.comment = "#{@comment}"
|
309
|
-
tag.title = (@title || @name.
|
318
|
+
tag.title = (@title || @name.tr('_',' ')) unless tag.title && tag.title != ""
|
310
319
|
if (@type == :mp3)
|
311
320
|
f.save(TagLib::MPEG::File::ID3v2)
|
312
321
|
else
|
@@ -349,7 +358,8 @@ module MediaFile; class MediaFile
|
|
349
358
|
end
|
350
359
|
when :flac
|
351
360
|
TagLib::FLAC::File.open(@source) do |file|
|
352
|
-
|
361
|
+
tag = file.xiph_comment
|
362
|
+
if tag
|
353
363
|
[
|
354
364
|
[:@album_artist, ['ALBUMARTIST', 'ALBUM ARTIST', 'ALBUM_ARTIST'], :to_s ],
|
355
365
|
[:@disc_number, ['DISCNUMBER'], :to_i ],
|
@@ -377,9 +387,10 @@ module MediaFile; class MediaFile
|
|
377
387
|
else
|
378
388
|
@album_artist ||= @artist
|
379
389
|
end
|
380
|
-
|
381
|
-
"
|
390
|
+
debug("album:'#{@album}', artist:'#{@artist}'" +
|
391
|
+
" title:'#{@title}' genre:'#{@genre}' year:'#{@year}'")
|
382
392
|
@red = true
|
383
393
|
end
|
384
|
-
end
|
394
|
+
end
|
395
|
+
end
|
385
396
|
|
data/lib/mediafile/version.rb
CHANGED
data/lib/mediafile.rb
CHANGED
@@ -12,6 +12,14 @@ module MakeMakefile::Logging
|
|
12
12
|
@logfile = File::NULL
|
13
13
|
end
|
14
14
|
|
15
|
+
class Numeric
|
16
|
+
def to_duration
|
17
|
+
[60,60,24].reduce([self.to_i]) do |m,o|
|
18
|
+
m.unshift(m.shift.divmod(o)).flatten
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
module MediaFile
|
16
24
|
|
17
25
|
autoload :MediaFile, 'mediafile/mediafile.rb'
|
@@ -27,8 +35,8 @@ module MediaFile
|
|
27
35
|
|
28
36
|
private
|
29
37
|
|
30
|
-
@@thread_count =
|
31
|
-
@@
|
38
|
+
@@thread_count = nil
|
39
|
+
@@mutex = nil
|
32
40
|
@@initialized = false
|
33
41
|
|
34
42
|
def initialize_threads(count = 1)
|
@@ -37,29 +45,36 @@ module MediaFile
|
|
37
45
|
@@thread_count = count
|
38
46
|
if @@thread_count > 1
|
39
47
|
require 'thread'
|
40
|
-
@@
|
48
|
+
@@mutex = Mutex.new
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
44
52
|
def safe_print(message = '')
|
45
53
|
lock {
|
46
|
-
print block_given? ? yield : message
|
54
|
+
print block_given? ? yield : message + "\n"
|
47
55
|
}
|
48
56
|
end
|
49
57
|
|
50
58
|
def cleanup
|
51
|
-
@@
|
59
|
+
@@mutex = nil
|
52
60
|
true
|
53
61
|
end
|
54
62
|
|
55
63
|
def lock
|
56
|
-
if @@
|
57
|
-
@@
|
64
|
+
if @@mutex && !@@mutex.owned?
|
65
|
+
@@mutex.synchronize do
|
58
66
|
yield
|
59
|
-
|
67
|
+
end
|
60
68
|
else
|
61
69
|
yield
|
62
70
|
end
|
63
71
|
end
|
64
72
|
|
65
|
-
|
73
|
+
def debug(msg = '')
|
74
|
+
safe_print("DEBUG: #{caller_locations(1, 2)[0].label} >> #{msg}") if @debug
|
75
|
+
end
|
76
|
+
|
77
|
+
def info(msg = '')
|
78
|
+
safe_print("INFO: #{caller_locations(1, 2)[0].label} >> #{msg}") if @verbose
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mediafile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Harvey-Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-01-
|
11
|
+
date: 2017-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: taglib-ruby
|