mediafile 0.1.9 → 0.2.1

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: 334aef8d37ba538e00245a02dc3aefafd60b4b3c
4
- data.tar.gz: 4f8de891ef857224aced4f20d4ff9b7cb329ae7e
3
+ metadata.gz: d5c394dc6d5a00be3d75ff15ee0b842743cfb86b
4
+ data.tar.gz: cad902cd12157f5792f3e56b87f417e9a3522b8c
5
5
  SHA512:
6
- metadata.gz: 53186aae0f9fd1b468a9f2b1fdf8dbae02017e4a59fe7897acc3bd438074b4c6bf76fae29ae872936a9fb7d5465e4d1307b6b73e21942b1c80917019e1ed0da3
7
- data.tar.gz: 169efd96844d7d386f72834407ea8f5e4daee2708fdb939d1d2d873133981fe9eacb9c638211eded3828d5176ac7624349dc7ab30cbd980bb24632391979203a
6
+ metadata.gz: 71d866a921add9b4b39a05d8fa20fe537a4d79b063fa99be72cea9e40ebf468ede7090d66ee177e5a5fec96df798e96456a5b0d7a0fa264272263de7566b8d95
7
+ data.tar.gz: d2de722d5d6039b8d988626edefbe84b5f4e24464e50868ce1849afb476cc2e2cd666990048a9bd4d37cce058938b2197b7577927537eccbce499dfe82c8008d
data/bin/music_cp CHANGED
@@ -44,7 +44,7 @@ opts = OptionParser.new do |opt|
44
44
  dest = d
45
45
  end
46
46
  opt.on('--transcode <from=to[,from1=to1]>',
47
- 'A comma-seperated series of name=value pairs.',
47
+ 'A comma-seperated list of name=value pairs.',
48
48
  'Default is ' \
49
49
  "#{transcode.to_a.map { |i| i.join('=') }.join(',')}}") do |fmt|
50
50
  kill = true
@@ -64,7 +64,7 @@ opts = OptionParser.new do |opt|
64
64
  end
65
65
  opt.on('--exclude PATTERN', '-x PATTERN', String,
66
66
  'Exclude files that match the given pattern.',
67
- 'Can specify more than once, file is excluded' \
67
+ 'Can specify more than once, file is excluded ' \
68
68
  'if any pattern matches') do |p|
69
69
  exclude_patterns.concat p.split(',')
70
70
  end
@@ -40,13 +40,12 @@ class BulkMediaCopy
40
40
  def run(max=4)
41
41
  start = Time.new
42
42
  debug "Call run with max => '#{max}'"
