Feat: 获取&写入 音频文件的 Metadata #43
@ -29,6 +29,7 @@ func RegisterDecoder(ext string, noop bool, dispatchFunc NewDecoderFunc) {
|
|||||||
DecoderRegistry[ext] = append(DecoderRegistry[ext],
|
DecoderRegistry[ext] = append(DecoderRegistry[ext],
|
||||||
decoderItem{noop: noop, decoder: dispatchFunc})
|
decoderItem{noop: noop, decoder: dispatchFunc})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDecoder(filename string, skipNoop bool) (rs []NewDecoderFunc) {
|
func GetDecoder(filename string, skipNoop bool) (rs []NewDecoderFunc) {
|
||||||
ext := strings.ToLower(strings.TrimLeft(filepath.Ext(filename), "."))
|
ext := strings.ToLower(strings.TrimLeft(filepath.Ext(filename), "."))
|
||||||
for _, dec := range DecoderRegistry[ext] {
|
for _, dec := range DecoderRegistry[ext] {
|
||||||
|
@ -5,6 +5,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StreamDecoder interface {
|
||||||
|
Decrypt(buf []byte, offset int)
|
||||||
|
}
|
||||||
|
|
||||||
type Decoder interface {
|
type Decoder interface {
|
||||||
Validate() error
|
Validate() error
|
||||||
io.Reader
|
io.Reader
|
||||||
@ -14,12 +18,12 @@ type CoverImageGetter interface {
|
|||||||
GetCoverImage(ctx context.Context) ([]byte, error)
|
GetCoverImage(ctx context.Context) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Meta interface {
|
type AudioMeta interface {
|
||||||
GetArtists() []string
|
GetArtists() []string
|
||||||
GetTitle() string
|
GetTitle() string
|
||||||
GetAlbum() string
|
GetAlbum() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamDecoder interface {
|
type AudioMetaGetter interface {
|
||||||
Decrypt(buf []byte, offset int)
|
GetAudioMeta(ctx context.Context) (AudioMeta, error)
|
||||||
}
|
}
|
@ -6,12 +6,17 @@ import (
|
|||||||
"unlock-music.dev/cli/algo/common"
|
"unlock-music.dev/cli/algo/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RawMeta interface {
|
type ncmMeta interface {
|
||||||
common.Meta
|
common.AudioMeta
|
||||||
|
|
||||||
|
// GetFormat return the audio format, e.g. mp3, flac
|
||||||
GetFormat() string
|
GetFormat() string
|
||||||
|
|
||||||
|
// GetAlbumImageURL return the album image url
|
||||||
GetAlbumImageURL() string
|
GetAlbumImageURL() string
|
||||||
}
|
}
|
||||||
type RawMetaMusic struct {
|
|
||||||
|
type ncmMetaMusic struct {
|
||||||
Format string `json:"format"`
|
Format string `json:"format"`
|
||||||
MusicID int `json:"musicId"`
|
MusicID int `json:"musicId"`
|
||||||
MusicName string `json:"musicName"`
|
MusicName string `json:"musicName"`
|
||||||
@ -28,10 +33,11 @@ type RawMetaMusic struct {
|
|||||||
TransNames []interface{} `json:"transNames"`
|
TransNames []interface{} `json:"transNames"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaMusic) GetAlbumImageURL() string {
|
func (m *ncmMetaMusic) GetAlbumImageURL() string {
|
||||||
return m.AlbumPic
|
return m.AlbumPic
|
||||||
}
|
}
|
||||||
func (m RawMetaMusic) GetArtists() (artists []string) {
|
|
||||||
|
func (m *ncmMetaMusic) GetArtists() (artists []string) {
|
||||||
for _, artist := range m.Artist {
|
for _, artist := range m.Artist {
|
||||||
for _, item := range artist {
|
for _, item := range artist {
|
||||||
name, ok := item.(string)
|
name, ok := item.(string)
|
||||||
@ -43,22 +49,23 @@ func (m RawMetaMusic) GetArtists() (artists []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaMusic) GetTitle() string {
|
func (m *ncmMetaMusic) GetTitle() string {
|
||||||
return m.MusicName
|
return m.MusicName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaMusic) GetAlbum() string {
|
func (m *ncmMetaMusic) GetAlbum() string {
|
||||||
return m.Album
|
return m.Album
|
||||||
}
|
}
|
||||||
func (m RawMetaMusic) GetFormat() string {
|
|
||||||
|
func (m *ncmMetaMusic) GetFormat() string {
|
||||||
return m.Format
|
return m.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
//goland:noinspection SpellCheckingInspection
|
//goland:noinspection SpellCheckingInspection
|
||||||
type RawMetaDJ struct {
|
type ncmMetaDJ struct {
|
||||||
ProgramID int `json:"programId"`
|
ProgramID int `json:"programId"`
|
||||||
ProgramName string `json:"programName"`
|
ProgramName string `json:"programName"`
|
||||||
MainMusic RawMetaMusic `json:"mainMusic"`
|
MainMusic ncmMetaMusic `json:"mainMusic"`
|
||||||
DjID int `json:"djId"`
|
DjID int `json:"djId"`
|
||||||
DjName string `json:"djName"`
|
DjName string `json:"djName"`
|
||||||
DjAvatarURL string `json:"djAvatarUrl"`
|
DjAvatarURL string `json:"djAvatarUrl"`
|
||||||
@ -80,32 +87,32 @@ type RawMetaDJ struct {
|
|||||||
RadioPurchaseCount int `json:"radioPurchaseCount"`
|
RadioPurchaseCount int `json:"radioPurchaseCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaDJ) GetArtists() []string {
|
func (m *ncmMetaDJ) GetArtists() []string {
|
||||||
if m.DjName != "" {
|
if m.DjName != "" {
|
||||||
return []string{m.DjName}
|
return []string{m.DjName}
|
||||||
}
|
}
|
||||||
return m.MainMusic.GetArtists()
|
return m.MainMusic.GetArtists()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaDJ) GetTitle() string {
|
func (m *ncmMetaDJ) GetTitle() string {
|
||||||
if m.ProgramName != "" {
|
if m.ProgramName != "" {
|
||||||
return m.ProgramName
|
return m.ProgramName
|
||||||
}
|
}
|
||||||
return m.MainMusic.GetTitle()
|
return m.MainMusic.GetTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaDJ) GetAlbum() string {
|
func (m *ncmMetaDJ) GetAlbum() string {
|
||||||
if m.Brand != "" {
|
if m.Brand != "" {
|
||||||
return m.Brand
|
return m.Brand
|
||||||
}
|
}
|
||||||
return m.MainMusic.GetAlbum()
|
return m.MainMusic.GetAlbum()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaDJ) GetFormat() string {
|
func (m *ncmMetaDJ) GetFormat() string {
|
||||||
return m.MainMusic.GetFormat()
|
return m.MainMusic.GetFormat()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m RawMetaDJ) GetAlbumImageURL() string {
|
func (m *ncmMetaDJ) GetAlbumImageURL() string {
|
||||||
if strings.HasPrefix(m.MainMusic.GetAlbumImageURL(), "http") {
|
if strings.HasPrefix(m.MainMusic.GetAlbumImageURL(), "http") {
|
||||||
return m.MainMusic.GetAlbumImageURL()
|
return m.MainMusic.GetAlbumImageURL()
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ type Decoder struct {
|
|||||||
|
|
||||||
metaRaw []byte
|
metaRaw []byte
|
||||||
metaType string
|
metaType string
|
||||||
meta RawMeta
|
meta ncmMeta
|
||||||
cover []byte
|
cover []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,10 +172,10 @@ func (d *Decoder) readCoverData() error {
|
|||||||
func (d *Decoder) parseMeta() error {
|
func (d *Decoder) parseMeta() error {
|
||||||
switch d.metaType {
|
switch d.metaType {
|
||||||
case "music":
|
case "music":
|
||||||
d.meta = new(RawMetaMusic)
|
d.meta = new(ncmMetaMusic)
|
||||||
return json.Unmarshal(d.metaRaw, d.meta)
|
return json.Unmarshal(d.metaRaw, d.meta)
|
||||||
case "dj":
|
case "dj":
|
||||||
d.meta = new(RawMetaDJ)
|
d.meta = new(ncmMetaDJ)
|
||||||
return json.Unmarshal(d.metaRaw, d.meta)
|
return json.Unmarshal(d.metaRaw, d.meta)
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown ncm meta type: " + d.metaType)
|
return errors.New("unknown ncm meta type: " + d.metaType)
|
||||||
@ -232,8 +232,8 @@ func (d *Decoder) GetCoverImage(ctx context.Context) ([]byte, error) {
|
|||||||
return d.cover, nil
|
return d.cover, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) GetMeta() common.Meta {
|
func (d *Decoder) GetAudioMeta(_ context.Context) (common.AudioMeta, error) {
|
||||||
return d.meta
|
return d.meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -225,7 +225,22 @@ func tryDecFile(inputFile string, outputDir string, allDec []common.NewDecoderFu
|
|||||||
logger.Warn("write cover image failed", zap.Error(err))
|
logger.Warn("write cover image failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if audioMetaGetter, ok := dec.(common.AudioMetaGetter); ok {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
meta, err := audioMetaGetter.GetAudioMeta(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("get audio meta failed", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Info("audio metadata",
|
||||||
|
zap.String("title", meta.GetTitle()),
|
||||||
|
zap.Strings("artists", meta.GetArtists()),
|
||||||
|
zap.String("album", meta.GetAlbum()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if source file need to be removed
|
// if source file need to be removed
|
||||||
|
Loading…
Reference in New Issue
Block a user