ruby-mp3info 0.6.14 → 0.6.15
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/.gemtest +0 -0
- data/History.txt +4 -0
- data/lib/mp3info.rb +123 -79
- data/test/test_ruby-mp3info.rb +75 -23
- metadata +13 -30
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
data/lib/mp3info.rb
CHANGED
@@ -17,7 +17,7 @@ end
|
|
17
17
|
|
18
18
|
class Mp3Info
|
19
19
|
|
20
|
-
VERSION = "0.6.
|
20
|
+
VERSION = "0.6.15"
|
21
21
|
|
22
22
|
LAYER = [ nil, 3, 2, 1]
|
23
23
|
BITRATE = {
|
@@ -155,22 +155,45 @@ class Mp3Info
|
|
155
155
|
# "close" method.
|
156
156
|
attr_accessor(:tag2)
|
157
157
|
|
158
|
-
# the original filename
|
158
|
+
# the original filename unless used with a StringIO
|
159
159
|
attr_reader(:filename)
|
160
160
|
|
161
|
-
# Test the presence of an id3v1 tag in file +
|
162
|
-
def self.hastag1?(
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
161
|
+
# Test the presence of an id3v1 tag in file or StringIO +filename_or_io+
|
162
|
+
def self.hastag1?(filename_or_io)
|
163
|
+
if filename_or_io.is_a?(StringIO)
|
164
|
+
io = filename_or_io
|
165
|
+
io.rewind
|
166
|
+
else
|
167
|
+
io = File.new(filename_or_io, "rb")
|
168
|
+
end
|
169
|
+
|
170
|
+
hastag1 = false
|
171
|
+
begin
|
172
|
+
io.seek(-TAG1_SIZE, File::SEEK_END)
|
173
|
+
hastag1 = io.read(3) == "TAG"
|
174
|
+
ensure
|
175
|
+
io.close if io.is_a?(File)
|
176
|
+
end
|
177
|
+
hastag1
|
167
178
|
end
|
168
179
|
|
169
|
-
# Test the presence of an id3v2 tag in file +
|
170
|
-
def self.hastag2?(
|
171
|
-
|
172
|
-
|
173
|
-
|
180
|
+
# Test the presence of an id3v2 tag in file or StringIO +filename_or_io+
|
181
|
+
def self.hastag2?(filename_or_io)
|
182
|
+
if filename_or_io.is_a?(StringIO)
|
183
|
+
io = filename_or_io
|
184
|
+
io.rewind
|
185
|
+
else
|
186
|
+
io = File.new(filename_or_io,"rb")
|
187
|
+
end
|
188
|
+
|
189
|
+
hastag2 = false
|
190
|
+
|
191
|
+
begin
|
192
|
+
hastag2 = io.read(3) == "ID3"
|
193
|
+
ensure
|
194
|
+
io.close if io.is_a?(File)
|
195
|
+
end
|
196
|
+
hastag2
|
174
197
|
end
|
175
198
|
|
176
199
|
# Remove id3v1 tag from +filename+
|
@@ -193,24 +216,38 @@ class Mp3Info
|
|
193
216
|
# Specify :parse_tags => false to disable the processing
|
194
217
|
# of the tags (read and write).
|
195
218
|
# Specify :parse_mp3 => false to disable processing of the mp3
|
196
|
-
def initialize(
|
219
|
+
def initialize(filename_or_io, options = {})
|
197
220
|
warn("#{self.class}::new() does not take block; use #{self.class}::open() instead") if block_given?
|
198
|
-
@
|
221
|
+
@filename_or_io = filename_or_io
|
199
222
|
options = {:parse_mp3 => true, :parse_tags => true}.update(options)
|
200
223
|
@tag_parsing_enabled = options.delete(:parse_tags)
|
201
224
|
@mp3_parsing_enabled = options.delete(:parse_mp3)
|
202
225
|
@id3v2_options = options
|
203
226
|
reload
|
204
227
|
end
|
205
|
-
|
228
|
+
|
206
229
|
# reload (or load for the first time) the file from disk
|
207
230
|
def reload
|
208
|
-
raise(Mp3InfoError, "empty file") unless File.size?(@filename)
|
209
|
-
|
210
231
|
@header = {}
|
232
|
+
|
233
|
+
if @filename_or_io.is_a?(String)
|
234
|
+
@io_is_a_file = true
|
235
|
+
@io = File.new(@filename_or_io, "rb")
|
236
|
+
@io_size = @io.stat.size
|
237
|
+
@filename = @filename_or_io
|
238
|
+
elsif @filename_or_io.is_a?(StringIO)
|
239
|
+
@io_is_a_file = false
|
240
|
+
@io = @filename_or_io
|
241
|
+
@io_size = @io.size
|
242
|
+
@filename = nil
|
243
|
+
end
|
244
|
+
|
245
|
+
if @io_size == 0
|
246
|
+
raise(Mp3InfoError, "empty file or IO")
|
247
|
+
end
|
211
248
|
|
212
|
-
|
213
|
-
@
|
249
|
+
|
250
|
+
@io.extend(Mp3FileMethods)
|
214
251
|
@tag1 = @tag = @tag1_orig = @tag_orig = {}
|
215
252
|
@tag1.extend(HashKeys)
|
216
253
|
@tag2 = ID3v2.new(@id3v2_options)
|
@@ -253,7 +290,9 @@ class Mp3Info
|
|
253
290
|
end
|
254
291
|
|
255
292
|
ensure
|
256
|
-
@
|
293
|
+
if @io_is_a_file
|
294
|
+
@io.close
|
295
|
+
end
|
257
296
|
end
|
258
297
|
end
|
259
298
|
|
@@ -302,6 +341,7 @@ class Mp3Info
|
|
302
341
|
|
303
342
|
# write to another filename at close()
|
304
343
|
def rename(new_filename)
|
344
|
+
raise(Mp3InfoError, "cannot rename an IO") unless @io_is_a_file
|
305
345
|
@filename = new_filename
|
306
346
|
end
|
307
347
|
|
@@ -311,7 +351,7 @@ class Mp3Info
|
|
311
351
|
# [position_in_the_file, length_of_the_data]
|
312
352
|
def audio_content
|
313
353
|
pos = 0
|
314
|
-
length =
|
354
|
+
length = @io_size
|
315
355
|
if hastag1?
|
316
356
|
length -= TAG1_SIZE
|
317
357
|
end
|
@@ -328,8 +368,10 @@ class Mp3Info
|
|
328
368
|
end
|
329
369
|
|
330
370
|
# Flush pending modifications to tags and close the file
|
371
|
+
# not used when source IO is a StringIO
|
331
372
|
def close
|
332
373
|
puts "close" if $DEBUG
|
374
|
+
return unless @io_is_a_file
|
333
375
|
if !@tag_parsing_enabled
|
334
376
|
return
|
335
377
|
end
|
@@ -352,12 +394,12 @@ class Mp3Info
|
|
352
394
|
|
353
395
|
if @tag1 != @tag1_orig
|
354
396
|
puts "@tag1 has changed" if $DEBUG
|
355
|
-
raise(Mp3InfoError, "file is not writable") unless File.writable?(@
|
397
|
+
raise(Mp3InfoError, "file is not writable") unless File.writable?(@filename_or_io)
|
356
398
|
#@tag1_orig.update(@tag1)
|
357
399
|
@tag1_orig = @tag1.dup
|
358
|
-
File.open(@
|
400
|
+
File.open(@filename_or_io, 'rb+') do |file|
|
359
401
|
if @tag1_orig.empty?
|
360
|
-
newsize =
|
402
|
+
newsize = @io_size - TAG1_SIZE
|
361
403
|
file.truncate(newsize)
|
362
404
|
else
|
363
405
|
file.seek(-TAG1_SIZE, File::SEEK_END)
|
@@ -384,21 +426,21 @@ class Mp3Info
|
|
384
426
|
|
385
427
|
if @tag2.changed?
|
386
428
|
puts "@tag2 has changed" if $DEBUG
|
387
|
-
raise(Mp3InfoError, "file is not writable") unless File.writable?(@
|
429
|
+
raise(Mp3InfoError, "file is not writable") unless File.writable?(@filename_or_io)
|
388
430
|
tempfile_name = nil
|
389
|
-
File.open(@
|
431
|
+
File.open(@filename_or_io, 'rb+') do |file|
|
390
432
|
#if tag2 already exists, seek to end of it
|
391
433
|
if @tag2.parsed?
|
392
434
|
file.seek(@tag2.io_position)
|
393
435
|
end
|
394
|
-
# if @
|
395
|
-
# version_maj, version_min, flags = @
|
436
|
+
# if @io.read(3) == "ID3"
|
437
|
+
# version_maj, version_min, flags = @io.read(3).unpack("CCB4")
|
396
438
|
# unsync, ext_header, experimental, footer = (0..3).collect { |i| flags[i].chr == '1' }
|
397
|
-
# tag2_len = @
|
398
|
-
# @
|
399
|
-
# @
|
439
|
+
# tag2_len = @io.get_syncsafe
|
440
|
+
# @io.seek(@io.get_syncsafe - 4, IO::SEEK_CUR) if ext_header
|
441
|
+
# @io.seek(tag2_len, IO::SEEK_CUR)
|
400
442
|
# end
|
401
|
-
tempfile_name = @
|
443
|
+
tempfile_name = @filename_or_io + ".tmp"
|
402
444
|
File.open(tempfile_name, "wb") do |tempfile|
|
403
445
|
unless @tag2.empty?
|
404
446
|
tempfile.write(@tag2.to_bin)
|
@@ -410,13 +452,14 @@ class Mp3Info
|
|
410
452
|
end
|
411
453
|
end
|
412
454
|
end
|
413
|
-
File.rename(tempfile_name, @
|
455
|
+
File.rename(tempfile_name, @filename_or_io)
|
414
456
|
end
|
415
457
|
end
|
416
458
|
|
417
459
|
# close and reopen the file, i.e. commit changes to disk and
|
418
|
-
# reload it
|
460
|
+
# reload it (only works with "true" files, not StringIO ones)
|
419
461
|
def flush
|
462
|
+
return unless @io_is_a_file
|
420
463
|
close
|
421
464
|
reload
|
422
465
|
end
|
@@ -434,16 +477,14 @@ class Mp3Info
|
|
434
477
|
# counter, or whatever you like ;) +frame+ is a hash with the following keys:
|
435
478
|
# :layer, :bitrate, :samplerate, :mpeg_version, :padding and :size (in bytes)
|
436
479
|
def each_frame
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
break if file.eof?
|
446
|
-
end
|
480
|
+
@io.seek(@first_frame_pos, File::SEEK_SET)
|
481
|
+
loop do
|
482
|
+
head = @io.read(4).unpack("N").first
|
483
|
+
frame = Mp3Info.get_frames_infos(head)
|
484
|
+
@io.seek(frame[:size] -4, File::SEEK_CUR)
|
485
|
+
yield frame
|
486
|
+
#puts "frame #{frame_count} len #{frame[:length]} br #{frame[:bitrate]} @io.pos #{@io.pos}"
|
487
|
+
break if @io.eof?
|
447
488
|
end
|
448
489
|
end
|
449
490
|
|
@@ -481,49 +522,50 @@ private
|
|
481
522
|
:size => size }
|
482
523
|
end
|
483
524
|
|
484
|
-
### parses the id3 tags of the currently open @
|
525
|
+
### parses the id3 tags of the currently open @io
|
485
526
|
def parse_tags
|
486
|
-
return if @
|
527
|
+
return if @io_size < TAG1_SIZE # file is too small
|
528
|
+
|
487
529
|
@tag1_parsed = false
|
488
|
-
@
|
489
|
-
f3 = @
|
530
|
+
@io.seek(0)
|
531
|
+
f3 = @io.read(3)
|
490
532
|
# v1 tag at beginning
|
491
533
|
if f3 == "TAG"
|
492
534
|
gettag1
|
493
535
|
@tag1_parsed = true
|
494
536
|
end
|
495
537
|
|
496
|
-
@tag2.from_io(@
|
538
|
+
@tag2.from_io(@io) if f3 == "ID3" # v2 tag at beginning
|
497
539
|
|
498
540
|
unless @tag1_parsed # v1 tag at end
|
499
541
|
# this preserves the file pos if tag2 found, since gettag2 leaves
|
500
542
|
# the file at the best guess as to the first MPEG frame
|
501
543
|
pos = (@tag2.io_position || 0)
|
502
544
|
# seek to where id3v1 tag should be
|
503
|
-
@
|
504
|
-
if @
|
545
|
+
@io.seek(-TAG1_SIZE, IO::SEEK_END)
|
546
|
+
if @io.read(3) == "TAG"
|
505
547
|
gettag1
|
506
548
|
end
|
507
|
-
@
|
549
|
+
@io.seek(pos)
|
508
550
|
end
|
509
551
|
end
|
510
552
|
|
511
|
-
### gets id3v1 tag information from @
|
512
|
-
### assumes @
|
553
|
+
### gets id3v1 tag information from @io
|
554
|
+
### assumes @io is pointing to char after "TAG" id
|
513
555
|
def gettag1
|
514
556
|
@tag1_parsed = true
|
515
|
-
@tag1["title"] = @
|
516
|
-
@tag1["artist"] = @
|
517
|
-
@tag1["album"] = @
|
518
|
-
year_t = @
|
557
|
+
@tag1["title"] = @io.read(30).unpack("A*").first
|
558
|
+
@tag1["artist"] = @io.read(30).unpack("A*").first
|
559
|
+
@tag1["album"] = @io.read(30).unpack("A*").first
|
560
|
+
year_t = @io.read(4).to_i
|
519
561
|
@tag1["year"] = year_t unless year_t == 0
|
520
|
-
comments = @
|
562
|
+
comments = @io.read(30)
|
521
563
|
if comments.getbyte(-2) == 0
|
522
564
|
@tag1["tracknum"] = comments.getbyte(-1).to_i
|
523
565
|
comments.chop! #remove the last char
|
524
566
|
end
|
525
567
|
@tag1["comments"] = comments.unpack("A*").first
|
526
|
-
@tag1["genre"] = @
|
568
|
+
@tag1["genre"] = @io.getbyte
|
527
569
|
@tag1["genre_s"] = GENRES[@tag1["genre"]] || ""
|
528
570
|
|
529
571
|
# clear empty tags
|
@@ -532,29 +574,30 @@ private
|
|
532
574
|
@tag1.delete("tracknum") if @tag1["tracknum"] == 0
|
533
575
|
end
|
534
576
|
|
535
|
-
### reads through @
|
577
|
+
### reads through @io from current pos until it finds a valid MPEG header
|
536
578
|
### returns the MPEG header as FixNum
|
537
579
|
def find_next_frame
|
538
|
-
# @
|
580
|
+
# @io will now be sitting at the best guess for where the MPEG frame is.
|
539
581
|
# It should be at byte 0 when there's no id3v2 tag.
|
540
582
|
# It should be at the end of the id3v2 tag or the zero padding if there
|
541
583
|
# is a id3v2 tag.
|
542
|
-
#dummyproof = @
|
543
|
-
|
584
|
+
#dummyproof = @io.stat.size - @io.pos => WAS TOO MUCH
|
585
|
+
|
586
|
+
dummyproof = [ @io_size - @io.pos, 2000000 ].min
|
544
587
|
dummyproof.times do |i|
|
545
|
-
if @
|
546
|
-
data = @
|
547
|
-
raise(Mp3InfoError, "end of file reached") if @
|
588
|
+
if @io.getbyte == 0xff
|
589
|
+
data = @io.read(3)
|
590
|
+
raise(Mp3InfoError, "end of file reached") if @io.eof?
|
548
591
|
head = 0xff000000 + (data.getbyte(0) << 16) + (data.getbyte(1) << 8) + data.getbyte(2)
|
549
592
|
begin
|
550
593
|
Mp3Info.get_frames_infos(head)
|
551
594
|
return head
|
552
595
|
rescue Mp3InfoInternalError
|
553
|
-
@
|
596
|
+
@io.seek(-3, IO::SEEK_CUR)
|
554
597
|
end
|
555
598
|
end
|
556
599
|
end
|
557
|
-
if @
|
600
|
+
if @io.eof?
|
558
601
|
raise Mp3InfoError, "cannot find a valid frame: got EOF"
|
559
602
|
else
|
560
603
|
raise Mp3InfoError, "cannot find a valid frame after reading #{dummyproof} bytes"
|
@@ -583,7 +626,7 @@ private
|
|
583
626
|
head = nil
|
584
627
|
5.times do
|
585
628
|
head = find_next_frame()
|
586
|
-
@first_frame_pos = @
|
629
|
+
@first_frame_pos = @io.pos - 4
|
587
630
|
current_frame = Mp3Info.get_frames_infos(head)
|
588
631
|
@mpeg_version = current_frame[:mpeg_version]
|
589
632
|
@layer = current_frame[:layer]
|
@@ -608,20 +651,20 @@ private
|
|
608
651
|
(@channel_num == 3 ? 17 : 32) :
|
609
652
|
(@channel_num == 3 ? 9 : 17)
|
610
653
|
|
611
|
-
@
|
654
|
+
@io.seek(seek, IO::SEEK_CUR)
|
612
655
|
|
613
|
-
vbr_head = @
|
656
|
+
vbr_head = @io.read(4)
|
614
657
|
if vbr_head == "Xing"
|
615
658
|
puts "Xing header (VBR) detected" if $DEBUG
|
616
|
-
flags = @
|
659
|
+
flags = @io.get32bits
|
617
660
|
stream_size = frame_count = 0
|
618
|
-
flags[1] == 1 and frame_count = @
|
619
|
-
flags[2] == 1 and stream_size = @
|
661
|
+
flags[1] == 1 and frame_count = @io.get32bits
|
662
|
+
flags[2] == 1 and stream_size = @io.get32bits
|
620
663
|
puts "#{frame_count} frames" if $DEBUG
|
621
664
|
raise(Mp3InfoError, "bad VBR header") if frame_count.zero?
|
622
665
|
# currently this just skips the TOC entries if they're found
|
623
|
-
@
|
624
|
-
#@vbr_quality = @
|
666
|
+
@io.seek(100, IO::SEEK_CUR) if flags[0] == 1
|
667
|
+
#@vbr_quality = @io.get32bits if flags[3] == 1
|
625
668
|
|
626
669
|
samples_per_frame = SAMPLES_PER_FRAME[@layer][@mpeg_version]
|
627
670
|
@length = frame_count * samples_per_frame / Float(@samplerate)
|
@@ -630,7 +673,8 @@ private
|
|
630
673
|
@vbr = true
|
631
674
|
else
|
632
675
|
# for cbr, calculate duration with the given bitrate
|
633
|
-
|
676
|
+
|
677
|
+
stream_size = @io_size - (hastag1? ? TAG1_SIZE : 0) - (@tag2.io_position || 0)
|
634
678
|
@length = ((stream_size << 3)/1000.0)/@bitrate
|
635
679
|
# read the first 100 frames and decide if the mp3 is vbr and needs full scan
|
636
680
|
begin
|
data/test/test_ruby-mp3info.rb
CHANGED
@@ -10,6 +10,8 @@ require "tempfile"
|
|
10
10
|
require "zlib"
|
11
11
|
require "yaml"
|
12
12
|
|
13
|
+
system("which id3v2 > /dev/null") || raise("id3v2 not found")
|
14
|
+
|
13
15
|
class Mp3InfoTest < Test::Unit::TestCase
|
14
16
|
|
15
17
|
TEMP_FILE = File.join(File.dirname(__FILE__), "test_mp3info.mp3")
|
@@ -86,21 +88,8 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
86
88
|
end
|
87
89
|
|
88
90
|
def test_detected_info
|
89
|
-
Mp3Info.open(TEMP_FILE) do |
|
90
|
-
|
91
|
-
assert_equal(3, info.layer)
|
92
|
-
assert_equal(false, info.vbr)
|
93
|
-
assert_equal(128, info.bitrate)
|
94
|
-
assert_equal("JStereo", info.channel_mode)
|
95
|
-
assert_equal(44100, info.samplerate)
|
96
|
-
assert_equal(0.1305625, info.length)
|
97
|
-
assert_equal({:original => true,
|
98
|
-
:error_protection => false,
|
99
|
-
:padding => false,
|
100
|
-
:emphasis => 0,
|
101
|
-
:private => true,
|
102
|
-
:mode_extension => 2,
|
103
|
-
:copyright => false}, info.header)
|
91
|
+
Mp3Info.open(TEMP_FILE) do |mp3|
|
92
|
+
assert_mp3_info_are_ok(mp3)
|
104
93
|
end
|
105
94
|
end
|
106
95
|
|
@@ -167,13 +156,23 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
167
156
|
end
|
168
157
|
|
169
158
|
def test_removetag2
|
170
|
-
w =
|
159
|
+
w = write_tag2_to_temp_file({"TIT2" => "sdfqdsf"})
|
171
160
|
|
172
161
|
assert( Mp3Info.hastag2?(TEMP_FILE) )
|
173
162
|
Mp3Info.removetag2(TEMP_FILE)
|
174
163
|
assert( ! Mp3Info.hastag2?(TEMP_FILE) )
|
175
164
|
end
|
176
165
|
|
166
|
+
def test_hastags
|
167
|
+
Mp3Info.open(TEMP_FILE) do |info|
|
168
|
+
info.tag1 = @tag
|
169
|
+
end
|
170
|
+
assert(Mp3Info.hastag1?(TEMP_FILE))
|
171
|
+
|
172
|
+
written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
|
173
|
+
assert(Mp3Info.hastag2?(TEMP_FILE))
|
174
|
+
end
|
175
|
+
|
177
176
|
def test_universal_tag
|
178
177
|
2.times do
|
179
178
|
tag = {"title" => "title"}
|
@@ -200,7 +199,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
200
199
|
end
|
201
200
|
|
202
201
|
def test_id3v2_version
|
203
|
-
written_tag =
|
202
|
+
written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
|
204
203
|
assert_equal( "2.#{ID3v2::WRITE_VERSION}.0", written_tag.version )
|
205
204
|
end
|
206
205
|
|
@@ -215,7 +214,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
215
214
|
end
|
216
215
|
|
217
216
|
def test_id3v2_basic
|
218
|
-
w =
|
217
|
+
w = write_tag2_to_temp_file(DUMMY_TAG2)
|
219
218
|
assert_equal(DUMMY_TAG2, w)
|
220
219
|
id3v2_prog_test(DUMMY_TAG2, w)
|
221
220
|
end
|
@@ -254,13 +253,13 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
254
253
|
tag[k] = random_string(50)
|
255
254
|
end
|
256
255
|
|
257
|
-
got_tag =
|
256
|
+
got_tag = write_tag2_to_temp_file(tag)
|
258
257
|
assert_equal(tag, got_tag)
|
259
258
|
end
|
260
259
|
|
261
260
|
def test_id3v2_bigtag
|
262
261
|
tag = {"APIC" => random_string(1024) }
|
263
|
-
assert_equal(tag,
|
262
|
+
assert_equal(tag, write_tag2_to_temp_file(tag))
|
264
263
|
end
|
265
264
|
|
266
265
|
def test_infinite_loop_on_seek_to_v2_end
|
@@ -270,7 +269,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
270
269
|
def test_leading_char_gets_chopped
|
271
270
|
tag2 = DUMMY_TAG2.dup
|
272
271
|
tag2["WOAR"] = "http://foo.bar"
|
273
|
-
w =
|
272
|
+
w = write_tag2_to_temp_file(tag2)
|
274
273
|
assert_equal("http://foo.bar", w["WOAR"])
|
275
274
|
|
276
275
|
system(%(id3v2 --WOAR "http://foo.bar" "#{TEMP_FILE}"))
|
@@ -465,7 +464,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
465
464
|
end
|
466
465
|
|
467
466
|
def test_parse_tags_disabled
|
468
|
-
|
467
|
+
write_tag2_to_temp_file(DUMMY_TAG2)
|
469
468
|
Mp3Info.open(TEMP_FILE, :parse_tags => false) do |mp3|
|
470
469
|
assert mp3.tag.empty?
|
471
470
|
assert mp3.tag1.empty?
|
@@ -480,6 +479,34 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
480
479
|
end
|
481
480
|
end
|
482
481
|
|
482
|
+
def test_string_io
|
483
|
+
io = load_string_io
|
484
|
+
Mp3Info.open(io) do |mp3|
|
485
|
+
assert_mp3_info_are_ok(mp3)
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
def test_trying_to_rename_a_stringio_should_raise_an_error
|
490
|
+
io = load_string_io
|
491
|
+
Mp3Info.open(io) do |mp3|
|
492
|
+
assert_raises(Mp3InfoError) do
|
493
|
+
mp3.rename("whatever_filename_is_error_should_be_raised.mp3")
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def test_hastag_class_methods_with_a_stringio
|
499
|
+
Mp3Info.open(TEMP_FILE) do |info|
|
500
|
+
info.tag1 = @tag
|
501
|
+
end
|
502
|
+
io = load_string_io
|
503
|
+
assert(Mp3Info.hastag1?(io))
|
504
|
+
|
505
|
+
written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
|
506
|
+
io = load_string_io
|
507
|
+
assert(Mp3Info.hastag2?(io))
|
508
|
+
end
|
509
|
+
|
483
510
|
def compute_audio_content_mp3_digest(mp3)
|
484
511
|
pos, size = mp3.audio_content
|
485
512
|
data = File.open(mp3.filename) do |f|
|
@@ -489,7 +516,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
489
516
|
Digest::MD5.new.update(data).hexdigest
|
490
517
|
end
|
491
518
|
|
492
|
-
def
|
519
|
+
def write_tag2_to_temp_file(tag)
|
493
520
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
494
521
|
mp3.tag2.update(tag)
|
495
522
|
end
|
@@ -503,6 +530,31 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
503
530
|
out
|
504
531
|
end
|
505
532
|
|
533
|
+
def assert_mp3_info_are_ok(mp3)
|
534
|
+
assert_equal(1, mp3.mpeg_version)
|
535
|
+
assert_equal(3, mp3.layer)
|
536
|
+
assert_equal(false, mp3.vbr)
|
537
|
+
assert_equal(128, mp3.bitrate)
|
538
|
+
assert_equal("JStereo", mp3.channel_mode)
|
539
|
+
assert_equal(44100, mp3.samplerate)
|
540
|
+
assert_equal(0.1305625, mp3.length)
|
541
|
+
assert_equal({:original => true,
|
542
|
+
:error_protection => false,
|
543
|
+
:padding => false,
|
544
|
+
:emphasis => 0,
|
545
|
+
:private => true,
|
546
|
+
:mode_extension => 2,
|
547
|
+
:copyright => false}, mp3.header)
|
548
|
+
end
|
549
|
+
|
550
|
+
def load_string_io(filename = TEMP_FILE)
|
551
|
+
io = StringIO.new
|
552
|
+
data = File.read(filename)
|
553
|
+
io.write(data)
|
554
|
+
io.rewind
|
555
|
+
io
|
556
|
+
end
|
557
|
+
|
506
558
|
=begin
|
507
559
|
|
508
560
|
def test_encoder
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mp3info
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 0.6.
|
9
|
+
- 15
|
10
|
+
version: 0.6.15
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Guillaume Pierronnet
|
@@ -15,40 +15,23 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-07-18 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name: hoe
|
21
|
+
name: hoe
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 23
|
29
29
|
segments:
|
30
|
-
- 0
|
31
|
-
- 1
|
32
30
|
- 2
|
33
|
-
|
31
|
+
- 10
|
32
|
+
version: "2.10"
|
34
33
|
type: :development
|
35
34
|
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: hoe
|
38
|
-
prerelease: false
|
39
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
-
none: false
|
41
|
-
requirements:
|
42
|
-
- - ">="
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
hash: 47
|
45
|
-
segments:
|
46
|
-
- 2
|
47
|
-
- 8
|
48
|
-
- 0
|
49
|
-
version: 2.8.0
|
50
|
-
type: :development
|
51
|
-
version_requirements: *id002
|
52
35
|
description: |-
|
53
36
|
* written in pure ruby
|
54
37
|
* read low-level informations like bitrate, length, samplerate, etc...
|
@@ -107,14 +90,14 @@ files:
|
|
107
90
|
- lib/mp3info/extension_modules.rb
|
108
91
|
- lib/mp3info/id3v2.rb
|
109
92
|
- test/test_ruby-mp3info.rb
|
93
|
+
- .gemtest
|
110
94
|
homepage:
|
111
95
|
licenses: []
|
112
96
|
|
113
97
|
post_install_message:
|
114
98
|
rdoc_options:
|
115
|
-
- --
|
116
|
-
-
|
117
|
-
- --quiet
|
99
|
+
- --main
|
100
|
+
- README.txt
|
118
101
|
require_paths:
|
119
102
|
- lib
|
120
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -138,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
121
|
requirements: []
|
139
122
|
|
140
123
|
rubyforge_project: ruby-mp3info
|
141
|
-
rubygems_version: 1.
|
124
|
+
rubygems_version: 1.7.2
|
142
125
|
signing_key:
|
143
126
|
specification_version: 3
|
144
127
|
summary: ruby-mp3info is a pure-ruby library to retrieve low level informations on mp3 files and manipulate id3v1 and id3v2 tags
|