Browse Source

Fixed a bug in writing enhanced tag, added creating functions to v2

main
Unbewohnte 3 years ago
parent
commit
96fc9cb111
  1. BIN
      testData/testwritev1.mp3
  2. 15
      v1/read.go
  3. 1
      v1/read_test.go
  4. 8
      v1/tag.go
  5. 13
      v1/write.go
  6. 1
      v1/write_test.go
  7. 90
      v2/frame.go
  8. 43
      v2/frame_test.go
  9. 29
      v2/header.go
  10. 4
      v2/read.go
  11. 16
      v2/v2tag.go
  12. 34
      v2/v2tag_test.go
  13. 12
      v2/write.go

BIN
testData/testwritev1.mp3

Binary file not shown.

15
v1/read.go

@ -41,6 +41,7 @@ func containsEnhancedTAG(rs io.ReadSeeker) bool {
return false
}
if !bytes.Equal(identifier, []byte(ENHANCEDIDENTIFIER)) {
fmt.Printf("UWAH: %s ---- %s\n", identifier, ENHANCEDIDENTIFIER)
return false
}
@ -88,19 +89,7 @@ func readEnhancedTag(rs io.ReadSeeker) (EnhancedID3v1Tag, error) {
return enhanced, err
}
var speed string
switch speedByte[0] {
case 0:
speed = "Unset"
case 1:
speed = "Slow"
case 2:
speed = "Medium"
case 3:
speed = "Fast"
case 4:
speed = "Hardcore"
}
var speed string = EnhancedSpeed[int(speedByte[0])]
enhanced.Speed = speed
// genre

1
v1/read_test.go

@ -18,6 +18,7 @@ var TESTv1TAG = &ID3v1Tag{
Artist: "ARRRTIST",
Album: "ALLLLBUUUM",
SongName: "NAME",
Speed: EnhancedSpeed[2],
},
}

8
v1/tag.go

@ -26,3 +26,11 @@ type EnhancedID3v1Tag struct {
StartTime string
EndTime string
}
var EnhancedSpeed = map[int]string{
0: "Unset",
1: "Slow",
2: "Medium",
3: "Fast",
4: "Hardcore",
}

13
v1/write.go

