-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate to go-flac v2 (go-flac/go-flac#5)
Signed-off-by: eternal-flame-AD <[email protected]>
- Loading branch information
1 parent
a593e72
commit e2254dd
Showing
7 changed files
with
316 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package flacvorbis | ||
|
||
const ( | ||
APP_VERSION = "0.1.0" | ||
) | ||
|
||
const ( | ||
// FIELD_TITLE Track/Work name | ||
FIELD_TITLE = "TITLE" | ||
// FIELD_VERSION The version field may be used to differentiate multiple versions of the same track title in a single collection. (e.g. remix info) | ||
FIELD_VERSION = "VERSION" | ||
// FIELD_ALBUM The collection name to which this track belongs | ||
FIELD_ALBUM = "ALBUM" | ||
// FIELD_TRACKNUMBER The track number of this piece if part of a specific larger collection or album | ||
FIELD_TRACKNUMBER = "TRACKNUMBER" | ||
// FIELD_ARTIST The artist generally considered responsible for the work. In popular music this is usually the performing band or singer. For classical music it would be the composer. For an audio book it would be the author of the original text. | ||
FIELD_ARTIST = "ARTIST" | ||
// FIELD_PERFORMER The artist(s) who performed the work. In classical music this would be the conductor, orchestra, soloists. In an audio book it would be the actor who did the reading. In popular music this is typically the same as the ARTIST and is omitted. | ||
FIELD_PERFORMER = "PERFORMER" | ||
// FIELD_COPYRIGHT Copyright attribution, e.g., '2001 Nobody's Band' or '1999 Jack Moffitt' | ||
FIELD_COPYRIGHT = "COPYRIGHT" | ||
// FIELD_LICENSE License information, eg, 'All Rights Reserved', 'Any Use Permitted', a URL to a license such as a Creative Commons license ("www.creativecommons.org/blahblah/license.html") or the EFF Open Audio License ('distributed under the terms of the Open Audio License. see http://www.eff.org/IP/Open_licenses/eff_oal.html for details'), etc. | ||
FIELD_LICENSE = "LICENSE" | ||
// FIELD_ORGANIZATION Name of the organization producing the track (i.e. the 'record label') | ||
FIELD_ORGANIZATION = "ORGANIZATION" | ||
// FIELD_DESCRIPTION A short text description of the contents | ||
FIELD_DESCRIPTION = "DESCRIPTION" | ||
// FIELD_GENRE A short text indication of music genre | ||
FIELD_GENRE = "GENRE" | ||
// FIELD_DATE Date the track was recorded | ||
FIELD_DATE = "DATE" | ||
// FIELD_LOCATION Location where track was recorded | ||
FIELD_LOCATION = "LOCATION" | ||
// FIELD_CONTACT Contact information for the creators or distributors of the track. This could be a URL, an email address, the physical address of the producing label. | ||
FIELD_CONTACT = "CONTACT" | ||
// FIELD_ISRC ISRC number for the track; see the ISRC intro page for more information on ISRC numbers. | ||
FIELD_ISRC = "ISRC" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package flacvorbis | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrorNotVorbisComment = errors.New("Not a vorbis comment metadata block") | ||
ErrorUnexpEof = errors.New("Unexpected end of stream") | ||
ErrorMalformedComment = errors.New("Malformed comment") | ||
ErrorInvalidFieldName = errors.New("Malformed Field Name") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/go-flac/flacvorbis | ||
|
||
go 1.20 | ||
|
||
require github.com/go-flac/go-flac/v2 v2.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/go-flac/go-flac/v2 v2.0.1 h1:1zilNkbmmpK9DLsz2NbjLHG8avOmthYqUfVc9YKB/Ps= | ||
github.com/go-flac/go-flac/v2 v2.0.1/go.mod h1:hvgeR2hElLbwk0Q1/vMazIDmIc2LAFSd9Bx/Fk6ViKo= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package flacvorbis | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"io" | ||
) | ||
|
||
func encodeUint32(n uint32) []byte { | ||
buf := bytes.NewBuffer([]byte{}) | ||
if err := binary.Write(buf, binary.LittleEndian, n); err != nil { | ||
panic(err) | ||
} | ||
return buf.Bytes() | ||
} | ||
|
||
func readUint32(r io.Reader) (res uint32, err error) { | ||
err = binary.Read(r, binary.LittleEndian, &res) | ||
return | ||
} | ||
|
||
func packStr(w io.Writer, s string) { | ||
data := []byte(s) | ||
w.Write(encodeUint32(uint32(len(data)))) | ||
w.Write(data) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package flacvorbis | ||
|
||
import ( | ||
"bytes" | ||
"strings" | ||
|
||
flac "github.com/go-flac/go-flac/v2" | ||
) | ||
|
||
type MetaDataBlockVorbisComment struct { | ||
Vendor string | ||
Comments []string | ||
} | ||
|
||
// New creates a new MetaDataBlockVorbisComment | ||
// vendor is set to flacvorbis <version> by default | ||
func New() *MetaDataBlockVorbisComment { | ||
return &MetaDataBlockVorbisComment{ | ||
"flacvorbis " + APP_VERSION, | ||
[]string{}, | ||
} | ||
} | ||
|
||
// Get get all comments with field name specified by the key parameter | ||
// If there is no match, error would still be nil | ||
func (c *MetaDataBlockVorbisComment) Get(key string) ([]string, error) { | ||
res := make([]string, 0) | ||
for _, cmt := range c.Comments { | ||
p := strings.SplitN(cmt, "=", 2) | ||
if len(p) != 2 { | ||
return nil, ErrorMalformedComment | ||
} | ||
if strings.EqualFold(p[0], key) { | ||
res = append(res, p[1]) | ||
} | ||
} | ||
return res, nil | ||
} | ||
|
||
// Add adds a key-val pair to the comments | ||
func (c *MetaDataBlockVorbisComment) Add(key string, val string) error { | ||
for _, char := range key { | ||
if char < 0x20 || char > 0x7d || char == '=' { | ||
return ErrorInvalidFieldName | ||
} | ||
} | ||
c.Comments = append(c.Comments, key+"="+val) | ||
return nil | ||
} | ||
|
||
// Marshal marshals this block back into a flac.MetaDataBlock | ||
func (c MetaDataBlockVorbisComment) Marshal() flac.MetaDataBlock { | ||
data := bytes.NewBuffer([]byte{}) | ||
packStr(data, c.Vendor) | ||
data.Write(encodeUint32(uint32(len(c.Comments)))) | ||
for _, cmt := range c.Comments { | ||
packStr(data, cmt) | ||
} | ||
return flac.MetaDataBlock{ | ||
Type: flac.VorbisComment, | ||
Data: data.Bytes(), | ||
} | ||
} | ||
|
||
// ParseFromMetaDataBlock parses an existing picture MetaDataBlock | ||
func ParseFromMetaDataBlock(meta flac.MetaDataBlock) (*MetaDataBlockVorbisComment, error) { | ||
if meta.Type != flac.VorbisComment { | ||
return nil, ErrorNotVorbisComment | ||
} | ||
|
||
reader := bytes.NewReader(meta.Data) | ||
res := new(MetaDataBlockVorbisComment) | ||
|
||
vendorlen, err := readUint32(reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
vendorbytes := make([]byte, vendorlen) | ||
nn, err := reader.Read(vendorbytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if nn != int(vendorlen) { | ||
return nil, ErrorUnexpEof | ||
} | ||
res.Vendor = string(vendorbytes) | ||
|
||
cmtcount, err := readUint32(reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
res.Comments = make([]string, cmtcount) | ||
for i := range res.Comments { | ||
cmtlen, err := readUint32(reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cmtbytes := make([]byte, cmtlen) | ||
nn, err := reader.Read(cmtbytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if nn != int(cmtlen) { | ||
return nil, ErrorUnexpEof | ||
} | ||
res.Comments[i] = string(cmtbytes) | ||
} | ||
return res, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package flacvorbis | ||
|
||
import ( | ||
"archive/zip" | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"strings" | ||
"testing" | ||
|
||
flac "github.com/go-flac/go-flac/v2" | ||
) | ||
|
||
func httpGetBytes(url string) ([]byte, error) { | ||
res, err := http.Get(url) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if res.StatusCode != 200 { | ||
return nil, fmt.Errorf("HTTP status %d", res.StatusCode) | ||
} | ||
return ioutil.ReadAll(res.Body) | ||
} | ||
|
||
func TestNewVorbisComment(t *testing.T) { | ||
cmt := New() | ||
if !strings.HasPrefix(cmt.Vendor, "flacvorbis") { | ||
t.Errorf("Unexpected vendor: %s\n", cmt.Vendor) | ||
t.Fail() | ||
} | ||
if len(cmt.Comments) != 0 { | ||
t.Error("Unexpected comments: ", cmt.Comments) | ||
t.Fail() | ||
} | ||
} | ||
func TestVorbisFromExistingFlac(t *testing.T) { | ||
zipdata, err := httpGetBytes("http://helpguide.sony.net/high-res/sample1/v1/data/Sample_BeeMoved_96kHz24bit.flac.zip") | ||
if err != nil { | ||
t.Errorf("Error while downloading test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
zipfile, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata))) | ||
if err != nil { | ||
t.Errorf("Error while decompressing test file: %s", err.Error()) | ||
t.FailNow() | ||
} | ||
if zipfile.File[0].Name != "Sample_BeeMoved_96kHz24bit.flac" { | ||
t.Errorf("Unexpected test file content: %s", zipfile.File[0].Name) | ||
t.FailNow() | ||
} | ||
|
||
flachandle, err := zipfile.File[0].Open() | ||
if err != nil { | ||
t.Errorf("Failed to decompress test file: %s", err) | ||
t.FailNow() | ||
} | ||
|
||
f, err := flac.ParseBytes(flachandle) | ||
if err != nil { | ||
t.Errorf("Failed to parse flac file: %s", err) | ||
t.FailNow() | ||
} | ||
|
||
var cmt *MetaDataBlockVorbisComment | ||
for _, meta := range f.Meta { | ||
if meta.Type == flac.VorbisComment { | ||
cmt, err = ParseFromMetaDataBlock(*meta) | ||
if err != nil { | ||
t.Errorf("Error while parsing metadata image: %s\n", err.Error()) | ||
t.Fail() | ||
} | ||
} | ||
} | ||
|
||
if err := cmt.Add(FIELD_GENRE, "Bee Pop"); err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} | ||
|
||
check := func(cmt *MetaDataBlockVorbisComment) { | ||
if cmt.Vendor != "reference libFLAC 1.2.1 win64 20080709" { | ||
t.Errorf("Unexpected vendor string: %s\n", cmt.Vendor) | ||
t.Fail() | ||
} | ||
if res, err := cmt.Get(FIELD_ALBUM); err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} else if len(res) != 1 || res[0] != "Bee Moved" { | ||
t.Error("Unexpected album name: ", res) | ||
t.Fail() | ||
} | ||
|
||
if res, err := cmt.Get(FIELD_ARTIST); err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} else if len(res) != 1 || res[0] != "Blue Monday FM" { | ||
t.Error("Unexpected artist name: ", res) | ||
t.Fail() | ||
} | ||
|
||
if res, err := cmt.Get(FIELD_TITLE); err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} else if len(res) != 1 || res[0] != "Bee Moved" { | ||
t.Error("Unexpected title name: ", res) | ||
t.Fail() | ||
} | ||
|
||
if res, err := cmt.Get(FIELD_GENRE); err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} else if len(res) != 1 || res[0] != "Bee Pop" { | ||
t.Error("Unexpected title name: ", res) | ||
t.Fail() | ||
} | ||
} | ||
check(cmt) | ||
new, err := ParseFromMetaDataBlock(cmt.Marshal()) | ||
if err != nil { | ||
t.Error(err) | ||
t.Fail() | ||
} | ||
check(new) | ||
|
||
} |