Browse Source

⬦ More structuralized project structure ⬦

main
Unbewohnte 3 years ago
parent
commit
6c876ff543
  1. 20
      README.md
  2. BIN
      testData/testwritev1.mp3
  3. 12
      util/util.go
  4. 5
      v1/constants.go
  5. 2
      v1/genres.go
  6. 34
      v1/id3v10.go
  7. 11
      v1/id3v10_test.go
  8. 43
      v1/id3v11.go
  9. 9
      v1/id3v11_test.go
  10. 7
      v2/constants.go
  11. 20
      v2/header.go
  12. 7
      v2/header_test.go

20
README.md

@ -30,7 +30,7 @@ package main
import(
"fmt"
"github.com/Unbewohnte/id3ed"
id3v1 "github.com/Unbewohnte/id3ed/v1"
)
func main() {
@ -40,7 +40,7 @@ func main() {
}
// extract ID3v1.1 tags
mp3tags, err := id3ed.GetID3v11Tags(mp3file)
mp3tags, err := id3v1.GetID3v11Tags(mp3file)
if err != nil {
panic(err)
}
@ -62,7 +62,7 @@ package main
import(
"fmt"
"github.com/Unbewohnte/id3ed"
"github.com/Unbewohnte/id3ed/v1"
)
func main() {
@ -73,7 +73,7 @@ func main() {
defer f.Close()
// create your tags struct
tags := &id3ed.ID3v11Tags{
tags := &id3v1.ID3v11Tags{
SongName: "mysong",
Artist: "me",
Album: "my album",
@ -95,15 +95,23 @@ func main() {
# ∙ Testing
To test everything
```
go test
go test ./...
```
or
```
go test -v
go test -v ./...
```
to get a verbose output
OR
```
go test ./package_name_here
```
to test a specific package
---
# ∙ License

BIN
testData/testwritev1.mp3

Binary file not shown.

12
util.go → util/util.go

@ -1,4 +1,4 @@
package id3ed
package util
import (
"bytes"
@ -8,7 +8,7 @@ import (
)
// 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) {
func Read(rs io.Reader, n int) ([]byte, error) {
read := make([]byte, n)
_, err := rs.Read(read)
if err != nil {
@ -20,7 +20,7 @@ func read(rs io.Reader, n int) ([]byte, error) {
// 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) {
func ReadToString(rs io.Reader, n int) (string, error) {
read := make([]byte, n)
_, err := rs.Read(read)
if err != nil {
@ -39,7 +39,7 @@ func readToString(rs io.Reader, n int) (string, error) {
}
// 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 {
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")
}
@ -69,7 +69,7 @@ func writeToExtent(wr io.Writer, data []byte, lenNeeded int) error {
// 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 {
func GetKey(mp map[int]string, givenValue string) int {
for key, value := range mp {
if value == givenValue {
return key
@ -79,7 +79,7 @@ func getKey(mp map[int]string, givenValue string) int {
}
// Decodes given integer bytes into integer
func bytesToInt(gBytes []byte) (int64, error) {
func BytesToInt(gBytes []byte) (int64, error) {
buff := bytes.NewBuffer(gBytes)
integer, err := binary.ReadVarint(buff)
if err != nil {

5
v1/constants.go

@ -0,0 +1,5 @@
package v1
const ID3v1IDENTIFIER string = "TAG"
const ID3v1SIZE int = 128 // bytes
const ID3v1INVALIDGENRE int = 255

2
id3v1genres.go → v1/genres.go

@ -1,4 +1,4 @@
package id3ed
package v1
// https://en.wikipedia.org/wiki/List_of_ID3v1_Genres

34
id3v10.go → v1/id3v10.go

@ -1,4 +1,4 @@
package id3ed
package v1
import (
"bytes"
@ -7,6 +7,8 @@ import (
"io"
"os"
"strconv"
"github.com/Unbewohnte/id3ed/util"
)
// https://id3.org/ID3v1 - documentation
@ -28,7 +30,7 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) {
return nil, fmt.Errorf("could not seek: %s", err)
}
tag, err := read(rs, 3)
tag, err := util.Read(rs, 3)
if err != nil {
return nil, err
}
@ -38,22 +40,22 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) {
return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag)
}
songname, err := readToString(rs, 30)
songname, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
artist, err := readToString(rs, 30)
artist, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
album, err := readToString(rs, 30)
album, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
yearStr, err := readToString(rs, 4)
yearStr, err := util.ReadToString(rs, 4)
if err != nil {
return nil, err
}
@ -62,16 +64,16 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) {
return nil, fmt.Errorf("could not convert yearbytes into int: %s", err)
}
comment, err := readToString(rs, 30)
comment, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
genreByte, err := read(rs, 1)
genreByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
genreInt, err := bytesToInt(genreByte)
genreInt, err := util.BytesToInt(genreByte)
if err != nil {
return nil, err
}
@ -103,37 +105,37 @@ func (tags *ID3v1Tags) Write(dst io.WriteSeeker) error {
}
// Song name
err = writeToExtent(dst, []byte(tags.SongName), 30)
err = util.WriteToExtent(dst, []byte(tags.SongName), 30)
if err != nil {
return err
}
// Artist
err = writeToExtent(dst, []byte(tags.Artist), 30)
err = util.WriteToExtent(dst, []byte(tags.Artist), 30)
if err != nil {
return err
}
// Album
err = writeToExtent(dst, []byte(tags.Album), 30)
err = util.WriteToExtent(dst, []byte(tags.Album), 30)
if err != nil {
return err
}
// Year
err = writeToExtent(dst, []byte(fmt.Sprint(tags.Year)), 4)
err = util.WriteToExtent(dst, []byte(fmt.Sprint(tags.Year)), 4)
if err != nil {
return err
}
// Comment
err = writeToExtent(dst, []byte(tags.Comment), 30)
err = util.WriteToExtent(dst, []byte(tags.Comment), 30)
if err != nil {
return err
}
// Genre
genreCode := getKey(id3v1genres, tags.Genre)
genreCode := util.GetKey(id3v1genres, tags.Genre)
if genreCode == -1 {
// if no genre found - encode genre code as 255
genreCode = ID3v1INVALIDGENRE
@ -156,7 +158,7 @@ func (tags *ID3v1Tags) WriteToFile(f *os.File) error {
// check for existing ID3v1 tag
f.Seek(-int64(ID3v1SIZE), io.SeekEnd)
tag, err := read(f, 3)
tag, err := util.Read(f, 3)
if err != nil {
return err
}

11
id3v10_test.go → v1/id3v10_test.go

@ -1,10 +1,13 @@
package id3ed
package v1
import (
"os"
"path/filepath"
"testing"
)
var TESTDATAPATH string = filepath.Join("..", "testData")
var TESTv1TAGS = &ID3v1Tags{
SongName: "testsong",
Artist: "testartist",
@ -15,7 +18,7 @@ var TESTv1TAGS = &ID3v1Tags{
}
func TestGetID3v1Tags(t *testing.T) {
testfile, err := os.OpenFile("./testData/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 {
t.Errorf("could not open file for testing: %s", err)
}
@ -30,7 +33,7 @@ func TestGetID3v1Tags(t *testing.T) {
}
func TestWriteID3v1Tags(t *testing.T) {
f, err := os.OpenFile("./testData/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 {
t.Errorf("%s", err)
}
@ -60,7 +63,7 @@ func TestWriteID3v1Tags(t *testing.T) {
}
func TestWriteID3v1ToFile(t *testing.T) {
f, err := os.OpenFile("./testData/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 {
t.Errorf("%s", err)
}

43
id3v11.go → v1/id3v11.go

@ -1,4 +1,4 @@
package id3ed
package v1
import (
"bytes"
@ -7,6 +7,8 @@ import (
"io"
"os"
"strconv"
"github.com/Unbewohnte/id3ed/util"
)
type ID3v11Tags struct {
@ -27,7 +29,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
return nil, fmt.Errorf("could not seek: %s", err)
}
tag, err := read(rs, 3)
tag, err := util.Read(rs, 3)
if err != nil {
return nil, err
}
@ -37,22 +39,22 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag)
}
songname, err := readToString(rs, 30)
songname, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
artist, err := readToString(rs, 30)
artist, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
album, err := readToString(rs, 30)
album, err := util.ReadToString(rs, 30)
if err != nil {
return nil, err
}
yearStr, err := readToString(rs, 4)
yearStr, err := util.ReadToString(rs, 4)
if err != nil {
return nil, err
}
@ -61,32 +63,32 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
return nil, fmt.Errorf("could not convert yearbytes into int: %s", err)
}
comment, err := readToString(rs, 28)
comment, err := util.ReadToString(rs, 28)
if err != nil {
return nil, err
}
// skip 1 null byte
_, err = read(rs, 1)
_, err = util.Read(rs, 1)
if err != nil {
return nil, err
}
trackByte, err := read(rs, 1)
trackByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
track, err := bytesToInt(trackByte)
track, err := util.BytesToInt(trackByte)
if err != nil {
return nil, err
}
genreByte, err := read(rs, 1)
genreByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
genreInt, err := bytesToInt(genreByte)
genreInt, err := util.BytesToInt(genreByte)
if err != nil {
return nil, err
}
@ -119,31 +121,31 @@ func (tags *ID3v11Tags) Write(dst io.WriteSeeker) error {
}
// Song name
err = writeToExtent(dst, []byte(tags.SongName), 30)
err = util.WriteToExtent(dst, []byte(tags.SongName), 30)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
// Artist
err = writeToExtent(dst, []byte(tags.Artist), 30)
err = util.WriteToExtent(dst, []byte(tags.Artist), 30)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
// Album
err = writeToExtent(dst, []byte(tags.Album), 30)
err = util.WriteToExtent(dst, []byte(tags.Album), 30)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
// Year
err = writeToExtent(dst, []byte(fmt.Sprint(tags.Year)), 4)
err = util.WriteToExtent(dst, []byte(fmt.Sprint(tags.Year)), 4)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
// Comment
err = writeToExtent(dst, []byte(tags.Comment), 28)
err = util.WriteToExtent(dst, []byte(tags.Comment), 28)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
@ -156,14 +158,13 @@ func (tags *ID3v11Tags) Write(dst io.WriteSeeker) error {
// Track
trackBytes := make([]byte, 1)
binary.PutVarint(trackBytes, int64(tags.Track))
// binary.BigEndian.PutUint16(trackBytes, uint16(tags.Track))
_, err = dst.Write(trackBytes)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
//Genre
genreCode := getKey(id3v1genres, tags.Genre)
genreCode := util.GetKey(id3v1genres, tags.Genre)
if genreCode == -1 {
// if no genre found - encode genre code as 255
genreCode = ID3v1INVALIDGENRE
@ -171,7 +172,7 @@ func (tags *ID3v11Tags) Write(dst io.WriteSeeker) error {
genrebyte := make([]byte, 1)
binary.PutVarint(genrebyte, int64(genreCode))
err = writeToExtent(dst, genrebyte, 1)
err = util.WriteToExtent(dst, genrebyte, 1)
if err != nil {
return fmt.Errorf("could not write to dst: %s", err)
}
@ -186,7 +187,7 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error {
// check for existing ID3v1.1 tag
f.Seek(-int64(ID3v1SIZE), io.SeekEnd)
tag, err := read(f, 3)
tag, err := util.Read(f, 3)
if err != nil {
return err
}

9
id3v11_test.go → v1/id3v11_test.go

@ -1,8 +1,9 @@
package id3ed
package v1
import (
"fmt"
"os"
"path/filepath"
"testing"
)
@ -17,7 +18,7 @@ var TESTV11TAGS = &ID3v11Tags{
}
func TestGetID3v11Tags(t *testing.T) {
testfile, err := os.Open("./testData/testreadv1.mp3")
testfile, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv1.mp3"))
if err != nil {
t.Errorf("could not open file for testing: %s", err)
}
@ -38,7 +39,7 @@ func TestGetID3v11Tags(t *testing.T) {
// WILL ADD NEW "TAG" WITHOUT REMOVING THE OLD ONE !!!
func TestWriteID3v11Tags(t *testing.T) {
f, err := os.OpenFile("./testData/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 {
t.Errorf("%s", err)
}
@ -70,7 +71,7 @@ func TestWriteID3v11Tags(t *testing.T) {
}
func TestWriteID3v11ToFile(t *testing.T) {
f, err := os.OpenFile("./testData/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 {
t.Errorf("%s", err)
}

7
constants.go → v2/constants.go

@ -1,9 +1,4 @@
package id3ed
// ID3v1
const ID3v1IDENTIFIER string = "TAG"
const ID3v1SIZE int = 128 // bytes
const ID3v1INVALIDGENRE int = 255
package v2
//ID3v2
const ID3v2IDENTIFIER string = "ID3"

20
id3v20.go → v2/header.go

@ -1,4 +1,4 @@
package id3ed
package v2
//////////////////////////////////////
//(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)//
@ -9,6 +9,8 @@ import (
"fmt"
"io"
"strconv"
"github.com/Unbewohnte/id3ed/util"
)
// ID3v2.x header structure
@ -17,7 +19,7 @@ type Header struct {
Version string
Unsynchronisated bool
Compressed bool
Size int64
Size int64 // size of the whole tag - 10 header bytes
}
// Reads and structuralises ID3v2 header
@ -26,7 +28,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) {
rs.Seek(0, io.SeekStart)
identifier, err := read(rs, 3)
identifier, err := util.Read(rs, 3)
if err != nil {
return nil, err
}
@ -37,27 +39,27 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) {
header.Identifier = string(identifier)
// version
majorVersionByte, err := read(rs, 1)
majorVersionByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
revisionNumberByte, err := read(rs, 1)
revisionNumberByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
majorVersion, err := bytesToInt(majorVersionByte)
majorVersion, err := util.BytesToInt(majorVersionByte)
if err != nil {
return nil, err
}
revisionNumber, err := bytesToInt(revisionNumberByte)
revisionNumber, err := util.BytesToInt(revisionNumberByte)
if err != nil {
return nil, err
}
header.Version = fmt.Sprintf("%d%d", -majorVersion, revisionNumber)
// flags
flags, err := read(rs, 1)
flags, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
@ -74,7 +76,7 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) {
}
// size
sizeBytes, err := read(rs, 4)
sizeBytes, err := util.Read(rs, 4)
if err != nil {
return nil, err
}

7
id3v20_test.go → v2/header_test.go

@ -1,12 +1,15 @@
package id3ed
package v2
import (
"os"
"path/filepath"
"testing"
)
var TESTDATAPATH string = filepath.Join("..", "testData")
func TestGetHeader(t *testing.T) {
f, err := os.Open("./testData/testreadv2.mp3")
f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3"))
if err != nil {
t.Errorf("%s", err)
}
Loading…
Cancel
Save