mediafile 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cac681a4c71a49d088590a7403cc02080c5bb36a
4
- data.tar.gz: 606bd21a86ca1213b885729710d60d7730cdee2f
3
+ metadata.gz: c0ac9d9cb6df74d620341c0410167100c8ab9bb9
4
+ data.tar.gz: 21b7b5e10a2dbffea4222758f48ce2176e36e117
5
5
  SHA512:
6
- metadata.gz: 94e1462a37a4535968baed779bfd274198c7d1032cea7e079d73bf087ef2f5d827ef257411ab0cd0de4aeba2a46c46c12c945be81d418545551932611b0d73fd
7
- data.tar.gz: 1bb6182f3f01199253c2e8485c7474e19c4ec835faab869d9485191764abbda761cc555cefa5e635184a5a48d988eb7b0a2a72a3c90dc9d847db0e82752b7fd0
6
+ metadata.gz: fea4af286c2c6ffe85078a0d8064742baf58229c3c179f177eaed5151f5fe3e8eccdda321b081525f3f0ddb7e9453740c2ca9a5676d3a1e292b5ae4c2d48ee63
7
+ data.tar.gz: 894d6b89e8b32ebd7e34a7dc336579e7e209fff6381d2ed5b34b5c3acede6b6dbf5baba06600620095990da235de2000113bb10545440f692077d901479a7af0
data/bin/music_cp CHANGED
@@ -19,12 +19,14 @@ opt_files = {
19
19
  }
20
20
  dest = "."
21
21
  verbose = false
22
+ debug = false
22
23
  progress = true
23
24
  count = `grep -c '^processor' /proc/cpuinfo`.strip.to_i/2|1
24
25
  transcode = { flac: :mp3, wav: :mp3 }
25
26
  exclude_patterns = []
26
27
  album_artist = nil
27
28
  file_types = "{flac,mp3,MP3,FLAC,wav,WAV,m4a,M4A}"
29
+ yes = nil
28
30
 
29
31
  opts = OptionParser.new do |opt|
30
32
 
@@ -58,6 +60,10 @@ opts = OptionParser.new do |opt|
58
60
  opt.on("-v", "--[no-]verbose", "Be verbose") do |v|
59
61
  verbose = v
60
62
  end
63
+ opt.on("--debug", "Show debug output. Also enables verbose.") do
64
+ debug = true
65
+ verbose = true
66
+ end
61
67
  opt.on("-t", "--threads NUM",
62
68
  "Number of threads to spawn, useful for transcoding. Default: #{count}" ) do |n|
63
69
  count = n.to_i
@@ -69,6 +75,9 @@ opts = OptionParser.new do |opt|
69
75
  puts MediaFile::VERSION
70
76
  exit 0
71
77
  end
78
+ opt.on("-y", "--yes", "Don't ask before running.") do
79
+ yes = "yes"
80
+ end
72
81
  opt.on_tail("-h", "--help", "Show this message") do
73
82
  warn opt
74
83
  exit
@@ -132,8 +141,8 @@ files.each { |l| puts "\t"+l }
132
141
  puts "#{files.count} files total"
133
142
  puts "The following transcode table will be used:"
134
143
  puts transcode.any? ? transcode : 'none'
135
- puts "Do you wish proceed? (Y/n)"
136
- y = gets
144
+ puts "Do you wish to proceed? (Y/n)"
145
+ y = yes || gets
137
146
  if /n/i.match(y)
138
147
  puts "User cancel."
139
148
  exit
@@ -143,6 +152,7 @@ copier = MediaFile::BulkMediaCopy.new(
143
152
  files,
144
153
  destination_root: dest,
145
154
  verbose: verbose,
155
+ debug: debug,
146
156
  transcode: transcode,
147
157
  progress: progress,
148
158
  album_artist: album_artist
@@ -1,10 +1,15 @@
1
+ # vim:et sw=2 ts=2
2
+
3
+ require 'mediafile'
1
4
  module MediaFile; class BulkMediaCopy
5
+ include ::MediaFile
2
6
  def initialize(source,
3
7
  album_artist: nil,
4
8
  destination_root: ".",
5
9
  progress: false,
6
10
  transcode: {},
7
- verbose: false)
11
+ verbose: false,
12
+ debug: false)
8
13
  source = case source
