wahwah 1.0.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,7 +17,7 @@ module WahWah
17
17
  TRCK: :track
18
18
  }
19
19
 
20
- CHANNEL_MODE_INDEX = %w(Mono Stereo)
20
+ CHANNEL_MODE_INDEX = %w[Mono Stereo]
21
21
 
22
22
  tag_delegate :@id3_tag,
23
23
  :title,
@@ -39,102 +39,104 @@ module WahWah
39
39
  end
40
40
 
41
41
  private
42
- def parse
43
- top_chunk = Riff::Chunk.new(@file_io)
44
- return unless top_chunk.valid?
45
42
 
46
- total_chunk_size = top_chunk.size + Riff::Chunk::HEADER_SIZE
43
+ def parse
44
+ top_chunk = Riff::Chunk.new(@file_io)
45
+ return unless top_chunk.valid?
47
46
 
48
- # The top "RIFF" chunks include an additional field in the first four bytes of the data field.
49
- # This additional field provides the form type of the field.
50
- # For wav file, the value of the type field is 'WAVE'
51
- return unless top_chunk.id == 'RIFF' && top_chunk.type == 'WAVE'
47
+ total_chunk_size = top_chunk.size + Riff::Chunk::HEADER_SIZE
52
48
 
53
- until total_chunk_size <= @file_io.pos || @file_io.eof? do
54
- sub_chunk = Riff::Chunk.new(@file_io)
55
- parse_sub_chunk(sub_chunk)
56
- end
57
- end
49
+ # The top "RIFF" chunks include an additional field in the first four bytes of the data field.
50
+ # This additional field provides the form type of the field.
51
+ # For wav file, the value of the type field is 'WAVE'
52
+ return unless top_chunk.id == "RIFF" && top_chunk.type == "WAVE"
58
53
 
59
- def parse_sub_chunk(sub_chunk)
60
- return unless sub_chunk.valid?
61
-
62
- case sub_chunk.id
63
- when 'fmt'
64
- parse_fmt_chunk(sub_chunk)
65
- when 'data'
66
- parse_data_chunk(sub_chunk)
67
- when 'LIST'
68
- parse_list_chunk(sub_chunk)
69
- when 'id3', 'ID3'
70
- parse_id3_chunk(sub_chunk)
71
- else
72
- @file_io.seek(sub_chunk.size, IO::SEEK_CUR)
73
- end
54
+ until total_chunk_size <= @file_io.pos || @file_io.eof?
55
+ sub_chunk = Riff::Chunk.new(@file_io)
56
+ parse_sub_chunk(sub_chunk)
74
57
  end
58
+ end
75
59
 
76
- # The fmt chunk data structure:
77
- # Length Meaning Description
78
- #
79
- # 2(little endian) AudioFormat PCM = 1 (i.e. Linear quantization)
80
- # Values other than 1 indicate some
81
- # form of compression.
82
- #
83
- # 2(little endian) NumChannels Mono = 1, Stereo = 2, etc.
84
- #
85
- # 4(little endian) SampleRate 8000, 44100, etc.
86
- #
87
- # 4(little endian) ByteRate == SampleRate * NumChannels * BitsPerSample/8
88
- #
89
- # 2(little endian) BlockAlign == NumChannels * BitsPerSample/8
90
- # The number of bytes for one sample including
91
- # all channels.
92
- #
93
- # 2(little endian) BitsPerSample 8 bits = 8, 16 bits = 16, etc.
94
- def parse_fmt_chunk(chunk)
95
- _, @channel, @sample_rate, _, _, @bits_per_sample = chunk.data.unpack('vvVVvv')
96
- @bitrate = @sample_rate * @channel * @bits_per_sample / 1000
60
+ def parse_sub_chunk(sub_chunk)
61
+ return unless sub_chunk.valid?
62
+
63
+ case sub_chunk.id
64
+ when "fmt"
65
+ parse_fmt_chunk(sub_chunk)
66
+ when "data"
67
+ parse_data_chunk(sub_chunk)
68
+ when "LIST"
69
+ parse_list_chunk(sub_chunk)
70
+ when "id3", "ID3"
71
+ parse_id3_chunk(sub_chunk)
72
+ else
73
+ sub_chunk.skip
97
74
  end
75
+ end
98
76
 
