diff --git a/README.md b/README.md index 5559dd7..dd4c018 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,20 @@ # ID3ED (ID3 - Encoder - Decoder) ## Library for encoding/decoding ID3 tags +--- + +# Under construction ! + +--- + # Installation ``` go get github.com/Unbewohnte/id3ed ``` +--- + # Usage ## Decoding ID3v1.1 @@ -33,10 +41,8 @@ func main() { // print all tags fmt.Printf("%+v",mp3tags) - // get a certain tag from "getter" function - songname := mp3tags.GetSongName() - - // get a certain tag from struct field + songname := mp3tags.SongName + genre := mp3tags.Genre // etc. @@ -52,7 +58,7 @@ func main() { defer f.Close() // create your tags struct - tags := ID3v11Tags{ + tags := &ID3v11Tags{ SongName: "mysong", Artist: "me", Album: "my album", @@ -62,13 +68,15 @@ func main() { Genre: "Christian Gangsta Rap", // list of genres see "id3v1genres.go" } - // write given tags in file - err = WriteID3v11Tags(f, tags) + // write given tags to file + err = WriteID3v11ToFile(f, tags) if err != nil { panic(err) } ``` +--- + # Testing ``` @@ -80,5 +88,4 @@ go test -v ``` to get a verbose output -# Under construction ! -## Bugs are a possibility rn in this state, the package is still not tested properly \ No newline at end of file +--- \ No newline at end of file diff --git a/id3v10.go b/id3v10.go index a007109..c3ee87a 100644 --- a/id3v10.go +++ b/id3v10.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "io" + "os" "strconv" ) @@ -91,8 +92,8 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { }, nil } -// Writes given ID3v1.0 tags to dst -func WriteID3v1Tags(dst io.WriteSeeker, tags ID3v1Tags) error { +// Writes given ID3v1.0 tags to given io.ReadWriteSeeker. +func WriteID3v1Tags(dst io.WriteSeeker, tags *ID3v1Tags) error { dst.Seek(0, io.SeekEnd) // TAG @@ -147,3 +148,45 @@ func WriteID3v1Tags(dst io.WriteSeeker, tags ID3v1Tags) error { return nil } + +// Checks for existing ID3v1 tag in file, if present - removes it and replaces with provided tags +func WriteID3v1ToFile(f *os.File, tags *ID3v1Tags) error { + defer f.Close() + + // check for existing ID3v1 tag + f.Seek(-int64(ID3V1SIZE), io.SeekEnd) + + tag, err := read(f, 3) + if err != nil { + return err + } + + if !bytes.Equal(tag, []byte("TAG")) { + // no existing tag, just write given tags + err = WriteID3v1Tags(f, tags) + if err != nil { + return err + } + return nil + } + + // does contain ID3v1 tag. Removing it + fStats, err := f.Stat() + if err != nil { + return err + } + + err = f.Truncate(fStats.Size() - int64(ID3V1SIZE)) + if err != nil { + return nil + } + + // writing new tags + err = WriteID3v1Tags(f, tags) + if err != nil { + return err + } + + return nil + +} diff --git a/id3v10_test.go b/id3v10_test.go index ea8ebe6..f0276aa 100644 --- a/id3v10_test.go +++ b/id3v10_test.go @@ -5,8 +5,17 @@ import ( "testing" ) +var TESTv1TAGS = &ID3v1Tags{ + SongName: "testsong", + Artist: "testartist", + Album: "testalbum", + Year: 727, + Comment: "testcomment", + Genre: "Blues", +} + func TestGetID3v1Tags(t *testing.T) { - testfile, err := os.Open("./testData/testread.mp3") + testfile, err := os.Open("./testData/testreadv1.mp3") if err != nil { t.Errorf("could not open file for testing: %s", err) } @@ -21,22 +30,15 @@ func TestGetID3v1Tags(t *testing.T) { } func TestWriteID3v1Tags(t *testing.T) { - os.Remove("./testData/testwrite.mp3") + os.Remove("./testData/testwritev1.mp3") - f, err := os.Create("./testData/testwrite.mp3") + f, err := os.Create("./testData/testwritev1.mp3") if err != nil { t.Errorf("%s", err) } defer f.Close() - tags := ID3v1Tags{ - SongName: "testsong", - Artist: "testartist", - Album: "testalbum", - Year: 727, - Comment: "testcomment", - Genre: "Blues", - } + tags := TESTv1TAGS err = WriteID3v1Tags(f, tags) if err != nil { @@ -56,3 +58,18 @@ func TestWriteID3v1Tags(t *testing.T) { t.Errorf("WriteID3v1Tags failed: expected %d; got %d", 727, readTags.Year) } } + +func TestWriteID3v1ToFile(t *testing.T) { + f, err := os.Open("./testData/testwritev1.mp3") + if err != nil { + t.Errorf("%s", err) + } + + tags := TESTv1TAGS + + err = WriteID3v1ToFile(f, tags) + if err != nil { + t.Errorf("WriteID3v1ToFile failed: %s", err) + } + +} diff --git a/id3v11.go b/id3v11.go index bc59d3c..a9a2ee0 100644 --- a/id3v11.go +++ b/id3v11.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "io" + "os" "strconv" ) @@ -18,7 +19,7 @@ type ID3v11Tags struct { Genre string } -// Retrieves ID3v1.1 field values of provided io.ReadSeeker (usually a file) +// Retrieves ID3v1.1 field values of provided io.ReadSeeker func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { // set reader to the last 128 bytes _, err := rs.Seek(-int64(ID3V1SIZE), io.SeekEnd) @@ -106,7 +107,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { } // Writes given ID3v1.1 tags to dst -func WriteID3v11Tags(dst io.WriteSeeker, tags ID3v11Tags) error { +func WriteID3v11Tags(dst io.WriteSeeker, tags *ID3v11Tags) error { dst.Seek(0, io.SeekEnd) // TAG @@ -175,3 +176,45 @@ func WriteID3v11Tags(dst io.WriteSeeker, tags ID3v11Tags) error { return nil } + +// Checks for existing ID3v1.1 tag in file, if present - removes it and replaces with provided tags +func WriteID3v11ToFile(f *os.File, tags *ID3v11Tags) error { + defer f.Close() + + // check for existing ID3v1.1 tag + f.Seek(-int64(ID3V1SIZE), io.SeekEnd) + + tag, err := read(f, 3) + if err != nil { + return err + } + + if !bytes.Equal(tag, []byte("TAG")) { + // no existing tag, just write given tags + err = WriteID3v11Tags(f, tags) + if err != nil { + return err + } + return nil + } + + // does contain ID3v1.1 tag. Removing it + fStats, err := f.Stat() + if err != nil { + return err + } + + err = f.Truncate(fStats.Size() - int64(ID3V1SIZE)) + if err != nil { + return nil + } + + // writing new tags + err = WriteID3v11Tags(f, tags) + if err != nil { + return err + } + + return nil + +} diff --git a/id3v11_test.go b/id3v11_test.go index 23ba797..5bc9d52 100644 --- a/id3v11_test.go +++ b/id3v11_test.go @@ -6,8 +6,18 @@ import ( "testing" ) +var TESTV11TAGS = &ID3v11Tags{ + SongName: "testsong", + Artist: "testartist", + Album: "testalbum", + Year: 727, + Comment: "testcomment", + Track: 5, + Genre: "Blues", +} + func TestGetID3v11Tags(t *testing.T) { - testfile, err := os.Open("./testData/testread.mp3") + testfile, err := os.Open("./testData/testreadv1.mp3") if err != nil { t.Errorf("could not open file for testing: %s", err) } @@ -27,23 +37,15 @@ func TestGetID3v11Tags(t *testing.T) { } func TestWriteID3v11Tags(t *testing.T) { - os.Remove("./testData/testwrite.mp3") + os.Remove("./testData/testwritev1.mp3") - f, err := os.Create("./testData/testwrite.mp3") + f, err := os.Create("./testData/testwritev1.mp3") if err != nil { t.Errorf("%s", err) } defer f.Close() - tags := ID3v11Tags{ - SongName: "testsong", - Artist: "testartist", - Album: "testalbum", - Year: 727, - Comment: "testcomment", - Track: 5, - Genre: "Blues", - } + tags := TESTV11TAGS err = WriteID3v11Tags(f, tags) if err != nil { @@ -67,3 +69,17 @@ func TestWriteID3v11Tags(t *testing.T) { t.Errorf("WriteID3v11Tags failed: expected %d; got %d", 5, readTags.Track) } } + +func TestWriteID3v11ToFile(t *testing.T) { + f, err := os.Open("./testData/testwritev1.mp3") + if err != nil { + t.Errorf("%s", err) + } + + tags := TESTV11TAGS + + err = WriteID3v11ToFile(f, tags) + if err != nil { + t.Errorf("WriteID3v1ToFile failed: %s", err) + } +} diff --git a/testData/testread.mp3 b/testData/testreadv1.mp3 similarity index 100% rename from testData/testread.mp3 rename to testData/testreadv1.mp3 diff --git a/testData/testwrite.mp3 b/testData/testwritev1.mp3 similarity index 100% rename from testData/testwrite.mp3 rename to testData/testwritev1.mp3