9
14
  when String
10
15
  [source]
@@ -18,14 +23,8 @@ module MediaFile; class BulkMediaCopy
18
23
  @destination_root = destination_root
19
24
  @verbose = verbose
20
25
  @progress = progress
21
- @work = source.map { |s|
22
- MediaFile.new(s,
23
- base_dir: @destination_root,
24
- force_album_artist: album_artist,
25
- verbose: @verbose,
26
- printer: proc{ |msg| self.safe_print( msg ) }
27
- )
28
- }
26
+ @album_artist = album_artist
27
+ @work = get_work(source)
29
28
  @width = [@work.count.to_s.size, 2].max
30
29
  @name_width = @work.max{ |a,b| a.name.size <=> b.name.size }.name.size
31
30
  @transcode = transcode
@@ -59,29 +58,24 @@ module MediaFile; class BulkMediaCopy
59
58
  end
60
59
  end
61
60
 
62
- def safe_print(message='')
63
- locked {
64
- print block_given? ? yield : message
65
- }
66
- end
67
-
68
61
  private
69
62
 
70
- def locked
71
- if @semaphore
72
- @semaphore.synchronize {
73
- yield
74
- }
75
- else
76
- yield
77
- end
63
+ def get_work(source)
64
+ source.map { |s|
65
+ MediaFile.new(
66
+ s,
67
+ base_dir: @destination_root,
68
+ force_album_artist: @album_artist,
69
+ verbose: @verbose,
70
+ debug: @debug,
71
+ )
72
+ }
78
73
  end
79
74
 
80
75
  def mcopy(max)
81
76
  raise "Argument must repond to :times" unless max.respond_to? :times
82
77
  raise "I haven't any work..." unless @work
83
- require 'thread'
84
- @semaphore = Mutex.new
78
+ initialize_threads(max)
85
79
  queue = Queue.new
86
80
  @work.each { |s| queue << s }
87
81
  threads = []
@@ -93,7 +87,7 @@ module MediaFile; class BulkMediaCopy
93
87
  end
94
88
  end
95
89
  threads.each { |t| t.join }
96
- @semaphore = nil
90
+ cleanup
97
91
  end
98
92
 
99
93
  def scopy
@@ -105,7 +99,7 @@ module MediaFile; class BulkMediaCopy
105
99
 
106
100
  def copy(mediafile)
107
101
  dest = mediafile.out_path transcode_table: @transcode
