From 37b183c3769532454d1c08717e5107794650f69e Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Mon, 28 Jun 2021 15:27:34 +0300 Subject: [PATCH] =?UTF-8?q?=E2=9A=ABNow=20can=20read=20ID3v2=20header=20?= =?UTF-8?q?=E2=9A=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++- id3v10.go | 2 +- id3v11.go | 5 ++- id3v20.go | 76 +++++++++++++++++++++++++++++++++++---- id3v20_test.go | 34 ++++++++++++++++++ metadata.go | 15 -------- testData/testreadv2.mp3 | Bin 0 -> 1148 bytes testData/testwritev1.mp3 | Bin 800 -> 1824 bytes util.go | 12 +++++++ 9 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 id3v20_test.go delete mode 100644 metadata.go create mode 100644 testData/testreadv2.mp3 diff --git a/README.md b/README.md index 8c2566f..4b84bbd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,10 @@ --- -# Under construction ! +# ////////////////////////////////////// +# //(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)// +# ////////////////////////////////////// + --- diff --git a/id3v10.go b/id3v10.go index 9ccab5a..588ca7b 100644 --- a/id3v10.go +++ b/id3v10.go @@ -71,7 +71,7 @@ func GetID3v1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { if err != nil { return nil, err } - genreInt, err := binary.ReadVarint(bytes.NewBuffer(genreByte)) + genreInt, err := bytesToInt(genreByte) if err != nil { return nil, err } diff --git a/id3v11.go b/id3v11.go index 112b234..3d348c7 100644 --- a/id3v11.go +++ b/id3v11.go @@ -77,7 +77,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { return nil, err } - track, err := binary.ReadVarint(bytes.NewBuffer(trackByte)) + track, err := bytesToInt(trackByte) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func GetID3v11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { if err != nil { return nil, err } - genreInt, err := binary.ReadVarint(bytes.NewBuffer(genreByte)) + genreInt, err := bytesToInt(genreByte) if err != nil { return nil, err } @@ -218,5 +218,4 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error { } return nil - } diff --git a/id3v20.go b/id3v20.go index fc80b97..d598aae 100644 --- a/id3v20.go +++ b/id3v20.go @@ -8,15 +8,19 @@ import ( "bytes" "fmt" "io" + "strconv" ) +// ID3v2.x header structure type Header struct { - Identifier string - Version int - Flags int - Size int64 + Identifier string + Version string + Unsynchronisated bool + Compressed bool + Size int64 } +// Reads and structuralises ID3v2 header func GetHeader(rs io.ReadSeeker) (*Header, error) { var header Header @@ -28,11 +32,69 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { } // check if ID3v2 is used 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) + // 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 } diff --git a/id3v20_test.go b/id3v20_test.go new file mode 100644 index 0000000..8a80781 --- /dev/null +++ b/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) + } +} diff --git a/metadata.go b/metadata.go deleted file mode 100644 index f9840f5..0000000 --- a/metadata.go +++ /dev/null @@ -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 -} diff --git a/testData/testreadv2.mp3 b/testData/testreadv2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..daa33c789050ef71c9ba716f9128b288b5589209 GIT binary patch literal 1148 zcmeZtF=k-^0*<1PAZKqNg9(TYLtKKKfix=+8yOgwg?NS-0hw$-T#{LmlNu7>Y6xVr z194(eNoH|Lh@+1aR6$}+QfaQUzppQl&jZ8}5fKc@`MJ5Nc_ksv{(dl3d6~JXK=vpY M4S~@R7@;8m093yhQ~&?~ literal 0 HcmV?d00001 diff --git a/testData/testwritev1.mp3 b/testData/testwritev1.mp3 index 9a44f1f33e10acf9976d4c6e4f189f692456bc96..7058049e18e07d0e5572acebdd457e83ad263dd8 100644 GIT binary patch delta 15 UcmZ3$wt#Pg0`p=8MkWvj03>b$v;Y7A delta 7 OcmZ3$w}5Sf0y6*#Mgk}R diff --git a/util.go b/util.go index 5117bcb..bb1bf06 100644 --- a/util.go +++ b/util.go @@ -2,6 +2,7 @@ package id3ed import ( "bytes" + "encoding/binary" "fmt" "io" ) @@ -76,3 +77,14 @@ func getKey(mp map[int]string, givenValue string) int { } 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 +}