mediafile 0.1.8 → 0.1.9
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.
- 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
|