Sha256: 855d3d143960e9fdc0c9fbffa61bd2748809ee2c561afc2676f408364cc37761

Contents?: true

Size: 1.3 KB

Versions: 6

Compression:

Stored size: 1.3 KB

Contents

module FormatParser::MP3Parser::ID3V1
  PACKSPEC = [
    :tag, :a3,
    :song_name, :a30,
    :artist, :a30,
    :album, :a30,
    :year, :N1,
    :comment, :a30,
    :genre, :C,
  ]
  packspec_keys = PACKSPEC.select.with_index{|_, i| i.even? }
  TAG_SIZE_BYTES = 128

  class TagInformation < Struct.new(*packspec_keys)
  end

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

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

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

    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' }
    if strings_from_id3v1.all?(&:empty?)
      return nil
    end

    id3_v1
  end

  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

  # Remove trailing whitespace and trailing nullbytes
  def trim_id3v1_string(str)
    str.tr("\x00".b, '').strip
  end

  extend self
end

Version data entries

6 entries across 6 versions & 1 rubygems

Version Path
format_parser-0.2.0 lib/parsers/mp3_parser/id3_v1.rb
format_parser-0.1.7 lib/parsers/mp3_parser/id3_v1.rb
format_parser-0.1.6 lib/parsers/mp3_parser/id3_v1.rb
format_parser-0.1.5 lib/parsers/mp3_parser/id3_v1.rb
format_parser-0.1.4 lib/parsers/mp3_parser/id3_v1.rb
format_parser-0.1.3 lib/parsers/mp3_parser/id3_v1.rb