flacinfo-rb 1.0 → 1.1.0

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.
Files changed (5) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +52 -0
  3. data/lib/flacinfo.rb +328 -353
  4. metadata +10 -14
  5. data/README +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d9267dacbedb7bac4eb13df1bb8c119bbbac61e2
4
- data.tar.gz: e1c40dd876b865c06c454b3d0ce686072128a255
2
+ SHA256:
3
+ metadata.gz: 515af99f113f7d698f0443b909c529c12e406c845992ca5cbf896031b212bf14
4
+ data.tar.gz: 574ce1176c11a953d7de9d0cdcdcd62d4e60cc6373dc762d088e699a03db87f7
5
5
  SHA512:
6
- metadata.gz: e264c66fd251c141c1acd991aee4c397708356147839e62c71cb02d3cab16dc5e91d5c0b425ea15cee7ace367069fc224f4c914209dadabff9759df30f1a5844
7
- data.tar.gz: 4653e488863c184a0117f8bb6b90cbf2e5571ecc96a3ba3ee10c37ce85e0a30fce1ca0b333f6325f5faca86a9ab273ba10e472bdfccce3e44d4d3ff4f25dbbc0
6
+ metadata.gz: ac7d2d9a0fcd3bc7429c85fba5cc85065a247ef25e613ee645a8e551b42e5e5a227085d33adae1fd47777bb750b74c2e6945170161524ee19244cf01d230d5cd
7
+ data.tar.gz: 269e6754eeaef0fec13d77c73251168634b9a652577ead6301a76c813de92fb6ee4548017e7ad5c0db7572802604a0d359b44fe3819c0efaded6faf560dc7dd2
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # flacinfo-rb
2
+
3
+ - Author: Darren Kirby
4
+ - mailto:darren@dragonbyte.ca
5
+ - License: GPL2
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/flacinfo-rb.svg)](https://badge.fury.io/rb/flacinfo-rb)
8
+
9
+ ## Quick API docs
10
+
11
+ ## Initializing
12
+
13
+ ```ruby
14
+ require 'flacinfo'
15
+ foo = FlacInfo.new("someSong.flac")
16
+ ```
17
+
18
+ ## Public attributes
19
+
20
+ - `streaminfo` - hash of STREAMINFO block metadata
21
+ - `seektable` - hash of arrays of seek points
22
+ - `comment` - array of VORBIS COMMENT block metadata
23
+ - `tags` - user-friendly hash of Vorbis comment metadata key=value pairs
24
+ - `application` - hash of APPLICATION block metadata
25
+ - `padding` - hash of PADDING block metadata
26
+ - `cuesheet` - hash of CUESHEET block metadata
27
+ - `picture` - hash of PICTURE block metadata
28
+ - `flac_file` - hash of APPLICATION Id 0x41544348 (Flac File) metadata if present
29
+
30
+ ## Public methods
31
+
32
+ - `comment_add` - adds a comment
33
+ - `comment_del` - deletes a comment
34
+ - `hastag('str')` - returns true if tags['str'] exists
35
+ - `meta_flac` - prints all META BLOCKS. (Mostly) equivelant to 'metaflac --list'
36
+ - `padding_add!(b)` - adds a PADDING block of size 'b' or 4096 bytes
37
+ - `padding_del!` - deletes the PADDING block
38
+ - `padding_resize!` - resizes (grow or shrink) a padding block to size 'b' or 4096 bytes
39
+ - `print_seektable` - pretty-print seektable hash
40
+ - `print_streaminfo` - pretty-print streaminfo hash
41
+ - `print_tags` - pretty-print tags hash
42
+ - `raw_data_dump(?)` - if passed a filename it will dump flac_file['raw_data'] to that file,
43
+ otherwise it will dump it to the console (even if binary!)
44
+ - `update!` - writes comment changes to disk
45
+ - `write_picture(?)` - write image from PICTURE block(s) to optional file
46
+
47
+ The public methods and attributes are very well documented in the source itself. Please read
48
+ there if you don't understand any of this. You can also use Rdoc to generate HTML documentation.
49
+
50
+ HELP: flacinfo-rb still does not parse cuesheets, as I have never encountered a flac file
51
+ that contains one. If you have a flac file with a cuesheet please consider emailing it to
52
+ me so I can add this remaining bit of code.
data/lib/flacinfo.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # = Description
2
4
  #
3
5
  # flacinfo-rb gives you access to low level information on Flac files.
@@ -16,13 +18,13 @@
16
18
  #
17
19
  # = Copyright and Disclaimer
18
20
  #
19
- # Copyright:: (C) 2006 - 2014 Darren Kirby
21
+ # Copyright:: (C) 2006 - 2026 Darren Kirby
20
22
  #
21
23
  # FlacInfo is free software. No warranty is provided and the author
22
24
  # cannot accept responsibility for lost or damaged files.
23
25
  #
24
- # License:: GPL3
25
- # Author:: Darren Kirby (mailto:bulliver@gmail.com)
26
+ # License:: GPL2
27
+ # Author:: Darren Kirby (mailto:darren@dragonbyte.ca)
26
28
  # Website:: https://github.com/DarrenKirby/flacinfo-rb
27
29
  #
28
30
  # = More information
@@ -32,20 +34,19 @@
32
34
  # * The Vorbis Comment spec is at:
33
35
  # http://www.xiph.org/vorbis/doc/v-comment.html
34
36
 
35
-
36
37
  # FlacInfoError is raised for general user errors.
37
38
  # It will print a string that describes the problem.
38
39
  FlacInfoError = Class.new(StandardError)
39
40
 
40
41
  # FlacInfoReadError is raised when an error occurs parsing the Flac file.
41
- # It will print a string that describes in which block the error occured.
42
+ # It will print a string that describes in which block the error occurred.
42
43
  FlacInfoReadError = Class.new(StandardError)
43
44
 
44
45
  # FlacInfoWriteError is raised when an error occurs writing the Flac file.
45
- # It will print a string that describes where the error occured.
46
+ # It will print a string that describes where the error occurred.
46
47
  FlacInfoWriteError = Class.new(StandardError)
47
48
 
48
- # Note: STREAMINFO is the only block guaranteed to be present in the Flac file.
49
+ # STREAMINFO is the only block guaranteed to be present in the Flac file.
49
50
  # All attributes will be present but empty if the associated block is not present in the Flac file,
50
51
  # except for 'picture' which will have the key 'n' with the value '0'.
51
52
  # All 'offset' and 'block_size' values do not include the block header. All block headers are 4 bytes
@@ -55,8 +56,8 @@ class FlacInfo
55
56
  # A list of 'standard field names' according to the Vorbis Comment specification. It is certainly
56
57
  # possible to use a non-standard name, but the spec recommends against it.
57
58
  # See: http://www.xiph.org/vorbis/doc/v-comment.html
58
- STANDARD_FIELD_NAMES= %w/TITLE VERSION ALBUM TRACKNUMBER ARTIST PERFORMER COPYRIGHT LICENSE
59
- ORGANIZATION DESCRIPTION GENRE DATE LOCATION CONTACT ISRC/
59
+ STANDARD_FIELD_NAMES = %w[TITLE VERSION ALBUM TRACKNUMBER ARTIST PERFORMER COPYRIGHT LICENSE
60
+ ORGANIZATION DESCRIPTION GENRE DATE LOCATION CONTACT ISRC].freeze
60
61
 
61
62
  # Hash of values extracted from the STREAMINFO block. Keys are:
62
63
  # 'offset':: The STREAMINFO block's offset from the beginning of the file (not including the block header).
@@ -119,8 +120,8 @@ class FlacInfo
119
120
  # 'type_string':: A text value representing the picture type.
120
121
  # 'description_string':: A text description of the picture.
121
122
  # 'mime_type':: The MIME type string. May be '-->' to signify that the data part is a URL of the picture.
122
- # 'colour_depth':: The color depth of the picture in bits-per-pixel.
123
- # 'n_colours':: For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed pictures.
123
+ # 'colour_depth':: The colour depth of the picture in bits-per-pixel.
124
+ # 'n_colours':: For indexed-colour pictures (e.g. GIF), the number of colours used, or 0 for non-indexed pictures.
124
125
  # 'width':: The width of the picture in pixels.
125
126
  # 'height':: The height of the picture in pixels.
126
127
  # 'raw_data_offset':: The raw picture data's offset from the beginning of the file.
@@ -150,7 +151,7 @@ class FlacInfo
150
151
  # FlacInfo.hastag?(tag) -> bool
151
152
  #
152
153
  def hastag?(tag)
153
- @tags["#{tag}"] ? true : false
154
+ @tags[tag.to_s] ? true : false
154
155
  end
155
156
 
156
157
  # Pretty print tags hash.
@@ -161,10 +162,9 @@ class FlacInfo
161
162
  # Raises FlacInfoError if METADATA_BLOCK_VORBIS_COMMENT is not present.
162
163
  #
163
164
  def print_tags
164
- if @tags == {}
165
- raise FlacInfoError, "METADATA_BLOCK_VORBIS_COMMENT not present"
166
- end
167
- @tags.each_pair { |key,val| puts "#{key}: #{val}" }
165
+ raise FlacInfoError, 'METADATA_BLOCK_VORBIS_COMMENT not present' if @tags == {}
166
+
167
+ @tags.each_pair { |key, val| puts "#{key}: #{val}" }
168
168
  nil
169
169
  end
170
170
 
@@ -175,7 +175,7 @@ class FlacInfo
175
175
  #
176
176
  def print_streaminfo
177
177
  # No test: METADATA_BLOCK_STREAMINFO must be present in valid Flac file
178
- @streaminfo.each_pair { |key,val| puts "#{key}: #{val}" }
178
+ @streaminfo.each_pair { |key, val| puts "#{key}: #{val}" }
179
179
  nil
180
180
  end
181
181
 
@@ -187,9 +187,8 @@ class FlacInfo
187
187
  # Raises FlacInfoError if METADATA_BLOCK_SEEKTABLE is not present.
188
188
  #
189
189
  def print_seektable
190
- if @seektable == {}
191
- raise FlacInfoError, "METADATA_BLOCK_SEEKTABLE not present"
192
- end
190
+ raise FlacInfoError, 'METADATA_BLOCK_SEEKTABLE not present' if @seektable == {}
191
+
193
192
  puts " seek points: #{@seektable['seek_points']}"
194
193
  n = 0
195
194
  @seektable['seek_points'].times do
@@ -212,23 +211,26 @@ class FlacInfo
212
211
  @metadata_blocks.each do |block|
213
212
  puts "METADATA block ##{n}"
214
213
  puts " type: #{block[1]} (#{block[0].upcase})"
215
- puts " is last: #{block[2] == 0 ? "false" : "true"}"
214
+ puts " is last: #{block[2].zero? ? 'false' : 'true'}"
216
215
  case block[1]
217
- when 0
218
- meta_stream
219
- when 1
220
- meta_padd
221
- when 2
222
- meta_app
223
- when 3
224
- meta_seek
225
- when 4
226
- meta_vorb
227
- when 5
228
- meta_cue
229
- when 6
230
- pictures_seen += 1
231
- meta_pict(pictures_seen)
216
+ when 0
217
+ meta_stream
218
+ when 1
219
+ meta_pad
220
+ when 2
221
+ meta_app
222
+ when 3
223
+ meta_seek
224
+ when 4
225
+ meta_vorb
226
+ when 5
227
+ meta_cue
228
+ when 6
229
+ pictures_seen += 1
230
+ meta_pict(pictures_seen)
231
+ else
232
+ # This will never run ... file already parsed.
233
+ raise FlacInfoError, 'Unknown metadata blocktype found'
232
234
  end
233
235
  n += 1
234
236
  end
@@ -246,21 +248,18 @@ class FlacInfo
246
248
  # if there is no Flac File data present.
247
249
  #
248
250
  def raw_data_dump(outfile = nil)
249
- if @flac_file == {}
250
- raise FlacInfoError, "Flac File data not present"
251
- end
252
- if outfile == nil
251
+ raise FlacInfoError, 'Flac File data not present' if @flac_file == {}
252
+
253
+ if outfile.nil?
253
254
  puts @flac_file['raw_data']
254
255
  else
255
- if @flac_file['mime_type'] =~ /text/
256
- f = File.new(outfile, "w")
257
- f.write(@flac_file['raw_data'])
258
- f.close
259
- else
260
- f = File.new(outfile, "wb")
261
- f.write(@flac_file['raw_data'])
262
- f.close
263
- end
256
+ f = if @flac_file['mime_type'] =~ /text/
257
+ File.new(outfile, 'w')
258
+ else
259
+ File.new(outfile, 'wb')
260
+ end
261
+ f.write(@flac_file['raw_data'])
262
+ f.close
264
263
  end
265
264
  end
266
265
 
@@ -278,32 +277,30 @@ class FlacInfo
278
277
  # extension appended. The argument to ':n' is which image to write in case of multiples.
279
278
  #
280
279
  def write_picture(args = {})
281
- if @picture["n"] == 0
282
- raise FlacInfoError, "There is no METADATA_BLOCK_PICTURE"
283
- end
280
+ raise FlacInfoError, 'There is no METADATA_BLOCK_PICTURE' if @picture['n'].zero?
284
281
 
285
- if args.has_key?(:n)
286
- n = args[:n]
287
- else
288
- n = 1
289
- end
282
+ n = if args.key?(:n)
283
+ args[:n]
284
+ else
285
+ 1
286
+ end
290
287
 
291
288
  # "image/jpeg" => "jpeg"
292
- extension = @picture[n]["mime_type"].split("/")[1]
293
-
294
- if not args.has_key?(:outfile)
295
- if @tags["album"] == nil or @tags["album"] == ""
296
- outfile = "flacimage#{n}.#{extension}"
297
- else
298
- # Try to use contents of "album" tag for the filename
299
- outfile = "#{@tags["album"]}#{n}.#{extension}"
300
- end
301
- else
302
- outfile = "#{args[:outfile]}.#{extension}"
303
- end
304
-
305
- in_p = File.new(@filename, "rb")
306
- out_p = File.new(outfile, "wb")
289
+ extension = @picture[n]['mime_type'].split('/')[1]
290
+
291
+ outfile = if !args.key?(:outfile)
292
+ if [nil, ''].include?(@tags['album'])
293
+ "flacimage#{n}.#{extension}"
294
+ else
295
+ # Try to use contents of "album" tag for the filename
296
+ "#{@tags['album']}#{n}.#{extension}"
297
+ end
298
+ else
299
+ "#{args[:outfile]}.#{extension}"
300
+ end
301
+
302
+ in_p = File.new(@filename, 'rb')
303
+ out_p = File.new(outfile, 'wb')
307
304
 
308
305
  out_p.binmode # For Windows folks...
309
306
 
@@ -338,16 +335,17 @@ class FlacInfo
338
335
  # false otherwise. Remember to call 'update!' to write changes to the file.
339
336
  #
340
337
  def comment_add(name)
341
- if name !~ /\w=/ # We accept 'name=' in case you want to leave the value empty
338
+ if name !~ /\w=/ # We accept 'name=' in case you want to leave the value empty
342
339
  raise FlacInfoError, "comments must be in the form 'name=value'"
343
340
  end
341
+
344
342
  begin
345
343
  @comment << name
346
344
  @comments_changed = 1
347
- rescue
345
+ rescue StandardError
348
346
  return false
349
347
  end
350
- return true
348
+ true
351
349
  end
352
350
 
353
351
  # Deletes a comment from the comment array
@@ -362,18 +360,18 @@ class FlacInfo
362
360
  # 'update!' to write changes to the file.
363
361
  #
364
362
  def comment_del(name)
365
- bc = Array.new(@comment) # We need a copy
366
- if name.include? "="
367
- nc = @comment.delete_if { |x| x == name }
368
- else
369
- nc = @comment.delete_if { |x| x.split("=")[0] == name }
370
- end
363
+ bc = Array.new(@comment) # We need a copy
364
+ nc = if name.include? '='
365
+ @comment.delete_if { |x| x == name }
366
+ else
367
+ @comment.delete_if { |x| x.split('=')[0] == name }
368
+ end
371
369
 
372
370
  if nc == bc
373
- return false
371
+ false
374
372
  else
375
373
  @comments_changed = 1
376
- return true
374
+ true
377
375
  end
378
376
  end
379
377
 
@@ -386,11 +384,9 @@ class FlacInfo
386
384
  # size of the padding block. It defaults to 4096 bytes.
387
385
  # Returns true if successful, else false.
388
386
  #
389
- def padding_add!(size=4096)
387
+ def padding_add!(size = 4096)
390
388
  @metadata_blocks.each do |type|
391
- if type[0] == "padding"
392
- raise FlacInfoError, "PADDING block exists. Use 'padding_resize!'"
393
- end
389
+ raise FlacInfoError, "PADDING block exists. Use 'padding_resize!'" if type[0] == 'padding'
394
390
  end
395
391
  build_padding_block(size) ? true : false
396
392
  end
@@ -416,24 +412,19 @@ class FlacInfo
416
412
  # size of the new padding block. It defaults to 4096 bytes.
417
413
  # Returns true if successful, else false.
418
414
  #
419
- def padding_resize!(size=4096)
420
- begin
421
- remove_padding_block
422
- build_padding_block(size)
423
- true
424
- rescue
425
- false
426
- end
415
+ def padding_resize!(size = 4096)
416
+ remove_padding_block
417
+ build_padding_block(size)
427
418
  end
428
419
 
429
420
  #--
430
421
  # This cleans up the output when using FlacInfo in irb
431
- def inspect #:nodoc:
432
- s = "#<#{self.class}:0x#{(self.object_id*2).to_s(16)} "
422
+ def inspect # :nodoc:
423
+ s = "#<#{self.class}:0x#{(object_id * 2).to_s(16)} "
433
424
  @metadata_blocks.each do |blk|
434
425
  s += "(#{blk[0].upcase} size=#{blk[4]} offset=#{blk[3]}) "
435
426
  end
436
- s += "\b>"
427
+ "#{s}\b>"
437
428
  end
438
429
  #++
439
430
 
@@ -442,7 +433,7 @@ class FlacInfo
442
433
  # The following six methods are just helpers for meta_flac
443
434
  def meta_stream
444
435
  puts " length: #{@streaminfo['block_size']}"
445
- puts " minumum blocksize: #{@streaminfo['minimum_block']} samples"
436
+ puts " minimum blocksize: #{@streaminfo['minimum_block']} samples"
446
437
  puts " maximum blocksize: #{@streaminfo['maximum_block']} samples"
447
438
  puts " minimum framesize: #{@streaminfo['minimum_frame']} bytes"
448
439
  puts " maximum framesize: #{@streaminfo['maximum_frame']} bytes"
@@ -453,7 +444,7 @@ class FlacInfo
453
444
  puts " MD5 signature: #{@streaminfo['md5']}"
454
445
  end
455
446
 
456
- def meta_padd
447
+ def meta_pad
457
448
  puts " length: #{@padding['block_size']}"
458
449
  end
459
450
 
@@ -461,18 +452,18 @@ class FlacInfo
461
452
  puts " length: #{@application['block_size']}"
462
453
  puts " id: #{@application['ID']}"
463
454
  puts " application name: #{@application['name']}"
464
- if @application['ID'] == "41544348"
455
+ if @application['ID'] == '41544348'
465
456
  puts " description: #{@flac_file['description']}"
466
457
  puts " mime type: #{@flac_file['mime_type']}"
467
458
  # Don't want to dump binary data
468
459
  if @flac_file['mime_type'] =~ /text/
469
- puts " raw data:"
460
+ puts ' raw data:'
470
461
  puts @flac_file['raw_data']
471
462
  else
472
463
  puts "'Flac File' data may be binary. Use 'raw_data_dump' to see it"
473
464
  end
474
465
  else
475
- puts " raw data"
466
+ puts ' raw data'
476
467
  puts @application['raw_data']
477
468
  end
478
469
  end
@@ -512,8 +503,8 @@ class FlacInfo
512
503
 
513
504
  # This is where the 'real' parsing starts
514
505
  def parse_flac_meta_blocks
515
- @fp = File.new(@filename, "rb") # Our file pointer
516
- @comments_changed = nil # Do we need to write a new VORBIS_BLOCK?
506
+ @fp = File.new(@filename, 'rb') # Our file pointer
507
+ @comments_changed = nil # Do we need to write a new VORBIS_BLOCK?
517
508
 
518
509
  # These next 8 lines initialize our public data structures.
519
510
  @streaminfo = {}
@@ -523,145 +514,138 @@ class FlacInfo
523
514
  @padding = {}
524
515
  @application = {}
525
516
  @cuesheet = {}
526
- @picture = {"n" => 0}
517
+ @picture = { 'n' => 0 }
527
518
 
528
519
  header = @fp.read(4)
529
520
  # First 4 bytes must be 0x66, 0x4C, 0x61, and 0x43
530
- if header != 'fLaC'
531
- raise FlacInfoReadError, "#{@filename} does not appear to be a valid Flac file"
532
- end
521
+ raise FlacInfoReadError, "#{@filename} does not appear to be a valid Flac file" if header != 'fLaC'
533
522
 
534
- typetable = { 0 => "streaminfo", 1 => "padding", 2 => "application",
535
- 3 => "seektable", 4 => "vorbis_comment", 5 => "cuesheet",
536
- 6 => "picture" }
523
+ type_table = { 0 => 'streaminfo', 1 => 'padding', 2 => 'application',
524
+ 3 => 'seektable', 4 => 'vorbis_comment', 5 => 'cuesheet',
525
+ 6 => 'picture' }
537
526
 
538
527
  @metadata_blocks = []
539
- lastheader = 0
528
+ last_header = 0
540
529
 
541
- until lastheader == 1
530
+ until last_header == 1
542
531
  # first bit = Last-metadata-block flag
543
- # bits 2-8 = BLOCK_TYPE. See typetable above
544
- block_header = @fp.read(1).unpack("B*")[0]
545
- lastheader = block_header[0].to_i & 1
546
- type = sprintf("%u", "0b#{block_header[1..7]}").to_i
547
- @metadata_blocks << [typetable[type], type, lastheader]
548
-
549
- if type >= typetable.size
550
- raise FlacInfoReadError, "Invalid block header type"
551
- end
532
+ # bits 2-8 = BLOCK_TYPE. See type_table above
533
+ block_header = @fp.read(1).unpack1('B*')
534
+ last_header = block_header[0].to_i & 1
535
+ type = format('%u', "0b#{block_header[1..7]}").to_i
536
+ @metadata_blocks << [type_table[type], type, last_header]
537
+
538
+ raise FlacInfoReadError, 'Invalid block header type' if type >= type_table.size
552
539
 
553
- self.send "parse_#{typetable[type]}"
540
+ send "parse_#{type_table[type]}"
554
541
  end
555
542
 
556
543
  @fp.close
544
+ p @metadata_blocks
557
545
  end
558
546
 
559
547
  def parse_seektable
560
- begin
561
- @seektable['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
562
- @seektable['offset'] = @fp.tell
563
- @seektable['seek_points'] = @seektable['block_size'] / 18
564
-
565
- @metadata_blocks[-1] << @seektable['offset']
566
- @metadata_blocks[-1] << @seektable['block_size']
567
-
568
- n = 0
569
- @seektable['points'] = {}
570
-
571
- @seektable['seek_points'].times do
572
- pt_arr = []
573
- pt_arr << @fp.read(8).reverse.unpack("V*")[0]
574
- pt_arr << @fp.read(8).reverse.unpack("V*")[0]
575
- pt_arr << @fp.read(2).reverse.unpack("v*")[0]
576
- @seektable['points'][n] = pt_arr
577
- n += 1
578
- end
579
548
 
580
- rescue
581
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_SEEKTABLE"
549
+ @seektable['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
550
+ @seektable['offset'] = @fp.tell
551
+ @seektable['seek_points'] = @seektable['block_size'] / 18
552
+
553
+ @metadata_blocks[-1] << @seektable['offset']
554
+ @metadata_blocks[-1] << @seektable['block_size']
555
+
556
+ n = 0
557
+ @seektable['points'] = {}
558
+
559
+ @seektable['seek_points'].times do
560
+ pt_arr = []
561
+ pt_arr << @fp.read(8).reverse.unpack1('V*')
562
+ pt_arr << @fp.read(8).reverse.unpack1('V*')
563
+ pt_arr << @fp.read(2).reverse.unpack1('v*')
564
+ @seektable['points'][n] = pt_arr
565
+ n += 1
582
566
  end
567
+
568
+ rescue StandardError => e
569
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_SEEKTABLE: #{e.message}"
583
570
  end
584
571
 
585
- # Not parsed yet, I have no flacs with a cuesheet!
572
+ # TODO: I finally found a flac file with a cuesheet!
586
573
  def parse_cuesheet
587
- begin
588
- @cuesheet['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
589
- @cuesheet['offset'] = @fp.tell
590
574
 
591
- @metadata_blocks[-1] << @cuesheet['offset']
592
- @metadata_blocks[-1] << @cuesheet['block_size']
575
+ @cuesheet['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
576
+ @cuesheet['offset'] = @fp.tell
593
577
 
594
- @fp.seek(@cuesheet['block_size'], IO::SEEK_CUR)
595
- rescue
596
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_CUESHEET"
597
- end
578
+ @metadata_blocks[-1] << @cuesheet['offset']
579
+ @metadata_blocks[-1] << @cuesheet['block_size']
580
+
581
+ @fp.seek(@cuesheet['block_size'], IO::SEEK_CUR)
582
+ rescue StandardError => e
583
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_CUESHEET: #{e.message}"
598
584
  end
599
585
 
600
586
  def parse_picture
601
- n = @picture["n"] + 1
602
- @picture["n"] = n
587
+ n = @picture['n'] + 1
588
+ @picture['n'] = n
603
589
  @picture[n] = {}
604
590
 
605
- picture_type = ["Other", "32x32 pixels file icon", "Other file icon", "Cover (front)", "Cover (back)",
606
- "Leaflet page", "Media", "Lead artist/lead performer/soloist", "Artist/performer",
607
- "Conductor", "Band/Orchestra", "Composer", "Lyricist/text writer", "Recording Location",
608
- "During recording", "During performance", "Movie/video screen capture", "A bright
609
- coloured fish", "Illustration", "Band/artist logotype", "Publisher/Studio logotype"]
591
+ picture_type = ['Other', '32x32 pixels file icon', 'Other file icon', 'Cover (front)', 'Cover (back)',
592
+ 'Leaflet page', 'Media', 'Lead artist/lead performer/soloist', 'Artist/performer',
593
+ 'Conductor', 'Band/Orchestra', 'Composer', 'Lyricist/text writer', 'Recording Location',
594
+ 'During recording', 'During performance', 'Movie/video screen capture', "A bright
595
+ coloured fish", 'Illustration', 'Band/artist logotype', 'Publisher/Studio logotype']
610
596
 
611
597
  begin
612
- @picture[n]['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
613
- @picture[n]['offset'] = @fp.tell
598
+ @picture[n]['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
599
+ @picture[n]['offset'] = @fp.tell
614
600
 
615
601
  @metadata_blocks[-1] << @picture[n]['offset']
616
602
 
617
- @picture[n]['type_int'] = @fp.read(4).reverse.unpack("v*")[0]
603
+ @picture[n]['type_int'] = @fp.read(4).reverse.unpack1('v*')
618
604
  @picture[n]['type_string'] = picture_type[@picture[n]['type_int']]
619
- mime_length = @fp.read(4).reverse.unpack("v*")[0]
620
- @picture[n]['mime_type'] = @fp.read(mime_length).unpack("a*")[0]
621
- description_length = @fp.read(4).reverse.unpack("v*")[0]
622
- @picture[n]['description_string'] = @fp.read(description_length).unpack("M*")[0]
623
- @picture[n]['width'] = @fp.read(4).reverse.unpack("v*")[0]
624
- @picture[n]['height'] = @fp.read(4).reverse.unpack("v*")[0]
625
- @picture[n]['colour_depth'] = @fp.read(4).reverse.unpack("v*")[0]
626
- @picture[n]['n_colours'] = @fp.read(4).reverse.unpack("v*")[0]
627
- @picture[n]['raw_data_length'] = @fp.read(4).reverse.unpack("V*")[0]
605
+ mime_length = @fp.read(4).reverse.unpack1('v*')
606
+ @picture[n]['mime_type'] = @fp.read(mime_length).unpack1('a*')
607
+ description_length = @fp.read(4).reverse.unpack1('v*')
608
+ @picture[n]['description_string'] = @fp.read(description_length).unpack1('M*')
609
+ @picture[n]['width'] = @fp.read(4).reverse.unpack1('v*')
610
+ @picture[n]['height'] = @fp.read(4).reverse.unpack1('v*')
611
+ @picture[n]['colour_depth'] = @fp.read(4).reverse.unpack1('v*')
612
+ @picture[n]['n_colours'] = @fp.read(4).reverse.unpack1('v*')
613
+ @picture[n]['raw_data_length'] = @fp.read(4).reverse.unpack1('V*')
628
614
  @picture[n]['raw_data_offset'] = @fp.tell
629
615
 
630
616
  @metadata_blocks[-1] << @picture[n]['block_size']
631
617
 
632
- @fp.seek((@picture[n]['raw_data_length']), IO::SEEK_CUR)
633
- rescue
634
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PICTURE"
618
+ @fp.seek(@picture[n]['raw_data_length'], IO::SEEK_CUR)
619
+ rescue StandardError => e
620
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PICTURE: #{e.message}"
635
621
  end
636
622
  end
637
623
 
638
624
  def parse_application
639
- begin
640
- @application['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
641
- @application['offset'] = @fp.tell
625
+ @application['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
626
+ @application['offset'] = @fp.tell
642
627
 
643
- @metadata_blocks[-1] << @application['offset']
644
- @metadata_blocks[-1] << @application['block_size']
628
+ @metadata_blocks[-1] << @application['offset']
629
+ @metadata_blocks[-1] << @application['block_size']
645
630
 
646
- @application['ID'] = @fp.read(4).unpack("H*")[0]
631
+ @application['ID'] = @fp.read(4).unpack1('H*')
647
632
 
648
- app_id = {"41544348" => "Flac File", "43756573" => "GoldWave Cue Points",
649
- "4D754D4C" => "MusicML", "46696361" => "CUE Splitter",
650
- "46746F6C" => "flac-tools", "5346464C" => "Sound Font FLAC",
651
- "7065656D" => "Parseable Embedded Extensible Metadata", "74756E65" => "TagTuner",
652
- "786D6364" => "xmcd"}
633
+ app_id = { '41544348' => 'Flac File', '43756573' => 'GoldWave Cue Points',
634
+ '4D754D4C' => 'MusicML', '46696361' => 'CUE Splitter',
635
+ '46746F6C' => 'flac-tools', '5346464C' => 'Sound Font FLAC',
636
+ '7065656D' => 'Parseable Embedded Extensible Metadata', '74756E65' => 'TagTuner',
637
+ '786D6364' => 'xmcd' }
653
638
 
654
- @application['name'] = "#{app_id[@application['ID']]}"
639
+ @application['name'] = app_id[@application['ID']].to_s
655
640
 
656
- # We only know how to parse data from 'Flac File'...
657
- if @application['ID'] = "41544348"
658
- parse_flac_file_contents(@application['block_size'] - 4)
659
- else
660
- @application['raw_data'] = @fp.read(@application['block_size'] - 4)
661
- end
662
- rescue
663
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_APPLICATION"
641
+ # We only know how to parse data from 'Flac File'...
642
+ if @application['ID'] == '41544348'
643
+ parse_flac_file_contents(@application['block_size'] - 4)
644
+ else
645
+ @application['raw_data'] = @fp.read(@application['block_size'] - 4)
664
646
  end
647
+ rescue StandardError => e
648
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_APPLICATION: #{e.message}"
665
649
  end
666
650
 
667
651
  # Unlike most values in the Flac header
@@ -671,163 +655,156 @@ class FlacInfo
671
655
  # @tags is a more user-friendly data structure with the values
672
656
  # separated into key=value pairs
673
657
  def parse_vorbis_comment
674
- begin
675
- @tags['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
676
- @tags['offset'] = @fp.tell
658
+ @tags['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
659
+ @tags['offset'] = @fp.tell
677
660
 
678
- @metadata_blocks[-1] << @tags['offset']
679
- @metadata_blocks[-1] << @tags['block_size']
661
+ @metadata_blocks[-1] << @tags['offset']
662
+ @metadata_blocks[-1] << @tags['block_size']
680
663
 
681
- vendor_length = @fp.read(4).reverse.unpack("B*")[0].to_i(2)
664
+ vendor_length = @fp.read(4).reverse.unpack1('B*').to_i(2)
682
665
 
683
- @tags['vendor_tag'] = @fp.read(vendor_length)
684
- user_comment_list_length = @fp.read(4).reverse.unpack("B*")[0].to_i(2)
666
+ @tags['vendor_tag'] = @fp.read(vendor_length)
667
+ user_comment_list_length = @fp.read(4).reverse.unpack1('B*').to_i(2)
685
668
 
686
- n = 0
687
- user_comment_list_length.times do
688
- length = @fp.read(4).reverse.unpack("B*")[0].to_i(2)
689
- @comment[n] = @fp.read(length)
690
- n += 1
691
- end
692
-
693
- @comment.each do |c|
694
- k,v = c.split("=")
695
- # Vorbis spec says we can have more than one identical comment ie:
696
- # comment[0]="Artist=Charlie Parker"
697
- # comment[1]="Artist=Miles Davis"
698
- # so we just append the second and subsequent values to the first
699
- if @tags.has_key?(k)
700
- @tags[k] = "#{@tags[k]}, #{v}"
701
- else
702
- @tags[k] = v
703
- end
704
- end
669
+ n = 0
670
+ user_comment_list_length.times do
671
+ length = @fp.read(4).reverse.unpack1('B*').to_i(2)
672
+ @comment[n] = @fp.read(length)
673
+ n += 1
674
+ end
705
675
 
706
- rescue
707
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_VORBIS_COMMENT"
676
+ @comment.each do |c|
677
+ k, v = c.split('=', 2)
678
+ # Vorbis spec says we can have more than one identical comment ie:
679
+ # comment[0]="Artist=Charlie Parker"
680
+ # comment[1]="Artist=Miles Davis"
681
+ # so we just append the second and subsequent values to the first
682
+ @tags[k] = if @tags.key?(k)
683
+ "#{@tags[k]}, #{v}"
684
+ else
685
+ v
686
+ end
708
687
  end
688
+
689
+ rescue StandardError => e
690
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_VORBIS_COMMENT: #{e.message}"
709
691
  end
710
692
 
711
693
  # padding is just a bunch of '0' bytes
712
694
  def parse_padding
713
- begin
714
- @padding['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
715
- @padding['offset'] = @fp.tell
695
+ @padding['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
696
+ @padding['offset'] = @fp.tell
716
697
 
717
- @metadata_blocks[-1] << @padding['offset']
718
- @metadata_blocks[-1] << @padding['block_size']
698
+ @metadata_blocks[-1] << @padding['offset']
699
+ @metadata_blocks[-1] << @padding['block_size']
719
700
 
720
- @fp.seek(@padding['block_size'], IO::SEEK_CUR)
721
- rescue
722
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PADDING"
723
- end
701
+ @fp.seek(@padding['block_size'], IO::SEEK_CUR)
702
+ rescue StandardError => e
703
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PADDING: #{e.message}"
724
704
  end
725
705
 
726
706
  def parse_streaminfo
727
- begin
728
- @streaminfo['block_size'] = @fp.read(3).unpack("B*")[0].to_i(2)
729
- @streaminfo['offset'] = @fp.tell
730
-
731
- @metadata_blocks[-1] << @streaminfo['offset']
732
- @metadata_blocks[-1] << @streaminfo['block_size']
733
-
734
- @streaminfo['minimum_block'] = @fp.read(2).reverse.unpack("v*")[0]
735
- @streaminfo['maximum_block'] = @fp.read(2).reverse.unpack("v*")[0]
736
- @streaminfo['minimum_frame'] = @fp.read(3).reverse.unpack("v*")[0]
737
- @streaminfo['maximum_frame'] = @fp.read(3).reverse.unpack("v*")[0]
738
-
739
- # 64 bits in MSB order
740
- bitstring = @fp.read(8).unpack("B*")[0]
741
- # 20 bits :: Sample rate in Hz.
742
- @streaminfo['samplerate'] = sprintf("%u", "0b#{bitstring[0..19]}").to_i
743
- # 3 bits :: (number of channels)-1
744
- @streaminfo['channels'] = sprintf("%u", "0b#{bitstring[20..22]}").to_i + 1
745
- # 5 bits :: (bits per sample)-1
746
- @streaminfo['bits_per_sample'] = sprintf("%u", "0b#{bitstring[23..27]}").to_i + 1
747
- # 36 bits :: Total samples in stream.
748
- @streaminfo['total_samples'] = sprintf("%u", "0b#{bitstring[28..63]}").to_i
749
-
750
- # 128 bits :: MD5 signature of the unencoded audio data.
751
- @streaminfo['md5'] = @fp.read(16).unpack("H32")[0]
752
- rescue
753
- raise FlacInfoReadError, "Could not parse METADATA_BLOCK_STREAMINFO"
754
- end
707
+ @streaminfo['block_size'] = @fp.read(3).unpack1('B*').to_i(2)
708
+ @streaminfo['offset'] = @fp.tell
709
+
710
+ @metadata_blocks[-1] << @streaminfo['offset']
711
+ @metadata_blocks[-1] << @streaminfo['block_size']
712
+
713
+ @streaminfo['minimum_block'] = @fp.read(2).reverse.unpack1('v*')
714
+ @streaminfo['maximum_block'] = @fp.read(2).reverse.unpack1('v*')
715
+ @streaminfo['minimum_frame'] = @fp.read(3).reverse.unpack1('v*')
716
+ @streaminfo['maximum_frame'] = @fp.read(3).reverse.unpack1('v*')
717
+
718
+ # 64 bits in MSB order
719
+ bitstring = @fp.read(8).unpack1('B*')
720
+
721
+ # 20 bits :: Sample rate in Hz.
722
+ @streaminfo['samplerate'] = format('%u', "0b#{bitstring[0..19]}").to_i
723
+
724
+ # 3 bits :: (number of channels)-1
725
+ @streaminfo['channels'] = format('%u', "0b#{bitstring[20..22]}").to_i + 1
726
+
727
+ # 5 bits :: (bits per sample)-1
728
+ @streaminfo['bits_per_sample'] = format('%u', "0b#{bitstring[23..27]}").to_i + 1
729
+
730
+ # 36 bits :: Total samples in stream.
731
+ @streaminfo['total_samples'] = format('%u', "0b#{bitstring[28..63]}").to_i
732
+
733
+ # 128 bits :: MD5 signature of the unencoded audio data.
734
+ @streaminfo['md5'] = @fp.read(16).unpack1('H32')
735
+ rescue StandardError => e
736
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_STREAMINFO: #{e.message}"
755
737
  end
756
738
 
757
739
  # See http://firestuff.org/flacfile/
758
740
  def parse_flac_file_contents(size)
759
- begin
760
- @flac_file = {}
761
- desc_length = @fp.read(1).unpack("C")[0]
762
- @flac_file['description'] = @fp.read(desc_length)
763
- mime_length = @fp.read(1).reverse.unpack("C")[0]
764
- @flac_file['mime_type'] = @fp.read(mime_length)
765
- size = size - 2 - desc_length - mime_length
766
- @flac_file['raw_data'] = @fp.read(size)
767
- rescue
768
- raise FlacInfoReadError, "Could not parse Flac File data"
769
- end
741
+ @flac_file = {}
742
+ desc_length = @fp.read(1).unpack1('C')
743
+ @flac_file['description'] = @fp.read(desc_length)
744
+ mime_length = @fp.read(1).reverse.unpack1('C')
745
+ @flac_file['mime_type'] = @fp.read(mime_length)
746
+ size = size - 2 - desc_length - mime_length
747
+ @flac_file['raw_data'] = @fp.read(size)
748
+ rescue StandardError => e
749
+ raise FlacInfoReadError, "Could not parse Flac File data: #{e.message}"
770
750
  end
771
751
 
772
752
  # Here we begin the FlacInfo write methods
773
753
 
774
-
775
754
  # Build a block header given a type, a size, and whether it is last
776
755
  def build_block_header(type, size, last)
777
- begin
778
- bit_string = sprintf("%b%7b", last, type).gsub(" ","0")
779
- block_header_s = [bit_string].pack("B*")
780
- block_header_s += [size].pack("VX").reverse # size is 3 bytes
781
- rescue
782
- raise FlacInfoWriteError, "error building block header"
783
- end
756
+ bit_string = format('%b%7b', last, type).gsub(' ', '0')
757
+ block_header_s = [bit_string].pack('B*')
758
+ block_header_s + [size].pack('VX').reverse # size is 3 bytes
759
+ rescue StandardError => e
760
+ raise FlacInfoWriteError, "error building block header: #{e.message}"
784
761
  end
785
762
 
786
763
  # Build a string of packed data for the Vorbis comments
787
764
  def build_vorbis_comment_block
788
- begin
789
- vorbis_comm_s = [@tags["vendor_tag"].length].pack("V")
790
- vorbis_comm_s += [@tags["vendor_tag"]].pack("A*")
791
- vorbis_comm_s += [@comment.length].pack("V")
792
- @comment.each do |c|
793
- vorbis_comm_s += [c.bytesize].pack("V")
794
- vorbis_comm_s += [c].pack("A*")
795
- end
796
- vorbis_comm_s
797
- rescue
798
- raise FlacInfoWriteError, "error building vorbis comment block"
765
+ vorbis_comm_s = [@tags['vendor_tag'].length].pack('V')
766
+ vorbis_comm_s += [@tags['vendor_tag']].pack('A*')
767
+ vorbis_comm_s += [@comment.length].pack('V')
768
+
769
+ @comment.each do |c|
770
+ vorbis_comm_s += [c.bytesize].pack('V')
771
+ vorbis_comm_s += [c].pack('A*')
799
772
  end
773
+
774
+ vorbis_comm_s
775
+ rescue StandardError => e
776
+ raise FlacInfoWriteError, "error building vorbis comment block: #{e.message}"
800
777
  end
801
778
 
802
779
  def write_to_disk
803
- if @comments_changed == nil
804
- raise FlacInfoWriteError, "No changes to write"
805
- else
806
- vcd = build_vorbis_comment_block # Build the VORBIS_COMMENT data
807
- vch = build_block_header(4, vcd.length, 0) # Build the VORBIS_COMMENT header
808
- end
780
+ raise FlacInfoWriteError, 'No changes to write' if @comments_changed.nil?
781
+
782
+ # Build the VORBIS_COMMENT data
783
+ vcd = build_vorbis_comment_block
784
+ # Build the VORBIS_COMMENT header
785
+ vch = build_block_header(4, vcd.length, 0)
809
786
 
810
787
  # Determine if we can shuffle the data or if a rewrite is necessary
811
788
  begin
812
- if not @padding.has_key?("block_size") or vcd.length > @padding['block_size']
789
+ if !@padding.key?('block_size') || (vcd.length > @padding['block_size'])
813
790
  rewrite(vcd, vch) # Rewriting is simpler but more expensive
814
791
  else
815
792
  shuffle(vcd, vch) # Shuffling is more complicated but cheaper
816
793
  end
817
- parse_flac_meta_blocks # Parse the file again to update new values
818
- return true
819
- rescue
820
- raise FlacInfoWriteError, "error writing new data to #{@filename}"
794
+ parse_flac_meta_blocks # Parse the file again to update new values
795
+ true
796
+ rescue StandardError => e
797
+ raise FlacInfoWriteError, "error writing new data to #{@filename}: #{e.message}"
821
798
  end
822
799
  end
823
800
 
824
801
  # Shuffle the data and update the PADDING block
825
802
  def shuffle(vcd, vch)
826
- flac = File.new(@filename, "r+b")
803
+ flac = File.new(@filename, 'r+b')
827
804
  flac.binmode # For Windows folks...
828
805
 
829
806
  # Position ourselves at end of current Vorbis block
830
- flac.seek((@tags['offset'] + @tags['block_size']), IO::SEEK_CUR)
807
+ flac.seek(@tags['offset'] + @tags['block_size'], IO::SEEK_CUR)
831
808
  # The data we need to shuffle starts at current position and ends at
832
809
  # the beginning of the padding block, so the size we need to read is:
833
810
  #
@@ -836,13 +813,13 @@ class FlacInfo
836
813
  size_to_read = (@padding['offset'] - 4) - flac.tell
837
814
  data_to_shuffle = flac.read(size_to_read)
838
815
 
839
- flac.seek((@tags['offset'] - 4), IO::SEEK_SET)
816
+ flac.seek(@tags['offset'] - 4, IO::SEEK_SET)
840
817
  flac.write(vch) # Write the VORBIS_COMMENT header
841
818
  flac.write(vcd) # Write the VORBIS_COMMENT data
842
819
  flac.write(data_to_shuffle) # Write the shuffled data
843
820
 
844
821
  new_padding_size = @padding['block_size'] - (vcd.length - @tags['block_size'])
845
- ph = build_block_header(1, new_padding_size, 1) # Build the new PADDING header
822
+ ph = build_block_header(1, new_padding_size, 1) # Build the new PADDING header
846
823
 
847
824
  flac.write(ph) # Write the new PADDING header
848
825
  flac.close # ...and we're done
@@ -850,12 +827,12 @@ class FlacInfo
850
827
 
851
828
  # Rewrite the entire file
852
829
  def rewrite(vcd, vch)
853
- flac = File.new(@filename, "r+b")
830
+ flac = File.new(@filename, 'r+b')
854
831
  flac.binmode # For Windows folks...
855
832
 
856
- flac.seek((@tags['offset'] + @tags['block_size']), IO::SEEK_CUR)
857
- rest_of_file = flac.read()
858
- flac.seek((@tags['offset'] - 4), IO::SEEK_SET)
833
+ flac.seek(@tags['offset'] + @tags['block_size'], IO::SEEK_CUR)
834
+ rest_of_file = flac.read
835
+ flac.seek(@tags['offset'] - 4, IO::SEEK_SET)
859
836
 
860
837
  flac.write(vch) # Write the VORBIS_COMMENT header
861
838
  flac.write(vcd) # Write the VORBIS_COMMENT data
@@ -866,66 +843,64 @@ class FlacInfo
866
843
 
867
844
  # remove the padding block
868
845
  def remove_padding_block
869
- begin
870
- new_last_block = @metadata_blocks[-2]
846
+ new_last_block = @metadata_blocks[-2]
871
847
 
872
- flac = File.new(@filename, "r+b")
873
- flac.binmode
848
+ flac = File.new(@filename, 'r+b')
849
+ flac.binmode
874
850
 
875
- flac.seek((@padding['offset'] + @padding['block_size']), IO::SEEK_CUR)
876
- rest_of_file = flac.read()
851
+ flac.seek(@padding['offset'] + @padding['block_size'], IO::SEEK_SET)
852
+ rest_of_file = flac.read
877
853
 
878
- flac.seek((@padding['offset'] - 4), IO::SEEK_SET)
879
- flac.write(rest_of_file)
854
+ flac.seek(@padding['offset'] - 4, IO::SEEK_SET)
855
+ flac.write(rest_of_file)
856
+ # Truncate the file at the 'new' end of file.
857
+ flac.truncate(flac.tell)
880
858
 
881
- nbh = build_block_header(new_last_block[1], new_last_block[4], 1)
859
+ nbh = build_block_header(new_last_block[1], new_last_block[4], 1)
882
860
 
883
- flac.seek((new_last_block[3] - 4), IO::SEEK_SET)
884
- flac.write(nbh)
885
- flac.close()
861
+ flac.seek(new_last_block[3] - 4, IO::SEEK_SET)
862
+ flac.write(nbh)
863
+ flac.close
886
864
 
887
- parse_flac_meta_blocks # Parse the file again to update new values
888
- true
889
- rescue
890
- false
891
- end
865
+ parse_flac_meta_blocks # Parse the file again to update new values
866
+ true
867
+ rescue StandardError => e
868
+ raise FlacInfoWriteError, "Could not update padding block: #{e.message}"
892
869
  end
893
870
 
894
871
  def build_padding_block(size)
895
- begin
896
- old_last_block = @metadata_blocks[-1]
872
+ old_last_block = @metadata_blocks[-1]
897
873
 
898
- a = Array.new(size / 2, 0)
899
- pbd = a.pack("v*")
900
- pbh = build_block_header(1, size, 1)
874
+ a = Array.new(size / 2, 0)
875
+ pbd = a.pack('v*')
876
+ pbh = build_block_header(1, size, 1)
901
877
 
902
- flac = File.new(@filename, "r+b")
903
- flac.binmode
878
+ flac = File.new(@filename, 'r+b')
879
+ flac.binmode
904
880
 
905
- flac.seek((old_last_block[4] + old_last_block[3]), IO::SEEK_CUR)
906
- co = flac.tell
907
- rest_of_file = flac.read()
908
- flac.seek(co, IO::SEEK_SET)
881
+ flac.seek(old_last_block[4] + old_last_block[3], IO::SEEK_SET)
882
+ co = flac.tell
883
+ rest_of_file = flac.read
884
+ flac.seek(co, IO::SEEK_SET)
909
885
 
910
- flac.write(pbh)
911
- flac.write(pbd)
912
- flac.write(rest_of_file)
913
- nbh = build_block_header(old_last_block[1], old_last_block[4], 0)
886
+ flac.write(pbh)
887
+ flac.write(pbd)
888
+ flac.write(rest_of_file)
889
+ nbh = build_block_header(old_last_block[1], old_last_block[4], 0)
914
890
 
915
- flac.seek((old_last_block[3] - 4), IO::SEEK_SET)
916
- flac.write(nbh)
891
+ flac.seek(old_last_block[3] - 4, IO::SEEK_SET)
892
+ flac.write(nbh)
917
893
 
918
- flac.close()
919
- parse_flac_meta_blocks # Parse the file again to update new values
920
- true
921
- rescue
922
- false
923
- end
894
+ flac.close
895
+ parse_flac_meta_blocks # Parse the file again to update new values
896
+ true
897
+ rescue StandardError => e
898
+ raise FlacInfoWriteError, "Could not update padding block: #{e.message}"
924
899
  end
925
900
  end
926
901
 
927
902
  # If called directly from the command line, run meta_flac on each argument
928
- if __FILE__ == $0
903
+ if __FILE__ == $PROGRAM_NAME
929
904
  ARGV.each do |filename|
930
905
  FlacInfo.new(filename).meta_flac
931
906
  puts
metadata CHANGED
@@ -1,51 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flacinfo-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.0'
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Kirby
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2014-08-29 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: |2
14
13
  flacinfo-rb is a pure Ruby library for low-level access to Flac files.
15
14
  You can use it to read, set, or delete 'id3' like data (Vorbis comments),
16
15
  delete, add, or resize padding blocks, and so on.
17
- email: bulliver@gmail.com
16
+ email: darren@dragonbyte.ca
18
17
  executables: []
19
18
  extensions: []
20
19
  extra_rdoc_files:
21
- - README
20
+ - README.md
22
21
  files:
23
- - README
22
+ - README.md
24
23
  - lib/flacinfo.rb
25
24
  - test/test-flacinfo.rb
26
25
  - test/test.flac
27
26
  homepage: https://github.com/DarrenKirby/flacinfo-rb
28
27
  licenses:
29
- - GPL-3.0
28
+ - GPL-2.0-only
30
29
  metadata: {}
31
- post_install_message:
32
30
  rdoc_options: []
33
31
  require_paths:
34
32
  - lib
35
33
  required_ruby_version: !ruby/object:Gem::Requirement
36
34
  requirements:
37
- - - '>='
35
+ - - ">="
38
36
  - !ruby/object:Gem::Version
39
- version: '0'
37
+ version: 2.7.0
40
38
  required_rubygems_version: !ruby/object:Gem::Requirement
41
39
  requirements:
42
- - - '>='
40
+ - - ">="
43
41
  - !ruby/object:Gem::Version
44
42
  version: '0'
45
43
  requirements: []
46
- rubyforge_project:
47
- rubygems_version: 2.0.14
48
- signing_key:
44
+ rubygems_version: 4.0.10
49
45
  specification_version: 4
50
46
  summary: Pure Ruby library for accessing metadata from Flac files
51
47
  test_files:
data/README DELETED
@@ -1,47 +0,0 @@
1
- :: flacinfo-rb ::
2
- Author: Darren Kirby
3
- mailto:bulliver@gmail.com
4
- License: GPL3
5
-
6
- = Quick API docs =
7
-
8
- == Initializing ==
9
-
10
- require 'flacinfo'
11
- foo = FlacInfo.new("someSong.flac")
12
-
13
- == Public attributes ==
14
-
15
- streaminfo :: hash of STREAMINFO block metadata
16
- seektable :: hash of arrays of seek points
17
- comment :: array of VORBIS COMMENT block metadata
18
- tags :: user-friendly hash of Vorbis comment metadata key=value pairs
19
- application :: hash of APPLICATION block metadata
20
- padding :: hash of PADDING block metadata
21
- cuesheet :: hash of CUESHEET block metadata
22
- picture :: hash of PICTURE block metadata
23
- flac_file :: hash of APPLICATION Id 0x41544348 (Flac File) metadata if present
24
-
25
- == Public methods ==
26
-
27
- comment_add :: adds a comment
28
- comment_del :: deletes a comment
29
- hastag('str') :: returns true if tags['str'] exists
30
- meta_flac :: prints all META BLOCKS. (Mostly) equivelant to 'metaflac --list'
31
- padding_add!(b) :: adds a PADDING block of size 'b' or 4096 bytes
32
- padding_del! :: deletes the PADDING block
33
- padding_resize! :: resizes (grow or shrink) a padding block to size 'b' or 4096 bytes
34
- print_seektable :: pretty-print seektable hash
35
- print_streaminfo :: pretty-print streaminfo hash
36
- print_tags :: pretty-print tags hash
37
- raw_data_dump(?) :: if passed a filename it will dump flac_file['raw_data'] to that file,
38
- otherwise it will dump it to the console (even if binary!)
39
- update! :: writes comment changes to disk
40
- write_picture(?) :: write image from PICTURE block(s) to optional file
41
-
42
- The public methods and attributes are very well documented in the source itself. Please read
43
- there if you don't understand any of this. You can also use Rdoc to generate HTML documentation.
44
-
45
- HELP: flacinfo-rb still does not parse cuesheets, as I have never encountered a flac file
46
- that contains one. If you have a flac file with a cuesheet please consider emailing it to
47
- me so I can add this remaining bit of code.