43
- puts "%#{@width + 8}s, %#{@width + 8}s,%#{@width + 8}s, %-#{@name_width}s => Destination Path" % [
43
+ puts "%#{@width + 8}s, %#{@width + 8}s,%#{@width + 9}s :: Mode" % [
44
44
  "Remaining",
45
45
  "Workers",
46
- "Complete",
47
- "File Name"
46
+ "Complete"
48
47
  ]
49
- puts "%#{@width}d ( 100%%), %#{@width}d (%4.1f%%), %#{@width}d ( 0.0%%)" % [
48
+ puts "%#{@width}d ( 100%%), %#{@width}d (%4.1f%%), %#{@width}d ( 0.0%%) :: *wait*" % [
50
49
  @work.count,
51
50
  0,
52
51
  0,
@@ -56,7 +55,7 @@ class BulkMediaCopy
56
55
  stop = Time.new
57
56
  duration = stop - start
58
57
  puts "Copied #{@count} files in #{ "%d:%d:%d:%d" % duration.to_duration} " +
59
- "(~#{(@count/duration).to_i} songs/second))."
58
+ "(~%.2f songs/second))." % [(@count/duration)]
60
59
  dupes = @copies.select{ |_k,a| a.size > 1 }
61
60
  if dupes.any?
62
61
  puts "dupes"
@@ -64,7 +63,7 @@ class BulkMediaCopy
64
63
  pp dupes
65
64
  end
66
65
  if @failed.any?
67
- puts "Some files timed out"
66
+ puts "Some files failed to transfer."
68
67
  @failed.each { |f| puts f.to_s }
69
68
  end
70
69
  end
@@ -112,43 +111,42 @@ class BulkMediaCopy
112
111
  dest = mediafile.out_path transcode_table: @transcode
113
112
  lock {
114
113
  return unless copy_check? mediafile.source_md5, mediafile.source, dest
115
- }
116
-
117
- err = false
118
- begin
119
- mediafile.copy transcode_table: @transcode
120
- rescue
121
- @failed << mediafile
122
- err = true
123
- end
124
-
125
- lock {
126
114
  @count += 1
127
115
  if @progress
128
116
  left = @work.count - @count
129
117
  left_perc = left == 0 ? left : left.to_f / @work.count * 100
130
- cur = @copies.count - @count
118
+ cur = @copies.count - @count
131
119
  cur_perc = cur == 0 ? cur : cur.to_f / left * 100 # @work.count * 100
132
120
  c = cur_perc == 100
133
121
  finished = @count.to_f / @work.count * 100
134
122
  f = finished == 100.0
135
123
  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" % [
138
- left,
139
- left_perc,
140
- cur,
141
- cur_perc,
142
- @count,
143
- finished,
144
- (@transcode[mediafile.type].nil? ? '*copy*' : '*transcode*'),
145
- (mediafile.source + (err ? " **" : "") ),
146
- mediafile.out_path(transcode_table:@transcode)
124
+ "%#{@width}d (%4.#{f ? 0 : 1}f%%) :: %-s\n source file => %-s\n " \
125
+ "destination => %-s\n" % [
126
+ left,
127
+ left_perc,
128
+ cur,
129
+ cur_perc,
130
+ @count,
131
+ finished,
132
+ (@transcode[mediafile.type].nil? ? '*copy*' : '*transcode*'),
133
+ (mediafile.source),
134
+ mediafile.out_path(transcode_table:@transcode)
147
135
  ]
148
136
  end
149
137
  debug "#{mediafile.type} == #{@transcode[mediafile.type]}"
150
138
  }
151
139
 
140
+ err = false
141
+ begin
142
+ mediafile.copy transcode_table: @transcode
143
+ rescue => e
144
+ debug("mediafile.copy failed. #{e}")
145
+ @failed << mediafile
146
+ err = true
147
+ raise
148
+ end
149
+ err
152
150
  end
153
151
 
154
152
  def copy_check?(md5,name,dest)
@@ -8,7 +8,7 @@ class MediaFile
8
8
 
9
9
  attr_reader :source, :type, :name, :base_dir
10
10
 
11
- def initialize(path,
11
+ def initialize(full_path,
12
12
  base_dir: '.',
13
13
  force_album_artist: nil,
14
14
  verbose: false,
@@ -16,11 +16,15 @@ class MediaFile
16
16
  @base_dir = base_dir
17
17
  @destinations = Hash.new{ |k,v| k[v] = {} }
18
18
  @force_album_artist = force_album_artist
19
- @name = File.basename( path, File.extname( path ) )
20
- @source = path
21
- @type = path[/(\w+)$/].downcase.to_sym
19
+ @name = File.basename( full_path, File.extname( full_path ) )
20
+ @source = full_path
21
+ @type = full_path[/(\w+)$/].downcase.to_sym
22
22
  @verbose = verbose
23
23
  @debug = debug
24
+ @cover = File.join(
25
+ File.dirname(full_path),
26
+ 'cover.jpg')
27
+ @cover = nil unless File.exist?(@cover)
24
28
  end
25
29
 
26
30
  def source_md5
@@ -37,25 +41,30 @@ class MediaFile
37
41
 
38
42
  def copy(dest: @base_dir, transcode_table: {})
39
43
  destination = out_path base_dir: dest, transcode_table: transcode_table
40
- temp_dest = tmp_path base_dir: dest, transcode_table: transcode_table
44
+ temp_dest = tmp_path base_dir: dest, typ: transcode_table[@type]
45
+ debug "temp dest is '#{temp_dest}'"
41
46
  lock{
42
47
  if File.exist?(temp_dest)
43
- warn "File transfer is already in progress for #{@source} => #{temp_dest} => #{destination}"
44
- warn "This shouldn't happen! Check to make sure it was really copied."
48
+ error "File transfer is already in progress for #{@source} => #{temp_dest} => #{destination}"
49
+ error "This shouldn't happen! Check to make sure it was really copied."
45
50
  raise
46
51
  #return
47
52
  end
48
53
  if File.exist?(destination)
49
- warn "File has already been transfered #{@source} => #{destination}" if @verbose
54
+ info("File has already been transfered #{@source} => #{destination}")
50
55
  return
51
56
  end
57
+ debug("Create parent directories at '#{File.dirname destination}'.")
52
58
  FileUtils.mkdir_p File.dirname destination
53
59
  FileUtils.touch temp_dest
54
60
  }
55
61
  begin
56
62
  transcode_table.has_key?(@type) ?
57
63
  transcode(transcode_table, temp_dest) :
58
- really_copy(@source, temp_dest)
64
+ FileUtils.cp(@source, temp_dest)
65
+ set_album_artist(temp_dest)
66
+ set_comment_and_title(temp_dest)
67
+ set_cover_art(temp_dest)
59
68
  FileUtils.mv temp_dest, destination
60
69
  rescue => e
61
70
  FileUtils.rm temp_dest if File.exist? temp_dest
@@ -85,12 +94,6 @@ class MediaFile
85
94
  :title, :genre, :year, :track,
86
95
  :comment, :disc_number, :disc_total
87
96
 
88
- def really_copy(src,dest)
89
- FileUtils.cp(src, dest)
90
- set_album_artist(dest)
91
- set_comment_and_title(dest)
92
- end
93
-
94
97
  def set_decoder()
95
98
  case @type
96
99
  when :flac
@@ -147,7 +150,7 @@ class MediaFile
147
150
  def transcode(trans , destination)
148
151
  to = trans[@type]
149
152
  if to == @type
150
- safe_print "Attempting to transcode to the same format #{@source} from #{@type} to #{to}"
153
+ error "Attempting to transcode to the same format #{@source} from #{@type} to #{to}"
151
154
  end
152
155
  FileUtils.mkdir_p File.dirname destination
153
156
 
@@ -185,7 +188,7 @@ class MediaFile
185
188
  end
186
189
  }
187
190
  rescue Timeout::Error
188
- safe_print "Timeout exceeded!\n" << tpids.map { |p|
191
+ error "Timeout exceeded!\n" << tpids.map { |p|
189
192
  Process.kill 15, p
190
193
  Process.kill 9, p
191
194
  "#{p} #{Process.wait2( p )[1]}"
@@ -194,9 +197,9 @@ class MediaFile
194
197
  raise
195
198
  end
196
199
  if err.any?
197
- safe_print "###\nError transcoding #{@source}: #{err.map{ |it,stat|
200
+ error "###\nError transcoding #{@source}: #{err.map{ |it,stat|
198
201
  "#{it} EOT:#{stat.exitstatus} #{stat}" }.join(" and ") }\n###\n"
199
- exit 1
202
+ raise
200
203
  end
201
204
  end
202
205
 
@@ -219,18 +222,16 @@ class MediaFile
219
222
  # this doesn't include the extension.
220
223
  @newname ||= (
221
224
  read_tags
222
- #file = clean_string(
223
- case
224
- when (@disc_number && (@track > 0) && @title) && !(@disc_total && @disc_total == 1)
225
- "%1d_%02d-" % [@disc_number, @track] + clean_string(@title)
226
- when (@track > 0 && @title)
227
- "%02d-" % @track + clean_string(@title)
228
- when @title && @title != ""
229
- clean_string(@title)
230
- else
231
- clean_string(@name)
232
- end
233
- #)
225
+ case
226
+ when (@disc_number && (@track > 0) && @title) && !(@disc_total && @disc_total == 1)
227
+ "%1d_%02d-" % [@disc_number, @track] + clean_string(@title)
228
+ when (@track > 0 && @title)
229
+ "%02d-" % @track + clean_string(@title)
230
+ when @title && @title != ""
231
+ clean_string(@title)
232
+ else
233
+ clean_string(@name)
234
+ end
234
235
  )
235
236
  end
236
237
 
@@ -264,17 +265,121 @@ class MediaFile
264
265
  "." + new_file_name
265
266
  end
266
267
 
267
- def tmp_path(base_dir: @base_dir, transcode_table: {})
268
+ def tmp_path(base_dir: @base_dir, typ: nil)
269
+ typ ||= @type
268
270
  File.join(
269
271
  base_dir,
270
272
  relative_path,
271
273
  tmp_file_name,
272
- ) << ".#{transcode_table[@type] || @type}"
274
+ ) << ".#{typ}"
275
+ end
276
+
277
+ def has_cover_art?(file)
278
+ typ = file[/(\w+)$/].downcase.to_sym
279
+ debug("Checking if #{file} has clover art. (#{typ})")
280
+ case typ
281
+ when :m4a
282
+ return true if file.tag.item_list_map['covr'].to_cover_art_list.find do |p|
283
+ p.format == TagLib::MP4::CoverArt::JPEG
284
+ end
285
+ when :flac
286
+ debug("It does.")
287
+ TagLib::FLAC::File.open(file) do |f|
288
+ return true if f.picture_list.find do |p|
289
+ p.type == TagLib::FLAC::Picture::FrontCover
290
+ end
291
+ end
292
+ when :mp3
293
+ TagLib::MPEG::File.open(file) do |f|
294
+ tag = f.id3v2_tag
295
+ # Don't overwrite an existing album cover.
296
+ debug("Checking if the target mp3 file already has a cover.")
297
+ return true if tag.frame_list('APIC').find do |p|
298
+ p.type == TagLib::ID3v2::AttachedPictureFrame::FrontCover
299
+ end
300
+ end
301
+ end
302
+ false
303
+ end
304
+
305
+ def set_cover_art(file)
306
+ debug("Checking for cover to apply to #{file}")
307
+ return if has_cover_art?(file)
308
+ write_cover_data(file, get_cover_data)
309
+ end
310
+
311
+ def get_cover_data
312
+ info("Getting cover art from #{@source}.")
313
+ # This is bad maybe
314
+ @cover ? File.open(@cover, 'rb') { |c| c.read } :
315
+ case @type
316
+ when :m4a
317
+ TagLib::MP4::File.open(@source) do
318
+ p = mp4.tag.item_list_map['covr'].to_cover_art_list.first
319
+ p.data if p
320
+ end
321
+ when :flac
322
+ TagLib::FLAC::File.open(@source) do |f|
323
+ info("Geting cover art from #{@source}.")
324
+ p = f.picture_list.find { |i| i.type == TagLib::FLAC::Picture::FrontCover }
325
+ p.data if p
326
+ end
327
+ when :mp3
328
+ TagLib::MPEG::File.open(@source) do |f|
329
+ tag = f.id3v2_tag
330
+ p = tag.frame_list('APIC').first
331
+ p.picture if p
332
+ end
333
+ else
334
+ error "Unsupported file type '#{@type}'. Not adding cover art from '#{@cover}'."
335
+ false
336
+ end
337
+ end
338
+
339
+ def write_cover_data(file, cover_art)
340
+ typ = file[/(\w+)$/].downcase.to_sym
341
+ case typ
342
+ when :m4a
343
+ TagLib::MP4::File.open(file) do
344
+ c = TagLib::MP4::CoverArt.new(TagLib::MP4::CoverArt::JPEG, cover_art)
345
+ item = TagLib::MP4::Item.from_cover_art_list([c])
346
+ file.tag.item_list_map.insert('covr', item)
347
+ file.save
348
+ end
349
+ when :flac
350
+ TagLib::FLAC::File.open(file) do |f|
351
+ pic = TagLib::FLAC::Picture.new
352
+ pic.type = TagLib::FLAC::Picture::FrontCover
353
+ pic.mime_type = 'image/jpeg'
354
+ pic.description = 'Cover'
355
+ pic.width = 90
356
+ pic.height = 90
357
+ pic.data = cover_art
358
+ info("Adding cover art tag to #{file}.")
359
+ f.add_picture(cover_art)
360
+ f.save
361
+ end
362
+ when :mp3
363
+ TagLib::MPEG::File.open(file) do |f|
364
+ tag = f.id3v2_tag
365
+ apic = TagLib::ID3v2::AttachedPictureFrame.new
366
+ apic.mime_type = 'image/jpeg'
367
+ apic.description = 'Cover'
368
+ apic.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
369
+ apic.picture = cover_art
370
+ tag.add_frame(apic)
371
+ f.save
372
+ end
373
+ else
374
+ error "Unsupported file type '#{typ}'. Not adding cover art from '#{@cover}'."
375
+ false
376
+ end
273
377
  end
274
378
 
275
379
  def set_album_artist(file)
276
380
  return unless @force_album_artist
277
- case @type
381
+ typ = file[/(\w+)$/].downcase.to_sym
382
+ case typ
278
383
  when :m4a
279
384
  TagLib::MP4::File.open(file) do |f|
280
385
  f.tag.item_list_map.insert("aART",
@@ -298,25 +403,27 @@ class MediaFile
298
403
  tag.add_frame(frame)
299
404
  f.save
300
405
  else
301
- safe_print("##########\nNo tag returned for #{@name}: #{@source}\n#############\n\n")
406
+ error("##########\nNo tag returned for #{@name}: #{@source}\n#############\n\n")
302
407
  end
303
408
  end
304
409
  end
305
410
  end
306
411
 
307
412
  def set_comment_and_title(file)
308
- klass = (@type == :mp3) ? TagLib::MPEG::File : TagLib::FileRef
309
- method = (@type == :mp3) ? :id3v2_tag : :tag
413
+ debug "file is #{file}"
414
+ typ = file[/(\w+)$/].downcase.to_sym
415
+ klass = (typ == :mp3) ? TagLib::MPEG::File : TagLib::FileRef
416
+ method = (typ == :mp3) ? :id3v2_tag : :tag
310
417
 
311
418
  klass.send(:open, file) do |f|
312
- tag = if (@type == :mp3)
419
+ tag = if (typ == :mp3)
313
420
  f.send(method, true)
314
421
  else
315
422
  f.send(method)
316
423
  end
317
424
  tag.comment = "#{@comment}"
318
425
  tag.title = (@title || @name.tr('_',' ')) unless tag.title && tag.title != ""
319
- if (@type == :mp3)
426
+ if (typ == :mp3)
320
427
  f.save(TagLib::MPEG::File::ID3v2)
321
428
  else
322
429
  f.save
@@ -332,7 +439,7 @@ class MediaFile
332
439
  @genre = nil
333
440
  @year = nil
334
441
  @track = 0
335
- @comment = "MediaFile from source: #{@source}\n"
442
+ @comment = "MediaFile source: #{@source}\n"
336
443
  TagLib::FileRef.open(@source) do |file|
337
444
  unless file.null?
338
445
  tag = file.tag
@@ -1,3 +1,3 @@
1
1
  module MediaFile
2
- VERSION = "0.1.9" unless defined?(::MediaFile::VERSION)
2
+ VERSION = "0.2.1" unless defined?(::MediaFile::VERSION)
3
3
  end
data/lib/mediafile.rb CHANGED
@@ -77,4 +77,9 @@ module MediaFile
77
77
  def info(msg = '')
78
78
  safe_print("INFO: #{caller_locations(1, 2)[0].label} >> #{msg}") if @verbose
79
79
  end
80
+
81
+ def error(msg = '')
82
+ safe_print("ERROR: #{caller_locations(1, 2)[0].label} >> #{msg}")
83
+ end
84
+
80
85
  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.9
4
+ version: 0.2.1
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-16 00:00:00.000000000 Z
11
+ date: 2017-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: taglib-ruby