flacinfo-rb 0.3.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
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: