Browse Source

Error-handling and an attempt to wrap read/write functions

main
Unbewohnte 3 years ago
parent
commit
c91bc93ba3
  1. 59
      id3ed.go
  2. 48
      id3ed_test.go
  3. 0
      testData/testWriteTags.mp3
  4. BIN
      testData/testwritev1.mp3
  5. 3
      util/etc.go
  6. 9
      util/write.go
  7. 26
      v1/id3v10.go
  8. 23
      v1/id3v11.go

59
id3ed.go

@ -0,0 +1,59 @@
package id3ed
import (
"fmt"
"io"
"os"
v1 "github.com/Unbewohnte/id3ed/v1"
)
type Tagger interface {
WriteToFile(*os.File) error
Version() int
}
// Reads certain ID3 tags from io.ReadSeeker according to given version.
// Wrapper function to v1|v2 package functions
func ReadTags(rs io.ReadSeeker, version int) (Tagger, error) {
switch version {
case 10:
// ID3v1
t, err := v1.Getv1Tags(rs)
if err != nil {
return nil, err
}
return t, nil
case 11:
// ID3v1.1
t, err := v1.Getv11Tags(rs)
if err != nil {
return nil, err
}
return t, nil
case 23:
// ID3v2.3
return nil, fmt.Errorf("v2.3 is not supported")
case 24:
// ID3v2.4
return nil, fmt.Errorf("v2.4 is not supported")
}
return nil, fmt.Errorf("invalid version or not supported")
}
// DOESN`T work for some reason !? err is coming from f.Seek(), but it`s completely fine
// when run directly from v1.WriteToFile() function.
// Writes tags to file.
func WriteTags(dstf *os.File, t Tagger) error {
err := t.WriteToFile(dstf)
if err != nil {
return err
}
return nil
}

48
id3ed_test.go

@ -0,0 +1,48 @@
package id3ed
import (
"os"
"path/filepath"
"testing"
)
var TESTDATAPATH string = filepath.Join("testData")
func TestReadTags(t *testing.T) {
f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_RDONLY, os.ModePerm)
if err != nil {
t.Errorf("%s", err)
}
_, err = ReadTags(f, 11)
if err != nil {
t.Errorf("ReadTags failed: %s", err)
}
_, err = ReadTags(f, 10)
if err != nil {
t.Errorf("ReadTags failed: %s", err)
}
}
// func TestWriteTags(t *testing.T) {
// f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_RDONLY, os.ModePerm)
// if err != nil {
// t.Errorf("%s", err)
// }
// tagger, err := ReadTags(f, 11)
// if err != nil {
// t.Errorf("%s", err)
// }
// f2, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testWriteTags.mp3"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
// if err != nil {
// t.Errorf("%s", err)
// }
// err = WriteTags(f2, tagger)
// if err != nil {
// t.Errorf("WriteTags failed: %s", err)
// }
// }

0
testData/testWriteTags.mp3

BIN
testData/testwritev1.mp3

Binary file not shown.

3
util/etc.go

@ -3,6 +3,7 @@ package util
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt"
) )
// Returns found key (int) in provided map by value (string); // Returns found key (int) in provided map by value (string);
@ -21,7 +22,7 @@ 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 {
return 0, err return 0, fmt.Errorf("could not decode integer: %s", err)
} }
buff = nil buff = nil
return integer, nil return integer, nil

9
util/write.go

@ -15,21 +15,24 @@ func WriteToExtent(wr io.Writer, data []byte, lenNeeded int) error {
buff := new(bytes.Buffer) buff := new(bytes.Buffer)
for i := 0; i < lenNeeded; i++ { for i := 0; i < lenNeeded; i++ {
if i < len(data) { if i < len(data) {
// write given data
err := buff.WriteByte(data[i]) err := buff.WriteByte(data[i])
if err != nil { if err != nil {
return err return fmt.Errorf("could not write byte: %s", err)
} }
} else { } else {
// write null bytes
err := buff.WriteByte(0) err := buff.WriteByte(0)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write byte: %s", err)
} }
} }
} }
// write constructed buffer`s bytes
_, err := wr.Write(buff.Bytes()) _, err := wr.Write(buff.Bytes())
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
return nil return nil

26
v1/id3v10.go

