flacinfo-rb 0.3.1 → 0.4

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.
data/README CHANGED
@@ -1,4 +1,4 @@
1
- :: flacinfo-rb ::
1
+ :: FlacInfo-rb ::
2
2
  Author: Darren Kirby
3
3
  mailto:bulliver@badcomputer.org
4
4
  License: Ruby
@@ -14,7 +14,7 @@ foo = FlacInfo.new("someSong.flac")
14
14
 
15
15
  streaminfo :: hash of STREAMINFO block metadata
16
16
  seektable :: hash of arrays of seek points
17
- comment :: array of VORBIS COMMENT block metadata
17
+ comment :: array of VORBIS COMMENT block metadata
18
18
  tags :: user-friendly hash of Vorbis comment metadata key=value pairs
19
19
  application :: hash of APPLICATION block metadata
20
20
  padding :: hash of PADDING block metadata
@@ -24,13 +24,19 @@ flac_file :: hash of APPLICATION Id 0x41544348 (Flac File) metadata if presen
24
24
 
25
25
  == Public methods ==
26
26
 
27
- print_streaminfo :: pretty-print streaminfo hash
27
+ comment_add :: adds a comment
28
+ comment_del :: deletes a comment
28
29
  hastag('str') :: returns true if tags['str'] exists
29
- print_tags :: pretty-print tags hash
30
- print_seektable :: pretty-print seektable hash
31
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
32
37
  raw_data_dump(?) :: if passed a filename it will dump flac_file['raw_data'] to that file,
33
- otherwise it will dump it to the console (even if binary!)
38
+ otherwise it will dump it to the console (even if binary!)
39
+ update! :: writes comment changes to disk
34
40
  write_picture(?) :: write image from PICTURE block(s) to optional file
35
41
 
36
42
  For more/different documentation see http://badcomputer.org/unix/code/flacinfo/
data/lib/flacinfo.rb CHANGED
@@ -17,9 +17,10 @@
17
17
  # = Copyright and Disclaimer
18
18
  #
19
19
  # Copyright:: (c) 2006, 2007 Darren Kirby
20
- # FlacInfo is free software.
21
- # No warranty is provided and the author cannot accept responsibility
22
- # for lost or damaged files.
20
+ #
21
+ # FlacInfo is free software. No warranty is provided and the author
22
+ # cannot accept responsibility for lost or damaged files.
23
+ #
23
24
  # License:: Ruby
24
25
  # Author:: Darren Kirby (mailto:bulliver@badcomputer.org)
25
26
  # Website:: http://badcomputer.org/unix/code/flacinfo/index.bot
@@ -53,7 +54,7 @@ end
53
54
  # All attributes will be present but empty if the associated block is not present in the Flac file,
54
55
  # except for 'picture' which will have the key 'n' with the value '0'.
55
56
  # All 'offset' and 'block_size' values do not include the block header. All block headers are 4 bytes
56
- # no matter the type, so if you need the offset including the header, subtract 4. If you need the size
57
+ # no matter the type, so if you need the offset including the header, subtract 4. If you need the size
57
58
  # including the header, add 4.
58
59
  class FlacInfo
59
60
  # A list of 'standard field names' according to the Vorbis Comment specification. It is certainly
@@ -321,19 +322,15 @@ class FlacInfo
321
322
  nil
322
323
  end
323
324
 
324
- # Writes changes to disk
325
+ # Writes Vorbis tag changes to disk
325
326
  #
326
327
  # :call-seq:
327
- # FlacInfo.update -> bool
328
+ # FlacInfo.update! -> bool
328
329
  #
329
330
  # Returns true if write was successful, false otherwise.
330
331
  #
331
- def update
332
- if write_to_disk
333
- return true
334
- else
335
- return false
336
- end
332
+ def update!
333
+ write_to_disk ? true : false
337
334
  end
338
335
 
339
336
  # Adds a new comment to the comment array
@@ -342,8 +339,8 @@ class FlacInfo
342
339
  # FlacInfo.comment_add(str) -> bool
343
340
  #
344
341
  # 'str' must be in the form 'name=value', or 'name=' if you want to
345
- # set an empty value for a particular tag.
346
- # Returns 'true' if successful, false otherwise.
342
+ # set an empty value for a particular tag. Returns 'true' if successful,
343
+ # false otherwise. Remember to call 'update!' to write changes to the file.
347
344
  #
348
345
  def comment_add(name)
349
346
  if name !~ /\w=/ # We accept 'name=' in case you want to leave the value empty
