4

我想使用id3-go从文件中读取 Popularmeter 框架。

这是使用mutagen-inspect打印时框架的外观:

$ mutagen-inspect samples/with_popm.mp3 | grep POPM
POPM=traktor@native-instruments.de=0 255/255

我想从文件中读取值(255/255)。由于我找不到任何文档,我的幼稚方法是:

popFrame := mp3File.Frame("POPM")
log.Println(popFrame.String())

但是当我运行它时(在一个带有和不带有popularmeter标签的文件上),我得到了分段错误:

$ ./id3-go-popm-example samples/with_popm.mp3 
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x4ac302]

goroutine 1 [running]:
main.main()
    /home/ifischer/src/rivamp/rivamp-dist/id3-go-popm-example/main.go:21 +0xd2
$ ./id3-go-popm-example samples/without_popm.mp3 
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x4ac302]

goroutine 1 [running]:
main.main()
    /home/ifischer/src/rivamp/rivamp-dist/id3-go-popm-example/main.go:21 +0xd2

我在此处设置了一个示例存储库,其中包含两个示例文件(一个带有,一个没有流行计框架):https ://github.com/ifischer/id3-go-popm-example

如何使用 id3-go 库获取 Popularmeter 值 (255/255)?

4

1 回答 1

4

您会遇到分段错误,因为mp3File.Frame("POPM")实际上是在返回一个nil值。我把它缩小到V23FrameTypeMap缺少id3-go框架的TRDC地方。我真的不熟悉 ID3 的内部结构,但也许您需要检查是否TRDC真的在 V2.3 中,如果是,请将缺少的 id 添加V23FrameTypeMapid3-go.

由于学习 ID3 太麻烦了,我已经设法使用另一个库https://github.com/dhowden/tagPOPM获取标签

f, _ := os.Open("with_popm.mp3")
m, _ := tag.ReadFrom(f)
fmt.Printf("%s\n", m.Raw()["POPM"])

输出:

traktor@native-instruments.de

编辑:我误TDRC认为TRDC,我的错误。POPM无论如何,这是您使用该字段所需要做的事情id3-go

V23FrameTypeMap在中添加以下内容github.com/mikkyang/id3-go/v2/idv23.go

V23FrameTypeMap = map[string]FrameType{
    //...
    "TDRC": FrameType{id: "TDRC", description: "Recording Date", constructor: ParseTextFrame},
}

然后您可以轻松获得该POPM字段,例如

package main

import (
    "fmt"
    id3 "github.com/mikkyang/id3-go"
)

func main() {

    f, _ := id3.Open("with_popm.mp3")
    p := f.Frame("POPM")
    fmt.Printf("%s\n", p.Bytes())

}

编辑 2:我添加了一种方法,以便您可以解析该POPM字段。然后,您可以从以下位置访问评级 255/255 Popularimeter.Rating

import (
    "bytes"
    "encoding/binary"
    "errors"
    "fmt"

    id3 "github.com/mikkyang/id3-go"
)

func main() {

    f, _ := id3.Open("with_popm.mp3")
    popm := f.Frame("POPM")
    popularimeter, _ := FromData(popm.Bytes())
    fmt.Println(popularimeter)
}

type Rating uint8

func (r Rating) String() string {
    if r == 0 {
        return "unknown"
    }
    return fmt.Sprintf("%d/255", r)
}

type Popularimeter struct {
    Email   string
    Rating  Rating
    Counter uint32
}

func FromData(data []byte) (*Popularimeter, error) {

    tokens := bytes.SplitN(data, []byte{0x0}, 2)
    // Pupolarimeter: <string>, null, 1byte rating, 4bytes counter
    if len(tokens) != 2 || len(tokens[1]) != 5 {
        return nil, errors.New("invalid Popularimeter")
    }

    return &Popularimeter{
        Email:   string(tokens[0]),
        Rating:  Rating(tokens[1][0]),
        Counter: binary.BigEndian.Uint32(tokens[1][1:]),
    }, nil
}
于 2018-10-29T14:19:36.250 回答