From 1fc6cacf34402924268b3bab8351758837d06494 Mon Sep 17 00:00:00 2001 From: David Howden Date: Wed, 15 Apr 2015 00:06:32 +1000 Subject: [PATCH] Updated ReadFrom to take io.ReadSeeker --- id3v1.go | 13 +++++-------- id3v2.go | 10 ++++++++-- mp4.go | 13 +++++++++---- tag.go | 26 +++++++++++++------------- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/id3v1.go b/id3v1.go index d054cbe..2243e84 100644 --- a/id3v1.go +++ b/id3v1.go @@ -5,10 +5,9 @@ package tag import ( - "bytes" "errors" "io" - "io/ioutil" + "os" "strconv" "strings" ) @@ -42,16 +41,14 @@ var id3v1Genres = [...]string{ // ErrNotID3v1 is an error which is returned when no ID3v1 header is found. var ErrNotID3v1 = errors.New("invalid ID3v1 header") -// ReadID3v1Tags reads ID3v1 tags from the given io.Reader. Returns a non-nil error -// if there was a problem. -func ReadID3v1Tags(r io.Reader) (Metadata, error) { - b, err := ioutil.ReadAll(r) +// ReadID3v1Tags reads ID3v1 tags from the io.ReadSeeker. Returns ErrNotID3v1 +// if there are no ID3v1 tags, otherwise non-nil error if there was a problem. +func ReadID3v1Tags(r io.ReadSeeker) (Metadata, error) { + _, err := r.Seek(-128, os.SEEK_END) if err != nil { return nil, err } - b = b[len(b)-128 : len(b)] - r = bytes.NewReader(b) if tag, err := readString(r, 3); err != nil { return nil, err } else if tag != "TAG" { diff --git a/id3v2.go b/id3v2.go index b1c30bf..32017b9 100644 --- a/id3v2.go +++ b/id3v2.go @@ -7,6 +7,7 @@ package tag import ( "fmt" "io" + "os" "strings" ) @@ -219,9 +220,14 @@ func readID3v2Frames(r io.Reader, h *ID3v2Header) (map[string]interface{}, error return result, nil } -// ReadID3v2Tags parses ID3v2.{2,3,4} tags from the given io.Reader into a Metadata, returning +// ReadID3v2Tags parses ID3v2.{2,3,4} tags from the io.ReadSeeker into a Metadata, returning // non-nil error on failure. -func ReadID3v2Tags(r io.Reader) (Metadata, error) { +func ReadID3v2Tags(r io.ReadSeeker) (Metadata, error) { + _, err := r.Seek(0, os.SEEK_SET) + if err != nil { + return nil, err + } + h, err := readID3v2Header(r) if err != nil { return nil, err diff --git a/mp4.go b/mp4.go index 150482d..f18aed1 100644 --- a/mp4.go +++ b/mp4.go @@ -8,6 +8,7 @@ import ( "encoding/binary" "fmt" "io" + "os" "strconv" ) @@ -56,11 +57,15 @@ func (f atomNames) Name(n string) []string { // metadataMP4 is the implementation of Metadata for MP4 tag (atom) data. type metadataMP4 map[string]interface{} -// ReadAtoms reads MP4 metadata atoms from the reader into a Metadata, returning non-nil -// error if there was a problem. -func ReadAtoms(r io.Reader) (Metadata, error) { +// 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) { + _, err := r.Seek(0, os.SEEK_SET) + if err != nil { + return nil, err + } m := make(metadataMP4) - err := m.readAtoms(r) + err = m.readAtoms(r) return m, err } diff --git a/tag.go b/tag.go index a38aa09..216fd42 100644 --- a/tag.go +++ b/tag.go @@ -6,7 +6,6 @@ package tag import ( - "bytes" "errors" "io" ) @@ -16,25 +15,26 @@ import ( var ErrNoTagsFound = errors.New("no tags found") // ReadFrom parses audio file metadata tags (currently supports ID3v1,2.{2,3,4} and MP4). -// This method attempts to determine the format of the data provided by the reader, and then -// chooses ReadAtoms (MP4), ReadID3v2Tags (ID3v2.{2,3,4}) or ReadID3v1Tags as appropriate. -// Returns non-nil error if the format of the given data could not be determined, or if -// there was a problem parsing the data. -func ReadFrom(r io.Reader) (Metadata, error) { +// This method attempts to determine the format of the data provided by the io.ReadSeeker, +// and then chooses ReadAtoms (MP4), ReadID3v2Tags (ID3v2.{2,3,4}) or ReadID3v1Tags as +// appropriate. Returns non-nil error if the format of the given data could not be determined, +// or if there was a problem parsing the data. +func ReadFrom(r io.ReadSeeker) (Metadata, error) { b, err := readBytes(r, 11) if err != nil { return nil, err } - rr := io.MultiReader(bytes.NewReader(b), r) - if string(b[4:11]) == "ftypM4A" { - return ReadAtoms(rr) - } - if string(b[0:3]) == "ID3" { - return ReadID3v2Tags(rr) + switch { + + case string(b[4:11]) == "ftypM4A": + return ReadAtoms(r) + + case string(b[0:3]) == "ID3": + return ReadID3v2Tags(r) } - m, err := ReadID3v1Tags(rr) + m, err := ReadID3v1Tags(r) if err != nil { if err == ErrNotID3v1 { err = ErrNoTagsFound