diff --git a/README.md b/README.md index 4c689ae..c7c2cf0 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ func main() { } // extract ID3v1.1 tags - mp3tags, err := id3v1.GetID3v11Tags(mp3file) + mp3tags, err := id3v1.Getv11Tags(mp3file) if err != nil { panic(err) } @@ -80,7 +80,7 @@ func main() { Year: 2021, Comment: "Cool song", Track: 1, - Genre: "Christian Gangsta Rap", // list of genres see "id3v1genres.go" + Genre: "Christian Gangsta Rap", // for list of genres see: "./v1/genres.go" } // write tags to file diff --git a/testData/testwritev1.mp3 b/testData/testwritev1.mp3 index f4f78e5..74b8811 100644 Binary files a/testData/testwritev1.mp3 and b/testData/testwritev1.mp3 differ diff --git a/util/etc.go b/util/etc.go new file mode 100644 index 0000000..f7e8835 --- /dev/null +++ b/util/etc.go @@ -0,0 +1,28 @@ +package util + +import ( + "bytes" + "encoding/binary" +) + +// Returns found key (int) in provided map by value (string); +// If key does not exist in map - returns -1 +func GetKey(mp map[int]string, givenValue string) int { + for key, value := range mp { + if value == givenValue { + return key + } + } + return -1 +} + +// Decodes given integer bytes into integer +func BytesToInt(gBytes []byte) (int64, error) { + buff := bytes.NewBuffer(gBytes) + integer, err := binary.ReadVarint(buff) + if err != nil { + return 0, err + } + buff = nil + return integer, nil +} diff --git a/util/read.go b/util/read.go new file mode 100644 index 0000000..c7e2eba --- /dev/null +++ b/util/read.go @@ -0,0 +1,37 @@ +package util + +import ( + "fmt" + "io" +) + +// Shortcut function to read n bytes from reader. The general idea peeked from here: https://github.com/dhowden/tag/blob/master/util.go +func Read(rs io.Reader, n uint64) ([]byte, error) { + read := make([]byte, n) + _, err := rs.Read(read) + if err != nil { + return nil, fmt.Errorf("could not read from reader: %s", err) + } + + return read, nil +} + +// Shortcut function to read n bytes and convert them into string. +// If encountered zero-byte - converts to string only previously read bytes +func ReadToString(rs io.Reader, n int) (string, error) { + read := make([]byte, n) + _, err := rs.Read(read) + if err != nil { + return "", fmt.Errorf("could not read from reader: %s", err) + } + + var readString string + for _, b := range read { + if b == 0 { + break + } + readString += string(b) + } + + return readString, nil +} diff --git a/util/util.go b/util/util.go deleted file mode 100644 index 8cc1c9d..0000000 --- a/util/util.go +++ /dev/null @@ -1,90 +0,0 @@ -package util - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" -) - -// Shortcut function to read n bytes from reader. Peeked from here: https://github.com/dhowden/tag/blob/master/util.go -func Read(rs io.Reader, n int) ([]byte, error) { - read := make([]byte, n) - _, err := rs.Read(read) - if err != nil { - return nil, fmt.Errorf("could not read from reader: %s", err) - } - - return read, nil -} - -// Shortcut function to read n bytes and convert them into string. -// If encountered zero-byte - converts to string only previously read bytes -func ReadToString(rs io.Reader, n int) (string, error) { - read := make([]byte, n) - _, err := rs.Read(read) - if err != nil { - return "", fmt.Errorf("could not read from reader: %s", err) - } - - var readString string - for _, b := range read { - if b == 0 { - break - } - readString += string(b) - } - - return readString, nil -} - -// Writes data to wr, if len(data) is less than lenNeeded - adds null bytes until written lenNeeded bytes -func WriteToExtent(wr io.Writer, data []byte, lenNeeded int) error { - if len(data) > lenNeeded { - return fmt.Errorf("length of given data bytes is bigger than length needed") - } - - buff := new(bytes.Buffer) - for i := 0; i < lenNeeded; i++ { - if i < len(data) { - err := buff.WriteByte(data[i]) - if err != nil { - return err - } - } else { - err := buff.WriteByte(0) - if err != nil { - return err - } - } - } - - _, err := wr.Write(buff.Bytes()) - if err != nil { - return err - } - - return nil -} - -// Returns found key (int) in provided map by value (string); -// If key does not exist in map - returns -1 -func GetKey(mp map[int]string, givenValue string) int { - for key, value := range mp { - if value == givenValue { - return key - } - } - return -1 -} - -// Decodes given integer bytes into integer -func BytesToInt(gBytes []byte) (int64, error) { - buff := bytes.NewBuffer(gBytes) - integer, err := binary.ReadVarint(buff) - if err != nil { - return 0, err - } - buff = nil - return integer, nil -} diff --git a/util/write.go b/util/write.go new file mode 100644 index 0000000..75ba32d --- /dev/null +++ b/util/write.go @@ -0,0 +1,36 @@ +package util + +import ( + "bytes" + "fmt" + "io" +) + +// Writes data to wr, if len(data) is less than lenNeeded - adds null bytes until written lenNeeded bytes +func WriteToExtent(wr io.Writer, data []byte, lenNeeded int) error { + if len(data) > lenNeeded { + return fmt.Errorf("length of given data bytes is bigger than length needed") + } + + buff := new(bytes.Buffer) + for i := 0; i < lenNeeded; i++ { + if i < len(data) { + err := buff.WriteByte(data[i]) + if err != nil { + return err + } + } else { + err := buff.WriteByte(0) + if err != nil { + return err + } + } + } + + _, err := wr.Write(buff.Bytes()) + if err != nil { + return err + } + + return nil +} diff --git a/v1/id3v10.go b/v1/id3v10.go index 6d27bd1..2101f07 100644 --- a/v1/id3v10.go +++ b/v1/id3v10.go @@ -23,7 +23,7 @@ type ID3v1Tags struct { } // Retrieves ID3v1 field values of provided io.ReadSeeker (usually a file) -func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { +func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { // set reader to the last 128 bytes _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) if err != nil { diff --git a/v1/id3v10_test.go b/v1/id3v10_test.go index 83ed33a..ac91d45 100644 --- a/v1/id3v10_test.go +++ b/v1/id3v10_test.go @@ -17,12 +17,12 @@ var TESTv1TAGS = &ID3v1Tags{ Genre: "Blues", } -func TestGetID3v1Tags(t *testing.T) { +func TestGetv1Tags(t *testing.T) { testfile, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_CREATE|os.O_RDONLY, os.ModePerm) if err != nil { t.Errorf("could not open file for testing: %s", err) } - tags, err := GetID3v1Tags(testfile) + tags, err := Getv1Tags(testfile) if err != nil { t.Errorf("GetID3v1Tags failed: %s", err) } @@ -32,7 +32,7 @@ func TestGetID3v1Tags(t *testing.T) { } } -func TestWriteID3v1Tags(t *testing.T) { +func TestWritev1Tags(t *testing.T) { f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testwritev1.mp3"), os.O_CREATE|os.O_RDWR, os.ModePerm) if err != nil { t.Errorf("%s", err) @@ -48,7 +48,7 @@ func TestWriteID3v1Tags(t *testing.T) { } // reading tags - readTags, err := GetID3v1Tags(f) + readTags, err := Getv1Tags(f) if err != nil { t.Errorf("%s", err) } diff --git a/v1/id3v11.go b/v1/id3v11.go index 2a10a81..ccf8a91 100644 --- a/v1/id3v11.go +++ b/v1/id3v11.go @@ -22,7 +22,7 @@ type ID3v11Tags struct { } // Retrieves ID3v1.1 field values of provided io.ReadSeeker -func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { +func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { // set reader to the last 128 bytes _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) if err != nil { diff --git a/v1/id3v11_test.go b/v1/id3v11_test.go index e1d864a..d42f46e 100644 --- a/v1/id3v11_test.go +++ b/v1/id3v11_test.go @@ -22,7 +22,7 @@ func TestGetID3v11Tags(t *testing.T) { if err != nil { t.Errorf("could not open file for testing: %s", err) } - mp3tags, err := GetID3v11Tags(testfile) + mp3tags, err := Getv11Tags(testfile) if err != nil { t.Errorf("GetID3v11Tags failed: %s", err) } @@ -52,7 +52,7 @@ func TestWriteID3v11Tags(t *testing.T) { t.Errorf("WriteID3v1Tags failed: %s", err) } - readTags, err := GetID3v11Tags(f) + readTags, err := Getv11Tags(f) if err != nil { t.Errorf("%s", err) } diff --git a/v2/constants.go b/v2/constants.go index a3ae2e3..ec81cf5 100644 --- a/v2/constants.go +++ b/v2/constants.go @@ -1,6 +1,6 @@ package v2 //ID3v2 -const ID3v2IDENTIFIER string = "ID3" -const ID3v2HEADERSIZE int = 10 // bytes -const ID3v2MAXSIZE int = 268435456 // bytes (256 MB) +const HEADERIDENTIFIER string = "ID3" +const HEADERSIZE int = 10 // bytes +const HEADERMAXSIZE int = 268435456 // bytes (256 MB) diff --git a/v2/frame.go b/v2/frame.go new file mode 100644 index 0000000..ed34f7d --- /dev/null +++ b/v2/frame.go @@ -0,0 +1,59 @@ +package v2 + +import ( + "io" + + "github.com/Unbewohnte/id3ed/util" +) + +//////////////////////////////////////////////////////////////////////////// +//(ᗜˬᗜ)~⭐//Under construction//Please don`t use it in this verison//(ᗜ‸ᗜ)/// +//////////////////////////////////////////////////////////////////////////// + +type FrameHeader struct { + Identifier string + FrameSize int64 +} + +type Frame struct { + Header *FrameHeader + Contents string +} + +// NOT TESTED ! +func Readv2Frame(rs io.Reader) (*Frame, error) { + var frameHeader *FrameHeader + var frame Frame + + identifier, err := util.ReadToString(rs, 3) + if err != nil { + return nil, err + } + frameHeader.Identifier = identifier + + framesizeBytes, err := util.Read(rs, 3) + if err != nil { + return nil, err + } + + framesize, err := util.BytesToInt(framesizeBytes) + if err != nil { + return nil, err + } + + frameHeader.FrameSize = framesize + + frameContents, err := util.ReadToString(rs, int(framesize)) + if err != nil { + return nil, err + } + + frame.Header = frameHeader + frame.Contents = frameContents + + return &frame, nil +} + +// func ReadFrame(rs io.Reader, version string) error { +// return nil +// } diff --git a/v2/frame_test.go b/v2/frame_test.go new file mode 100644 index 0000000..c86280d --- /dev/null +++ b/v2/frame_test.go @@ -0,0 +1,16 @@ +package v2 + +// func TestReadFrame(t *testing.T) { +// f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) +// if err != nil { +// t.Errorf("%s", err) +// } + +// // read right after header`s bytes +// f.Seek(int64(HEADERSIZE), io.SeekStart) + +// _, err = Readv2Frame(f) +// if err != nil { +// t.Errorf("ReadFrame failed: %s", err) +// } +// } diff --git a/v2/header.go b/v2/header.go index 6b3a63d..4cfdbe3 100644 --- a/v2/header.go +++ b/v2/header.go @@ -1,9 +1,5 @@ package v2 -////////////////////////////////////// -//(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)// -////////////////////////////////////// - import ( "bytes" "fmt" @@ -33,7 +29,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { return nil, err } // check if ID3v2 is used - if !bytes.Equal([]byte(ID3v2IDENTIFIER), identifier) { + if !bytes.Equal([]byte(HEADERIDENTIFIER), identifier) { return nil, fmt.Errorf("no ID3v2 identifier found") } header.Identifier = string(identifier)