99
- def parse_data_chunk(chunk)
100
- @duration = chunk.size * 8 / (@bitrate * 1000)
101
- @file_io.seek(chunk.size, IO::SEEK_CUR)
102
- end
77
+ # The fmt chunk data structure:
78
+ # Length Meaning Description
79
+ #
80
+ # 2(little endian) AudioFormat PCM = 1 (i.e. Linear quantization)
81
+ # Values other than 1 indicate some
82
+ # form of compression.
83
+ #
84
+ # 2(little endian) NumChannels Mono = 1, Stereo = 2, etc.
85
+ #
86
+ # 4(little endian) SampleRate 8000, 44100, etc.
87
+ #
88
+ # 4(little endian) ByteRate == SampleRate * NumChannels * BitsPerSample/8
89
+ #
90
+ # 2(little endian) BlockAlign == NumChannels * BitsPerSample/8
91
+ # The number of bytes for one sample including
92
+ # all channels.
93
+ #
94
+ # 2(little endian) BitsPerSample 8 bits = 8, 16 bits = 16, etc.
95
+ def parse_fmt_chunk(chunk)
96
+ _, @channel, @sample_rate, _, _, @bit_depth = chunk.data.unpack("vvVVvv")
97
+ @bitrate = @sample_rate * @channel * @bit_depth / 1000
98
+ end
103
99
 
104
- def parse_list_chunk(chunk)
105
- list_chunk_end_position = @file_io.pos + chunk.size
100
+ def parse_data_chunk(chunk)
101
+ @duration = chunk.size * 8 / (@bitrate * 1000).to_f
102
+ chunk.skip
103
+ end
106
104
 
107
- # RIFF can be tagged with metadata in the INFO chunk.
108
- # And INFO chunk as a subchunk for LIST chunk.
109
- if chunk.type != 'INFO'
110
- @file_io.seek(chunk.size, IO::SEEK_CUR)
111
- else
112
- until list_chunk_end_position <= @file_io.pos do
113
- info_chunk = Riff::Chunk.new(@file_io)
105
+ def parse_list_chunk(chunk)
106
+ list_chunk_end_position = @file_io.pos + chunk.size
114
107
 
115
- unless INFO_ID_MAPPING.keys.include? info_chunk.id.to_sym
116
- @file_io.seek(info_chunk.size, IO::SEEK_CUR); next
117
- end
108
+ # RIFF can be tagged with metadata in the INFO chunk.
109
+ # And INFO chunk as a subchunk for LIST chunk.
110
+ if chunk.type != "INFO"
111
+ chunk.skip
112
+ else
113
+ until list_chunk_end_position <= @file_io.pos
114
+ info_chunk = Riff::Chunk.new(@file_io)
118
115
 
119
- update_attribute(info_chunk)
116
+ unless INFO_ID_MAPPING.key? info_chunk.id.to_sym
117
+ info_chunk.skip
118
+ next
120
119
  end
120
+
121
+ update_attribute(info_chunk)
121
122
  end
122
123
  end
124
+ end
123
125
 
124
- def parse_id3_chunk(chunk)
125
- @id3_tag = ID3::V2.new(StringIO.new(chunk.data))
126
- end
126
+ def parse_id3_chunk(chunk)
127
+ @id3_tag = ID3::V2.new(StringIO.new(chunk.data))
128
+ end
127
129
 
128
- def update_attribute(chunk)
129
- attribute_name = INFO_ID_MAPPING[chunk.id.to_sym]
130
- chunk_data = Helper.encode_to_utf8(chunk.data)
130
+ def update_attribute(chunk)
131
+ attr_name = INFO_ID_MAPPING[chunk.id.to_sym]
132
+ chunk_data = Helper.encode_to_utf8(chunk.data)
131
133
 
132
- case attribute_name
133
- when :comment
134
- @comments.push(chunk_data)
135
- else
136
- instance_variable_set("@#{attribute_name}", chunk_data)
137
- end
134
+ case attr_name
135
+ when :comment
136
+ @comments.push(chunk_data)
137
+ else
138
+ instance_variable_set("@#{attr_name}", chunk_data)
138
139
  end
140
+ end
139
141
  end
140
142
  end
data/lib/wahwah/tag.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  module WahWah
4
4
  class Tag
5
- INTEGER_ATTRIBUTES = %i(disc disc_total track track_total)
6
- INSPECT_ATTRIBUTES = %i(title artist album albumartist composer track track_total genre year disc disc_total duration bitrate sample_rate)
5
+ INTEGER_ATTRIBUTES = %i[disc disc_total track track_total]
6
+ INSPECT_ATTRIBUTES = %i[title artist album albumartist composer track track_total genre year disc disc_total duration bitrate sample_rate bit_depth]
7
7
 
8
8
  attr_reader(
9
9
  :title,
@@ -18,10 +18,10 @@ module WahWah
18
18
  :year,
19
19
  :disc,
20
20
  :disc_total,
21
- :images,
22
21
  :duration,
23
22
  :bitrate,
24
23
  :sample_rate,
24
+ :bit_depth,
25
25
  :file_size
26
26
  )
