Module: FormatParser::MP3Parser::ID3Extraction
Constant Summary
collapse
- ID3V1_TAG_SIZE_BYTES =
128
- ID3V2_MINOR_TAG_VERSIONS =
[2, 3, 4]
- MAX_SIZE_FOR_ID3V2 =
1 * 1024 * 1024
Constants included
from IOUtils
IOUtils::INTEGER_DIRECTIVES
Instance Method Summary
collapse
Methods included from IOUtils
read_bytes, read_fixed_point, read_int, safe_read, safe_skip, skip_bytes
Instance Method Details
10
11
12
13
14
15
16
17
18
19
20
21
|
# File 'lib/parsers/mp3_parser/id3_extraction.rb', line 10
def (io)
return if io.size < ID3V1_TAG_SIZE_BYTES
io.seek(io.size - 128)
trailer_bytes = io.read(128)
return unless trailer_bytes && trailer_bytes.bytesize == ID3V1_TAG_SIZE_BYTES
return unless trailer_bytes.byteslice(0, 3) == 'TAG'
buf = StringIO.new(trailer_bytes)
swallow_exceptions { ID3Tag.read(buf, :v1) }
end
|
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
# File 'lib/parsers/mp3_parser/id3_extraction.rb', line 23
def (io)
io.seek(0) = (io)
return unless [:tag] == 'ID3' && [:size] > 0
return unless ID3V2_MINOR_TAG_VERSIONS.include?([:version].unpack('C').first)
id3_tag_size = io.pos + [:size]
if id3_tag_size > MAX_SIZE_FOR_ID3V2
io.seek(id3_tag_size) return
end
io.seek(0)
blob = safe_read(io, id3_tag_size)
swallow_exceptions { ID3Tag.read(StringIO.new(blob), :v2) }
rescue FormatParser::IOUtils::InvalidRead
nil
end
|
60
61
62
63
64
65
|
# File 'lib/parsers/mp3_parser/id3_extraction.rb', line 60
def (io)
fields = {tag: :a3, version: :a2, flags: :a1, syncsafe_size: :N1}
= read_and_unpack_packspec(io, **fields)
[:size] = ID3Tag::SynchsafeInteger.decode(.delete(:syncsafe_size))
end
|
#read_and_unpack_packspec(io, **packspec) ⇒ Object
51
52
53
54
55
56
57
58
|
# File 'lib/parsers/mp3_parser/id3_extraction.rb', line 51
def read_and_unpack_packspec(io, **packspec)
sizes = {'a' => 1, 'N' => 4}
n = packspec.values.map { |e| sizes.fetch(e[0]) * e[1].to_i }.inject(&:+)
byte_str = safe_read(io, n)
unpacked_values = byte_str.unpack(packspec.values.join)
Hash[packspec.keys.zip(unpacked_values)]
end
|
#swallow_exceptions ⇒ Object
We swallow exceptions from ID3Tag primarily because it does not have a single wrapping error class we could capture. We also do not touch our original IO object when working with ID3Tag
70
71
72
73
74
75
|
# File 'lib/parsers/mp3_parser/id3_extraction.rb', line 70
def swallow_exceptions
yield
rescue => e
warn(e)
nil
end
|