Browse Source

⯄ Started working on ID3v2 frames ⯄

main
Unbewohnte 3 years ago
parent
commit
9fae050359
  1. 4
      README.md
  2. BIN
      testData/testwritev1.mp3
  3. 28
      util/etc.go
  4. 37
      util/read.go
  5. 90
      util/util.go
  6. 36
      util/write.go
  7. 2
      v1/id3v10.go
  8. 8
      v1/id3v10_test.go
  9. 2
      v1/id3v11.go
  10. 4
      v1/id3v11_test.go
  11. 6
      v2/constants.go
  12. 59
      v2/frame.go
  13. 16
      v2/frame_test.go
  14. 6
      v2/header.go

4
README.md

@ -40,7 +40,7 @@ func main() {
} }
// extract ID3v1.1 tags // extract ID3v1.1 tags
mp3tags, err := id3v1.GetID3v11Tags(mp3file) mp3tags, err := id3v1.Getv11Tags(mp3file)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -80,7 +80,7 @@ func main() {
Year: 2021, Year: 2021,
Comment: "Cool song", Comment: "Cool song",
Track: 1, 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 // write tags to file

BIN
testData/testwritev1.mp3

Binary file not shown.

28
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
}

37
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
}

90
util/util.go

@ -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
}

36
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
}

2
v1/id3v10.go

@ -23,7 +23,7 @@ type ID3v1Tags struct {
} }
// Retrieves ID3v1 field values of provided io.ReadSeeker (usually a file) // 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 // set reader to the last 128 bytes
_, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd)
if err != nil { if err != nil {

8
v1/id3v10_test.go

@ -17,12 +17,12 @@ var TESTv1TAGS = &ID3v1Tags{
Genre: "Blues", 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) testfile, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_CREATE|os.O_RDONLY, os.ModePerm)
if err != nil { if err != nil {
t.Errorf("could not open file for testing: %s", err) t.Errorf("could not open file for testing: %s", err)
} }
tags, err := GetID3v1Tags(testfile) tags, err := Getv1Tags(testfile)
if err != nil { if err != nil {
t.Errorf("GetID3v1Tags failed: %s", err) 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) f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testwritev1.mp3"), os.O_CREATE|os.O_RDWR, os.ModePerm)
if err != nil { if err != nil {
t.Errorf("%s", err) t.Errorf("%s", err)
@ -48,7 +48,7 @@ func TestWriteID3v1Tags(t *testing.T) {
} }
// reading tags // reading tags
readTags, err := GetID3v1Tags(f) readTags, err := Getv1Tags(f)
if err != nil { if err != nil {
t.Errorf("%s", err) t.Errorf("%s", err)
} }

2
v1/id3v11.go

@ -22,7 +22,7 @@ type ID3v11Tags struct {
} }
// Retrieves ID3v1.1 field values of provided io.ReadSeeker // 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 // set reader to the last 128 bytes
_, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd) _, err := rs.Seek(-int64(ID3v1SIZE), io.SeekEnd)
if err != nil { if err != nil {

4
v1/id3v11_test.go

@ -22,7 +22,7 @@ func TestGetID3v11Tags(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("could not open file for testing: %s", err) t.Errorf("could not open file for testing: %s", err)
} }
mp3tags, err := GetID3v11Tags(testfile) mp3tags, err := Getv11Tags(testfile)
if err != nil { if err != nil {
t.Errorf("GetID3v11Tags failed: %s", err) t.Errorf("GetID3v11Tags failed: %s", err)
} }
@ -52,7 +52,7 @@ func TestWriteID3v11Tags(t *testing.T) {
t.Errorf("WriteID3v1Tags failed: %s", err) t.Errorf("WriteID3v1Tags failed: %s", err)
} }
readTags, err := GetID3v11Tags(f) readTags, err := Getv11Tags(f)
if err != nil { if err != nil {
t.Errorf("%s", err) t.Errorf("%s", err)
} }

6
v2/constants.go

@ -1,6 +1,6 @@
package v2 package v2
//ID3v2 //ID3v2
const ID3v2IDENTIFIER string = "ID3" const HEADERIDENTIFIER string = "ID3"
const ID3v2HEADERSIZE int = 10 // bytes const HEADERSIZE int = 10 // bytes
const ID3v2MAXSIZE int = 268435456 // bytes (256 MB) const HEADERMAXSIZE int = 268435456 // bytes (256 MB)

59
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
// }

16
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)
// }
// }

6
v2/header.go

@ -1,9 +1,5 @@
package v2 package v2
//////////////////////////////////////
//(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)//
//////////////////////////////////////
import ( import (
"bytes" "bytes"
"fmt" "fmt"
@ -33,7 +29,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) {
return nil, err return nil, err
} }
// check if ID3v2 is used // 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") return nil, fmt.Errorf("no ID3v2 identifier found")
} }
header.Identifier = string(identifier) header.Identifier = string(identifier)

Loading…
Cancel
Save