@@ -366,7 +363,8 @@ class FlacInfo
366
363
  # If 'str' is in the form 'name=value' only exact matches
367
364
  # will be deleted. If 'str' is in the form 'name' any and all
368
365
  # comments named 'name' will be deleted. Returns 'true' if a
369
- # comment was deleted, false otherwise.
366
+ # comment was deleted, false otherwise. Remember to call
367
+ # 'update!' to write changes to the file.
370
368
  #
371
369
  def comment_del(name)
372
370
  bc = Array.new(@comment) # We need a copy
@@ -384,6 +382,55 @@ class FlacInfo
384
382
  end
385
383
  end
386
384
 
385
+ # Adds a padding block
386
+ #
387
+ # :call-seq:
388
+ # FlacInfo.padding_add!(size) --> Boolean
389
+ #
390
+ # 'size' is an optional integer argument for the
391
+ # size of the padding block. It defaults to 4096 bytes.
392
+ # Returns true if successful, else false.
393
+ #
394
+ def padding_add!(size=4096)
395
+ @metadata_blocks.each do |type|
396
+ if type[0] == "padding"
397
+ raise FlacInfoError, "PADDING block exists. Use 'padding_resize!'"
398
+ end
399
+ end
400
+ build_padding_block(size) ? true : false
401
+ end
402
+
403
+ # Removes a padding block
404
+ #
405
+ # :call-seq:
406
+ # FlacInfo.padding_del!() --> Boolean
407
+ #
408
+ # Returns true if the padding block is
409
+ # successfully removed else false.
410
+ #
411
+ def padding_del!
412
+ remove_padding_block ? true : false
413
+ end
414
+
415
+ # Resizes a padding block
416
+ #
417
+ # :call-seq:
418
+ # FlacInfo.padding_resize!(size) --> Boolean
419
+ #
420
+ # 'size' is an optional integer argument for the
421
+ # size of the new padding block. It defaults to 4096 bytes.
422
+ # Returns true if successful, else false.
423
+ #
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
432
+ end
433
+
387
434
  #--
388
435
  # This cleans up the output when using FlacInfo in irb
389
436
  def inspect #:nodoc:
@@ -486,7 +533,7 @@ class FlacInfo
486
533
  header = @fp.read(4)
487
534
  # First 4 bytes must be 0x66, 0x4C, 0x61, and 0x43
488
535
  if header != 'fLaC'
489
- raise FlacInfoError, "#{@filename} does not appear to be a valid Flac file"
536
+ raise FlacInfoReadError, "#{@filename} does not appear to be a valid Flac file"
490
537
  end
491
538
 
