wahwah 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/lib/wahwah.rb +5 -0
- data/lib/wahwah/asf/object.rb +5 -10
- data/lib/wahwah/asf_tag.rb +2 -2
- data/lib/wahwah/flac/block.rb +5 -11
- data/lib/wahwah/flac/streaminfo_block.rb +2 -2
- data/lib/wahwah/flac_tag.rb +5 -5
- data/lib/wahwah/id3/frame.rb +11 -16
- data/lib/wahwah/id3/v2.rb +9 -8
- data/lib/wahwah/lazy_read.rb +26 -0
- data/lib/wahwah/mp3_tag.rb +0 -2
- data/lib/wahwah/mp4/atom.rb +7 -12
- data/lib/wahwah/mp4_tag.rb +17 -10
- data/lib/wahwah/ogg/flac_tag.rb +1 -1
- data/lib/wahwah/ogg/vorbis_comment.rb +1 -1
- data/lib/wahwah/ogg_tag.rb +8 -0
- data/lib/wahwah/riff/chunk.rb +5 -10
- data/lib/wahwah/riff_tag.rb +9 -9
- data/lib/wahwah/tag.rb +16 -7
- data/lib/wahwah/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e742f50b1a22c7cbbe63ba26506803720bbc44dbfe9943ac07a32e7efe048cbe
|
4
|
+
data.tar.gz: 47e1352b98217e34eb3e3fb3c258695a8f7cf2a4d579ce6baaeda1216703f4e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5450f35d5478a3a434ac0e366589edb3999b40eb1f321e53086ccd1d3d20c5542ce63ac9d8d7b380379cafd719bbc97c33d2768d585c9a2b1d71218950f1b36
|
7
|
+
data.tar.gz: 86a134f7ac39a2430fcc2a62756a23354aa42825bf1a97ad4b7ba6b71f42bb72c20f3dda4a884db06e77faa84517c7fe5f4004e317939bd36d4c60369067c93e
|
data/lib/wahwah.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'stringio'
|
4
|
+
require 'forwardable'
|
5
|
+
require 'zlib'
|
6
|
+
|
3
7
|
require 'wahwah/version'
|
4
8
|
require 'wahwah/errors'
|
5
9
|
require 'wahwah/helper'
|
6
10
|
require 'wahwah/tag_delegate'
|
11
|
+
require 'wahwah/lazy_read'
|
7
12
|
require 'wahwah/tag'
|
8
13
|
|
9
14
|
require 'wahwah/id3/v1'
|
data/lib/wahwah/asf/object.rb
CHANGED
@@ -11,29 +11,24 @@ module WahWah
|
|
11
11
|
# 8 bytes: Object size
|
12
12
|
# variable-sized: Object data
|
13
13
|
class Object
|
14
|
+
prepend LazyRead
|
15
|
+
|
14
16
|
HEADER_SIZE = 24
|
15
17
|
HEADER_FORMAT = 'a16Q<'
|
16
18
|
|
17
|
-
attr_reader :
|
19
|
+
attr_reader :guid
|
18
20
|
|
19
|
-
def initialize
|
20
|
-
guid_bytes, @size = file_io.read(HEADER_SIZE)&.unpack(HEADER_FORMAT)
|
21
|
+
def initialize
|
22
|
+
guid_bytes, @size = @file_io.read(HEADER_SIZE)&.unpack(HEADER_FORMAT)
|
21
23
|
return unless valid?
|
22
24
|
|
23
25
|
@size = @size - HEADER_SIZE
|
24
26
|
@guid = Helper.byte_string_to_guid(guid_bytes)
|
25
|
-
@file_io = file_io
|
26
|
-
@position = file_io.pos
|
27
27
|
end
|
28
28
|
|
29
29
|
def valid?
|
30
30
|
!@size.nil? && @size >= HEADER_SIZE
|
31
31
|
end
|
32
|
-
|
33
|
-
def data
|
34
|
-
@file_io.seek(@position)
|
35
|
-
@file_io.read(size)
|
36
|
-
end
|
37
32
|
end
|
38
33
|
end
|
39
34
|
end
|
data/lib/wahwah/asf_tag.rb
CHANGED
@@ -54,7 +54,7 @@ module WahWah
|
|
54
54
|
when CONTENT_DESCRIPTION_OBJECT_GUID
|
55
55
|
parse_content_description_object(sub_object)
|
56
56
|
else
|
57
|
-
|
57
|
+
sub_object.skip
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -187,7 +187,7 @@ module WahWah
|
|
187
187
|
|
188
188
|
return unless stream_type_guid == AUDIO_MEDIA_OBJECT_GUID
|
189
189
|
|
190
|
-
@sample_rate, bytes_per_second = object_data.read(type_specific_data_length).unpack('
|
190
|
+
@sample_rate, bytes_per_second, @bit_depth = object_data.read(type_specific_data_length).unpack('x4VVx2v')
|
191
191
|
@bitrate = (bytes_per_second * 8.0 / 1000).round
|
192
192
|
end
|
193
193
|
|
data/lib/wahwah/flac/block.rb
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
module WahWah
|
4
4
|
module Flac
|
5
5
|
class Block
|
6
|
+
prepend LazyRead
|
7
|
+
|
6
8
|
HEADER_SIZE = 4
|
7
9
|
HEADER_FORMAT = 'B*'
|
8
10
|
BLOCK_TYPE_INDEX = %w(STREAMINFO PADDING APPLICATION SEEKTABLE VORBIS_COMMENT CUESHEET PICTURE)
|
9
11
|
|
10
|
-
attr_reader :
|
12
|
+
attr_reader :type
|
11
13
|
|
12
|
-
def initialize
|
14
|
+
def initialize
|
13
15
|
# Block header structure:
|
14
16
|
#
|
15
17
|
# Length(bit) Meaning
|
@@ -30,14 +32,11 @@ module WahWah
|
|
30
32
|
#
|
31
33
|
# 24 Length (in bytes) of metadata to follow
|
32
34
|
# (does not include the size of the METADATA_BLOCK_HEADER)
|
33
|
-
header_bits = file_io.read(HEADER_SIZE).unpack(HEADER_FORMAT).first
|
35
|
+
header_bits = @file_io.read(HEADER_SIZE).unpack(HEADER_FORMAT).first
|
34
36
|
|
35
37
|
@last_flag = header_bits[0]
|
36
38
|
@type = BLOCK_TYPE_INDEX[header_bits[1..7].to_i(2)]
|
37
39
|
@size = header_bits[8..-1].to_i(2)
|
38
|
-
|
39
|
-
@file_io = file_io
|
40
|
-
@position = file_io.pos
|
41
40
|
end
|
42
41
|
|
43
42
|
def valid?
|
@@ -47,11 +46,6 @@ module WahWah
|
|
47
46
|
def is_last?
|
48
47
|
@last_flag.to_i == 1
|
49
48
|
end
|
50
|
-
|
51
|
-
def data
|
52
|
-
@file_io.seek(@position)
|
53
|
-
@file_io.read(size)
|
54
|
-
end
|
55
49
|
end
|
56
50
|
end
|
57
51
|
end
|
@@ -40,11 +40,11 @@ module WahWah
|
|
40
40
|
info_bits = block_data.unpack('x10B64').first
|
41
41
|
|
42
42
|
@sample_rate = info_bits[0..19].to_i(2)
|
43
|
-
|
43
|
+
@bit_depth = info_bits[23..27].to_i(2) + 1
|
44
44
|
total_samples = info_bits[28..-1].to_i(2)
|
45
45
|
|
46
46
|
@duration = (total_samples.to_f / @sample_rate).round if @sample_rate > 0
|
47
|
-
@bitrate = @sample_rate *
|
47
|
+
@bitrate = @sample_rate * @bit_depth / 1000
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/wahwah/flac_tag.rb
CHANGED
@@ -38,9 +38,9 @@ module WahWah
|
|
38
38
|
when 'VORBIS_COMMENT'
|
39
39
|
parse_vorbis_comment(block.data)
|
40
40
|
when 'PICTURE'
|
41
|
-
|
41
|
+
@images_data.push(block); block.skip
|
42
42
|
else
|
43
|
-
|
43
|
+
block.skip
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -69,8 +69,8 @@ module WahWah
|
|
69
69
|
# 32 The length of the picture data in bytes.
|
70
70
|
#
|
71
71
|
# n*8 The binary picture data.
|
72
|
-
def
|
73
|
-
block_content = StringIO.new(
|
72
|
+
def parse_image_data(picture_block)
|
73
|
+
block_content = StringIO.new(picture_block.data)
|
74
74
|
|
75
75
|
type_index, mime_type_length = block_content.read(8).unpack('NN')
|
76
76
|
mime_type = Helper.encode_to_utf8(block_content.read(mime_type_length))
|
@@ -78,7 +78,7 @@ module WahWah
|
|
78
78
|
data_length = block_content.read(description_length + 20).unpack("#{'x' * (description_length + 16)}N").first
|
79
79
|
data = block_content.read(data_length)
|
80
80
|
|
81
|
-
|
81
|
+
{ data: data, mime_type: mime_type, type: ID3::ImageFrameBody::TYPES[type_index] }
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
data/lib/wahwah/id3/frame.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'zlib'
|
4
|
-
|
5
3
|
module WahWah
|
6
4
|
module ID3
|
7
5
|
class Frame
|
6
|
+
prepend LazyRead
|
7
|
+
|
8
8
|
ID_MAPPING = {
|
9
9
|
# ID3v2.2 frame id
|
10
10
|
COM: :comment,
|
@@ -78,10 +78,9 @@ module WahWah
|
|
78
78
|
array[15] = :data_length_indicator
|
79
79
|
end
|
80
80
|
|
81
|
-
attr_reader :name
|
81
|
+
attr_reader :name
|
82
82
|
|
83
|
-
def initialize(
|
84
|
-
@file_io = file_io
|
83
|
+
def initialize(version)
|
85
84
|
@version = version
|
86
85
|
|
87
86
|
parse_frame_header
|
@@ -98,8 +97,6 @@ module WahWah
|
|
98
97
|
@file_io.seek(4, IO::SEEK_CUR)
|
99
98
|
@size = @size - 4
|
100
99
|
end
|
101
|
-
|
102
|
-
parse_body
|
103
100
|
end
|
104
101
|
|
105
102
|
def valid?
|
@@ -114,6 +111,13 @@ module WahWah
|
|
114
111
|
@flags.include? :data_length_indicator
|
115
112
|
end
|
116
113
|
|
114
|
+
def value
|
115
|
+
return unless @size > 0
|
116
|
+
|
117
|
+
content = compressed? ? Zlib.inflate(data) : data
|
118
|
+
frame_body = frame_body_class.new(content, @version)
|
119
|
+
frame_body.value
|
120
|
+
end
|
117
121
|
|
118
122
|
private
|
119
123
|
# ID3v2.2 frame header structure:
|
@@ -154,15 +158,6 @@ module WahWah
|
|
154
158
|
end.compact
|
155
159
|
end
|
156
160
|
|
157
|
-
def parse_body
|
158
|
-
return unless @size > 0
|
159
|
-
(@file_io.seek(@size, IO::SEEK_CUR); return) if @name.nil?
|
160
|
-
|
161
|
-
content = compressed? ? Zlib.inflate(@file_io.read(@size)) : @file_io.read(@size)
|
162
|
-
frame_body = frame_body_class.new(content, @version)
|
163
|
-
@value = frame_body.value
|
164
|
-
end
|
165
|
-
|
166
161
|
def frame_body_class
|
167
162
|
case @name
|
168
163
|
when :comment
|
data/lib/wahwah/id3/v2.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
3
|
module WahWah
|
6
4
|
module ID3
|
7
5
|
class V2 < Tag
|
@@ -22,7 +20,7 @@ module WahWah
|
|
22
20
|
|
23
21
|
until end_of_tag? do
|
24
22
|
frame = ID3::Frame.new(@file_io, major_version)
|
25
|
-
next unless frame.valid?
|
23
|
+
(frame.skip; next) unless frame.valid?
|
26
24
|
|
27
25
|
update_attribute(frame)
|
28
26
|
end
|
@@ -30,31 +28,34 @@ module WahWah
|
|
30
28
|
|
31
29
|
def update_attribute(frame)
|
32
30
|
name = frame.name
|
33
|
-
value = frame.value
|
34
31
|
|
35
32
|
case name
|
36
33
|
when :comment
|
37
34
|
# Because there may be more than one comment frame in each tag,
|
38
35
|
# so push it into a array.
|
39
|
-
@comments.push(value)
|
36
|
+
@comments.push(frame.value)
|
40
37
|
when :image
|
41
38
|
# Because there may be more than one image frame in each tag,
|
42
39
|
# so push it into a array.
|
43
|
-
@
|
40
|
+
@images_data.push(frame); frame.skip
|
44
41
|
when :track, :disc
|
45
42
|
# Track and disc value may be extended with a "/" character
|
46
43
|
# and a numeric string containing the total numer.
|
47
|
-
count, total_count = value.split('/', 2)
|
44
|
+
count, total_count = frame.value.split('/', 2)
|
48
45
|
instance_variable_set("@#{name}", count)
|
49
46
|
instance_variable_set("@#{name}_total", total_count) unless total_count.nil?
|
50
47
|
else
|
51
|
-
instance_variable_set("@#{name}", value)
|
48
|
+
instance_variable_set("@#{name}", frame.value)
|
52
49
|
end
|
53
50
|
end
|
54
51
|
|
55
52
|
def end_of_tag?
|
56
53
|
size <= @file_io.pos || file_size <= @file_io.pos
|
57
54
|
end
|
55
|
+
|
56
|
+
def parse_image_data(image_frame)
|
57
|
+
image_frame.value
|
58
|
+
end
|
58
59
|
end
|
59
60
|
end
|
60
61
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WahWah
|
4
|
+
module LazyRead
|
5
|
+
def self.prepended(base)
|
6
|
+
base.class_eval do
|
7
|
+
attr_reader :size
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(file_io, *arg)
|
12
|
+
@file_io = file_io
|
13
|
+
super(*arg)
|
14
|
+
@position = @file_io.pos
|
15
|
+
end
|
16
|
+
|
17
|
+
def data
|
18
|
+
@file_io.seek(@position)
|
19
|
+
@file_io.read(size)
|
20
|
+
end
|
21
|
+
|
22
|
+
def skip
|
23
|
+
@file_io.seek(size, IO::SEEK_CUR)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/wahwah/mp3_tag.rb
CHANGED
data/lib/wahwah/mp4/atom.rb
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
module WahWah
|
4
4
|
module Mp4
|
5
5
|
class Atom
|
6
|
+
prepend LazyRead
|
7
|
+
|
6
8
|
VERSIONED_ATOMS = %w(meta stsd)
|
7
9
|
FLAGGED_ATOMS = %w(stsd)
|
8
10
|
HEADER_SIZE = 8
|
9
11
|
HEADER_SIZE_FIELD_SIZE = 4
|
10
12
|
EXTENDED_HEADER_SIZE = 8
|
11
13
|
|
12
|
-
attr_reader :
|
14
|
+
attr_reader :type
|
13
15
|
|
14
16
|
def self.find(file_io, *atom_path)
|
15
17
|
file_io.rewind
|
@@ -39,25 +41,18 @@ module WahWah
|
|
39
41
|
# Type:
|
40
42
|
# A 32-bit integer that contains the type of the atom.
|
41
43
|
# This can often be usefully treated as a four-character field with a mnemonic value .
|
42
|
-
def initialize
|
43
|
-
@size, @type = file_io.read(HEADER_SIZE)&.unpack('Na4')
|
44
|
+
def initialize
|
45
|
+
@size, @type = @file_io.read(HEADER_SIZE)&.unpack('Na4')
|
44
46
|
return unless valid?
|
45
47
|
|
46
48
|
# If the size field of an atom is set to 1, the type field is followed by a 64-bit extended size field,
|
47
49
|
# which contains the actual size of the atom as a 64-bit unsigned integer.
|
48
|
-
@size = file_io.read(EXTENDED_HEADER_SIZE).unpack('Q>').first - EXTENDED_HEADER_SIZE if @size == 1
|
50
|
+
@size = @file_io.read(EXTENDED_HEADER_SIZE).unpack('Q>').first - EXTENDED_HEADER_SIZE if @size == 1
|
49
51
|
|
50
52
|
# If the size field of an atom is set to 0, which is allowed only for a top-level atom,
|
51
53
|
# designates the last atom in the file and indicates that the atom extends to the end of the file.
|
52
|
-
@size = file_io.size if @size == 0
|
54
|
+
@size = @file_io.size if @size == 0
|
53
55
|
@size = @size - HEADER_SIZE
|
54
|
-
@file_io = file_io
|
55
|
-
@position = file_io.pos
|
56
|
-
end
|
57
|
-
|
58
|
-
def data
|
59
|
-
@file_io.seek(@position)
|
60
|
-
@file_io.read(size)
|
61
56
|
end
|
62
57
|
|
63
58
|
def valid?
|
data/lib/wahwah/mp4_tag.rb
CHANGED
@@ -59,7 +59,7 @@ module WahWah
|
|
59
59
|
# The metadata item list atom is of type ‘ilst’ and contains a number of metadata items, each of which is an atom.
|
60
60
|
# each metadata item atom contains a Value Atom, to hold the value of the metadata item
|
61
61
|
atom.children.each do |child_atom|
|
62
|
-
|
62
|
+
attr_name = META_ATOM_MAPPING[child_atom.type]
|
63
63
|
|
64
64
|
# The value of the metadata item is expressed as immediate data in a value atom.
|
65
65
|
# The value atom starts with two fields: a type indicator, and a locale indicator.
|
@@ -68,27 +68,30 @@ module WahWah
|
|
68
68
|
data_atom = child_atom.find('data')
|
69
69
|
return unless data_atom.valid?
|
70
70
|
|
71
|
-
|
72
|
-
encoded_data_value = META_ATOM_DECODE_BY_TYPE[data_type]&.call(data_value)
|
71
|
+
(@images_data.push(data_atom); next) if attr_name == :image
|
73
72
|
|
74
|
-
|
73
|
+
encoded_data_value = parse_meta_data_atom(data_atom)
|
74
|
+
next if attr_name.nil? || encoded_data_value.nil?
|
75
75
|
|
76
|
-
case
|
77
|
-
when :image
|
78
|
-
@images.push(encoded_data_value)
|
76
|
+
case attr_name
|
79
77
|
when :comment
|
80
78
|
@comments.push(encoded_data_value)
|
81
79
|
when :track, :disc
|
82
80
|
count, total_count = encoded_data_value.unpack('x2nn')
|
83
81
|
|
84
|
-
instance_variable_set("@#{
|
85
|
-
instance_variable_set("@#{
|
82
|
+
instance_variable_set("@#{attr_name}", count) unless count.zero?
|
83
|
+
instance_variable_set("@#{attr_name}_total", total_count) unless total_count.zero?
|
86
84
|
else
|
87
|
-
instance_variable_set("@#{
|
85
|
+
instance_variable_set("@#{attr_name}", encoded_data_value)
|
88
86
|
end
|
89
87
|
end
|
90
88
|
end
|
91
89
|
|
90
|
+
def parse_meta_data_atom(atom)
|
91
|
+
data_type, data_value = atom.data.unpack('Nx4a*')
|
92
|
+
META_ATOM_DECODE_BY_TYPE[data_type]&.call(data_value)
|
93
|
+
end
|
94
|
+
|
92
95
|
def parse_mvhd_atom(atom)
|
93
96
|
return unless atom.valid?
|
94
97
|
|
@@ -122,5 +125,9 @@ module WahWah
|
|
122
125
|
@sample_rate = mp4a_atom.data.unpack('x22I>').first if mp4a_atom.valid?
|
123
126
|
@bitrate = esds_atom.data.unpack('x26I>').first / 1000 if esds_atom.valid?
|
124
127
|
end
|
128
|
+
|
129
|
+
def parse_image_data(image_data_atom)
|
130
|
+
parse_meta_data_atom(image_data_atom)
|
131
|
+
end
|
125
132
|
end
|
126
133
|
end
|
data/lib/wahwah/ogg/flac_tag.rb
CHANGED
@@ -6,7 +6,7 @@ module WahWah
|
|
6
6
|
include VorbisComment
|
7
7
|
include Flac::StreaminfoBlock
|
8
8
|
|
9
|
-
attr_reader :bitrate, :duration, :sample_rate, *COMMET_FIELD_MAPPING.values
|
9
|
+
attr_reader :bitrate, :duration, :sample_rate, :bit_depth, *COMMET_FIELD_MAPPING.values
|
10
10
|
|
11
11
|
def initialize(identification_packet, comment_packet)
|
12
12
|
# Identification packet structure:
|
@@ -39,7 +39,7 @@ module WahWah
|
|
39
39
|
comment_length = comment_content.read(4).unpack('V').first
|
40
40
|
comment = Helper.encode_to_utf8(comment_content.read(comment_length))
|
41
41
|
field_name, field_value = comment.split('=', 2)
|
42
|
-
attr_name = COMMET_FIELD_MAPPING[field_name]
|
42
|
+
attr_name = COMMET_FIELD_MAPPING[field_name&.upcase]
|
43
43
|
|
44
44
|
field_value = field_value.to_i if %i(track disc).include? attr_name
|
45
45
|
|
data/lib/wahwah/ogg_tag.rb
CHANGED
@@ -24,6 +24,10 @@ module WahWah
|
|
24
24
|
@bitrate ||= parse_bitrate
|
25
25
|
end
|
26
26
|
|
27
|
+
def bit_depth
|
28
|
+
@bit_depth ||= parse_bit_depth
|
29
|
+
end
|
30
|
+
|
27
31
|
private
|
28
32
|
def packets
|
29
33
|
@packets ||= Ogg::Packets.new(@file_io)
|
@@ -62,5 +66,9 @@ module WahWah
|
|
62
66
|
return @tag.bitrate if @tag.respond_to? :bitrate
|
63
67
|
((file_size - @overhead_packets_size) * 8.0 / duration / 1000).round
|
64
68
|
end
|
69
|
+
|
70
|
+
def parse_bit_depth
|
71
|
+
@tag.bit_depth if @tag.respond_to? :bit_depth
|
72
|
+
end
|
65
73
|
end
|
66
74
|
end
|
data/lib/wahwah/riff/chunk.rb
CHANGED
@@ -16,19 +16,19 @@ module WahWah
|
|
16
16
|
# 4 bytes: an ASCII identifier for this particular RIFF or LIST chunk (for RIFF in the typical case, these 4 bytes describe the content of the entire file, such as "AVI " or "WAVE").
|
17
17
|
# rest of data: subchunks.
|
18
18
|
class Chunk
|
19
|
+
prepend LazyRead
|
20
|
+
|
19
21
|
HEADER_SIZE = 8
|
20
22
|
HEADER_FORMAT = 'A4V'
|
21
23
|
HEADER_TYPE_SIZE = 4
|
22
24
|
|
23
25
|
attr_reader :id, :type
|
24
26
|
|
25
|
-
def initialize
|
26
|
-
@id, @size = file_io.read(HEADER_SIZE)&.unpack(HEADER_FORMAT)
|
27
|
+
def initialize
|
28
|
+
@id, @size = @file_io.read(HEADER_SIZE)&.unpack(HEADER_FORMAT)
|
27
29
|
return unless valid?
|
28
30
|
|
29
|
-
@type = file_io.read(HEADER_TYPE_SIZE).unpack('A4').first if have_type?
|
30
|
-
@file_io = file_io
|
31
|
-
@position = file_io.pos
|
31
|
+
@type = @file_io.read(HEADER_TYPE_SIZE).unpack('A4').first if have_type?
|
32
32
|
end
|
33
33
|
|
34
34
|
def size
|
@@ -36,11 +36,6 @@ module WahWah
|
|
36
36
|
have_type? ? @size - HEADER_TYPE_SIZE : @size
|
37
37
|
end
|
38
38
|
|
39
|
-
def data
|
40
|
-
@file_io.seek(@position)
|
41
|
-
@file_io.read(size)
|
42
|
-
end
|
43
|
-
|
44
39
|
def valid?
|
45
40
|
!@id.empty? && !@size.nil? && @size > 0
|
46
41
|
end
|
data/lib/wahwah/riff_tag.rb
CHANGED
@@ -69,7 +69,7 @@ module WahWah
|
|
69
69
|
when 'id3', 'ID3'
|
70
70
|
parse_id3_chunk(sub_chunk)
|
71
71
|
else
|
72
|
-
|
72
|
+
sub_chunk.skip
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -92,13 +92,13 @@ module WahWah
|
|
92
92
|
#
|
93
93
|
# 2(little endian) BitsPerSample 8 bits = 8, 16 bits = 16, etc.
|
94
94
|
def parse_fmt_chunk(chunk)
|
95
|
-
_, @channel, @sample_rate, _, _, @
|
96
|
-
@bitrate = @sample_rate * @channel * @
|
95
|
+
_, @channel, @sample_rate, _, _, @bit_depth = chunk.data.unpack('vvVVvv')
|
96
|
+
@bitrate = @sample_rate * @channel * @bit_depth / 1000
|
97
97
|
end
|
98
98
|
|
99
99
|
def parse_data_chunk(chunk)
|
100
100
|
@duration = chunk.size * 8 / (@bitrate * 1000)
|
101
|
-
|
101
|
+
chunk.skip
|
102
102
|
end
|
103
103
|
|
104
104
|
def parse_list_chunk(chunk)
|
@@ -107,13 +107,13 @@ module WahWah
|
|
107
107
|
# RIFF can be tagged with metadata in the INFO chunk.
|
108
108
|
# And INFO chunk as a subchunk for LIST chunk.
|
109
109
|
if chunk.type != 'INFO'
|
110
|
-
|
110
|
+
chunk.skip
|
111
111
|
else
|
112
112
|
until list_chunk_end_position <= @file_io.pos do
|
113
113
|
info_chunk = Riff::Chunk.new(@file_io)
|
114
114
|
|
115
115
|
unless INFO_ID_MAPPING.keys.include? info_chunk.id.to_sym
|
116
|
-
|
116
|
+
info_chunk.skip; next
|
117
117
|
end
|
118
118
|
|
119
119
|
update_attribute(info_chunk)
|
@@ -126,14 +126,14 @@ module WahWah
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def update_attribute(chunk)
|
129
|
-
|
129
|
+
attr_name = INFO_ID_MAPPING[chunk.id.to_sym]
|
130
130
|
chunk_data = Helper.encode_to_utf8(chunk.data)
|
131
131
|
|
132
|
-
case
|
132
|
+
case attr_name
|
133
133
|
when :comment
|
134
134
|
@comments.push(chunk_data)
|
135
135
|
else
|
136
|
-
instance_variable_set("@#{
|
136
|
+
instance_variable_set("@#{attr_name}", chunk_data)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
data/lib/wahwah/tag.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module WahWah
|
4
4
|
class Tag
|
5
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)
|
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
|
-
@
|
38
|
+
@images_data = []
|
39
39
|
|
40
40
|
parse if @file_size > 0
|
41
41
|
|
@@ -45,15 +45,24 @@ module WahWah
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def parse
|
49
|
-
raise WahWahNotImplementedError, 'The parse method is not implemented'
|
50
|
-
end
|
51
|
-
|
52
48
|
def inspect
|
53
49
|
inspect_id = ::Kernel.format '%x', (object_id * 2)
|
54
50
|
inspect_attributes_values = INSPECT_ATTRIBUTES.map { |attr_name| "#{attr_name}=#{self.send(attr_name)}" }.join(' ')
|
55
51
|
|
56
52
|
"<#{self.class.name}:0x#{inspect_id} #{inspect_attributes_values}>"
|
57
53
|
end
|
54
|
+
|
55
|
+
def images
|
56
|
+
return @images_data if @images_data.empty?
|
57
|
+
|
58
|
+
@images_data.map do |data|
|
59
|
+
parse_image_data(data)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def parse
|
65
|
+
raise WahWahNotImplementedError, 'The parse method is not implemented'
|
66
|
+
end
|
58
67
|
end
|
59
68
|
end
|
data/lib/wahwah/version.rb
CHANGED
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.
|
4
|
+
version: 1.1.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-
|
11
|
+
date: 2020-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.1.17
|
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
|