ruby-mp3info 0.6.13 → 0.6.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,12 @@
1
+ === 0.6.14 / 2011-06-17
2
+
3
+ * Added a check for nil that was seen causing problems when processing files. (thanks to Carl Hall)
4
+ * Fixed reading on win32, requires binary flag. (thanks to Jonas Tingeborn)
5
+ * Fixed white spaces. Replaced tabs with spaces to make the source readable on for users other than the original author. (thanks to Jonas Tingeborn)
6
+ * Add :parse_mp3 flag to new/open. (thanks to Dave Lee)
7
+ * Add benchmark for parsing performance. (thanks to Dave Lee)
8
+ * fixed ID3v2#io_position computing, so Mp3Info#audio_content() is correct now
9
+
1
10
  === 0.6.13 / 2009-05-26
2
11
 
3
12
  * fixed bad mapping of artist inside id3 2.2
@@ -1,6 +1,6 @@
1
1
  History.txt
2
2
  Manifest.txt
3
- README.txt
3
+ README.rdoc
4
4
  Rakefile
5
5
  install.rb
6
6
  lib/mp3info.rb
@@ -3,7 +3,7 @@ ruby-mp3info
3
3
  by Guillaume Pierronnet
4
4
  * http://ruby-mp3info.rubyforge.org/
5
5
  * http://rubyforge.org/projects/ruby-mp3info/
6
- * mercurial repository since v0.6.10: http://www.bitbucket.org/moumar/ruby-mp3info/overview/
6
+ * https://github.com/moumar/ruby-mp3info
7
7
 
8
8
  == DESCRIPTION:
9
9
 
data/Rakefile CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
+
6
+ Hoe.plugin :yard
7
+
5
8
  $:.unshift("./lib/")
6
9
  require 'mp3info'
7
10
 
@@ -10,10 +13,11 @@ Hoe.new('ruby-mp3info', Mp3Info::VERSION) do |p|
10
13
  p.author = "Guillaume Pierronnet"
11
14
  p.email = "moumar@rubyforge.org"
12
15
  p.summary = "ruby-mp3info is a pure-ruby library to retrieve low level informations on mp3 files and manipulate id3v1 and id3v2 tags"
13
- p.description = p.paragraphs_of('README.txt', 5..9).join("\n\n")
14
- p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
16
+ p.description = p.paragraphs_of('README.rdoc', 5..9).join("\n\n")
17
+ p.url = p.paragraphs_of('README.rdoc', 0).first.split(/\n/)[1..-1]
15
18
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
19
  p.remote_rdoc_dir = ''
20
+ p.rdoc_locations << "rubyforge.org:/var/www/gforge-projects/ruby-mp3info/"
17
21
  end
18
22
 
19
23
  # vim: syntax=Ruby
@@ -1,5 +1,4 @@
1
1
  # coding:utf-8
2
- # $Id: mp3info.rb 98 2008-09-16 11:07:31Z moumar $
3
2
  # License:: Ruby
4
3
  # Author:: Guillaume Pierronnet (mailto:moumar_AT__rubyforge_DOT_org)
5
4
  # Website:: http://ruby-mp3info.rubyforge.org/
@@ -18,7 +17,7 @@ end
18
17
 
19
18
  class Mp3Info
20
19
 
21
- VERSION = "0.6.13"
20
+ VERSION = "0.6.14"
22
21
 
23
22
  LAYER = [ nil, 3, 2, 1]