492
539
  typetable = { 0 => "streaminfo", 1 => "padding", 2 => "application",
@@ -501,12 +548,13 @@ class FlacInfo
501
548
  # first bit = Last-metadata-block flag
502
549
  # bits 2-8 = BLOCK_TYPE. See typetable above
503
550
  block_header = @fp.read(1).unpack("B*")[0]
551
+ #puts block_header
504
552
  lastheader = block_header[0].to_i & 1
505
553
  type = sprintf("%u", "0b#{block_header[1..7]}").to_i
506
554
  @metadata_blocks << [typetable[type], type, lastheader]
507
555
 
508
556
  if type >= typetable.size
509
- raise FlacInfoError, "Invalid block header type"
557
+ raise FlacInfoReadError, "Invalid block header type"
510
558
  end
511
559
 
512
560
  pos += 1
@@ -538,7 +586,7 @@ class FlacInfo
538
586
  end
539
587
 
540
588
  rescue
541
- raise FlacInfoError, "Could not parse METADATA_BLOCK_SEEKTABLE"
589
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_SEEKTABLE"
542
590
  end
543
591
  end
544
592
 
@@ -553,7 +601,7 @@ class FlacInfo
553
601
 
554
602
  @fp.seek(@cuesheet['block_size'], IO::SEEK_CUR)
555
603
  rescue
556
- raise FlacInfoError, "Could not parse METADATA_BLOCK_CUESHEET"
604
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_CUESHEET"
557
605
  end
558
606
  end
559
607
 
@@ -591,7 +639,7 @@ class FlacInfo
591
639
 
592
640
  @fp.seek((@picture[n]['raw_data_length']), IO::SEEK_CUR)
593
641
  rescue
594
- raise FlacInfoError, "Could not parse METADATA_BLOCK_PICTURE"
642
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PICTURE"
595
643
  end
596
644
  end
597
645
 
@@ -620,7 +668,7 @@ class FlacInfo
620
668
  @application['raw_data'] = @fp.read(@application['block_size'] - 4)
621
669
  end
622
670
  rescue
623
- raise FlacInfoError, "Could not parse METADATA_BLOCK_APPLICATION"
671
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_APPLICATION"
624
672
  end
625
673
  end
626
674
 
@@ -664,7 +712,7 @@ class FlacInfo
664
712
  end
665
713
 
666
714
  rescue
667
- raise FlacInfoError, "Could not parse METADATA_BLOCK_VORBIS_COMMENT"
715
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_VORBIS_COMMENT"
668
716
  end
669
717
  end
670
718
 
@@ -679,7 +727,7 @@ class FlacInfo
679
727
 
680
728
  @fp.seek(@padding['block_size'], IO::SEEK_CUR)
681
729
  rescue
682
- raise FlacInfoError, "Could not parse METADATA_BLOCK_PADDING"
730
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_PADDING"
683
731
  end
684
732
  end
685
733
 
@@ -710,7 +758,7 @@ class FlacInfo
710
758
  # 128 bits :: MD5 signature of the unencoded audio data.
711
759
  @streaminfo['md5'] = @fp.read(16).unpack("H32")[0]
712
760
  rescue
713
- raise FlacInfoError, "Could not parse METADATA_BLOCK_STREAMINFO"
761
+ raise FlacInfoReadError, "Could not parse METADATA_BLOCK_STREAMINFO"
714
762
  end
715
763
  end
716
764
 
@@ -725,7 +773,7 @@ class FlacInfo
725
773
  size = size - 2 - desc_length - mime_length
726
774
  @flac_file['raw_data'] = @fp.read(size)
727
775
  rescue
728
- raise FlacInfoError, "Could not parse Flac File data"
776
+ raise FlacInfoReadError, "Could not parse Flac File data"
729
777
  end
730
778
  end
731
779
 
@@ -824,6 +872,64 @@ class FlacInfo
824
872
  flac.close
825
873
  end
826
874
 
875
+ # remove the padding block
876
+ def remove_padding_block
877
+ begin
878
+ new_last_block = @metadata_blocks[-2]
879
+
880
+ flac = File.new(@filename, "r+b")
881
+ flac.binmode
882
+
883
+ flac.seek((@padding['offset'] + @padding['block_size']), IO::SEEK_CUR)
884
+ rest_of_file = flac.read()
885
+
886
+ flac.seek((@padding['offset'] - 4), IO::SEEK_SET)
887
+ flac.write(rest_of_file)
888
+
889
+ nbh = build_block_header(new_last_block[1], new_last_block[4], 1)
890
+
891
+ flac.seek((new_last_block[3] - 4), IO::SEEK_SET)
892
+ flac.write(nbh)
893
+ flac.close()
894
+
895
+ parse_flac_meta_blocks # Parse the file again to update new values
896
+ true
897
+ rescue
898
+ false
899
+ end
900
+ end
901
+
902
+ def build_padding_block(size)
903
+ begin
904
+ old_last_block = @metadata_blocks[-1]
905
+
906
+ a = Array.new(size / 2, 0)
907
+ pbd = a.pack("v*")
908
+ pbh = build_block_header(1, size, 1)
909
+
910
+ flac = File.new(@filename, "r+b")
911
+ flac.binmode
912
+
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)
917
+
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)
922
+
923
+ flac.seek((old_last_block[3] - 4), IO::SEEK_SET)
924
+ flac.write(nbh)
925
+
926
+ flac.close()
927
+ parse_flac_meta_blocks # Parse the file again to update new values
928
+ true
929
+ rescue
930
+ false
931
+ end
932
+ end
827
933
  end
828
934
 
829
935
  # If called directly from the command line, run meta_flac on each argument
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4
+
5
+ require 'test/unit'
6
+ require 'flacinfo'
7
+
8
+ class TestFlacInfo < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @flac = FlacInfo.new("test.flac")
12
+ end
13
+
14
+ def test_streaminfo
15
+ assert_equal(34, @flac.streaminfo['block_size'])
16
+ assert_equal(8, @flac.streaminfo['offset'])
17
+ assert_equal(4096, @flac.streaminfo['minimum_block'])
18
+ assert_equal(4096, @flac.streaminfo['maximum_block'])
19
+ assert_equal(4454, @flac.streaminfo['minimum_frame'])
20
+ assert_equal(7491, @flac.streaminfo['maximum_frame'])
21
+ assert_equal(44100, @flac.streaminfo['samplerate'])
22
+ assert_equal(2, @flac.streaminfo['channels'])
23
+ assert_equal(16, @flac.streaminfo['bits_per_sample'])
24
+ assert_equal(663552, @flac.streaminfo['total_samples'])
25
+ assert_equal("8cde6ba4d9b7458f1446215941ea5e1b", @flac.streaminfo['md5'])
26
+ end
27
+
28
+ def test_vorbis_comments
29
+ assert_equal(294, @flac.tags['block_size'])
30
+ assert_equal(46, @flac.tags['offset'])
31
+ assert_equal("test.flac", @flac.tags['TITLE'])
32
+ assert_equal("Darren Kirby", @flac.tags['ARTIST'])
33
+ assert_equal("No Thanks", @flac.tags['COPYRIGHT'])
34
+ assert_equal("Badcomputer Org.", @flac.tags['ORGANIZATION'])
35
+ assert_equal("A simple reference flac for the unit tests", @flac.tags['DESCRIPTION'])
36
+ assert_equal("Spoken Word", @flac.tags['GENRE'])
37
+ assert_equal("Wed Aug 15 14:28:07 2007", @flac.tags['DATE'])
38
+ assert_equal("IN UR COMPUTER READING UR FLACS", @flac.tags['LOCATION'])
39
+ assert_equal("reference libFLAC 1.2.0 20070715", @flac.tags['vendor_tag'])
40
+ end
41
+
42
+ def test_picture_one
43
+ assert_equal(2, @flac.picture["n"])
44
+ assert_equal(15921, @flac.picture[1]['block_size'])
45
+ assert_equal(344, @flac.picture[1]['offset'])
46
+ assert_equal("image/png", @flac.picture[1]['mime_type'])
47
+ assert_equal("Artist/performer", @flac.picture[1]['type_string'])
48
+ assert_equal(8, @flac.picture[1]['type_int'])
49
+ assert_equal("The author of flacinfo", @flac.picture[1]['description_string'])
50
+ assert_equal(0, @flac.picture[1]['n_colours'])
51
+ assert_equal(32, @flac.picture[1]['colour_depth'])
52
+ assert_equal(99, @flac.picture[1]['height'])
53
+ assert_equal(100, @flac.picture[1]['width'])
54
+ assert_equal(407, @flac.picture[1]['raw_data_offset'])
55
+ assert_equal(15858, @flac.picture[1]['raw_data_length'])
56
+ end
57
+
58
+ def test_picture_two
59
+ assert_equal(2, @flac.picture["n"])
60
+ assert_equal(22183, @flac.picture[2]['block_size'])
61
+ assert_equal(16269, @flac.picture[2]['offset'])
62
+ assert_equal("image/jpeg", @flac.picture[2]['mime_type'])
63
+ assert_equal("Other", @flac.picture[2]['type_string'])
64
+ assert_equal(0, @flac.picture[2]['type_int'])
65
+ assert_equal("A silly picture for the unit test", @flac.picture[2]['description_string'])
66
+ assert_equal(0, @flac.picture[2]['n_colours'])
67
+ assert_equal(24, @flac.picture[2]['colour_depth'])
68
+ assert_equal(353, @flac.picture[2]['height'])
69
+ assert_equal(507, @flac.picture[2]['width'])
70
+ assert_equal(16344, @flac.picture[2]['raw_data_offset'])
71
+ assert_equal(22108, @flac.picture[2]['raw_data_length'])
72
+ end
73
+
74
+ def test_padding
75
+ assert_equal(258, @flac.padding['block_size'])
76
+ assert_equal(38456, @flac.padding['offset'])
77
+ end
78
+
79
+ end
80
+
data/test/test.flac ADDED
Binary file
metadata CHANGED
@@ -3,14 +3,14 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: flacinfo-rb
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.1
7
- date: 2007-07-12 00:00:00 -06:00
8
- summary: Pure Ruby lib for accessing metadata (including Vorbis tags) from Flac files
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
9
  require_paths:
10
10
  - lib
11
11
  email: bulliver@badcomputer.org
12
12
  homepage: http://badcomputer.org/unix/code/flacinfo/
13
- rubyforge_project:
13
+ rubyforge_project: flacinfo-rb
14
14
  description:
15
15
  autorequire: flacinfo
16
16
  default_executable:
@@ -31,8 +31,9 @@ authors:
31
31
  files:
32
32
  - README
33
33
  - lib/flacinfo.rb
34
- test_files: []
35
-
34
+ test_files:
35
+ - test/test-flacinfo.rb
36
+ - test/test.flac
36
37
  rdoc_options: []
37
38
 
38
39
  extra_rdoc_files: