diff --git a/id.go b/id.go index b2c8a0c..4670192 100644 --- a/id.go +++ b/id.go @@ -26,8 +26,20 @@ func Identify(r io.ReadSeeker) (format Format, fileType FileType, err error) { case string(b[0:4]) == "OggS": return VORBIS, OGG, nil - case string(b[4:11]) == "ftypM4A": - return AAC, MP4, nil + case string(b[4:8]) == "ftyp": + b = b[8:11] + fileType = UnknownFileType + switch string(b) { + case "M4A": + fileType = M4A + + case "M4B": + fileType = M4B + + case "M4P": + fileType = M4P + } + return MP4, fileType, nil case string(b[0:3]) == "ID3": b := b[3:] diff --git a/mp4.go b/mp4.go index 84f241d..be31261 100644 --- a/mp4.go +++ b/mp4.go @@ -57,12 +57,18 @@ func (f atomNames) Name(n string) []string { } // metadataMP4 is the implementation of Metadata for MP4 tag (atom) data. -type metadataMP4 map[string]interface{} +type metadataMP4 struct { + fileType FileType + data map[string]interface{} +} // ReadAtoms reads MP4 metadata atoms from the io.ReadSeeker into a Metadata, returning // non-nil error if there was a problem. func ReadAtoms(r io.ReadSeeker) (Metadata, error) { - m := make(metadataMP4) + m := metadataMP4{ + data: make(map[string]interface{}), + fileType: UnknownFileType, + } err := m.readAtoms(r) return m, err } @@ -137,8 +143,8 @@ func (m metadataMP4) readAtomData(r io.ReadSeeker, name string, size uint32) err b = b[8:] if name == "trkn" || name == "disk" { - m[name] = int(b[3]) - m[name+"_count"] = int(b[5]) + m.data[name] = int(b[3]) + m.data[name+"_count"] = int(b[5]) return nil } @@ -157,7 +163,7 @@ func (m metadataMP4) readAtomData(r io.ReadSeeker, name string, size uint32) err Data: b, } } - m[name] = data + m.data[name] = data return nil } @@ -220,13 +226,13 @@ func readCustomAtom(r io.ReadSeeker, size uint32) (string, uint32, error) { } func (metadataMP4) Format() Format { return MP4 } -func (metadataMP4) FileType() FileType { return AAC } +func (m metadataMP4) FileType() FileType { return m.fileType } -func (m metadataMP4) Raw() map[string]interface{} { return m } +func (m metadataMP4) Raw() map[string]interface{} { return m.data } func (m metadataMP4) getString(n []string) string { for _, k := range n { - if x, ok := m[k]; ok { + if x, ok := m.data[k]; ok { return x.(string) } } @@ -235,7 +241,7 @@ func (m metadataMP4) getString(n []string) string { func (m metadataMP4) getInt(n []string) int { for _, k := range n { - if x, ok := m[k]; ok { + if x, ok := m.data[k]; ok { return x.(int) } } @@ -277,7 +283,7 @@ func (m metadataMP4) Year() int { func (m metadataMP4) Track() (int, int) { x := m.getInt([]string{"trkn"}) - if n, ok := m["trkn_count"]; ok { + if n, ok := m.data["trkn_count"]; ok { return x, n.(int) } return x, 0 @@ -285,14 +291,14 @@ func (m metadataMP4) Track() (int, int) { func (m metadataMP4) Disc() (int, int) { x := m.getInt([]string{"disk"}) - if n, ok := m["disk_count"]; ok { + if n, ok := m.data["disk_count"]; ok { return x, n.(int) } return x, 0 } func (m metadataMP4) Lyrics() string { - t, ok := m["\xa9lyr"] + t, ok := m.data["\xa9lyr"] if !ok { return "" } @@ -300,7 +306,7 @@ func (m metadataMP4) Lyrics() string { } func (m metadataMP4) Picture() *Picture { - v, ok := m["covr"] + v, ok := m.data["covr"] if !ok { return nil } diff --git a/tag.go b/tag.go index 96a70b8..8e5afbc 100644 --- a/tag.go +++ b/tag.go @@ -73,7 +73,7 @@ const ( ID3v2_2 = "ID3v2.2" // ID3v2.2 tag format. ID3v2_3 = "ID3v2.3" // ID3v2.3 tag format (most common). ID3v2_4 = "ID3v2.4" // ID3v2.4 tag format. - MP4 = "MP4" // MP4 tag (atom) format. + MP4 = "MP4" // MP4 tag (atom) format (see http://www.ftyps.com/ for a full file type list) VORBIS = "VORBIS" // Vorbis Comment tag format. ) @@ -86,7 +86,9 @@ type FileType string const ( UnknownFileType FileType = "" // Unknown FileType. MP3 = "MP3" // MP3 file - AAC = "AAC" // M4A file (MP4) + M4A = "M4A" // M4A file Apple iTunes (ACC) Audio + M4B = "M4B" // M4A file Apple iTunes (ACC) Audio Book + M4P = "M4P" // M4A file Apple iTunes (ACC) AES Protected Audio ALAC = "ALAC" // Apple Lossless file FIXME: actually detect this FLAC = "FLAC" // FLAC file OGG = "OGG" // OGG file