@ -75,7 +75,7 @@ func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) {
} }
genreInt, err := util.BytesToInt(genreByte) genreInt, err := util.BytesToInt(genreByte)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot convert bytes to int: %s", err)
} }
genre, exists := id3v1genres[int(genreInt)] genre, exists := id3v1genres[int(genreInt)]
if !exists { if !exists {
@ -101,37 +101,37 @@ func (tags *ID3v1Tags) Write(dst io.WriteSeeker) error {
// TAG // TAG
_, err := dst.Write([]byte(ID3v1IDENTIFIER)) _, err := dst.Write([]byte(ID3v1IDENTIFIER))
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
// Song name // Song name
err = util.WriteToExtent(dst, []byte(tags.SongName), 30) err = util.WriteToExtent(dst, []byte(tags.SongName), 30)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
// Artist // Artist
err = util.WriteToExtent(dst, []byte(tags.Artist), 30) err = util.WriteToExtent(dst, []byte(tags.Artist), 30)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
// Album // Album
err = util.WriteToExtent(dst, []byte(tags.Album), 30) err = util.WriteToExtent(dst, []byte(tags.Album), 30)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
// Year // Year
err = util.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 fmt.Errorf("could not write to writer: %s", err)
} }
// Comment // Comment
err = util.WriteToExtent(dst, []byte(tags.Comment), 30) err = util.WriteToExtent(dst, []byte(tags.Comment), 30)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
// Genre // Genre
@ -145,7 +145,7 @@ func (tags *ID3v1Tags) Write(dst io.WriteSeeker) error {
_, err = dst.Write(genrebyte) _, err = dst.Write(genrebyte)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
return nil return nil
@ -175,20 +175,24 @@ func (tags *ID3v1Tags) WriteToFile(f *os.File) error {
// does contain ID3v1 tag. Removing it // does contain ID3v1 tag. Removing it
fStats, err := f.Stat() fStats, err := f.Stat()
if err != nil { if err != nil {
return err return fmt.Errorf("cannot get file stats: %s", err)
} }
err = f.Truncate(fStats.Size() - int64(ID3v1SIZE)) err = f.Truncate(fStats.Size() - int64(ID3v1SIZE))
if err != nil { if err != nil {
return nil return fmt.Errorf("could not truncate file %s", err)
} }
// writing new tags // writing new tags
err = tags.Write(f) err = tags.Write(f)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
return nil return nil
} }
func (tags *ID3v1Tags) Version() int {
return 10
}

23
v1/id3v11.go

@ -81,7 +81,7 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
track, err := util.BytesToInt(trackByte) track, err := util.BytesToInt(trackByte)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot convert bytes to int: %s", err)
} }
genreByte, err := util.Read(rs, 1) genreByte, err := util.Read(rs, 1)
@ -90,7 +90,7 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) {
} }
genreInt, err := util.BytesToInt(genreByte) genreInt, err := util.BytesToInt(genreByte)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot convert bytes to int: %s", err)
} }
genre, exists := id3v1genres[int(genreInt)] genre, exists := id3v1genres[int(genreInt)]
if !exists { if !exists {
@ -185,18 +185,23 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error {
defer f.Close() defer f.Close()
// check for existing ID3v1.1 tag // check for existing ID3v1.1 tag
f.Seek(-int64(ID3v1SIZE), io.SeekEnd) _, err := f.Seek(-int64(ID3v1SIZE), io.SeekEnd)
if err != nil {
return fmt.Errorf("could not seek: %s", err)
}
tag, err := util.Read(f, 3) tag, err := util.Read(f, 3)
if err != nil { if err != nil {
// return err
return err return err
} }
if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) {
// no existing tag, just write given tags // no existing tag, just write given tags
err = tags.Write(f) err = tags.Write(f)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
return nil return nil
} }
@ -204,19 +209,23 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error {
// does contain ID3v1.1 tag. Removing it // does contain ID3v1.1 tag. Removing it
fStats, err := f.Stat() fStats, err := f.Stat()
if err != nil { if err != nil {
return err return fmt.Errorf("cannot get file stats: %s", err)
} }
err = f.Truncate(fStats.Size() - int64(ID3v1SIZE)) err = f.Truncate(fStats.Size() - int64(ID3v1SIZE))
if err != nil { if err != nil {
return nil return fmt.Errorf("could not truncate file %s", err)
} }
// writing new tags // writing new tags
err = tags.Write(f) err = tags.Write(f)
if err != nil { if err != nil {
return err return fmt.Errorf("could not write to writer: %s", err)
} }
return nil return nil
} }
func (tags *ID3v11Tags) Version() int {
return 11
}

Loading…
Cancel
Save