108
- locked {
102
+ lock {
109
103
  return unless copy_check? mediafile.source_md5, mediafile.source, dest
110
104
  }
111
105
 
@@ -117,7 +111,7 @@ module MediaFile; class BulkMediaCopy
117
111
  err = true
118
112
  end
119
113
 
120
- locked {
114
+ lock {
121
115
  @count += 1
122
116
  if @progress
123
117
  left = @work.count - @count
@@ -1,23 +1,24 @@
1
- #!/usr/bin/env ruby
2
1
  # vim:et sw=2 ts=2
3
2
 
3
+ require 'mediafile'
4
4
  module MediaFile; class MediaFile
5
+ include ::MediaFile
5
6
 
6
7
  attr_reader :source, :type, :name, :base_dir
7
8
 
8
9
  def initialize(path,
9
10
  base_dir: '.',
10
11
  force_album_artist: nil,
11
- printer: proc {|msg| puts msg},
12
- verbose: false)
12
+ verbose: false,
13
+ debug: false)
13
14
  @base_dir = base_dir
14
15
  @destinations = Hash.new{ |k,v| k[v] = {} }
15
16
  @force_album_artist = force_album_artist
16
17
  @name = File.basename( path, File.extname( path ) )
17
- @printer = printer
18
18
  @source = path
19
19
  @type = path[/(\w+)$/].downcase.to_sym
20
20
  @verbose = verbose
21
+ @debug = debug
21
22
  end
22
23
 
23
24
  def source_md5
@@ -35,22 +36,30 @@ module MediaFile; class MediaFile
35
36
  def copy(dest: @base_dir, transcode_table: {})
36
37
  destination = out_path base_dir: dest, transcode_table: transcode_table
37
38
  temp_dest = tmp_path base_dir: dest, transcode_table: transcode_table
38
- unless File.exists? destination
39
- FileUtils.mkdir_p File.dirname destination
40
- begin
41
- transcode_table.has_key?(@type) ?
42
- transcode(transcode_table, temp_dest) :
43
- really_copy(@source, temp_dest)
44
- FileUtils.mv temp_dest, destination
45
- rescue => e
46
- FileUtils.rm temp_dest if File.exists? temp_dest
47
- raise e
39
+ lock{
40
+ if File.exists?(destination)
41
+ warn "File has already been transfered #{@source} => #{destination}" if @verbose
42
+ return
43
+ end
44
+ if File.exists?(temp_dest)
45
+ warn "File transfer is already in progress for #{@source} => #{temp_dest} => #{destination}"
46
+ warn "This shouldn't happen! Check to make sure it was really copied."
47
+ return
48
48
  end
49
+ FileUtils.mkdir_p File.dirname destination
50
+ FileUtils.touch temp_dest
51
+ }
52
+ begin
53
+ transcode_table.has_key?(@type) ?
54
+ transcode(transcode_table, temp_dest) :
55
+ really_copy(@source, temp_dest)
56
+ FileUtils.mv temp_dest, destination
57
+ rescue => e
58
+ FileUtils.rm temp_dest if File.exists? temp_dest
59
+ raise e
49
60
  end
50
- end
51
-
52
- def printit(msg)
53
- @printer.call msg
61
+ ensure
62
+ FileUtils.rm temp_dest if File.exists? temp_dest
54
63
  end
55
64
 
56
65
  def to_s
@@ -75,6 +84,7 @@ module MediaFile; class MediaFile
75
84
  def really_copy(src,dest)
76
85
  FileUtils.cp(src, dest)
77
86
  set_album_artist(dest)
87
+ set_comment_and_title(dest)
78
88
  end
79
89
 
80
90
  def set_decoder()
@@ -131,7 +141,7 @@ module MediaFile; class MediaFile
131
141
  def transcode(trans , destination)
132
142
  to = trans[@type]
133
143
  if to == @type
134
- printit "Attempting to transcode to the same format #{@source} from #{@type} to #{to}"
144
+ safe_print "Attempting to transcode to the same format #{@source} from #{@type} to #{to}"
135
145
  end
136
146
  FileUtils.mkdir_p File.dirname destination
137
147
 
@@ -139,13 +149,13 @@ module MediaFile; class MediaFile
139
149
 
140
150
  encoder = set_encoder(to, destination)
141
151
 
142
- printit "Decoder: '#{decoder.join(' ')}'\nEncoder: '#{encoder.join(' ')}'" if @verbose
152
+ safe_print "Decoder: '#{decoder.join(' ')}'\nEncoder: '#{encoder.join(' ')}'" if @verbose
143
153
 
144
154
  pipes = Hash[[:encoder,:decoder].zip IO.pipe]
145
155
  #readable, writeable = IO.pipe
146
156
  pids = {
147
- spawn(*decoder, :out=>pipes[:decoder], :err=>"/dev/null") => :decoder,
148
- spawn(*encoder, :in =>pipes[:encoder], :err=>"/dev/null") => :encoder,
157
+ spawn(*decoder, :out=>pipes[:decoder], :err=>"/tmp/decoder.err") => :decoder,
158
+ spawn(*encoder, :in =>pipes[:encoder], :err=>"/tmp/encoder.err") => :encoder,
149
159
  }
150
160
  tpids = pids.keys
151
161
  err = []
@@ -169,7 +179,7 @@ module MediaFile; class MediaFile
169
179
  end
170
180
  }
171
181
  rescue Timeout::Error
172
- printit "Timeout exceeded!\n" << tpids.map { |p|
182
+ safe_print "Timeout exceeded!\n" << tpids.map { |p|
173
183
  Process.kill 15, p
174
184
  Process.kill 9, p
175
185
  "#{p} #{Process.wait2( p )[1]}"
@@ -178,7 +188,7 @@ module MediaFile; class MediaFile
178
188
  raise
179
189
  end
180
190
  if err.any?
181
- printit "###\nError transcoding #{@source}: #{err.map{ |it,stat|
191
+ safe_print "###\nError transcoding #{@source}: #{err.map{ |it,stat|
182
192
  "#{it} EOT:#{stat.exitstatus} #{stat}" }.join(" and ") }\n###\n"
183
193
  exit 1
184
194
  end
@@ -191,14 +201,10 @@ module MediaFile; class MediaFile
191
201
  @relpath ||= (
192
202
  read_tags
193
203
  dest = File.join(
194
- [(@album_artist||"UNKNOWN"), (@album||"UNKNOWN")].map { |word|
195
- word.gsub(/^\.+|\.+$/,"").gsub(/\//,"_")
204
+ [@album_artist, @album].map { |word|
205
+ clean_string(word)
196
206
  }
197
207
  )
198
- bool=true
199
- dest.gsub(/\s/,"_").gsub(/[,:)\]\[('"@$^*<>?!]/,"").gsub(/_[&]_/,"_and_").split('').map{ |c|
200
- b = bool; bool = c.match('/|_'); b ? c.capitalize : c
201
- }.join('').gsub(/__+/,'_')
202
208
  )
203
209
  end
204
210
 
@@ -207,33 +213,45 @@ module MediaFile; class MediaFile
207
213
  @newname ||= (
208
214
  read_tags
209
215
  bool = true
210
- file = (
216
+ file = clean_string(
211
217
  case
212
218
  when (@disc_number && (@track > 0) && @title) && !(@disc_total && @disc_total == 1)
213
219
  "%1d_%02d-" % [@disc_number, @track] + @title
214
220
  when (@track > 0 && @title)
215
221
  "%02d-" % @track + @title
216
- when @title
222
+ when @title && @title != ""
217
223
  @title
218
224
  else
219
225
  @name
220
226
  end
221
- ).gsub(
222
- /^\.+|\.+$/,""
223
- ).gsub(
224
- /\//,"_"
225
- ).gsub(
226
- /\s/,"_"
227
- ).gsub(
228
- /[,:)\]\[('"@$^*<>?!=]/,""
229
- ).gsub(
230
- /_[&]_/,"_and_"
231
- ).split('').map{ |c|
232
- b = bool; bool = c.match('/|_'); b ? c.capitalize : c
233
- }.join('').gsub(/__+/,'_')
227
+ )
234
228
  )
235
229
  end
236
230
 
231
+ def clean_string(my_string)
232
+ my_string ||= ""
233
+ t = my_string.gsub(
234
+ /^\.+|\.+$/,""
235
+ ).gsub(
236
+ /\//,"_"
237
+ ).gsub(
238
+ /\s/,"_"
239
+ ).gsub(
240
+ /[,:;)\]\[('"@$^*<>?!=]/,""
241
+ ).gsub(
242
+ /^[.]/,''
243
+ ).gsub(
244
+ /_?[&]_?/,"_and_"
245
+ ).split('_').map{ |c|
246
+ puts "DEBUG: capitalize: '#{c}'" if @debug
247
+ "_and_" == c ? c : c.capitalize
248
+ }.join('_').gsub(
249
+ /__+/,'_'
250
+ ).gsub(/^[.]/, '')
251
+ puts "DEBUG: clean_string: '#{my_string} => '#{t}'" if @debug
252
+ t == "" ? "UNKNOWN" : t
253
+ end
254
+
237
255
  def tmp_file_name
238
256
  "." + new_file_name
239
257
  end
@@ -271,27 +289,51 @@ module MediaFile; class MediaFile
271
289
  tag.add_frame(frame)
272
290
  f.save
273
291
  else
274
- printit("##########\nNo tag returned for #{@name}: #{@source}\n#############\n\n")
292
+ safe_print("##########\nNo tag returned for #{@name}: #{@source}\n#############\n\n")
275
293
  end
276
294
  end
277
295
  end
278
296
  end
279
297
 
298
+ def set_comment_and_title(file)
299
+ klass = (@type == :mp3) ? TagLib::MPEG::File : TagLib::FileRef
300
+ method = (@type == :mp3) ? :id3v2_tag : :tag
301
+
302
+ klass.send(:open, file) do |f|
303
+ tag = if (@type == :mp3)
304
+ f.send(method, true)
305
+ else
306
+ f.send(method)
307
+ end
308
+ tag.comment = "#{@comment}"
309
+ tag.title = (@title || @name.gsub('_',' ')) unless tag.title && tag.title != ""
310
+ if (@type == :mp3)
311
+ f.save(TagLib::MPEG::File::ID3v2)
312
+ else
313
+ f.save
314
+ end
315
+ end
316
+ end
317
+
280
318
  def read_tags
281
319
  return if @red
282
- @album = @artist= @title = @genre = @year = nil
320
+ @album = nil
321
+ @artist= nil
322
+ @title = nil
323
+ @genre = nil
324
+ @year = nil
283
325
  @track = 0
284
- @comment = ""
326
+ @comment = "MediaFile from source: #{@source}\n"
285
327
  TagLib::FileRef.open(@source) do |file|
286
328
  unless file.null?
287
329
  tag = file.tag
288
- @album = tag.album if tag.album
289
- @artist = tag.artist if tag.artist
290
- @title = tag.title if tag.title
291
- @genre = tag.genre if tag.genre
292
- @comment= tag.comment if tag.comment
293
- @track = tag.track if tag.track
294
- @year = tag.year if tag.year
330
+ @album = tag.album if tag.album && tag.album != ""
331
+ @artist = tag.artist if tag.artist && tag.artist != ""
332
+ @title = tag.title if tag.title && tag.title != ""
333
+ @genre = tag.genre if tag.genre && tag.genre != ""
334
+ @comment+= tag.comment if tag.comment && tag.comment != ""
335
+ @track = tag.track if tag.track && tag.track != ""
336
+ @year = tag.year if tag.year && tag.year != ""
295
337
  end
296
338
  end
297
339
  @album_artist = @artist
@@ -335,6 +377,8 @@ module MediaFile; class MediaFile
335
377
  else
336
378
  @album_artist ||= @artist
337
379
  end
380
+ puts "DEBUG: album:'#{@album}', artist:'#{@artist}'" +
381
+ " @title:'#{@title}' @genre:'#{@genre}' @year:'#{@year}'" if @debug
338
382
  @red = true
339
383
  end
340
384
  end; end
@@ -1,3 +1,3 @@
1
1
  module MediaFile
2
- VERSION = "0.1.7" unless defined?(::MediaFile::VERSION)
2
+ VERSION = "0.1.8" unless defined?(::MediaFile::VERSION)
3
3
  end
data/lib/mediafile.rb CHANGED
@@ -25,4 +25,41 @@ module MediaFile
25
25
  "Transcoding may not work in all cases."
26
26
  end
27
27
 
28
- end
28
+ private
29
+
30
+ @@thread_count = 1
31
+ @@semaphore = nil
32
+ @@initialized = false
33
+
34
+ def initialize_threads(count = 1)
35
+ return if @@initialized
36
+ @@initialized = 1
37
+ @@thread_count = count
38
+ if @@thread_count > 1
39
+ require 'thread'
40
+ @@semaphore = Mutex.new
41
+ end
42
+ end
43
+
44
+ def safe_print(message = '')
45
+ lock {
46
+ print block_given? ? yield : message
47
+ }
48
+ end
49
+
50
+ def cleanup
51
+ @@semaphore = nil
52
+ true
53
+ end
54
+
55
+ def lock
56
+ if @@semaphore
57
+ @@semaphore.synchronize {
58
+ yield
59
+ }
60
+ else
61
+ yield
62
+ end
63
+ end
64
+
65
+ 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.7
4
+ version: 0.1.8
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: 2016-11-11 00:00:00.000000000 Z
11
+ date: 2017-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: taglib-ruby