ruby-mp3info 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce54c521b67a367467f344b231debdbb1e36b543
4
- data.tar.gz: 160261476cab97ea32fddd4870ff67a92ffd6ac5
3
+ metadata.gz: ec6e84b6d95639a26f8ff0baf64625889bfd6b3a
4
+ data.tar.gz: 9de4508c025b0c865f0eb4b29fe9c70b75495ed2
5
5
  SHA512:
6
- metadata.gz: 0609877cdd0fba3d09a74bc613338da699eb67dfe7bedf80f872ff09bdc23689bcb3e86c97632133f4c60bbad1c4ba8ac6e188799670e73772f818803627c9a4
7
- data.tar.gz: 08999c5701caab8ba9a2a6e0d0ac0961e076d1acea747114878f1d84e2238631cf36cf472f5b2a4ad3bc880c6efa0eef2f0b558d544afb20bdfaf8c94c7e6076
6
+ metadata.gz: f619a8973e5dee36135546d5be127c9a9d105e255cd94323ce073ec58f03aa4e668dcc156398984c5ab4a9a756dd8ea9006cadab62e2824a3741c6a6f20a6d77
7
+ data.tar.gz: 171267103c889d7a3136e5f727a74db06acc664d5d7a5118e9cfb011abe0daa2165d06d1b71f2d4edd77ff6b8f4669d306c94a256ade3c6f7b4093e1eb5e9629
@@ -1,3 +1,7 @@
1
+ === 0.8.10 / 2016-10-31
2
+
3
+ * bugfix on /^(T|COM|USLT)/ tags parsing
4
+
1
5
  === 0.8.9 / 2016-02-03
2
6
 
3
7
  * bugfix on JPEG picture parsing + testsuite
@@ -18,7 +18,7 @@ end
18
18
 
19
19
  class Mp3Info
20
20
 
21
- VERSION = "0.8.9"
21
+ VERSION = "0.8.10"
22
22
 
23
23
  LAYER = [ nil, 3, 2, 1]
