ruby-mp3info 0.6.13 → 0.6.14
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/History.txt +9 -0
- data/Manifest.txt +1 -1
- data/{README.txt → README.rdoc} +1 -1
- data/Rakefile +6 -2
- data/lib/mp3info.rb +99 -95
- data/lib/mp3info/extension_modules.rb +6 -1
- data/lib/mp3info/id3v2.rb +8 -2
- data/test/test_ruby-mp3info.rb +10 -0
- metadata +91 -18
data/History.txt
CHANGED
@@ -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
|
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -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
|
-
*
|
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.
|
14
|
-
p.url = p.paragraphs_of('README.
|
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
|
data/lib/mp3info.rb
CHANGED
@@ -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.
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
407
|
-
|
408
|
-
|
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
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
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
|
-
#
|
397
|
+
# tag2_len = @file.get_syncsafe
|
463
398
|
# @file.seek(@file.get_syncsafe - 4, IO::SEEK_CUR) if ext_header
|
464
|
-
#
|
399
|
+
# @file.seek(tag2_len, IO::SEEK_CUR)
|
465
400
|
# end
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
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, '
|
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
|
data/lib/mp3info/id3v2.rb
CHANGED
@@ -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
|
data/test/test_ruby-mp3info.rb
CHANGED
@@ -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
|
-
|
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:
|
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
|
-
|
19
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
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.
|
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
|
-
- --
|
50
|
-
-
|
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.
|
141
|
+
rubygems_version: 1.8.5
|
69
142
|
signing_key:
|
70
|
-
specification_version:
|
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
|