mp3file 1.0.3 → 1.1.0

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: fe6010e6463c0bfe01c34dcc53081a9cd3ff0dd7
4
- data.tar.gz: 88bcc7293fd8702980fb2344ef8d6e50457e7441
3
+ metadata.gz: 0bfcaa237ab4362c6e5ff6267f84c6becd95aab3
4
+ data.tar.gz: 3d86a90044fbf1ed37cf558a660e464993f71ec8
5
5
  SHA512:
6
- metadata.gz: b37617a0dabcc81bd28b4b1ee5c09bd472270792737fdc5298d20970063236a4afc635344a69730665085d518c0d8d42cfaefb211eb1dc73a20a5395301e1447
7
- data.tar.gz: 76330c2fc6d7654a634732f88652d46309dbefd5a92ad354e7dcc9dc9595e4017d6f014314852d754fbcf28b321577184e173205f90ec7e77fbac1f94aec443d
6
+ metadata.gz: 13e2cf72a0f6db63c9676d3a78eeed4345bd01e9cfb7487d1b24a864cf9ff35c9a4c945bf3890c97c269efb13ef0125177ee89902d2b5f8eb94f5c798faf36c2
7
+ data.tar.gz: e483622cdc9d209500c82809fb619f19e8ef0caa454c3ff209923d66438568b173c0d39cbe67c2852d16650f2b690b7b23b0c5b61a7e1d81c95bd4190fe1b16a
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ pkg/*
2
2
  *.gem
3
3
  .bundle
4
4
  .DS_Store
5
+ /Gemfile.lock
@@ -3,21 +3,33 @@
3
3
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
  require 'mp3file'
5
5
 
6
+ def humanize(num, places = 2)
7
+ if num.is_a?(Float)
8
+ parts = ("%.#{places}f" % [ num ]).split(".")
9
+ else
10
+ parts = num.to_s.to_str.split(".")
11
+ end
12
+
13
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
14
+ parts.join(".")
15
+ end
16
+ alias :h :humanize
17
+
6
18
  ARGV.each do |file|
7
19
  begin
8
- mp3 = Mp3file::MP3File.new(file)
20
+ mp3 = Mp3file::MP3File.new(file, scan_all_headers: true)
9
21
 
10
22
  puts("File: #{mp3.file.path}")
11
- puts(" Size: #{mp3.file_size} bytes Audio_size: #{mp3.audio_size} bytes")
23
+ puts(" Size: #{h(mp3.file_size)} bytes Audio_size: #{h(mp3.audio_size)} bytes")
12
24
  puts(" #{mp3.mpeg_version} #{mp3.layer}")
13
- puts(" Bitrate: #{mp3.bitrate} kbps Samplerate: #{mp3.samplerate} Hz Mode: #{mp3.mode}")
14
- puts(" Duration: #{mp3.length} s")
15
- puts(" Frames: #{mp3.num_frames} Samples: #{mp3.total_samples}")
25
+ puts(" Bitrate: #{h(mp3.bitrate)} kbits/sec (vbr? #{mp3.vbr?.to_s}) Samplerate: #{mp3.samplerate} Hz Mode: #{mp3.mode}")
26
+ puts(" Duration: #{h(mp3.length)} s")
27
+ puts(" Frames: #{h(mp3.num_frames)} Samples: #{h(mp3.total_samples)}")
16
28
 
17
29
  header = mp3.first_header
18
- puts(" First MPEG frame at #{mp3.first_header_offset} bytes:")
30
+ puts(" First MPEG frame at #{h(mp3.first_header_offset)} bytes:")
19
31
  puts(" #{header.version} #{header.layer}")
20
- puts(" Bitrate: #{header.bitrate} bps Samplerate: #{header.samplerate} Hz")
32
+ puts(" Bitrate: #{header.bitrate} bps Samplerate: #{h(header.samplerate)} Hz")
21
33
  puts(" Mode: #{header.mode} Mode Extension: #{header.mode_extension} Emphasis: #{header.emphasis}")
22
34
  puts(" CRC: #{header.has_crc} Padding: #{header.has_padding}")
23
35
  puts(" Copyright: #{header.copyright} Original: #{header.original}")
@@ -26,7 +38,7 @@ ARGV.each do |file|
26
38
  if mp3.xing_header
27
39
  xing = mp3.xing_header
28
40
  puts(" Xing header:")
29
- puts(" Frames: #{xing.frames} Bytes: #{xing.bytes} Quality: #{xing.quality} TOC: #{xing.toc ? 'present' : 'not present'}")
41
+ puts(" Frames: #{h(xing.frames)} Bytes: #{h(xing.bytes)} Quality: #{xing.quality} TOC: #{xing.toc ? 'present' : 'not present'}")
30
42
  end
31
43
 
32
44
  if mp3.vbri_header
@@ -47,13 +59,13 @@ ARGV.each do |file|
47
59
  if mp3.id3v2tag?
48
60
  tag = mp3.id3v2_tag
49
61
  puts(" ID3v2 tag:")
50
- puts(" Size: #{tag.size} bytes")
62
+ puts(" Size: #{h(tag.size)} bytes")
51
63
  puts(" Version: #{tag.version.inspect}")
52
- puts(" Unused byes: #{tag.unused_bytes.inspect}")
64
+ puts(" Unused byes: #{h(tag.unused_bytes)}")
53
65
  if !tag.frames.empty?
54
66
  puts(" Frames:")
55
67
  tag.frames.each do |frame|
56
- puts(" ID: #{frame.frame_id.inspect} size: #{frame.frame_size}")
68
+ puts(" ID: #{frame.frame_id.inspect} size: #{h(frame.frame_size)}")
57
69
  end
58
70
  end
59
71
  end
@@ -63,11 +75,11 @@ ARGV.each do |file|
63
75
  puts(" Offset: #{offset} bytes")
64
76
  puts(" Size: #{tag2.size} bytes")
65
77
  puts(" Version: #{tag2.version.inspect}")
66
- puts(" Unused byes: #{tag2.unused_bytes.inspect}")
78
+ puts(" Unused byes: #{h(tag2.unused_bytes)}")
67
79
  if !tag2.frames.empty?
68
80
  puts(" Frames:")
69
81
  tag2.frames.each do |frame|
70
- puts(" ID: #{frame.frame_id.inspect} size: #{frame.frame_size}")
82
+ puts(" ID: #{frame.frame_id.inspect} size: #{h(frame.frame_size)}")
71
83
  end
72
84
  end
73
85
  end
@@ -61,6 +61,7 @@ module Mp3file::ID3v2
61
61
  if @tag.version >= ID3V2_2_0 && @tag.version < ID3V2_3_0
62
62
  header = ID3v220FrameHeaderFormat.read(io)
63
63
  @header_size = 6
64
+ @frame_size = header.frame_size
64
65
  elsif @tag.version >= ID3V2_3_0 && @tag.version < ID3V2_4_0
65
66
  header = ID3v230FrameHeaderFormat.read(io)
66
67
  @header_size = 10
@@ -75,16 +76,17 @@ module Mp3file::ID3v2
75
76
  if header.has_group == 1
76
77
  @group = header.group_id
77
78
  end
79
+ @frame_size = header.frame_size
78
80
  elsif @tag.version >= ID3V2_4_0
79
81
  header = ID3v240FrameHeaderFormat.read(io)
80
82
  @header_size = 10
83
+ @frame_size = BitPaddedInt.unpad_number(header.frame_size)
81
84
  end
82
85
  rescue BinData::ValidityError => ve
83
86
  raise InvalidID3v2TagError, ve.message
84
87
  end
85
88
 
86
89
  @frame_id = header.frame_id
87
- @frame_size = BitPaddedInt.unpad_number(header.frame_size)
88
90
  @size = @header_size + @frame_size
89
91
  end
90
92
  end
@@ -25,11 +25,14 @@ module Mp3file::ID3v2
25
25
  data.force_encoding("ASCII-8BIT")
26
26
  offset = 0
27
27
 
28
- frame_offset, frame = get_next_frame_header(data, offset)
29
- while frame
30
- @frames << frame
31
- offset = frame_offset + frame.size
28
+ loop do
32
29
  frame_offset, frame = get_next_frame_header(data, offset)
30
+ if frame
31
+ @frames << frame
32
+ offset = frame_offset + frame.size
33
+ else
34
+ break
35
+ end
33
36
  end
34
37
  end
35
38
 
@@ -11,9 +11,9 @@ module Mp3file
11
11
 
12
12
  attr_accessor(:id3v1_tag, :id3v2_tag, :extra_id3v2_tags)
13
13
 
14
- def initialize(file_path)
14
+ def initialize(file_path, options = {})
15
15
  file_path = Pathname.new(file_path).expand_path if file_path.is_a?(String)
16
- load_file(file_path)
16
+ load_file(file_path, options)
17
17
  end
18
18
 
19
19
  def vbr?
@@ -82,7 +82,9 @@ module Mp3file
82
82
  end
83
83
  end
84
84
 
85
- def load_file(file_path)
85
+ def load_file(file_path, options = {})
86
+ scan_all_headers = %w{ t true 1 }.include?(options[:scan_all_headers].to_s)
87
+
86
88
  @file = file_path.open('rb')
87
89
  @file.seek(0, IO::SEEK_END)
88
90
  @file_size = @file.tell
@@ -150,8 +152,8 @@ module Mp3file
150
152
  if @id3v1_tag
151
153
  @audio_size -= 128
152
154
  end
153
- if @id3v2_header
154
- @audio_size -= (@id3v2_header.tag_size + 10)
155
+ if @id3v2_tag
156
+ @audio_size -= @id3v2_tag.size
155
157
  end
156
158
 
157
159
  # If it's VBR, there should be an Xing header after the
@@ -164,22 +166,43 @@ module Mp3file
164
166
  @file.seek(@first_header_offset + 4, IO::SEEK_CUR)
165
167
  end
166
168
 
167
- if @xing_header
168
- @vbr = true
169
- # Do the VBR length calculation. What to do if we don't have
170
- # both of these pieces of information?
171
- if @xing_header.frames && @xing_header.bytes
172
- @num_frames = @xing_header.frames
173
- @total_samples = @xing_header.frames * @first_header.samples
174
- @length = total_samples.to_f / @samplerate.to_f
175
- @bitrate = ((@xing_header.bytes.to_f / @length.to_f) * 8 / 1000).to_i
169
+ if scan_all_headers
170
+ # Loop through all the frame headers, to check for VBR / CBR (as
171
+ # a Xing header can show up in either case).
172
+ frame_headers = [ @first_header ]
173
+ last_header_offset = @first_header_offset
174
+ loop do
175
+ file.seek(last_header_offset + frame_headers.last.frame_size)
176
+ last_header_offset, header = get_next_header(file)
177
+ if header.nil?
178
+ break
179
+ else
180
+ frame_headers << header
181
+ end
182
+ end
183
+
184
+ uniq_brs = frame_headers.map { |h| h.bitrate }.uniq
185
+ @vbr = uniq_brs.size > 1
186
+ if uniq_brs.size == 1
187
+ @bitrate = uniq_brs.first / 1000
176
188
  end
189
+ else
190
+ # Use the Xing header to make the VBR / CBR call. Assume that
191
+ # Xing headers, when present in a CBR file, are called "Info".
192
+ @vbr = @xing_header.nil? || @xing_header.name == "Xing"
193
+ end
194
+
195
+ if @xing_header && @xing_header.frames && @xing_header.bytes
196
+ # Use the Xing header to calculate the duration (and overall bitrate).
197
+ @num_frames = @xing_header.frames
198
+ @total_samples = @xing_header.frames * @first_header.samples
199
+ @length = total_samples.to_f / @samplerate.to_f
200
+ @bitrate = ((@xing_header.bytes.to_f / @length.to_f) * 8 / 1000)
177
201
  else
178
202
  # Do the CBR length calculation.
179
- @vbr = false
180
203
  @num_frames = @audio_size / @first_header.frame_size
181
204
  @total_samples = @num_frames * @first_header.samples
182
- @length = @total_samples / @samplerate
205
+ @length = @total_samples.to_f / @samplerate.to_f
183
206
  end
184
207
 
185
208
  @file.close
@@ -206,6 +229,8 @@ module Mp3file
206
229
  file.seek(header_offset, IO::SEEK_SET)
207
230
  retry
208
231
  end
232
+ rescue EOFError
233
+ break
209
234
  end
210
235
 
211
236
  # byte = file.readbyte
@@ -226,6 +251,10 @@ module Mp3file
226
251
  # end
227
252
  end
228
253
 
254
+ # if initial_header_offset != header_offset
255
+ # puts "Had to skip past #{header_offset - initial_header_offset} to find the next header."
256
+ # end
257
+
229
258
  [ header_offset, header ]
230
259
  end
231
260
  end
@@ -1,3 +1,3 @@
1
1
  module Mp3file
2
- VERSION = "1.0.3"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -2,7 +2,7 @@ module Mp3file
2
2
  class InvalidXingHeaderError < Mp3fileError; end
3
3
 
4
4
  class XingHeader
5
- attr_reader(:frames, :bytes, :toc, :quality)
5
+ attr_reader(:name, :frames, :bytes, :toc, :quality)
6
6
 
7
7
  class XingHeaderFormat < BinData::Record
8
8
  string(:vbr_id, :length => 4, :check_value => lambda { value == 'Xing' || value == 'Info' })
@@ -30,6 +30,7 @@ module Mp3file
30
30
  raise InvalidXingHeaderError, ve.message
31
31
  end
32
32
 
33
+ @name = head.vbr_id
33
34
  @frames = head.frames if head.frames_present == 1
34
35
  @bytes = head.bytes if head.bytes_present == 1
35
36
  @toc = head.toc.dup if head.toc_present == 1
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_development_dependency('rspec')
19
19
  s.add_development_dependency('rake')
20
+ s.add_development_dependency('pry')
21
+
20
22
  s.add_dependency('bindata', '~> 1.5.0')
21
23
 
22
24
  s.files = `git ls-files`.split("\n")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mp3file
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Watts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-28 00:00:00.000000000 Z
11
+ date: 2015-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bindata
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -65,7 +79,6 @@ files:
65
79
  - ".ruby-gemset"
66
80
  - ".ruby-version"
67
81
  - Gemfile
68
- - Gemfile.lock
69
82
  - README.md
70
83
  - Rakefile
71
84
  - bin/mp3info
@@ -1,29 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- mp3file (1.0.3)
5
- bindata (~> 1.5.0)
6
-
7
- GEM
8
- remote: http://rubygems.org/
9
- specs:
10
- bindata (1.5.1)
11
- diff-lcs (1.1.2)
12
- rake (0.9.2)
13
- rspec (2.6.0)
14
- rspec-core (~> 2.6.0)
15
- rspec-expectations (~> 2.6.0)
16
- rspec-mocks (~> 2.6.0)
17
- rspec-core (2.6.4)
18
- rspec-expectations (2.6.0)
19
- diff-lcs (~> 1.1.2)
20
- rspec-mocks (2.6.0)
21
-
22
- PLATFORMS
23
- ruby
24
- x86-mingw32
25
-
26
- DEPENDENCIES
27
- mp3file!
28
- rake
29
- rspec