24
24
  BITRATE = {
@@ -17,19 +17,7 @@ class Mp3Info
17
17
  end
18
18
  end
19
19
 
20
- class ::String
21
- if RUBY_VERSION < "1.9.0"
22
- alias getbyte []
23
- end
24
- end
25
-
26
20
  module Mp3FileMethods #:nodoc:
27
- if RUBY_VERSION < "1.9.0"
28
- def getbyte
29
- getc
30
- end
31
- end
32
-
33
21
  def get32bits
34
22
  (getbyte << 24) + (getbyte << 16) + (getbyte << 8) + getbyte
35
23
  end
@@ -41,26 +29,15 @@ class Mp3Info
41
29
 
42
30
  class EncodingHelper #:nodoc:
43
31
  def self.convert_to(value, from, to)
44
- if RUBY_1_8
45
- if to == "iso-8859-1"
46
- to = to + "//TRANSLIT"
47
- end
48
- ruby_18_encode(from, to, value)
32
+ if to == "utf-16"
33
+ ("\uFEFF" + value).encode("UTF-16LE") # Chab 01.apr.2012 : moved from big to little endian for more compatibility (Windows Media Player, older Quicktime..)
49
34
  else
50
- if to == "utf-16"
51
- ("\uFEFF" + value).encode("UTF-16LE") # Chab 01.apr.2012 : moved from big to little endian for more compatibility (Windows Media Player, older Quicktime..)
52
- else
53
- value.encode(to)
54
- end
35
+ value.encode(to)
55
36
  end
56
37
  end
57
38
 
58
39
  def self.convert_from_iso_8859_1(value)
59
- if RUBY_1_8
60
- ruby_18_encode("utf-8", "iso-8859-1", value)
61
- else
62
- value.force_encoding("iso-8859-1").encode("utf-8")
63
- end
40
+ value.force_encoding("iso-8859-1").encode("utf-8")
64
41
  end
65
42
 
66
43
  def self.ruby_18_encode(from, to, value)
@@ -68,26 +45,22 @@ class Mp3Info
68
45
  end
69
46
 
70
47
  def self.decode_utf16(out)
71
- if RUBY_1_8
72
- convert_to(out, "UTF-8", "UTF-16")
48
+ # String#bytes is not an array in Ruby 1.9
49
+ bytes = out.bytes.to_a
50
+ if out.length >= 2 and bytes[0] == 0xff and bytes[1] == 0xfe
51
+ tag_encoding = "UTF-16LE"
52
+ first_valid = 1
53
+ elsif out.length >= 2 and bytes[0] == 0xfe and bytes[1] == 0xff
54
+ tag_encoding = "UTF-16BE"
55
+ first_valid = 1
73
56
  else
74
- # String#bytes is not an array in Ruby 1.9
75
- bytes = out.bytes.to_a
76
- if out.length >= 2 and bytes[0] == 0xff and bytes[1] == 0xfe
77
- tag_encoding = "UTF-16LE"
78
- first_valid = 1
79
- elsif out.length >= 2 and bytes[0] == 0xfe and bytes[1] == 0xff
80
- tag_encoding = "UTF-16BE"
81
- first_valid = 1
82
- else
83
- # ID3v2.3.0 section 3.3 mandates a BOM but some software
84
- # erroneously omits it so we have to guess. Since most of
85
- # the world is little endian we might as well go with that.
86
- tag_encoding = "UTF-16LE"
87
- first_valid = 0
88
- end
89
- out = out.dup.force_encoding(tag_encoding)[first_valid..-1]
57
+ # ID3v2.3.0 section 3.3 mandates a BOM but some software
58
+ # erroneously omits it so we have to guess. Since most of
59
+ # the world is little endian we might as well go with that.
60
+ tag_encoding = "UTF-16LE"
61
+ first_valid = 0
90
62
  end
63
+ out = out.dup.force_encoding(tag_encoding)[first_valid..-1]
91
64
  end
92
65
  end
93
66
  end
@@ -4,13 +4,6 @@
4
4
 
5
5
  require "delegate"
6
6
 
7
- if RUBY_VERSION[0..2] == "1.8"
8
- require "iconv"
9
- RUBY_1_8 = true
10
- else
11
- RUBY_1_8 = false
12
- end
13
-
14
7
  require "mp3info/extension_modules"
15
8
 
16
9
  class ID3v2Error < StandardError ; end
@@ -19,8 +12,8 @@ class ID3v2Error < StandardError ; end
19
12
  # It works like a hash, where key represents the tag name as 3 or 4 upper case letters
20
13
  # (respectively related to 2.2 and 2.3+ tag) and value represented as array or raw value.
21
14
  # Written version is always 2.3.
22
- class ID3v2 < DelegateClass(Hash)
23
-
15
+ class ID3v2 < DelegateClass(Hash)
16
+
24
17
  TAGS = {
25
18
  "AENC" => "Audio encryption",
26
19
  "APIC" => "Attached picture",
@@ -168,17 +161,17 @@ class ID3v2 < DelegateClass(Hash)
168
161
 
169
162
  # In Ruby 2.1.0 (and possibly others), DelegateClass breaks Kernel methods.
170
163
  include Kernel
171
-
164
+
172
165
  # this is the position in the file where the tag really ends
173
166
  attr_reader :io_position
174
167
 
175
168
  # :+lang+: for writing comments
176
169
  #
177
- # [DEPRECATION] :+encoding+: one of the string of +TEXT_ENCODINGS+,
170
+ # [DEPRECATION] :+encoding+: one of the string of +TEXT_ENCODINGS+,
178
171
  # use of :encoding parameter is DEPRECATED. In ruby 1.8, use utf-8 encoded strings for tags.
179
172
  # In ruby >= 1.9, strings are automatically transcoded from their originaloriginal encoding.
180
173
  attr_reader :options
181
-
174
+
182
175
  # possible options are described above ('options' attribute)
183
176
  # you can access this object like an hash, with [] and []= methods
184
177
  # special cases are ["disc_number"] and ["disc_total"] mirroring TPOS attribute
@@ -208,7 +201,7 @@ class ID3v2 < DelegateClass(Hash)
208
201
  def changed?
209
202
  @hash_orig != @hash
210
203
  end
211
-
204
+
212
205
  # full version of this tag (like "2.3.0") or nil
213
206
  # if tag was not correctly read
214
207
  def version
@@ -237,14 +230,14 @@ class ID3v2 < DelegateClass(Hash)
237
230
  end
238
231
 
239
232
  ### ID3V2::add_picture
240
- ### Takes an image string as input and writes it with header.
233
+ ### Takes an image string as input and writes it with header.
241
234
  ### Mime type is automatically guessed by default.
242
235
  ### It is possible but not necessary to include:
243
236
  ### :pic_type => 0 - 14 (see http://id3.org/id3v2.3.0#Attached_picture)
244
- ### :mime => 'gif'
237
+ ### :mime => 'gif'
245
238
  ### :description => "Image description"
246
239
  def add_picture(data, opts = {})
247
- options = {
240
+ options = {
248
241
  :pic_type => 0,
249
242
  :mime => nil,
250
243
  :description => "image"
@@ -282,7 +275,7 @@ class ID3v2 < DelegateClass(Hash)
282
275
  apic_images.each_index do |index|
283
276
  pic = apic_images[index]
284
277
  next if !pic.is_a?(String) or pic == ""
285
- pic.force_encoding 'BINARY'
278
+ pic.force_encoding 'BINARY'
286
279
  picture = []
287
280
  jpg_regexp = Regexp.new("jpg|JPG|jpeg|JPEG".force_encoding("BINARY"),
288
281
  Regexp::FIXEDENCODING )
@@ -290,7 +283,7 @@ class ID3v2 < DelegateClass(Hash)
290
283
  Regexp::FIXEDENCODING )
291
284
  header = pic.unpack('a120').first.force_encoding "BINARY"
292
285
  mime_pos = 0
293
-
286
+
294
287
  # safest way to correctly extract jpg and png is finding mime
295
288
  if header.match jpg_regexp and not header.match png_regexp
296
289
  mime = "jpg"
@@ -300,7 +293,7 @@ class ID3v2 < DelegateClass(Hash)
300
293
  start_with_anchor = Regexp.new("^\xFF\xD8".force_encoding("BINARY"),
301
294
  Regexp::FIXEDENCODING )
302
295
  end
303
-
296
+
304
297
  if header.match png_regexp and not header.match jpg_regexp
305
298
  mime = "png"
306
299
  mime_pos = header =~ png_regexp
@@ -309,7 +302,7 @@ class ID3v2 < DelegateClass(Hash)
309
302
  start_with_anchor = Regexp.new("^\x89PNG".force_encoding("BINARY"),
310
303
  Regexp::FIXEDENCODING )
311
304
  end
312
-
305
+
313
306
  puts "analysing image: #{header.inspect}..." if $DEBUG
314
307
  _, _, desc, data = pic[mime_pos, pic.length].unpack('Z*hZ*a*')
315
308
 
@@ -318,10 +311,10 @@ class ID3v2 < DelegateClass(Hash)
318
311
  real_start = pic =~ start
319
312
  data = pic[real_start, pic.length]
320
313
  end
321
-
314
+
322
315
  if mime == "jpg"
323
316
  # inspect jpg image header (first 10 chars) for "\xFF\x00" (expect "\xFF")
324
- trailing_null_byte = Regexp.new("(\377)(\000)".force_encoding('BINARY'),
317
+ trailing_null_byte = Regexp.new("(\377)(\000)".force_encoding('BINARY'),
325
318
  Regexp::FIXEDENCODING)
326
319
  md = data =~ trailing_null_byte
327
320
  if !md.nil? and md < 10
@@ -335,7 +328,7 @@ class ID3v2 < DelegateClass(Hash)
335
328
  end
336
329
 
337
330
  filename = ("%02i_#{desc[0,25]}" % (index + 1)).gsub('/','')
338
-
331
+
339
332
  picture[0] = filename
340
333
  picture[1] = data
341
334
  result << picture
@@ -346,7 +339,7 @@ class ID3v2 < DelegateClass(Hash)
346
339
  def inspect
347
340
  self.to_inspect_hash
348
341
  end
349
-
342
+
350
343
  def remove_pictures
351
344
  self["APIC"] = ""
352
345
  self["PIC"] = ""
@@ -362,7 +355,7 @@ class ID3v2 < DelegateClass(Hash)
362
355
  raise(ID3v2Error, "can't find version_maj ('#{version_maj}')") unless [2, 3, 4].include?(version_maj)
363
356
  @version_maj, @version_min = version_maj, version_min
364
357
  @tag_length = @io.get_syncsafe
365
-
358
+
366
359
  @parsed = true
367
360
  begin
368
361
  case @version_maj
@@ -409,9 +402,7 @@ class ID3v2 < DelegateClass(Hash)
409
402
  tag << k[0,4] #4 characte max for a tag's key
410
403
  #tag << to_syncsafe(data.size) #+1 because of the language encoding byte
411
404
  size = data.size
412
- unless RUBY_1_8
413
- size = data.dup.force_encoding("binary").size
414
- end
405
+ size = data.dup.force_encoding("binary").size
415
406
  tag << [size].pack("N") #+1 because of the language encoding byte
416
407
  tag << "\x00"*2 #flags
417
408
  tag << data
@@ -442,9 +433,8 @@ class ID3v2 < DelegateClass(Hash)
442
433
  s = [ 1, @options[:lang], "\xFE\xFF\x00\x00", transcoded_value].pack("ca3a*a*")
443
434
  return s
444
435
  when /^T/
445
- unless RUBY_1_8
446
- transcoded_value.force_encoding("BINARY")
447
- end
436
+ transcoded_value.force_encoding("BINARY")
437
+
448
438
  return "\x01" + transcoded_value
449
439
  else
450
440
  return value
@@ -455,55 +445,55 @@ class ID3v2 < DelegateClass(Hash)
455
445
  def decode_tag(name, raw_value)
456
446
  puts("decode_tag(#{name.inspect}, #{raw_value.inspect})") if $DEBUG
457
447
  if name =~ /^(T|COM|USLT)/
458
- if name =~ /^(COM|USLT)/
459
- #FIXME improve this
460
- encoding_index, lang, raw_tag = raw_value.unpack("ca3a*")
461
- if encoding_index == 1
462
- =begin
463
- comment = Mp3Info::EncodingHelper.decode_utf16(raw_tag)
464
- e = comment.encoding
465
- out = comment.force_encoding("BINARY").split("\x00\x00").last.force_encoding(e)
466
- p out
467
- =end
468
- comment = Mp3Info::EncodingHelper.decode_utf16(raw_tag)
469
- split_val = RUBY_1_8 ? "\x00\x00" : "\x00".encode(comment.encoding).force_encoding('ASCII-8BIT')
470
- out = raw_tag.split(split_val).last rescue ""
448
+ begin
449
+ if name =~ /^(COM|USLT)/
450
+ encoding_index, lang, raw_tag = raw_value.unpack("ca3a*")
451
+ if raw_tag == "\x00"
452
+ return nil
453
+ else
454
+ if encoding_index == 1
455
+ split_str = /\x00\x00\x00?/
456
+ else
457
+ split_str = "\x00"
458
+ end
459
+ head, tail = raw_tag.split(split_str)
460
+ if head == "\xFF\xFE".force_encoding('binary')
461
+ rgx = Regexp.new("^\xFF\xFE\x00\x00".force_encoding("BINARY"))
462
+ out = raw_tag.sub(rgx, '')
463
+ elsif tail
464
+ out = tail
465
+ elsif head
466
+ out = head
467
+ else
468
+ warn("warning: cannot decode tag #{name} with raw value #{raw_value.inspect}")
469
+ return nil
470
+ end
471
+ end
472
+ puts "COM tag found. encoding: #{encoding_index} lang: #{lang} str: #{out.inspect}" if $DEBUG
471
473
  else
472
- comment, out = raw_tag.split("\x00", 2)
474
+ encoding_index = raw_value.getbyte(0) # language encoding (see TEXT_ENCODINGS constant)
475
+ out = raw_value[1..-1]
473
476
  end
474
- puts "COM tag found. encoding: #{encoding_index} lang: #{lang} str: #{out.inspect}" if $DEBUG
475
- else
476
- encoding_index = raw_value.getbyte(0) # language encoding (see TEXT_ENCODINGS constant)
477
- out = raw_value[1..-1]
478
- end
479
- # we need to convert the string in order to match
480
- # the requested encoding
481
- if encoding_index && TEXT_ENCODINGS[encoding_index] && out
482
- if RUBY_1_8
483
- out = Mp3Info::EncodingHelper.convert_to(out, TEXT_ENCODINGS[encoding_index], "utf-8")
484
- else
477
+ # we need to convert the string in order to match
478
+ # the requested encoding
479
+ if TEXT_ENCODINGS[encoding_index]
485
480
  if encoding_index == 1
486
481
  out = Mp3Info::EncodingHelper.decode_utf16(out)
487
482
  else
488
483
  out.force_encoding(TEXT_ENCODINGS[encoding_index])
489
484
  end
490
- if out
491
- out.encode!("utf-8")
492
- end
485
+ out.encode!("utf-8")
493
486
  end
494
- end
495
487
 
496
- if out
497
488
  # remove padding zeros for textual tags
498
- if RUBY_1_8
499
- r = /\0*$/
500
- else
501
- r = Regexp.new("\x00*$".encode(out.encoding))
502
- end
503
- out.sub!(r, '')
504
- end
489
+ r = Regexp.new("\x00*$".encode(out.encoding))
490
+ out.sub!(r, '')
505
491
 
506
- return out
492
+ return out
493
+ rescue => e
494
+ warn "warning: cannot decode tag #{name} with raw value #{raw_value.inspect}: #{e}"
495
+ return nil
496
+ end
507
497
  else
508
498
  return raw_value
509
499
  end
@@ -518,7 +508,7 @@ class ID3v2 < DelegateClass(Hash)
518
508
  @io.seek(-4, IO::SEEK_CUR) # 1. find a padding zero,
519
509
  seek_to_v2_end
520
510
  break
521
- else
511
+ else
522
512
  if @version_maj == 4
523
513
  size = @io.get_syncsafe
524
514
  else
@@ -530,7 +520,7 @@ class ID3v2 < DelegateClass(Hash)
530
520
  end
531
521
  break if @io.pos >= @tag_length # 2. reach length from header
532
522
  end
533
- end
523
+ end
534
524
 
535
525
  ### reads id3 ver 2.2.x frames and adds the contents to @tag2 hash
536
526
  ### NOTE: the id3v2 header does not take padding zero's into consideration
@@ -547,8 +537,8 @@ class ID3v2 < DelegateClass(Hash)
547
537
  break if @io.pos >= @tag_length
548
538
  end
549
539
  end
550
- end
551
-
540
+ end
541
+
552
542
  ### Add data to tag2["name"]
553
543
  ### read lang_encoding, decode data if unicode and
554
544
  ### create an array if the key already exists in the tag
@@ -558,11 +548,11 @@ class ID3v2 < DelegateClass(Hash)
558
548
  if size > 50_000_000
559
549
  raise ID3v2Error, "tag size is > 50_000_000"
560
550
  end
561
-
551
+
562
552
  data_io = @io.read(size)
563
553
  data = decode_tag(name, data_io)
564
554
  if data && !data.empty?
565
- if self.keys.include?(name)
555
+ if self.keys.include?(name)
566
556
  if self[name].is_a?(Array)
567
557
  unless self[name].include?(data)
568
558
  self[name] << data
@@ -571,7 +561,7 @@ class ID3v2 < DelegateClass(Hash)
571
561
  self[name] = [ self[name], data ]
572
562
  end
573
563
  else
574
- self[name] = data
564
+ self[name] = data
575
565
  end
576
566
 
577
567
  if name == "TPOS" && data =~ /(\d+)\s*\/\s*(\d+)/
@@ -582,7 +572,7 @@ class ID3v2 < DelegateClass(Hash)
582
572
 
583
573
  puts "self[#{name.inspect}] = #{self[name].inspect}" if $DEBUG
584
574
  end
585
-
575
+
586
576
  ### runs thru @file one char at a time looking for best guess of first MPEG
587
577
  ### frame, which should be first 0xff byte after id3v2 padding zero's
588
578
  def seek_to_v2_end
@@ -591,12 +581,12 @@ class ID3v2 < DelegateClass(Hash)
591
581
  end
592
582
  @io.seek(-1, IO::SEEK_CUR)
593
583
  end
594
-
584
+
595
585
  ### convert an 32 integer to a syncsafe string
596
586
  def to_syncsafe(num)
597
587
  ( (num<<3) & 0x7f000000 ) + ( (num<<2) & 0x7f0000 ) + ( (num<<1) & 0x7f00 ) + ( num & 0x7f )
598
588
  end
599
-
589
+
600
590
  ### this is especially useful for printing out APIC data because
601
591
  ### only the header of the APIC tag is of interest
602
592
  def pretty_header(str, chars=128)
@@ -604,4 +594,3 @@ class ID3v2 < DelegateClass(Hash)
604
594
  end
605
595
 
606
596
  end
607
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-mp3info
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.9
4
+ version: 0.8.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillaume Pierronnet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-02 00:00:00.000000000 Z
11
+ date: 2016-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.12'
33
+ version: '3.15'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.12'
40
+ version: '3.15'
41
41
  description: ruby-mp3info read low-level informations and manipulate tags on mp3 files.
42
42
  email:
43
43
  - guillaume.pierronnet@gmail.com
@@ -48,7 +48,6 @@ extra_rdoc_files:
48
48
  - Manifest.txt
49
49
  - README.md
50
50
  files:
51
- - ".gemtest"
52
51
  - History.txt
53
52
  - Manifest.txt
54
53
  - README.md
@@ -80,9 +79,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
79
  version: '0'
81
80
  requirements: []
82
81
  rubyforge_project:
83
- rubygems_version: 2.2.2
82
+ rubygems_version: 2.5.1
84
83
  signing_key:
85
84
  specification_version: 4
86
85
  summary: ruby-mp3info read low-level informations and manipulate tags on mp3 files.
87
- test_files:
88
- - test/test_ruby-mp3info.rb
86
+ test_files: []
data/.gemtest DELETED
File without changes