diff --git a/id3v2.go b/id3v2.go index a2af714..37ed734 100644 --- a/id3v2.go +++ b/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 } diff --git a/id3v2frames.go b/id3v2frames.go index 6d55967..979bb29 100644 --- a/id3v2frames.go +++ b/id3v2frames.go @@ -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 //
//
-// -- readTextWithDescrFrame +// -- readTextWithDescrFrame(data, true, true) // Text encoding $xx // Language $xx xx xx // Content descriptor $00 (00) // Lyrics/text -func readTextWithDescrFrame(b []byte) (*Comm, error) { +// -- Header +//
+//
+// -- readTextWithDescrFrame(data, false, ) +// Text encoding $xx +// Description $00 (00) +// Value +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