@ -45,7 +45,8 @@ func (tag *ID3v1Tag) write(dst io.WriteSeeker) error {
}
// Speed
_, err = dst.Write([]byte(tag.EnhancedTag.Speed))
speed := util.GetKey(EnhancedSpeed, tag.EnhancedTag.Speed)
_, err = dst.Write([]byte{byte(speed)})
if err != nil {
return err
}
@ -162,8 +163,10 @@ func (tag *ID3v1Tag) WriteToFile(f *os.File) error {
switch {
case containsEnhancedTAG(f) && containsTAG(f):
fmt.Println("HEA1")
// remove both
err = f.Truncate(filesize - int64(TAGSIZE) - int64(ENHANCEDSIZE))
err = f.Truncate(filesize - int64(TAGSIZE+ENHANCEDSIZE))
if err != nil {
return fmt.Errorf("could not truncate file %s", err)
}
@ -174,6 +177,8 @@ func (tag *ID3v1Tag) WriteToFile(f *os.File) error {
}
case containsEnhancedTAG(f) && !containsTAG(f):
fmt.Println("HEA2")
// remove enhanced tag, replace with new
err = f.Truncate(filesize - int64(ENHANCEDSIZE))
if err != nil {
@ -186,6 +191,8 @@ func (tag *ID3v1Tag) WriteToFile(f *os.File) error {
}
case !containsEnhancedTAG(f) && containsTAG(f):
fmt.Println("HEA3")
// remove regular one, replace with new
err = f.Truncate(filesize - int64(TAGSIZE))
if err != nil {
@ -198,6 +205,8 @@ func (tag *ID3v1Tag) WriteToFile(f *os.File) error {
}
case !containsEnhancedTAG(f) && !containsTAG(f):
fmt.Println("HEA4")
// no existing TAGs, simply write what we have
err := tag.write(f)
if err != nil {

1
v1/write_test.go

@ -20,5 +20,4 @@ func TestWriteID3v1ToFile(t *testing.T) {
if err != nil {
t.Errorf("WriteID3v1ToFile failed: %s", err)
}
}

90
v2/frame.go

@ -2,6 +2,7 @@ package v2
import (
"bytes"
"fmt"
"io"
"unicode"
@ -20,9 +21,9 @@ type FrameFlags struct {
}
type FrameHeader struct {
ID string
Size uint32
Flags FrameFlags
id string
size uint32
flags FrameFlags
}
type Frame struct {
@ -30,6 +31,20 @@ type Frame struct {
Contents []byte
}
// getters
func (fh *FrameHeader) ID() string {
return fh.id
}
func (fh *FrameHeader) Size() uint32 {
return fh.size
}
func (fh *FrameHeader) Flags() FrameFlags {
return fh.flags
}
// Checks if given identifier is valid by specification
func isValidID(frameID string) bool {
// check if id is in ASCII table
@ -50,10 +65,10 @@ func isValidID(frameID string) bool {
func getV22FrameHeader(fHeaderbytes []byte) FrameHeader {
var header FrameHeader
header.ID = string(fHeaderbytes[0:3])
header.id = string(fHeaderbytes[0:3])
framesizeBytes := util.BytesToIntSynchsafe(fHeaderbytes[3:6])
header.Size = framesizeBytes
header.size = framesizeBytes
return header
}
@ -62,14 +77,14 @@ func getV23FrameHeader(fHeaderbytes []byte) FrameHeader {
var header FrameHeader
// ID
header.ID = string(fHeaderbytes[0:4])
header.id = string(fHeaderbytes[0:4])
// Size
framesizeBytes := fHeaderbytes[4:8]
framesize := util.BytesToIntSynchsafe(framesizeBytes)
header.Size = framesize
header.size = framesize
// Flags
frameFlags1 := fHeaderbytes[8]
@ -108,7 +123,7 @@ func getV23FrameHeader(fHeaderbytes []byte) FrameHeader {
flags.InGroup = false
}
header.Flags = flags
header.flags = flags
return header
}
@ -116,14 +131,14 @@ func getV23FrameHeader(fHeaderbytes []byte) FrameHeader {
func getV24FrameHeader(fHeaderbytes []byte) FrameHeader {
var header FrameHeader
header.ID = string(fHeaderbytes[0:4])
header.id = string(fHeaderbytes[0:4])
// Size
framesizeBytes := fHeaderbytes[4:8]
framesize := util.BytesToIntSynchsafe(framesizeBytes)
header.Size = framesize
header.size = framesize
// Flags
frameFlags1 := fHeaderbytes[8]
@ -172,7 +187,7 @@ func getV24FrameHeader(fHeaderbytes []byte) FrameHeader {
flags.HasDataLengthIndicator = false
}
header.Flags = flags
header.flags = flags
return header
}
@ -229,7 +244,7 @@ func readNextFrame(r io.Reader, version string) (Frame, error) {
frame.Header = frameHeader
// Contents
contents, err := util.Read(r, uint64(frameHeader.Size))
contents, err := util.Read(r, uint64(frameHeader.size))
if err != nil {
return Frame{}, err
}
@ -309,17 +324,25 @@ func frameFlagsToBytes(ff FrameFlags, version string) []byte {
}
// Converts frame to ready-to-write bytes
func (f *Frame) toBytes(version string) []byte {
func (f *Frame) toBytes() []byte {
buff := new(bytes.Buffer)
// identifier
buff.Write([]byte(f.Header.ID))
buff.Write([]byte(f.Header.id))
// size
buff.Write(util.IntToBytesSynchsafe(f.Header.Size))
buff.Write(util.IntToBytesSynchsafe(f.Header.size))
// flags
flagBytes := frameFlagsToBytes(f.Header.Flags, version)
var version string
if len(f.Header.id) == 4 {
version = V2_4
} else {
version = V2_2
}
flagBytes := frameFlagsToBytes(f.Header.flags, version)
if flagBytes != nil {
buff.Write(flagBytes)
}
@ -329,3 +352,38 @@ func (f *Frame) toBytes(version string) []byte {
return buff.Bytes()
}
// Constructs a new frame from provided information.
// isTextFrame must be set to true if gContents are not a binary data.
// Returns an error if provided id`s len is neither 3 or 4
func NewFrame(id string, gContents []byte, isTextframe bool) (*Frame, error) {
if len(id) != 3 && len(id) != 4 {
return nil, fmt.Errorf("frame identifier`s length must be 3 or 4")
}
var fheader FrameHeader
// contents
var contents []byte
if isTextframe {
// add UTF-8 encoding byte
contents = []byte{util.EncodingUTF8}
contents = append(contents, gContents...)
} else {
contents = gContents
}
// id
fheader.id = id
// size
fheader.size = uint32(len(contents))
// flags (all false)
fheader.flags = FrameFlags{}
return &Frame{
Header: fheader,
Contents: contents,
}, nil
}

43
v2/frame_test.go

@ -24,14 +24,14 @@ func TestReadNextFrame(t *testing.T) {
t.Errorf("ReadFrame failed: %s", err)
}
if firstFrame.Header.ID != "TRCK" {
if firstFrame.Header.ID() != "TRCK" {
t.Errorf("GetFrame failed: expected ID %s; got %s",
"TRCK", firstFrame.Header.ID)
"TRCK", firstFrame.Header.ID())
}
if firstFrame.Header.Flags.Encrypted != false {
if firstFrame.Header.Flags().Encrypted != false {
t.Errorf("ReadFrame failed: expected compressed flag to be %v; got %v",
false, firstFrame.Header.Flags.Encrypted)
false, firstFrame.Header.Flags().Encrypted)
}
secondFrame, err := readNextFrame(f, header.Version())
@ -39,9 +39,9 @@ func TestReadNextFrame(t *testing.T) {
t.Errorf("ReadFrame failed: %s", err)
}
if secondFrame.Header.ID != "TDRC" {
if secondFrame.Header.ID() != "TDRC" {
t.Errorf("ReadFrame failed: expected ID %s; got %s",
"TDRC", secondFrame.Header.ID)
"TDRC", secondFrame.Header.ID())
}
if util.ToStringLossy(secondFrame.Contents) != "2006" {
@ -72,14 +72,14 @@ func TestFrameFlagsToBytes(t *testing.T) {
func TestFrameToBytes(t *testing.T) {
testframe := Frame{
Header: FrameHeader{
ID: "TEST",
Flags: FrameFlags{}, // all false
Size: 4,
id: "TEST",
flags: FrameFlags{}, // all false
size: 4,
},
Contents: []byte{util.EncodingUTF8, 60, 60, 60}, // 60 == <
}
frameBytes := testframe.toBytes(V2_4)
frameBytes := testframe.toBytes()
// t.Errorf("%+v", frameBytes)
// 84 69 83 84 0 0 0 4 0 0 3 60 60 60
@ -90,9 +90,9 @@ func TestFrameToBytes(t *testing.T) {
// header - 4 + 4 + 2 = 10 bytes (success)
// 3 60 60 60 - contents
if len(frameBytes)-int(testframe.Header.Size) != HEADERSIZE {
if len(frameBytes)-int(testframe.Header.Size()) != HEADERSIZE {
t.Errorf("FrameToBytes failed: expected header size to be %d; got %d",
HEADERSIZE, len(frameBytes)-int(testframe.Header.Size))
HEADERSIZE, len(frameBytes)-int(testframe.Header.Size()))
}
if util.DecodeText(frameBytes[10:]) != "<<<" {
@ -100,3 +100,22 @@ func TestFrameToBytes(t *testing.T) {
testframe.Contents, frameBytes[10:])
}
}
func TestNewFrame(t *testing.T) {
gotFrame, err := NewFrame("TMRK", []byte("Very cool"), true)
if err != nil {
t.Errorf("CreateFrame failed: %s", err)
}
// check for encoding byte
if gotFrame.Contents[0] != util.EncodingUTF8 {
t.Errorf("CreateFrame failed: contents are expected to have an encoding byte %v; got %v",
util.EncodingUTF8, gotFrame.Contents[0])
}
if gotFrame.Header.Size() != uint32(len(gotFrame.Contents)) {
t.Errorf("CreateFrame failed: expected size to be %d; got %d",
len(gotFrame.Contents), gotFrame.Header.Size())
}
}

29
v2/header.go

@ -452,3 +452,32 @@ func (h *Header) toBytes() []byte {
return buff.Bytes()
}
// Creates an appropriate header based on
// provided frames
func newHeader(frames []Frame) *Header {
var header Header
// flags (all false)
header.flags = HeaderFlags{}
// version
if len(frames[0].Header.ID()) == 4 {
header.version = V2_4
} else {
header.version = V2_2
}
// size
var framesSize uint32 = 0
for _, frame := range frames {
framesSize += uint32(len(frame.toBytes()))
}
header.size = framesSize
// extended header (not used)
header.extendedHeader = ExtendedHeader{}
return &header
}

4
v2/read.go

@ -50,9 +50,9 @@ func ReadV2Tag(rs io.ReadSeeker) (*ID3v2Tag, error) {
// counting how many bytes read
if header.Version() == V2_2 {
read += uint64(V2_2FrameHeaderSize) + uint64(frame.Header.Size)
read += uint64(V2_2FrameHeaderSize) + uint64(frame.Header.Size())
} else {
read += uint64(V2_3FrameHeaderSize) + uint64(frame.Header.Size)
read += uint64(V2_3FrameHeaderSize) + uint64(frame.Header.Size())
}
}

16
v2/v2tag.go

@ -7,11 +7,23 @@ type ID3v2Tag struct {
Frames []Frame
}
// Creates a new v2 tag from given created frames
func NewTAG(frames []Frame) *ID3v2Tag {
var newtag ID3v2Tag
header := newHeader(frames)
newtag.Header = *header
newtag.Frames = frames
return &newtag
}
// Searches for frame with the same identifier as id in tag,
// returns &it if found
func (tag *ID3v2Tag) GetFrame(id string) *Frame {
for _, frame := range tag.Frames {
if strings.EqualFold(frame.Header.ID, id) {
if strings.EqualFold(frame.Header.ID(), id) {
return &frame
}
}
@ -21,7 +33,7 @@ func (tag *ID3v2Tag) GetFrame(id string) *Frame {
// Checks if a frame with given id exists
func (tag *ID3v2Tag) FrameExists(id string) bool {
for _, frame := range tag.Frames {
if strings.EqualFold(frame.Header.ID, id) {
if strings.EqualFold(frame.Header.ID(), id) {
return true
}
}

34
v2/v2tag_test.go

@ -0,0 +1,34 @@
package v2
import "testing"
func TestNewTAG(t *testing.T) {
frame1, err := NewFrame("TTST", []byte("TEST text FRAME (ᗜˬᗜ)"), true)
if err != nil {
t.Errorf("%s", err)
}
frame2, err := NewFrame("BNRY", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 255}, false)
if err != nil {
t.Errorf("%s", err)
}
newtag := NewTAG([]Frame{*frame1, *frame2})
if newtag.Header.Version() != V2_4 {
t.Errorf("NewTAG failed: expected version to be %s; got %s",
V2_4, newtag.Header.Version())
}
var size uint32 = 0
for _, frame := range newtag.Frames {
size += uint32(len(frame.toBytes()))
}
if newtag.Header.Size() != size {
t.Errorf("NewTAG failed: expected size to be %d; got %d",
size, newtag.Header.Size())
}
// t.Errorf("%+v", newtag)
}

12
v2/write.go

@ -1,6 +1,6 @@
package v2
// Writes ID3v2Tag to ws
// // Writes ID3v2Tag to ws
// func (tag *ID3v2Tag) write(ws io.WriteSeeker) error {
// _, err := ws.Seek(0, io.SeekStart)
// if err != nil {
@ -8,11 +8,17 @@ package v2
// }
// // write header
// ws.Write(tag.Header.toBytes())
// _, err = ws.Write(tag.Header.toBytes())
// if err != nil {
// return fmt.Errorf("could not write to writer: %s", err)
// }
// // write frames
// for _, frame := range tag.Frames {
// ws.Write(frame.toBytes(tag.Header.Version()))
// _, err = ws.Write(frame.toBytes())
// if err != nil {
// return fmt.Errorf("could not write to writer: %s", err)
// }
// }
// return nil

Loading…
Cancel
Save