Feat: 获取&写入 音频文件的 Metadata #43

Merged
um-dev merged 13 commits from feat/audio-meta into master 2022-12-06 17:55:19 +00:00
5 changed files with 50 additions and 23 deletions
Showing only changes of commit 138adbf846 - Show all commits

View File

@ -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] {

View File

@ -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)
} }

View File

@ -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()
} }

View File

@ -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() {

View File

@ -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