From 625f33f9eaea08bfb4f2b0a94dfabaeac623abd6 Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Tue, 6 Jul 2021 15:53:55 +0300 Subject: [PATCH] =?UTF-8?q?=E2=96=A3=20Now=20can=20read=20all=20ID3v2=20fr?= =?UTF-8?q?ames=20!=20=E2=96=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- v2/frame.go | 76 ++++++++++++++++++++++++++---------------------- v2/frame_test.go | 42 +++++++++++++++++++------- v2/header.go | 25 ++++++++-------- v2/v2tags.go | 4 +-- 4 files changed, 88 insertions(+), 59 deletions(-) diff --git a/v2/frame.go b/v2/frame.go index 669eace..3ff9f39 100644 --- a/v2/frame.go +++ b/v2/frame.go @@ -3,6 +3,7 @@ package v2 import ( "fmt" "io" + "strings" "github.com/Unbewohnte/id3ed/util" ) @@ -24,26 +25,37 @@ type Frame struct { Contents []byte } -// Reads ID3v2.3.0 or ID3v2.4.0 frame -func ReadFrame(rs io.Reader) (*Frame, error) { +var ErrGotPadding error = fmt.Errorf("got padding") + +// Reads next ID3v2.3.0 or ID3v2.4.0 frame. +// Returns a blank Frame struct if encountered an error +func ReadFrame(rs io.Reader) (Frame, error) { var frame Frame // ID identifier, err := util.ReadToString(rs, 4) if err != nil { - return nil, err + return Frame{}, err + } + if len(identifier) < 1 { + // probably read all frames and got padding as identifier + + // I know that it`s a terrible desicion, but with my current + // implementation it`s the only way I can see that will somewhat work + + return Frame{}, ErrGotPadding } frame.ID = identifier // Size framesizeBytes, err := util.Read(rs, 4) if err != nil { - return nil, err + return Frame{}, err } framesize, err := util.BytesToIntIgnoreFirstBit(framesizeBytes) if err != nil { - return nil, err + return Frame{}, err } frame.Size = framesize @@ -52,12 +64,12 @@ func ReadFrame(rs io.Reader) (*Frame, error) { frameFlagsByte1, err := util.Read(rs, 1) if err != nil { - return nil, err + return Frame{}, err } frameFlagsByte2, err := util.Read(rs, 1) if err != nil { - return nil, err + return Frame{}, err } // I don`t have enough knowledge to handle this more elegantly @@ -103,7 +115,7 @@ func ReadFrame(rs io.Reader) (*Frame, error) { if flags.InGroup { groupByte, err := util.Read(rs, 1) if err != nil { - return nil, err + return Frame{}, err } frame.GroupByte = groupByte[0] } @@ -111,48 +123,44 @@ func ReadFrame(rs io.Reader) (*Frame, error) { // Body frameContents, err := util.Read(rs, uint64(framesize)) if err != nil { - return nil, err + return Frame{}, err } frame.Contents = frameContents - return &frame, nil + return frame, nil } -// Reads ID3v2 frames from rs. NOT TESTED !!!! -func GetFrames(rs io.ReadSeeker) ([]*Frame, error) { - header, err := GetHeader(rs) +// Reads all ID3v2 frames from rs. +// Returns a nil as []Frame if encountered an error +func GetFrames(rs io.ReadSeeker) ([]Frame, error) { + // skip header + _, err := rs.Seek(10, io.SeekStart) if err != nil { - return nil, err + return nil, fmt.Errorf("could not skip header: %s", err) } - tagsize := header.Size - - fmt.Println("NEED TO READ ", tagsize) - - var frames []*Frame - var read uint64 = 0 + var frames []Frame for { - if read == uint64(tagsize) { - break + frame, err := ReadFrame(rs) + if err == ErrGotPadding { + return frames, nil } - frame, err := ReadFrame(rs) if err != nil { - return frames, fmt.Errorf("could not read frame: %s", err) + return nil, fmt.Errorf("could not read frame: %s", err) } + frames = append(frames, frame) + } +} - // counting how many bytes has been read - read += 10 // frame header - if frame.Flags.InGroup { - // header has 1 additional byte - read += 1 +// Looks for a certain identificator in given frames and returns frame if found +func GetFrame(id string, frames []Frame) Frame { + for _, frame := range frames { + if strings.Contains(frame.ID, id) { + return frame } - read += uint64(frame.Size) // and the contents itself - - fmt.Println("Read: ", read, " ", frame.ID) } - - return frames, nil + return Frame{} } diff --git a/v2/frame_test.go b/v2/frame_test.go index 5a1ed3c..e6bab29 100644 --- a/v2/frame_test.go +++ b/v2/frame_test.go @@ -45,15 +45,35 @@ func TestReadFrame(t *testing.T) { } } +func TestGetFrames(t *testing.T) { + f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) + if err != nil { + t.Errorf("%s", err) + } + + _, err = GetFrames(f) + if err != nil { + t.Errorf("GetFrames failed: %s", err) + } +} + +func TestGetFrame(t *testing.T) { + f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) + if err != nil { + t.Errorf("%s", err) + } + + frames, err := GetFrames(f) + if err != nil { + t.Errorf("GetFrames failed: %s", err) + } + + frame := GetFrame("TIT2", frames) + if frame.ID == "" { + t.Errorf("GetFrame failed: expected to find %s; got nothing", "TIT1") + } -// func TestGetFrames(t *testing.T) { -// f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) -// if err != nil { -// t.Errorf("%s", err) -// } - -// _, err = GetFrames(f) -// if err != nil { -// t.Errorf("GetFrames failed: %s", err) -// } -// } \ No newline at end of file + if util.ToString(frame.Contents) != "title" { + t.Errorf("GetFrame failed: expected contents to be %s; got %s", "title", util.ToString(frame.Contents)) + } +} diff --git a/v2/header.go b/v2/header.go index d96c580..7217b02 100644 --- a/v2/header.go +++ b/v2/header.go @@ -23,35 +23,36 @@ type Header struct { Size int64 // size of the whole tag - 10 header bytes } -// Reads and structuralises ID3v2.3.0 or ID3v2.4.0 header -func GetHeader(rs io.ReadSeeker) (*Header, error) { +// Reads and structuralises ID3v2.3.0 or ID3v2.4.0 header. +// Returns a blank header struct if encountered an error +func GetHeader(rs io.ReadSeeker) (Header, error) { var header Header rs.Seek(0, io.SeekStart) identifier, err := util.Read(rs, 3) if err != nil { - return nil, err + return Header{}, err } // check if ID3v2 is used if !bytes.Equal([]byte(HEADERIDENTIFIER), identifier) { - return nil, fmt.Errorf("no ID3v2 identifier found") + return Header{}, fmt.Errorf("no ID3v2 identifier found") } header.Identifier = string(identifier) // version VersionBytes, err := util.Read(rs, 2) if err != nil { - return nil, err + return Header{}, err } majorVersion, err := util.ByteToInt(VersionBytes[0]) if err != nil { - return nil, err + return Header{}, err } revisionNumber, err := util.ByteToInt(VersionBytes[1]) if err != nil { - return nil, err + return Header{}, err } var version string @@ -63,7 +64,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { case 4: version = V2_4 default: - return nil, fmt.Errorf("ID3v2.%d.%d is not supported", majorVersion, revisionNumber) + return Header{}, fmt.Errorf("ID3v2.%d.%d is not supported", majorVersion, revisionNumber) } header.Version = version @@ -71,7 +72,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { // flags flags, err := util.Read(rs, 1) if err != nil { - return nil, err + return Header{}, err } flagBits := fmt.Sprintf("%08b", flags) // 1 byte is 8 bits @@ -123,15 +124,15 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { // size sizeBytes, err := util.Read(rs, 4) if err != nil { - return nil, err + return Header{}, err } size, err := util.BytesToIntIgnoreFirstBit(sizeBytes) if err != nil { - return nil, err + return Header{}, err } header.Size = size - return &header, nil + return header, nil } diff --git a/v2/v2tags.go b/v2/v2tags.go index 924a515..8870f37 100644 --- a/v2/v2tags.go +++ b/v2/v2tags.go @@ -1,8 +1,8 @@ package v2 // type ID3v2Tag struct { -// Header *Header -// Frames []*Frame +// Header Header +// Frames []Frame // } // type V2TagReader interface {