24
23
  BITRATE = {
@@ -161,7 +160,7 @@ class Mp3Info
161
160
 
162
161
  # Test the presence of an id3v1 tag in file +filename+
163
162
  def self.hastag1?(filename)
164
- File.open(filename) { |f|
163
+ File.open(filename,"rb") { |f|
165
164
  f.seek(-TAG1_SIZE, File::SEEK_END)
166
165
  f.read(3) == "TAG"
167
166
  }
@@ -169,7 +168,7 @@ class Mp3Info
169
168
 
170
169
  # Test the presence of an id3v2 tag in file +filename+
171
170
  def self.hastag2?(filename)
172
- File.open(filename) { |f|
171
+ File.open(filename,"rb") { |f|
173
172
  f.read(3) == "ID3"
174
173
  }
175
174
  end
@@ -191,15 +190,15 @@ class Mp3Info
191
190
 
192
191
  # Instantiate Mp3Info object with name +filename+.
193
192
  # options hash is used for ID3v2#new.
194
- # You can specify :parse_tags => false to disable the processing
193
+ # Specify :parse_tags => false to disable the processing
195
194
  # of the tags (read and write).
195
+ # Specify :parse_mp3 => false to disable processing of the mp3
196
196
  def initialize(filename, options = {})
197
197
  warn("#{self.class}::new() does not take block; use #{self.class}::open() instead") if block_given?
198
198
  @filename = filename
199
+ options = {:parse_mp3 => true, :parse_tags => true}.update(options)
199
200
  @tag_parsing_enabled = options.delete(:parse_tags)
200
- if @tag_parsing_enabled == nil
201
- @tag_parsing_enabled = true
202
- end
201
+ @mp3_parsing_enabled = options.delete(:parse_mp3)
203
202
  @id3v2_options = options
204
203
  reload
205
204
  end
@@ -249,74 +248,10 @@ class Mp3Info
249
248
  @tag_orig = @tag.dup
250
249
  end
251
250
 
252
-
253
- ### extracts MPEG info from MPEG header and stores it in the hash @mpeg
254
- ### head (fixnum) = valid 4 byte MPEG header
255
-
256
- found = false
257
-
258
- head = nil
259
- 5.times do
260
- head = find_next_frame()
261
- @first_frame_pos = @file.pos - 4
262
- current_frame = Mp3Info.get_frames_infos(head)
263
- @mpeg_version = current_frame[:mpeg_version]
264
- @layer = current_frame[:layer]
265
- @header[:error_protection] = head[16] == 0 ? true : false
266
- @bitrate = current_frame[:bitrate]
267
- @samplerate = current_frame[:samplerate]
268
- @header[:padding] = current_frame[:padding]
269
- @header[:private] = head[8] == 0 ? true : false
270
- @channel_mode = CHANNEL_MODE[@channel_num = Mp3Info.bits(head, 7,6)]
271
- @header[:mode_extension] = Mp3Info.bits(head, 5,4)
272
- @header[:copyright] = (head[3] == 1 ? true : false)
273
- @header[:original] = (head[2] == 1 ? true : false)
274
- @header[:emphasis] = Mp3Info.bits(head, 1,0)
275
- @vbr = false
276
- found = true
277
- break
251
+ if @mp3_parsing_enabled
252
+ parse_mp3
278
253
  end
279
254
 
280
- raise(Mp3InfoError, "Cannot find good frame") unless found
281
-
282
- seek = @mpeg_version == 1 ?
283
- (@channel_num == 3 ? 17 : 32) :
284
- (@channel_num == 3 ? 9 : 17)
285
-
286
- @file.seek(seek, IO::SEEK_CUR)
287
-
288
- vbr_head = @file.read(4)
289
- if vbr_head == "Xing"
290
- puts "Xing header (VBR) detected" if $DEBUG
291
- flags = @file.get32bits
292
- stream_size = frame_count = 0
293
- flags[1] == 1 and frame_count = @file.get32bits
294
- flags[2] == 1 and stream_size = @file.get32bits
295
- puts "#{frame_count} frames" if $DEBUG
296
- raise(Mp3InfoError, "bad VBR header") if frame_count.zero?
297
- # currently this just skips the TOC entries if they're found
298
- @file.seek(100, IO::SEEK_CUR) if flags[0] == 1
299
- #@vbr_quality = @file.get32bits if flags[3] == 1
300
-
301
- samples_per_frame = SAMPLES_PER_FRAME[@layer][@mpeg_version]
302
- @length = frame_count * samples_per_frame / Float(@samplerate)
303
-
304
- @bitrate = (((stream_size/frame_count)*@samplerate)/144) / 1024
305
- @vbr = true
306
- else
307
- # for cbr, calculate duration with the given bitrate
308
- stream_size = @file.stat.size - (hastag1? ? TAG1_SIZE : 0) - (@tag2.io_position || 0)
309
- @length = ((stream_size << 3)/1000.0)/@bitrate
310
- # read the first 100 frames and decide if the mp3 is vbr and needs full scan
311
- begin
312
- bitrate, length = frame_scan(100)
313
- if @bitrate != bitrate
314
- @vbr = true
315
- @bitrate, @length = frame_scan
316
- end
317
- rescue Mp3InfoInternalError
318
- end
319
- end
320
255
  ensure
321
256
  @file.close
322
257
  end
@@ -403,9 +338,9 @@ class Mp3Info
403
338
 
404
339
  # @tag1 has precedence over @tag
405
340
  if @tag1 == @tag1_orig
406
- @tag.each do |k, v|
407
- @tag1[k] = v
408
- end
341
+ @tag.each do |k, v|
342
+ @tag1[k] = v
343
+ end
409
344
  end
410
345
 
411
346
  # ruby-mp3info can only write v2.3 tags
@@ -452,28 +387,28 @@ class Mp3Info
452
387
  raise(Mp3InfoError, "file is not writable") unless File.writable?(@filename)
453
388
  tempfile_name = nil
454
389
  File.open(@filename, 'rb+') do |file|
455
- #if tag2 already exists, seek to end of it
456
- if @tag2.parsed?
457
- file.seek(@tag2.io_position)
458
- end
390
+ #if tag2 already exists, seek to end of it
391
+ if @tag2.parsed?
392
+ file.seek(@tag2.io_position)
393
+ end
459
394
  # if @file.read(3) == "ID3"
460
395
  # version_maj, version_min, flags = @file.read(3).unpack("CCB4")
461
396
  # unsync, ext_header, experimental, footer = (0..3).collect { |i| flags[i].chr == '1' }
462
- # tag2_len = @file.get_syncsafe
397
+ # tag2_len = @file.get_syncsafe
463
398
  # @file.seek(@file.get_syncsafe - 4, IO::SEEK_CUR) if ext_header
464
- # @file.seek(tag2_len, IO::SEEK_CUR)
399
+ # @file.seek(tag2_len, IO::SEEK_CUR)
465
400
  # end
466
- tempfile_name = @filename + ".tmp"
467
- File.open(tempfile_name, "wb") do |tempfile|
468
- unless @tag2.empty?
469
- tempfile.write(@tag2.to_bin)
470
- end
471
-
472
- bufsiz = file.stat.blksize || 4096
473
- while buf = file.read(bufsiz)
474
- tempfile.write(buf)
475
- end
476
- end
401
+ tempfile_name = @filename + ".tmp"
402
+ File.open(tempfile_name, "wb") do |tempfile|
403
+ unless @tag2.empty?
404
+ tempfile.write(@tag2.to_bin)
405
+ end
406
+
407
+ bufsiz = file.stat.blksize || 4096
408
+ while buf = file.read(bufsiz)
409
+ tempfile.write(buf)
410
+ end
411
+ end
477
412
  end
478
413
  File.rename(tempfile_name, @filename)
479
414
  end
@@ -499,7 +434,7 @@ class Mp3Info
499
434
  # counter, or whatever you like ;) +frame+ is a hash with the following keys:
500
435
  # :layer, :bitrate, :samplerate, :mpeg_version, :padding and :size (in bytes)
501
436
  def each_frame
502
- File.open(@filename, 'r') do |file|
437
+ File.open(@filename, 'rb') do |file|
503
438
  file.seek(@first_frame_pos, File::SEEK_SET)
504
439
  loop do
505
440
  head = file.read(4).unpack("N").first
@@ -639,6 +574,75 @@ private
639
574
  [average_bitrate, length]
640
575
  end
641
576
 
577
+ def parse_mp3
578
+ ### extracts MPEG info from MPEG header and stores it in the hash @mpeg
579
+ ### head (fixnum) = valid 4 byte MPEG header
580
+
581
+ found = false
582
+
583
+ head = nil
584
+ 5.times do
585
+ head = find_next_frame()
586
+ @first_frame_pos = @file.pos - 4
587
+ current_frame = Mp3Info.get_frames_infos(head)
588
+ @mpeg_version = current_frame[:mpeg_version]
589
+ @layer = current_frame[:layer]
590
+ @header[:error_protection] = head[16] == 0 ? true : false
591
+ @bitrate = current_frame[:bitrate]
592
+ @samplerate = current_frame[:samplerate]
593
+ @header[:padding] = current_frame[:padding]
594
+ @header[:private] = head[8] == 0 ? true : false
595
+ @channel_mode = CHANNEL_MODE[@channel_num = Mp3Info.bits(head, 7,6)]
596
+ @header[:mode_extension] = Mp3Info.bits(head, 5,4)
597
+ @header[:copyright] = (head[3] == 1 ? true : false)
598
+ @header[:original] = (head[2] == 1 ? true : false)
599
+ @header[:emphasis] = Mp3Info.bits(head, 1,0)
600
+ @vbr = false
601
+ found = true
602
+ break
603
+ end
604
+
605
+ raise(Mp3InfoError, "Cannot find good frame") unless found
606
+
607
+ seek = @mpeg_version == 1 ?
608
+ (@channel_num == 3 ? 17 : 32) :
609
+ (@channel_num == 3 ? 9 : 17)
610
+
611
+ @file.seek(seek, IO::SEEK_CUR)
612
+
613
+ vbr_head = @file.read(4)
614
+ if vbr_head == "Xing"
615
+ puts "Xing header (VBR) detected" if $DEBUG
616
+ flags = @file.get32bits
617
+ stream_size = frame_count = 0
618
+ flags[1] == 1 and frame_count = @file.get32bits
619
+ flags[2] == 1 and stream_size = @file.get32bits
620
+ puts "#{frame_count} frames" if $DEBUG
621
+ raise(Mp3InfoError, "bad VBR header") if frame_count.zero?
622
+ # currently this just skips the TOC entries if they're found
623
+ @file.seek(100, IO::SEEK_CUR) if flags[0] == 1
624
+ #@vbr_quality = @file.get32bits if flags[3] == 1
625
+
626
+ samples_per_frame = SAMPLES_PER_FRAME[@layer][@mpeg_version]
627
+ @length = frame_count * samples_per_frame / Float(@samplerate)
628
+
629
+ @bitrate = (((stream_size/frame_count)*@samplerate)/144) / 1024
630
+ @vbr = true
631
+ else
632
+ # for cbr, calculate duration with the given bitrate
633
+ stream_size = @file.stat.size - (hastag1? ? TAG1_SIZE : 0) - (@tag2.io_position || 0)
634
+ @length = ((stream_size << 3)/1000.0)/@bitrate
635
+ # read the first 100 frames and decide if the mp3 is vbr and needs full scan
636
+ begin
637
+ bitrate, length = frame_scan(100)
638
+ if @bitrate != bitrate
639
+ @vbr = true
640
+ @bitrate, @length = frame_scan
641
+ end
642
+ rescue Mp3InfoInternalError
643
+ end
644
+ end
645
+ end
642
646
 
643
647
  ### returns the selected bit range (b, a) as a number
644
648
  ### NOTE: b > a if not, returns 0
@@ -1,3 +1,8 @@
1
+ # coding:utf-8
2
+ # License:: Ruby
3
+ # Author:: Guillaume Pierronnet (mailto:moumar_AT__rubyforge_DOT_org)
4
+ # Website:: http://ruby-mp3info.rubyforge.org/
5
+
1
6
  class Mp3Info
2
7
  module HashKeys #:nodoc:
3
8
  ### lets you specify hash["key"] as hash.key
@@ -18,7 +23,7 @@ class Mp3Info
18
23
  alias getbyte []
19
24
  else
20
25
  def getbyte(i)
21
- self[i].ord
26
+ self[i].ord unless self[i].nil?
22
27
  end
23
28
  end
24
29
  end
@@ -1,3 +1,8 @@
1
+ # coding:utf-8
2
+ # License:: Ruby
3
+ # Author:: Guillaume Pierronnet (mailto:moumar_AT__rubyforge_DOT_org)
4
+ # Website:: http://ruby-mp3info.rubyforge.org/
5
+
1
6
  require "delegate"
2
7
  require "iconv"
3
8
 
@@ -223,7 +228,6 @@ class ID3v2 < DelegateClass(Hash)
223
228
  raise(ID3v2Error, "can't find version_maj ('#{version_maj}')") unless [2, 3, 4].include?(version_maj)
224
229
  @version_maj, @version_min = version_maj, version_min
225
230
  @tag_length = @io.get_syncsafe
226
- @io_position = original_pos + @tag_length
227
231
 
228
232
  @parsed = true
229
233
  begin
@@ -238,6 +242,8 @@ class ID3v2 < DelegateClass(Hash)
238
242
  rescue ID3v2Error => e
239
243
  warn("warning: id3v2 tag not fully parsed: #{e.message}")
240
244
  end
245
+ @io_position = @io.pos
246
+ @tag_length = @io_position - original_pos
241
247
 
242
248
  @hash_orig = @hash.dup
243
249
  #no more reading
@@ -339,7 +345,7 @@ class ID3v2 < DelegateClass(Hash)
339
345
  end
340
346
  end
341
347
  # remove padding zeros for textual tags
342
- out.sub!(/\0*$/, '')
348
+ out.sub!(/\0*$/, '') unless out.nil?
343
349
  return out
344
350
  else
345
351
  return raw_value
@@ -441,6 +441,16 @@ class Mp3InfoTest < Test::Unit::TestCase
441
441
  end
442
442
  end
443
443
 
444
+ def test_audio_content_problematic
445
+ File.open(TEMP_FILE, "w") { |f| f.write(FIXTURES["audio_content_fixture"]) }
446
+ Mp3Info.open(TEMP_FILE) do |mp3|
447
+ expected_pos = 150
448
+ audio_content_pos, audio_content_size = mp3.audio_content
449
+ assert_equal expected_pos, audio_content_pos
450
+ assert_equal File.size(TEMP_FILE) - expected_pos, audio_content_size
451
+ end
452
+ end
453
+
444
454
  def test_headerless_vbr_file
445
455
  mp3_length = 3
446
456
  # this will generate a 15 sec mp3 file (44100hz*16bit*2channels) = 60/4 = 15
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-mp3info
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.13
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 14
10
+ version: 0.6.14
5
11
  platform: ruby
6
12
  authors:
7
13
  - Guillaume Pierronnet
@@ -9,20 +15,80 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-05-26 00:00:00 +02:00
13
- default_executable:
18
+ date: 2011-06-17 00:00:00 Z
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
- name: hoe
21
+ name: hoe-yard
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 31
29
+ segments:
30
+ - 0
31
+ - 1
32
+ - 2
33
+ version: 0.1.2
17
34
  type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: hoe
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
20
41
  requirements:
21
42
  - - ">="
22
43
  - !ruby/object:Gem::Version
23
- version: 1.9.0
24
- version:
25
- description: "* written in pure ruby * read low-level informations like bitrate, length, samplerate, etc... * read, write, remove id3v1 and id3v2 tags * correctly read VBR files (with or without Xing header) * only 2.3 version is supported for writings id3v2 tags == SYNOPSIS: a good exercise is to read the test.rb to understand how the library works deeper require \"mp3info\" # read and display infos & tags Mp3Info.open(\"myfile.mp3\") do |mp3info| puts mp3info end # read/write tag1 and tag2 with Mp3Info#tag attribute # when reading tag2 have priority over tag1 # when writing, each tag is written. Mp3Info.open(\"myfile.mp3\") do |mp3| puts mp3.tag.title puts mp3.tag.artist puts mp3.tag.album puts mp3.tag.tracknum mp3.tag.title = \"track title\" mp3.tag.artist = \"artist name\" end Mp3Info.open(\"myfile.mp3\") do |mp3| # you can access four letter v2 tags like this puts mp3.tag2.TIT2 mp3.tag2.TIT2 = \"new TIT2\" # or like that mp3.tag2[\"TIT2\"] # at this time, only COMM tag is processed after reading and before writing # according to ID3v2#options hash mp3.tag2.options[:lang] = \"FRE\" mp3.tag2.COMM = \"my comment in french, correctly handled when reading and writing\" end"
44
+ hash: 47
45
+ segments:
46
+ - 2
47
+ - 8
48
+ - 0
49
+ version: 2.8.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ description: |-
53
+ * written in pure ruby
54
+ * read low-level informations like bitrate, length, samplerate, etc...
55
+ * read, write, remove id3v1 and id3v2 tags
56
+ * correctly read VBR files (with or without Xing header)
57
+ * only 2.3 version is supported for writings id3v2 tags
58
+
59
+ == SYNOPSIS:
60
+
61
+ a good exercise is to read the test.rb to understand how the library works deeper
62
+
63
+ require "mp3info"
64
+ # read and display infos & tags
65
+ Mp3Info.open("myfile.mp3") do |mp3info|
66
+ puts mp3info
67
+ end
68
+
69
+ # read/write tag1 and tag2 with Mp3Info#tag attribute
70
+ # when reading tag2 have priority over tag1
71
+ # when writing, each tag is written.
72
+ Mp3Info.open("myfile.mp3") do |mp3|
73
+ puts mp3.tag.title
74
+ puts mp3.tag.artist
75
+ puts mp3.tag.album
76
+ puts mp3.tag.tracknum
77
+ mp3.tag.title = "track title"
78
+ mp3.tag.artist = "artist name"
79
+ end
80
+
81
+ Mp3Info.open("myfile.mp3") do |mp3|
82
+ # you can access four letter v2 tags like this
83
+ puts mp3.tag2.TIT2
84
+ mp3.tag2.TIT2 = "new TIT2"
85
+ # or like that
86
+ mp3.tag2["TIT2"]
87
+ # at this time, only COMM tag is processed after reading and before writing
88
+ # according to ID3v2#options hash
89
+ mp3.tag2.options[:lang] = "FRE"
90
+ mp3.tag2.COMM = "my comment in french, correctly handled when reading and writing"
91
+ end
26
92
  email: moumar@rubyforge.org
27
93
  executables: []
28
94
 
@@ -31,43 +97,50 @@ extensions: []
31
97
  extra_rdoc_files:
32
98
  - History.txt
33
99
  - Manifest.txt
34
- - README.txt
35
100
  files:
36
101
  - History.txt
37
102
  - Manifest.txt
38
- - README.txt
103
+ - README.rdoc
39
104
  - Rakefile
40
105
  - install.rb
41
106
  - lib/mp3info.rb
42
107
  - lib/mp3info/extension_modules.rb
43
108
  - lib/mp3info/id3v2.rb
44
109
  - test/test_ruby-mp3info.rb
45
- has_rdoc: true
46
110
  homepage:
111
+ licenses: []
112
+
47
113
  post_install_message:
48
114
  rdoc_options:
49
- - --main
50
- - README.txt
115
+ - --title
116
+ - RubyMp3info Documentation
117
+ - --quiet
51
118
  require_paths:
52
119
  - lib
53
120
  required_ruby_version: !ruby/object:Gem::Requirement
121
+ none: false
54
122
  requirements:
55
123
  - - ">="
56
124
  - !ruby/object:Gem::Version
125
+ hash: 3
126
+ segments:
127
+ - 0
57
128
  version: "0"
58
- version:
59
129
  required_rubygems_version: !ruby/object:Gem::Requirement
130
+ none: false
60
131
  requirements:
61
132
  - - ">="
62
133
  - !ruby/object:Gem::Version
134
+ hash: 3
135
+ segments:
136
+ - 0
63
137
  version: "0"
64
- version:
65
138
  requirements: []
66
139
 
67
140
  rubyforge_project: ruby-mp3info
68
- rubygems_version: 1.3.1
141
+ rubygems_version: 1.8.5
69
142
  signing_key:
70
- specification_version: 2
143
+ specification_version: 3
71
144
  summary: ruby-mp3info is a pure-ruby library to retrieve low level informations on mp3 files and manipulate id3v1 and id3v2 tags
72
145
  test_files:
73
146
  - test/test_ruby-mp3info.rb