Support for TXXX, WXXX and generic W frames
I hacked readTextWithDescrFrame() and readTFrame() to generalize them
to other case (presence or not of a language and whether or not the
data part is encoded (URL are not)
This patch depend of 3b7a3d5485
since I found the
bug while developping this patch
This commit is contained in:
parent
f6a1e5325c
commit
45d987ac1d
25
id3v2.go
25
id3v2.go
@ -211,15 +211,36 @@ func readID3v2Frames(r io.Reader, h *ID3v2Header) (map[string]interface{}, error
|
||||
}
|
||||
|
||||
switch {
|
||||
case name == "TXXX" || name == "TXX":
|
||||
t, err := readTextWithDescrFrame(b, false, true) // no lang, but enc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[rawName] = t
|
||||
|
||||
case name[0] == 'T':
|
||||
txt, err := readTFrame(b)
|
||||
txt, err := readTFrame(b, true) // text is encoded
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[rawName] = txt
|
||||
|
||||
case name == "WXXX" || name == "WXX":
|
||||
t, err := readTextWithDescrFrame(b, false, false) // no lang, no enc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[rawName] = t
|
||||
|
||||
case name[0] == 'W':
|
||||
txt, err := readTFrame(b, false) // url are not encoded
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[rawName] = txt
|
||||
|
||||
case name == "COMM" || name == "USLT":
|
||||
t, err := readTextWithDescrFrame(b)
|
||||
t, err := readTextWithDescrFrame(b, true, true) // both lang and enc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -12,7 +12,11 @@ import (
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
func readTFrame(b []byte) (string, error) {
|
||||
// when the frame is not encoded, add a 0 at the start
|
||||
func readTFrame(b []byte, encoded bool) (string, error) {
|
||||
if !encoded {
|
||||
b = append([]byte{0}, b[0:]...)
|
||||
}
|
||||
txt, err := parseText(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -118,8 +122,10 @@ func decodeUTF16(b []byte, bo binary.ByteOrder) string {
|
||||
return string(utf16.Decode(s))
|
||||
}
|
||||
|
||||
// Comm is a type used in COMM and USLT tag. It's a text with a description and
|
||||
// a specified language
|
||||
// Comm is a type used in COMM, UFID, TXXX, WXXX and USLT tag.
|
||||
// It's a text with a description and a specified language
|
||||
// For WXXX, TXXX and UFID, we don't set a Language
|
||||
|
||||
type Comm struct {
|
||||
Language string
|
||||
Description string
|
||||
@ -128,38 +134,62 @@ type Comm struct {
|
||||
|
||||
// String returns a string representation of the underlying Comm instance.
|
||||
func (t Comm) String() string {
|
||||
return fmt.Sprintf("Text{Lang: '%v', Description: '%v', %v lines}",
|
||||
t.Language, t.Description, strings.Count(t.Text, "\n"))
|
||||
if t.Language != "" {
|
||||
return fmt.Sprintf("Text{Lang: '%v', Description: '%v', %v lines}",
|
||||
t.Language, t.Description, strings.Count(t.Text, "\n"))
|
||||
}
|
||||
return fmt.Sprintf("Text{Description: '%v', %v}", t.Description, t.Text)
|
||||
}
|
||||
|
||||
// IDv2.{3,4}
|
||||
// -- Header
|
||||
// <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT">
|
||||
// <Header for 'Comment', ID: "COMM">
|
||||
// -- readTextWithDescrFrame
|
||||
// -- readTextWithDescrFrame(data, true, true)
|
||||
// Text encoding $xx
|
||||
// Language $xx xx xx
|
||||
// Content descriptor <text string according to encoding> $00 (00)
|
||||
// Lyrics/text <full text string according to encoding>
|
||||
func readTextWithDescrFrame(b []byte) (*Comm, error) {
|
||||
// -- Header
|
||||
// <Header for 'User defined text information frame', ID: "TXXX">
|
||||
// <Header for 'User defined URL link frame', ID: "WXXX">
|
||||
// -- readTextWithDescrFrame(data, false, <isDataEncoded>)
|
||||
// Text encoding $xx
|
||||
// Description <text string according to encoding> $00 (00)
|
||||
// Value <text string according to encoding>
|
||||
func readTextWithDescrFrame(b []byte, hasLang bool, encoded bool) (*Comm, error) {
|
||||
var descTextSplit [][]byte
|
||||
var lang string
|
||||
var err error
|
||||
enc := b[0]
|
||||
|
||||
descTextSplit, err := dataSplit(b[4:], enc)
|
||||
if hasLang {
|
||||
lang = string(b[1:4])
|
||||
descTextSplit, err = dataSplit(b[4:], enc)
|
||||
} else {
|
||||
lang = ""
|
||||
descTextSplit, err = dataSplit(b[1:], enc)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
desc, err := decodeText(enc, descTextSplit[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding tag description text: %v", err)
|
||||
}
|
||||
|
||||
if !encoded {
|
||||
enc = byte(0)
|
||||
}
|
||||
|
||||
text, err := decodeText(enc, descTextSplit[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding tag text: %v", err)
|
||||
}
|
||||
|
||||
return &Comm{
|
||||
Language: string(b[1:4]),
|
||||
Language: lang,
|
||||
Description: desc,
|
||||
Text: text,
|
||||
}, nil
|
||||
|
Loading…
Reference in New Issue
Block a user