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