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

BIN
testData/testwritev1.mp3

Binary file not shown.

12
util.go → util/util.go

@ -1,4 +1,4 @@
package id3ed package util
import ( import (
"bytes" "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 // 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) read := make([]byte, n)
_, err := rs.Read(read) _, err := rs.Read(read)
if err != nil { 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. // Shortcut function to read n bytes and convert them into string.
// If encountered zero-byte - converts to string only previously read bytes // 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) read := make([]byte, n)
_, err := rs.Read(read) _, err := rs.Read(read)
if err != nil { 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 // 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 { if len(data) > lenNeeded {
return fmt.Errorf("length of given data bytes is bigger than length needed") 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); // Returns found key (int) in provided map by value (string);
// If key does not exist in map - returns -1 // 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 { for key, value := range mp {
if value == givenValue { if value == givenValue {
return key return key
@ -79,7 +79,7 @@ func getKey(mp map[int]string, givenValue string) int {
} }
// Decodes given integer bytes into integer // Decodes given integer bytes into integer
func bytesToInt(gBytes []byte) (int64, error) { func BytesToInt(gBytes []byte) (int64, error) {
buff := bytes.NewBuffer(gBytes) buff := bytes.NewBuffer(gBytes)
integer, err := binary.ReadVarint(buff) integer, err := binary.ReadVarint(buff)
if err != nil { 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 // https://en.wikipedia.org/wiki/List_of_ID3v1_Genres

34
id3v10.go → v1/id3v10.go

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

11
id3v10_test.go → v1/id3v10_test.go

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

43
id3v11.go → v1/id3v11.go

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

9
id3v11_test.go → v1/id3v11_test.go

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

7
constants.go → v2/constants.go

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

20
id3v20.go → v2/header.go

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

7
id3v20_test.go → v2/header_test.go

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