27
27
 
@@ -35,7 +35,7 @@ module WahWah
35
35
  end
36
36
 
37
37
  @comments = []
38
- @images = []
38
+ @images_data = []
39
39
 
40
40
  parse if @file_size > 0
41
41
 
@@ -43,17 +43,29 @@ module WahWah
43
43
  value = instance_variable_get("@#{attr_name}")&.to_i
44
44
  instance_variable_set("@#{attr_name}", value)
45
45
  end
46
- end
47
-
48
- def parse
49
- raise WahWahNotImplementedError, 'The parse method is not implemented'
46
+ ensure
47
+ @file_io.close
50
48
  end
51
49
 
52
50
  def inspect
53
- inspect_id = ::Kernel.format '%x', (object_id * 2)
54
- inspect_attributes_values = INSPECT_ATTRIBUTES.map { |attr_name| "#{attr_name}=#{self.send(attr_name)}" }.join(' ')
51
+ inspect_id = ::Kernel.format "%x", (object_id * 2)
52
+ inspect_attributes_values = INSPECT_ATTRIBUTES.map { |attr_name| "#{attr_name}=#{send(attr_name)}" }.join(" ")
55
53
 
56
54
  "<#{self.class.name}:0x#{inspect_id} #{inspect_attributes_values}>"
57
55
  end
56
+
57
+ def images
58
+ return @images_data if @images_data.empty?
59
+
60
+ @images_data.map do |data|
61
+ parse_image_data(data)
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def parse
68
+ raise WahWahNotImplementedError, "The parse method is not implemented"
69
+ end
58
70
  end
59
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WahWah
4
- VERSION = '1.0.0'
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/wahwah.rb CHANGED
@@ -1,57 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wahwah/version'
4
- require 'wahwah/errors'
5
- require 'wahwah/helper'
6
- require 'wahwah/tag_delegate'
7
- require 'wahwah/tag'
8
-
9
- require 'wahwah/id3/v1'
10
- require 'wahwah/id3/v2'
11
- require 'wahwah/id3/v2_header'
12
- require 'wahwah/id3/frame'
13
- require 'wahwah/id3/frame_body'
14
- require 'wahwah/id3/text_frame_body'
15
- require 'wahwah/id3/genre_frame_body'
16
- require 'wahwah/id3/comment_frame_body'
17
- require 'wahwah/id3/image_frame_body'
18
-
19
- require 'wahwah/mp3/mpeg_frame_header'
20
- require 'wahwah/mp3/xing_header'
21
- require 'wahwah/mp3/vbri_header'
22
-
23
- require 'wahwah/riff/chunk'
24
-
25
- require 'wahwah/flac/block'
26
- require 'wahwah/flac/streaminfo_block'
27
-
28
- require 'wahwah/ogg/page'
29
- require 'wahwah/ogg/pages'
30
- require 'wahwah/ogg/packets'
31
- require 'wahwah/ogg/vorbis_comment'
32
- require 'wahwah/ogg/vorbis_tag'
33
- require 'wahwah/ogg/opus_tag'
34
- require 'wahwah/ogg/flac_tag'
35
-
36
- require 'wahwah/asf/object'
37
-
38
- require 'wahwah/mp4/atom'
39
-
40
- require 'wahwah/mp3_tag'
41
- require 'wahwah/mp4_tag'
42
- require 'wahwah/ogg_tag'
43
- require 'wahwah/riff_tag'
44
- require 'wahwah/asf_tag'
45
- require 'wahwah/flac_tag'
3
+ require "stringio"
4
+ require "forwardable"
5
+ require "zlib"
6
+
7
+ require "wahwah/version"
8
+ require "wahwah/errors"
9
+ require "wahwah/helper"
10
+ require "wahwah/tag_delegate"
11
+ require "wahwah/lazy_read"
12
+ require "wahwah/tag"
13
+
14
+ require "wahwah/id3/v1"
15
+ require "wahwah/id3/v2"
16
+ require "wahwah/id3/v2_header"
17
+ require "wahwah/id3/frame"
18
+ require "wahwah/id3/frame_body"
19
+ require "wahwah/id3/text_frame_body"
20
+ require "wahwah/id3/genre_frame_body"
21
+ require "wahwah/id3/comment_frame_body"
22
+ require "wahwah/id3/image_frame_body"
23
+
24
+ require "wahwah/mp3/mpeg_frame_header"
25
+ require "wahwah/mp3/xing_header"
26
+ require "wahwah/mp3/vbri_header"
27
+
28
+ require "wahwah/riff/chunk"
29
+
30
+ require "wahwah/flac/block"
31
+ require "wahwah/flac/streaminfo_block"
32
+
33
+ require "wahwah/ogg/page"
34
+ require "wahwah/ogg/pages"
35
+ require "wahwah/ogg/packets"
36
+ require "wahwah/ogg/vorbis_comment"
37
+ require "wahwah/ogg/vorbis_tag"
38
+ require "wahwah/ogg/opus_tag"
39
+ require "wahwah/ogg/flac_tag"
40
+
41
+ require "wahwah/asf/object"
42
+
43
+ require "wahwah/mp4/atom"
44
+
45
+ require "wahwah/mp3_tag"
46
+ require "wahwah/mp4_tag"
47
+ require "wahwah/ogg_tag"
48
+ require "wahwah/riff_tag"
49
+ require "wahwah/asf_tag"
50
+ require "wahwah/flac_tag"
46
51
 
