func (m *mp3Parser) parseID3v2Frames() error {
	tagMap := map[string]string{}
	var frameBuf []byte
	if m.id3Header.MajorVersion == 2 {
		frameBuf = make([]byte, 3)
	} else {
		frameBuf = make([]byte, 4)
	}
	var frameLength uint32
	tagBuf := make([]byte, 2048)
	var bufLen = uint32(len(tagBuf))
	trimPrefix := []byte{255, 254}
	trimSuffix := []byte{0}
	for {
		if _, err := m.reader.Read(frameBuf); err != nil {
			return err
		}
		if frameBuf[0] == byte(0) {
			break
		}
		if frameBuf[0] == byte(255) {
			if _, err := m.reader.Read(tagBuf); err != nil {
				return err
			}
			m.reader = bytes.NewReader(append(frameBuf, tagBuf...))
			break
		}
		if m.id3Header.MajorVersion == 2 {
			if _, err := m.reader.Read(tagBuf[:3]); err != nil {
				return err
			}
			frameLength = uint32(tagBuf[0])<<16 | uint32(tagBuf[1])<<8 | uint32(tagBuf[2])
		} else {
			if err := binary.Read(m.reader, binary.BigEndian, &frameLength); err != nil {
				return err
			}
			if m.id3Header.MajorVersion == 4 && !m.id3Header.Unsynchronization {
				b := [4]byte{}
				binary.BigEndian.PutUint32(b[:], uint32(frameLength))
				frameLength = uint32(unSynch(b))
			}
			if _, err := m.reader.Seek(2, 1); err != nil {
				return err
			}
		}
		if bytes.Equal(frameBuf, mp3APICFrame) || frameLength > bufLen {
			if _, err := m.reader.Seek(int64(frameLength), 1); err != nil {
				return err
			}
			continue
		}
		n, err := m.reader.Read(tagBuf[:frameLength])
		if err != nil {
			return err
		}
		tag := string(bytes.TrimPrefix(bytes.TrimSuffix(tagBuf[1:n], trimSuffix), trimPrefix))
		tagMap[mp3ID3v2FrameToTag[string(frameBuf)]] = tag
	}
	m.tags = tagMap
	return nil
}
parseID3v2Frames parses ID3v2 frames from an MP3 stream
package taggolib
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"
	"github.com/eaburns/bit"
)
const (
	mp3TagEncoder = "ENCODER"
	mp3TagLength  = "LENGTH"
	mp3SamplesPerFrame = 1152
)
var (
	mp3MagicNumber = []byte("ID3")
	mp3APICFrame = []byte("APIC")
	mp3XingMarker = []byte("Xing")
	mp3InfoMarker = []byte("Info")
)
type mp3Parser struct {
	id3Header  *mp3ID3v2Header
	mp3Header  *mp3Header
	reader     io.ReadSeeker
	tags       map[string]string
	xingHeader *mp3XingHeader
}
func unSynch(data [4]byte) int32 {
	size := int32(0)
	for i, b := range data {
		shift := uint32(len(data)-i-1) * 7
		size |= int32(b&0x7f) << shift
	}
	return size
}
func (m mp3Parser) Album() string {
	return m.tags[tagAlbum]
}
func (m mp3Parser) AlbumArtist() string {
	return m.tags[tagAlbumArtist]
}
func (m mp3Parser) Artist() string {
	return m.tags[tagArtist]
}
func (m mp3Parser) BitDepth() int {
	return 16
}
func (m mp3Parser) Bitrate() int {
	if m.xingHeader != nil && m.xingHeader.Bitrate > 0 {
		return m.xingHeader.Bitrate
	}
	return mp3BitrateMap[m.mp3Header.Bitrate]
}
func (m mp3Parser) Channels() int {
	return mp3ChannelModeMap[m.mp3Header.ChannelMode]
}
func (m mp3Parser) Comment() string {
	return m.tags[tagComment]
}
func (m mp3Parser) Date() string {
	return m.tags[tagDate]
}
func (m mp3Parser) DiscNumber() int {
	disc, err := strconv.Atoi(m.tags[tagDiscNumber])
	if err != nil {
		return 0
	}
	return disc
}
func (m mp3Parser) Duration() time.Duration {
	if m.xingHeader != nil && m.xingHeader.Duration > 0 {
		return time.Duration(m.xingHeader.Duration) * time.Second
	}
	length, err := strconv.Atoi(m.tags[mp3TagLength])
	if err != nil {
		return time.Duration(0 * time.Second)
	}
	return time.Duration(length/1000) * time.Second
}
func (m mp3Parser) Encoder() string {
	return m.tags[mp3TagEncoder]
}
func (m mp3Parser) Format() string {
	return "MP3"
}
func (m mp3Parser) Genre() string {
	return m.tags[tagGenre]
}
func (m mp3Parser) Publisher() string {
	return m.tags[tagPublisher]
}
func (m mp3Parser) SampleRate() int {
	return mp3SampleRateMap[m.mp3Header.SampleRate]
}
func (m mp3Parser) Tag(name string) string {
	return m.tags[name]
}
func (m mp3Parser) Title() string {
	return m.tags[tagTitle]
}
func (m mp3Parser) TrackNumber() int {
	track, err := strconv.Atoi(strings.Split(m.tags[tagTrackNumber], "/")[0])
	if err != nil {
		return 0
	}
	return track
}
func newMP3Parser(reader io.ReadSeeker) (*mp3Parser, error) {
	parser := &mp3Parser{
		reader: reader,
	}
	if err := parser.parseID3v2Header(); err != nil {
		return nil, err
	}
	if err := parser.parseID3v2Frames(); err != nil {
		return nil, err
	}
	if err := parser.parseMP3Header(); err != nil {
		return nil, err
	}
	return parser, nil
}
func (m *mp3Parser) parseID3v2Header() error {
	fields, err := bit.NewReader(m.reader).ReadFields(8, 8, 1, 1, 1, 1, 4, 32)
	if err != nil {
		return err
	}
	m.id3Header = &mp3ID3v2Header{
		MajorVersion:      uint8(fields[0]),
		MinorVersion:      uint8(fields[1]),
		Unsynchronization: fields[2] == 1,
		Extended:          fields[3] == 1,
		Experimental:      fields[4] == 1,
		Footer:            fields[5] == 1,
		Size:              uint32(fields[7]),
	}
	if m.id3Header.MajorVersion < 2 || m.id3Header.MajorVersion > 4 {
		return TagError{
			Err:     errUnsupportedVersion,
			Format:  m.Format(),
			Details: fmt.Sprintf("unsupported ID3 version: ID3v2.%d.%d", m.id3Header.MajorVersion, m.id3Header.MinorVersion),
		}
	}
	if m.id3Header.MajorVersion < 4 && m.id3Header.Footer {
		return TagError{
			Err:     errInvalidStream,
			Format:  m.Format(),
			Details: "ID3 footer bit set prior to version ID3v2.4",
		}
	}
	if m.id3Header.Extended {
		var headerSize uint32
		if err := binary.Read(m.reader, binary.BigEndian, &headerSize); err != nil {
			return err
		}
		if _, err := m.reader.Seek(int64(headerSize)-4, 1); err != nil {
			return err
		}
	}
	return nil
}