From bc832479b899c07b46ee1f6a68f09656b151f69f Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Sun, 4 Jul 2021 17:05:32 +0300 Subject: [PATCH] =?UTF-8?q?=E2=8E=A3Re-did=20the=20structure,=20tried=20to?= =?UTF-8?q?=20implement=20frame=20reading,=20but=20looks=20like=20failed?= =?UTF-8?q?=E2=8E=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testData/testwritev1.mp3 | Bin 5535 -> 6815 bytes v1/v11read.go | 97 ++++++++++++++++++++++++++++++++ v1/v11tags.go | 15 +++++ v1/{id3v11.go => v11write.go} | 102 ---------------------------------- v1/v1read.go | 80 ++++++++++++++++++++++++++ v1/v1tags.go | 16 ++++++ v1/{id3v10.go => v1write.go} | 86 ---------------------------- v2/constants.go | 2 - v2/frame.go | 2 +- v2/frame_test.go | 4 +- v2/header.go | 3 +- v2/read.go | 34 ++++++++++++ v2/read_test.go | 13 +++++ 13 files changed, 259 insertions(+), 195 deletions(-) create mode 100644 v1/v11read.go create mode 100644 v1/v11tags.go rename v1/{id3v11.go => v11write.go} (59%) create mode 100644 v1/v1read.go create mode 100644 v1/v1tags.go rename v1/{id3v10.go => v1write.go} (59%) create mode 100644 v2/read.go create mode 100644 v2/read_test.go diff --git a/testData/testwritev1.mp3 b/testData/testwritev1.mp3 index 7b827e28e8a1f152e48cd5bc1c2761fb2232f0ec..784e19a1fc7a15b8dd3310d88c20f50fde91af72 100644 GIT binary patch delta 11 ScmbQQJ>PW0e9^`88Cd}xFa%2g delta 7 OcmbPlI$wLkd{F=l$O8ia diff --git a/v1/v11read.go b/v1/v11read.go new file mode 100644 index 0000000..84c95d9 --- /dev/null +++ b/v1/v11read.go @@ -0,0 +1,97 @@ +package v1 + +import ( + "bytes" + "fmt" + "io" + "strconv" + + "github.com/Unbewohnte/id3ed/util" +) + +// Retrieves ID3v1.1 field values of provided io.ReadSeeker +func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { + // set reader to the last 128 bytes + _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) + if err != nil { + return nil, fmt.Errorf("could not seek: %s", err) + } + + tag, err := util.Read(rs, 3) + if err != nil { + return nil, err + } + + if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { + // no TAG, given file does not use ID3v1 + return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) + } + + songname, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + artist, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + album, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + yearStr, err := util.ReadToString(rs, 4) + if err != nil { + return nil, err + } + year, err := strconv.Atoi(yearStr) + if err != nil { + return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) + } + + comment, err := util.ReadToString(rs, 28) + if err != nil { + return nil, err + } + + // skip 1 null byte + _, err = util.Read(rs, 1) + if err != nil { + return nil, err + } + + trackByte, err := util.Read(rs, 1) + if err != nil { + return nil, err + } + + track, err := util.BytesToInt(trackByte) + if err != nil { + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) + } + + genreByte, err := util.Read(rs, 1) + if err != nil { + return nil, err + } + genreInt, err := util.BytesToInt(genreByte) + if err != nil { + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) + } + genre, exists := id3v1genres[int(genreInt)] + if !exists { + genre = "" + } + + return &ID3v11Tags{ + SongName: songname, + Artist: artist, + Album: album, + Year: year, + Comment: comment, + Track: int(track), + Genre: genre, + }, nil +} diff --git a/v1/v11tags.go b/v1/v11tags.go new file mode 100644 index 0000000..ada42df --- /dev/null +++ b/v1/v11tags.go @@ -0,0 +1,15 @@ +package v1 + +type ID3v11Tags struct { + SongName string + Artist string + Album string + Year int + Comment string + Track int + Genre string +} + +func (tags *ID3v11Tags) Version() int { + return 11 +} diff --git a/v1/id3v11.go b/v1/v11write.go similarity index 59% rename from v1/id3v11.go rename to v1/v11write.go index a05b23f..74626ed 100644 --- a/v1/id3v11.go +++ b/v1/v11write.go @@ -6,108 +6,10 @@ import ( "fmt" "io" "os" - "strconv" "github.com/Unbewohnte/id3ed/util" ) -type ID3v11Tags struct { - SongName string - Artist string - Album string - Year int - Comment string - Track int - Genre string -} - -// Retrieves ID3v1.1 field values of provided io.ReadSeeker -func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { - // set reader to the last 128 bytes - _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) - if err != nil { - return nil, fmt.Errorf("could not seek: %s", err) - } - - tag, err := util.Read(rs, 3) - if err != nil { - return nil, err - } - - if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { - // no TAG, given file does not use ID3v1 - return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) - } - - songname, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - artist, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - album, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - yearStr, err := util.ReadToString(rs, 4) - if err != nil { - return nil, err - } - year, err := strconv.Atoi(yearStr) - if err != nil { - return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) - } - - comment, err := util.ReadToString(rs, 28) - if err != nil { - return nil, err - } - - // skip 1 null byte - _, err = util.Read(rs, 1) - if err != nil { - return nil, err - } - - trackByte, err := util.Read(rs, 1) - if err != nil { - return nil, err - } - - track, err := util.BytesToInt(trackByte) - if err != nil { - return nil, fmt.Errorf("cannot convert bytes to int: %s", err) - } - - genreByte, err := util.Read(rs, 1) - if err != nil { - return nil, err - } - genreInt, err := util.BytesToInt(genreByte) - if err != nil { - return nil, fmt.Errorf("cannot convert bytes to int: %s", err) - } - genre, exists := id3v1genres[int(genreInt)] - if !exists { - genre = "" - } - - return &ID3v11Tags{ - SongName: songname, - Artist: artist, - Album: album, - Year: year, - Comment: comment, - Track: int(track), - Genre: genre, - }, nil -} - // Writes given ID3v1.1 tags to dst // NOTE: will not remove already existing ID3v1.1 tag if it`s present, // use ⁕WriteToFile⁕ method if you`re working with REAL mp3 files !!! @@ -225,7 +127,3 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error { return nil } - -func (tags *ID3v11Tags) Version() int { - return 11 -} diff --git a/v1/v1read.go b/v1/v1read.go new file mode 100644 index 0000000..976591d --- /dev/null +++ b/v1/v1read.go @@ -0,0 +1,80 @@ +package v1 + +import ( + "bytes" + "fmt" + "io" + "strconv" + + "github.com/Unbewohnte/id3ed/util" +) + +// Retrieves ID3v1 field values of provided io.ReadSeeker (usually a file) +func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { + // set reader to the last 128 bytes + _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) + if err != nil { + return nil, fmt.Errorf("could not seek: %s", err) + } + + tag, err := util.Read(rs, 3) + if err != nil { + return nil, err + } + + if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { + // no TAG, given file does not use ID3v1 + return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) + } + + songname, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + artist, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + album, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + yearStr, err := util.ReadToString(rs, 4) + if err != nil { + return nil, err + } + year, err := strconv.Atoi(yearStr) + if err != nil { + return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) + } + + comment, err := util.ReadToString(rs, 30) + if err != nil { + return nil, err + } + + genreByte, err := util.Read(rs, 1) + if err != nil { + return nil, err + } + genreInt, err := util.BytesToInt(genreByte) + if err != nil { + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) + } + genre, exists := id3v1genres[int(genreInt)] + if !exists { + genre = "" + } + + return &ID3v1Tags{ + SongName: songname, + Artist: artist, + Album: album, + Year: year, + Comment: comment, + Genre: genre, + }, nil +} diff --git a/v1/v1tags.go b/v1/v1tags.go new file mode 100644 index 0000000..76c6c6a --- /dev/null +++ b/v1/v1tags.go @@ -0,0 +1,16 @@ +package v1 + +// https://id3.org/ID3v1 - documentation + +type ID3v1Tags struct { + SongName string + Artist string + Album string + Year int + Comment string + Genre string +} + +func (tags *ID3v1Tags) Version() int { + return 10 +} diff --git a/v1/id3v10.go b/v1/v1write.go similarity index 59% rename from v1/id3v10.go rename to v1/v1write.go index a50802b..e2146ef 100644 --- a/v1/id3v10.go +++ b/v1/v1write.go @@ -6,92 +6,10 @@ import ( "fmt" "io" "os" - "strconv" "github.com/Unbewohnte/id3ed/util" ) -// https://id3.org/ID3v1 - documentation - -type ID3v1Tags struct { - SongName string - Artist string - Album string - Year int - Comment string - Genre string -} - -// Retrieves ID3v1 field values of provided io.ReadSeeker (usually a file) -func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { - // set reader to the last 128 bytes - _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) - if err != nil { - return nil, fmt.Errorf("could not seek: %s", err) - } - - tag, err := util.Read(rs, 3) - if err != nil { - return nil, err - } - - if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { - // no TAG, given file does not use ID3v1 - return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) - } - - songname, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - artist, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - album, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - yearStr, err := util.ReadToString(rs, 4) - if err != nil { - return nil, err - } - year, err := strconv.Atoi(yearStr) - if err != nil { - return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) - } - - comment, err := util.ReadToString(rs, 30) - if err != nil { - return nil, err - } - - genreByte, err := util.Read(rs, 1) - if err != nil { - return nil, err - } - genreInt, err := util.BytesToInt(genreByte) - if err != nil { - return nil, fmt.Errorf("cannot convert bytes to int: %s", err) - } - genre, exists := id3v1genres[int(genreInt)] - if !exists { - genre = "" - } - - return &ID3v1Tags{ - SongName: songname, - Artist: artist, - Album: album, - Year: year, - Comment: comment, - Genre: genre, - }, nil -} - // Writes given ID3v1.0 tags to given io.WriteSeeker. // NOTE: will not remove already existing ID3v1 tag if it`s present, // use ⁕WriteToFile⁕ method if you`re working with REAL mp3 files !!! @@ -192,7 +110,3 @@ func (tags *ID3v1Tags) WriteToFile(f *os.File) error { return nil } - -func (tags *ID3v1Tags) Version() int { - return 10 -} diff --git a/v2/constants.go b/v2/constants.go index 9048b14..ec81cf5 100644 --- a/v2/constants.go +++ b/v2/constants.go @@ -4,5 +4,3 @@ package v2 const HEADERIDENTIFIER string = "ID3" const HEADERSIZE int = 10 // bytes const HEADERMAXSIZE int = 268435456 // bytes (256 MB) - -// Version specific constants diff --git a/v2/frame.go b/v2/frame.go index ba84f84..6dc3084 100644 --- a/v2/frame.go +++ b/v2/frame.go @@ -25,7 +25,7 @@ type Frame struct { } // Reads ID3v2.3.0 or ID3v2.4.0 frame -func ReadFrame(rs io.Reader, version uint) (*Frame, error) { +func ReadFrame(rs io.Reader) (*Frame, error) { var frame Frame // ID diff --git a/v2/frame_test.go b/v2/frame_test.go index 9e7fa3d..1c536de 100644 --- a/v2/frame_test.go +++ b/v2/frame_test.go @@ -18,7 +18,7 @@ func TestReadFrame(t *testing.T) { // read right after header`s bytes f.Seek(int64(HEADERSIZE), io.SeekStart) - firstFrame, err := ReadFrame(f, 24) + firstFrame, err := ReadFrame(f) if err != nil { t.Errorf("ReadFrame failed: %s", err) } @@ -31,7 +31,7 @@ func TestReadFrame(t *testing.T) { t.Errorf("ReadFrame failed: expected compressed flag to be %v; got %v", false, firstFrame.Flags.Encrypted) } - secondFrame, err := ReadFrame(f, 24) + secondFrame, err := ReadFrame(f) if err != nil { t.Errorf("ReadFrame failed: %s", err) } diff --git a/v2/header.go b/v2/header.go index ee14b6f..86b5a83 100644 --- a/v2/header.go +++ b/v2/header.go @@ -21,8 +21,7 @@ type Header struct { Identifier string Flags HeaderFlags Version uint - - Size int64 // size of the whole tag - 10 header bytes + Size int64 // size of the whole tag - 10 header bytes } // Reads and structuralises ID3v2.3.0 or ID3v2.4.0 header diff --git a/v2/read.go b/v2/read.go new file mode 100644 index 0000000..7898d62 --- /dev/null +++ b/v2/read.go @@ -0,0 +1,34 @@ +package v2 + +// Reads ID3v2 frames from rs. NOT TESTED !!!! +// func GetFrames(rs io.ReadSeeker) ([]*Frame, error) { +// header, err := GetHeader(rs) +// if err != nil { +// return nil, fmt.Errorf("could not get header: %s", err) +// } +// tagsize := header.Size + +// var frames []*Frame +// var read uint64 = 0 +// for { +// if read == uint64(tagsize) { +// break +// } + +// frame, err := ReadFrame(rs) +// if err != nil { +// return frames, 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 +// } +// read += uint64(frame.Size) // and the contents itself +// } + +// return frames, nil +// } diff --git a/v2/read_test.go b/v2/read_test.go new file mode 100644 index 0000000..736c351 --- /dev/null +++ b/v2/read_test.go @@ -0,0 +1,13 @@ +package v2 + +// 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) +// } +// }