47
52
  module WahWah
48
53
  FORMATE_MAPPING = {
49
- Mp3Tag: ['mp3'],
50
- OggTag: ['ogg', 'oga', 'opus'],
51
- RiffTag: ['wav'],
52
- FlacTag: ['flac'],
53
- AsfTag: ['wma'],
54
- Mp4Tag: ['m4a']
54
+ Mp3Tag: ["mp3"],
55
+ OggTag: ["ogg", "oga", "opus"],
56
+ RiffTag: ["wav"],
57
+ FlacTag: ["flac"],
58
+ AsfTag: ["wma"],
59
+ Mp4Tag: ["m4a"]
55
60
  }.freeze
56
61
 
57
62
  def self.open(file_path)
@@ -60,10 +65,10 @@ module WahWah
60
65
 
61
66
  file_format = Helper.file_format(file_path)
62
67
 
63
- raise WahWahArgumentError, 'File is not exists' unless File.exist? file_path
64
- raise WahWahArgumentError, 'File is unreadable' unless File.readable? file_path
65
- raise WahWahArgumentError, 'File is empty' unless File.size(file_path) > 0
66
- raise WahWahArgumentError, 'No supported format found' unless support_formats.include? file_format
68
+ raise WahWahArgumentError, "File is not exists" unless File.exist? file_path
69
+ raise WahWahArgumentError, "File is unreadable" unless File.readable? file_path
70
+ raise WahWahArgumentError, "File is empty" unless File.size(file_path) > 0
71
+ raise WahWahArgumentError, "No supported format found" unless support_formats.include? file_format
67
72
 
68
73
  FORMATE_MAPPING.each do |tag, formats|
69
74
  break const_get(tag).new(file_path) if formats.include?(file_format)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wahwah
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aidewoode
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-02 00:00:00.000000000 Z
11
+ date: 2022-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,47 +53,61 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: standard
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.80.1
61
+ version: 1.4.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.80.1
68
+ version: 1.4.0
69
69
  - !ruby/object:Gem::Dependency
70
- name: rubocop-performance
70
+ name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.5.2
75
+ version: 0.21.2
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 1.5.2
82
+ version: 0.21.2
83
83
  - !ruby/object:Gem::Dependency
84
- name: codecov
84
+ name: simplecov-lcov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.1.17
89
+ version: 0.8.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.1.17
96
+ version: 0.8.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: memory_profiler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.9.14
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.9.14
97
111
  description: WahWah is an audio metadata reader ruby gem, it supports many popular
98
112
  formats including mp3(ID3 v1, v2.2, v2.3, v2.4), m4a, ogg, oga, opus, wav, flac
99
113
  and wma.
@@ -121,6 +135,7 @@ files:
121
135
  - lib/wahwah/id3/v1.rb
122
136
  - lib/wahwah/id3/v2.rb
123
137
  - lib/wahwah/id3/v2_header.rb
138
+ - lib/wahwah/lazy_read.rb
124
139
  - lib/wahwah/mp3/mpeg_frame_header.rb
125
140
  - lib/wahwah/mp3/vbri_header.rb
126
141
  - lib/wahwah/mp3/xing_header.rb
@@ -152,15 +167,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
167
  requirements:
153
168
  - - ">="
154
169
  - !ruby/object:Gem::Version
155
- version: 2.5.0
170
+ version: 2.6.0
156
171
  required_rubygems_version: !ruby/object:Gem::Requirement
157
172
  requirements:
158
173
  - - ">="
159
174
  - !ruby/object:Gem::Version
160
175
  version: '0'
161
176
  requirements: []
162
- rubyforge_project:
163
- rubygems_version: 2.7.6.2
177
+ rubygems_version: 3.2.32
164
178
  signing_key:
165
179
  specification_version: 4
166
180
  summary: Audio metadata reader ruby gem