Browse Source

Now can read ID3v2 header

main
Unbewohnte 3 years ago
parent
commit
37b183c376
  1. 5
      README.md
  2. 2
      id3v10.go
  3. 5
      id3v11.go
  4. 72
      id3v20.go
  5. 34
      id3v20_test.go
  6. 15
      metadata.go
  7. BIN
      testData/testreadv2.mp3
  8. BIN
      testData/testwritev1.mp3
  9. 12
      util.go

5
README.md

@ -3,7 +3,10 @@
--- ---
# Under construction ! # //////////////////////////////////////
# //(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)//
# //////////////////////////////////////
--- ---

2
id3v10.go

@ -71,7 +71,7 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
genreInt, err := binary.ReadVarint(bytes.NewBuffer(genreByte)) genreInt, err := bytesToInt(genreByte)
if err != nil { if err != nil {
return nil, err return nil, err
} }

5
id3v11.go

@ -77,7 +77,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
return nil, err return nil, err
} }
track, err := binary.ReadVarint(bytes.NewBuffer(trackByte)) track, err := bytesToInt(trackByte)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,7 +86,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
genreInt, err := binary.ReadVarint(bytes.NewBuffer(genreByte)) genreInt, err := bytesToInt(genreByte)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -218,5 +218,4 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error {
} }
return nil return nil
} }

72
id3v20.go

@ -8,15 +8,19 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"strconv"
) )
// ID3v2.x header structure
type Header struct { type Header struct {
Identifier string Identifier string
Version int Version string
Flags int Unsynchronisated bool
Compressed bool
Size int64 Size int64
} }
// Reads and structuralises ID3v2 header
func GetHeader(rs io.ReadSeeker) (*Header, error) { func GetHeader(rs io.ReadSeeker) (*Header, error) {
var header Header var header Header
@ -28,11 +32,69 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) {
} }
// check if ID3v2 is used // check if ID3v2 is used
if !bytes.Equal([]byte(ID3v2IDENTIFIER), identifier) { if !bytes.Equal([]byte(ID3v2IDENTIFIER), identifier) {
return nil, fmt.Errorf("does not use ID3v2") return nil, fmt.Errorf("no ID3v2 identifier found")
} }
////
header.Identifier = string(identifier) header.Identifier = string(identifier)
// version
majorVersionByte, err := read(rs, 1)
if err != nil {
return nil, err
}
revisionNumberByte, err := read(rs, 1)
if err != nil {
return nil, err
}
majorVersion, err := bytesToInt(majorVersionByte)
if err != nil {
return nil, err
}
revisionNumber, err := bytesToInt(revisionNumberByte)
if err != nil {
return nil, err
}
header.Version = fmt.Sprintf("%d%d", -majorVersion, revisionNumber)
// flags
flags, err := read(rs, 1)
if err != nil {
return nil, err
}
bits := fmt.Sprintf("%08b", flags) // 1 byte is 8 bits
if bits[0] == 1 {
header.Unsynchronisated = true
} else {
header.Unsynchronisated = false
}
if bits[1] == 1 {
header.Compressed = true
} else {
header.Compressed = false
}
// size
sizeBytes, err := read(rs, 4)
if err != nil {
return nil, err
}
// represent each byte in size as binary and get rid from the first useless bit,
// then concatenate filtered parts
var filteredSizeStr string
for _, b := range sizeBytes {
// the first bit is always 0, so filter it out
filteredPart := fmt.Sprintf("%08b", b)[1:] // byte is 8 bits
filteredSizeStr += filteredPart
}
// converting filtered binary size into usable int64
size, err := strconv.ParseInt(filteredSizeStr, 2, 64)
if err != nil {
return nil, err
}
header.Size = int64(size)
return &header, nil return &header, nil
} }

34
id3v20_test.go

@ -0,0 +1,34 @@
package id3ed
import (
"os"
"testing"
)
func TestGetHeader(t *testing.T) {
f, err := os.Open("./testData/testreadv2.mp3")
if err != nil {
t.Errorf("%s", err)
}
header, err := GetHeader(f)
if err != nil {
t.Errorf("GetHeader failed: %s", err)
}
if header.Identifier != "ID3" {
t.Errorf("GetHeader failed: expected identifier %s; got %s", "ID3", header.Identifier)
}
if header.Compressed != false {
t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Compressed)
}
if header.Unsynchronisated != false {
t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Unsynchronisated)
}
if header.Size != 1138 {
t.Errorf("GetHeader failed: expected size %v; got %v", 1138, header.Size)
}
}

15
metadata.go

@ -1,15 +0,0 @@
package id3ed
import (
"io"
"os"
)
// I`m still a bit confused about interfaces,
// I`ll look into them and try to figure out
// how to use them properly
type Metadata interface {
Read(io.ReadSeeker) error
Write(io.WriteSeeker) error
WriteToFile(*os.File) error
}

BIN
testData/testreadv2.mp3

Binary file not shown.

BIN
testData/testwritev1.mp3

Binary file not shown.

12
util.go

@ -2,6 +2,7 @@ package id3ed
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
) )
@ -76,3 +77,14 @@ func getKey(mp map[int]string, givenValue string) int {
} }
return -1 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
}

Loading…
Cancel
Save