Reorganised Vorbis Comment parsing into own type

- Added FileType to Metadata to distinguish between FLAC and OGG
- TODO: fix ALAC files being identified as AAC
This commit is contained in:
David Howden
2015-05-24 10:44:45 +10:00
parent 77d9aa6414
commit 4c2b34fa94
8 changed files with 262 additions and 211 deletions
+3 -206
View File
@@ -6,11 +6,8 @@ package tag
import (
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
)
// BlockType is a type which represents an enumeration of valid FLAC blocks
@@ -43,7 +40,7 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
}
m := &metadataFLAC{
c: make(map[string]string),
newMetadataVorbis(),
}
for {
@@ -60,8 +57,7 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
}
type metadataFLAC struct {
c map[string]string // the vorbis comments
p *Picture
*metadataVorbis
}
func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
@@ -93,205 +89,6 @@ func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err er
return
}
func (m *metadataFLAC) readVorbisComment(r io.Reader) error {
vendorLen, err := readInt32LittleEndian(r)
if err != nil {
return err
}
vendor, err := readString(r, vendorLen)
if err != nil {
return err
}
m.c["vendor"] = vendor
commentsLen, err := readInt32LittleEndian(r)
if err != nil {
return err
}
for i := 0; i < commentsLen; i++ {
l, err := readInt32LittleEndian(r)
if err != nil {
return err
}
s, err := readString(r, l)
if err != nil {
return err
}
k, v, err := parseComment(s)
if err != nil {
return err
}
m.c[strings.ToLower(k)] = v
}
return nil
}
func (m *metadataFLAC) readPictureBlock(r io.Reader) error {
b, err := readInt(r, 4)
if err != nil {
return err
}
pictureType, ok := pictureTypes[byte(b)]
if !ok {
return fmt.Errorf("invalid picture type: %v", b)
}
mimeLen, err := readInt(r, 4)
if err != nil {
return err
}
mime, err := readString(r, mimeLen)
if err != nil {
return err
}
ext := ""
switch mime {
case "image/jpeg":
ext = "jpg"
case "image/png":
ext = "png"
case "image/gif":
ext = "gif"
}
descLen, err := readInt(r, 4)
if err != nil {
return err
}
desc, err := readString(r, descLen)
if err != nil {
return err
}
// We skip width <32>, height <32>, colorDepth <32>, coloresUsed <32>
_, err = readInt(r, 4) // width
if err != nil {
return err
}
_, err = readInt(r, 4) // height
if err != nil {
return err
}
_, err = readInt(r, 4) // color depth
if err != nil {
return err
}
_, err = readInt(r, 4) // colors used
if err != nil {
return err
}
dataLen, err := readInt(r, 4)
if err != nil {
return err
}
data := make([]byte, dataLen)
_, err = io.ReadFull(r, data)
if err != nil {
return err
}
m.p = &Picture{
Ext: ext,
MIMEType: mime,
Type: pictureType,
Description: desc,
Data: data,
}
return nil
}
func parseComment(c string) (k, v string, err error) {
kv := strings.SplitN(c, "=", 2)
if len(kv) != 2 {
err = errors.New("vorbis comment must contain '='")
return
}
k = kv[0]
v = kv[1]
return
}
func (m *metadataFLAC) Format() Format {
func (m *metadataFLAC) FileType() FileType {
return FLAC
}
func (m *metadataFLAC) Raw() map[string]interface{} {
raw := make(map[string]interface{}, len(m.c))
for k, v := range m.c {
raw[k] = v
}
return raw
}
func (m *metadataFLAC) Title() string {
return m.c["title"]
}
func (m *metadataFLAC) Artist() string {
// PERFORMER
// The artist(s) who performed the work. In classical music this would be the
// conductor, orchestra, soloists. In an audio book it would be the actor who
// did the reading. In popular music this is typically the same as the ARTIST
// and is omitted.
if m.c["performer"] != "" {
return m.c["performer"]
}
return m.c["artist"]
}
func (m *metadataFLAC) Album() string {
return m.c["album"]
}
func (m *metadataFLAC) AlbumArtist() string {
// This field isn't included in the standard.
return ""
}
func (m *metadataFLAC) Composer() string {
// ARTIST
// The artist generally considered responsible for the work. In popular music
// this is usually the performing band or singer. For classical music it would
// be the composer. For an audio book it would be the author of the original text.
if m.c["composer"] != "" {
return m.c["composer"]
}
if m.c["performer"] == "" {
return ""
}
return m.c["artist"]
}
func (m *metadataFLAC) Genre() string {
return m.c["genre"]
}
func (m *metadataFLAC) Year() int {
// FIXME: try to parse the date in m.c["date"] to extract this
return 0
}
func (m *metadataFLAC) Track() (int, int) {
x, _ := strconv.Atoi(m.c["tracknumber"])
// https://wiki.xiph.org/Field_names
n, _ := strconv.Atoi(m.c["tracktotal"])
return x, n
}
func (m *metadataFLAC) Disc() (int, int) {
// https://wiki.xiph.org/Field_names
x, _ := strconv.Atoi(m.c["discnumber"])
n, _ := strconv.Atoi(m.c["disctotal"])
return x, n
}
func (m *metadataFLAC) Lyrics() string {
return m.c["lyrics"]
}
func (m *metadataFLAC) Picture() *Picture {
return m.p
}