feat(meta): separate flac meta process

This commit is contained in:
Unlock Music Dev
2022-12-07 01:37:53 +08:00
parent f3cbd2f3b4
commit 0acf905d08
5 changed files with 127 additions and 9 deletions

View File

@@ -39,11 +39,18 @@ type UpdateMetadataParams struct {
Meta common.AudioMeta // required
AlbumArt io.Reader // optional
AlbumArtExt string // required if AlbumArt is not nil
AlbumArt []byte // optional
AlbumArtExt string // required if AlbumArt is not nil
}
func UpdateAudioMetadata(ctx context.Context, outPath string, params *UpdateMetadataParams) error {
func UpdateMeta(ctx context.Context, outPath string, params *UpdateMetadataParams) error {
if params.AudioExt == ".flac" {
return updateMetaFlac(ctx, outPath, params)
} else {
return updateMetaFFmpeg(ctx, outPath, params)
}
}
func updateMetaFFmpeg(ctx context.Context, outPath string, params *UpdateMetadataParams) error {
builder := newFFmpegBuilder()
out := newOutputBuilder(outPath) // output to file
@@ -60,7 +67,7 @@ func UpdateAudioMetadata(ctx context.Context, outPath string, params *UpdateMeta
params.AudioExt != ".wav" /* wav doesn't support attached image */ {
// write cover to temp file
artPath, err := utils.WriteTempFile(params.AlbumArt, params.AlbumArtExt)
artPath, err := utils.WriteTempFile(bytes.NewReader(params.AlbumArt), params.AlbumArtExt)
if err != nil {
return fmt.Errorf("updateAudioMeta write temp file: %w", err)
}
@@ -77,6 +84,10 @@ func UpdateAudioMetadata(ctx context.Context, outPath string, params *UpdateMeta
out.AddOption("disposition:v", "attached_pic")
out.AddMetadata("s:v", "title", "Album cover")
out.AddMetadata("s:v", "comment", "Cover (front)")
case ".mp3":
out.AddOption("codec:v", "mjpeg")
out.AddMetadata("s:v", "title", "Album cover")
out.AddMetadata("s:v", "comment", "Cover (front)")
default: // other formats use default behavior
}
}
@@ -98,6 +109,11 @@ func UpdateAudioMetadata(ctx context.Context, outPath string, params *UpdateMeta
out.AddMetadata("", "artist", strings.Join(artists, " / "))
}
if params.AudioExt == ".mp3" {
out.AddOption("write_id3v1", "true")
out.AddOption("id3v2_version", "3")
}
// execute ffmpeg
cmd := builder.Command(ctx)

View File

@@ -0,0 +1,90 @@
package ffmpeg
import (
"context"
"mime"
"strings"
"github.com/go-flac/flacpicture"
"github.com/go-flac/flacvorbis"
"github.com/go-flac/go-flac"
"golang.org/x/exp/slices"
)
func updateMetaFlac(_ context.Context, outPath string, m *UpdateMetadataParams) error {
f, err := flac.ParseFile(m.Audio)
if err != nil {
return err
}
// generate comment block
comment := flacvorbis.MetaDataBlockVorbisComment{Vendor: "unlock-music.dev"}
// add metadata
title := m.Meta.GetTitle()
if title != "" {
_ = comment.Add(flacvorbis.FIELD_TITLE, title)
}
album := m.Meta.GetAlbum()
if album != "" {
_ = comment.Add(flacvorbis.FIELD_ALBUM, album)
}
artists := m.Meta.GetArtists()
for _, artist := range artists {
_ = comment.Add(flacvorbis.FIELD_ARTIST, artist)
}
existCommentIdx := slices.IndexFunc(f.Meta, func(b *flac.MetaDataBlock) bool {
return b.Type == flac.VorbisComment
})
if existCommentIdx >= 0 { // copy existing comment fields
exist, err := flacvorbis.ParseFromMetaDataBlock(*f.Meta[existCommentIdx])
if err != nil {
for _, s := range exist.Comments {
if strings.HasPrefix(s, flacvorbis.FIELD_TITLE+"=") && title != "" ||
strings.HasPrefix(s, flacvorbis.FIELD_ALBUM+"=") && album != "" ||
strings.HasPrefix(s, flacvorbis.FIELD_ARTIST+"=") && len(artists) != 0 {
continue
}
comment.Comments = append(comment.Comments, s)
}
}
}
// add / replace flac comment
cmtBlock := comment.Marshal()
if existCommentIdx < 0 {
f.Meta = append(f.Meta, &cmtBlock)
} else {
f.Meta[existCommentIdx] = &cmtBlock
}
if m.AlbumArt != nil {
cover, err := flacpicture.NewFromImageData(
flacpicture.PictureTypeFrontCover,
"Front cover",
m.AlbumArt,
mime.TypeByExtension(m.AlbumArtExt),
)
if err != nil {
return err
}
coverBlock := cover.Marshal()
f.Meta = append(f.Meta, &coverBlock)
// add / replace flac cover
coverIdx := slices.IndexFunc(f.Meta, func(b *flac.MetaDataBlock) bool {
return b.Type == flac.Picture
})
if coverIdx < 0 {
f.Meta = append(f.Meta, &coverBlock)
} else {
f.Meta[coverIdx] = &coverBlock
}
}
return f.Save(outPath)
}