Module: FormatParser::MP3Parser::ID3V1

Extended by:
ID3V1
Included in:
ID3V1
Defined in:
lib/parsers/mp3_parser/id3_v1.rb

Defined Under Namespace

Classes: TagInformation

Constant Summary collapse

PACKSPEC =
[
  :tag, :a3,
  :song_name, :a30,
  :artist, :a30,
  :album, :a30,
  :year, :N1,
  :comment, :a30,
  :genre, :C,
]
TAG_SIZE_BYTES =
128

Instance Method Summary collapse

Instance Method Details

#attempt_id3_v1_extraction(io) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/parsers/mp3_parser/id3_v1.rb', line 17

def attempt_id3_v1_extraction(io)
  return if io.size < TAG_SIZE_BYTES # Won't fit the ID3v1 regardless

  io.seek(io.size - 128)
  trailer_bytes = io.read(128)

  return unless trailer_bytes && trailer_bytes.byteslice(0, 3) == 'TAG'

  id3_v1 = parse_id3_v1(trailer_bytes)

  # If all of the resulting strings are empty this ID3v1 tag is invalid and
  # we should ignore it.
  strings_from_id3v1 = id3_v1.values.select { |e| e.is_a?(String) && e != 'TAG' }
  return if strings_from_id3v1.all?(&:empty?)

  id3_v1
end

#parse_id3_v1(byte_str) ⇒ Object



35
36
37
38
39
40
# File 'lib/parsers/mp3_parser/id3_v1.rb', line 35

def parse_id3_v1(byte_str)
  _keys, values = PACKSPEC.partition.with_index { |_, i| i.even? }
  unpacked_values = byte_str.unpack(values.join)
  unpacked_values.map! { |e| e.is_a?(String) ? trim_id3v1_string(e) : e }
  TagInformation.new(unpacked_values)
end

#trim_id3v1_string(str) ⇒ Object

Remove trailing whitespace and trailing nullbytes



43
44
45
# File 'lib/parsers/mp3_parser/id3_v1.rb', line 43

def trim_id3v1_string(str)
  str.tr("\x00".b, '').strip
end