Compare commits
No commits in common. "6493b2c5fc46bf21e82372cc30a327c5245b10d0" and "b2ef27761f12adcb1af877f4595c42d960055b11" have entirely different histories.
6493b2c5fc
...
b2ef27761f
@ -1,7 +1,6 @@
|
|||||||
package ncm
|
package ncm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.uber.org/zap"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"unlock-music.dev/cli/algo/common"
|
"unlock-music.dev/cli/algo/common"
|
||||||
@ -18,11 +17,9 @@ type ncmMeta interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ncmMetaMusic struct {
|
type ncmMetaMusic struct {
|
||||||
logger *zap.Logger
|
|
||||||
|
|
||||||
Format string `json:"format"`
|
Format string `json:"format"`
|
||||||
MusicName string `json:"musicName"`
|
MusicName string `json:"musicName"`
|
||||||
Artist interface{} `json:"artist"`
|
Artist [][]interface{} `json:"artist"`
|
||||||
Album string `json:"album"`
|
Album string `json:"album"`
|
||||||
AlbumPicDocID interface{} `json:"albumPicDocId"`
|
AlbumPicDocID interface{} `json:"albumPicDocId"`
|
||||||
AlbumPic string `json:"albumPic"`
|
AlbumPic string `json:"albumPic"`
|
||||||
@ -33,34 +30,20 @@ type ncmMetaMusic struct {
|
|||||||
TransNames []interface{} `json:"transNames"`
|
TransNames []interface{} `json:"transNames"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNcmMetaMusic(logger *zap.Logger) *ncmMetaMusic {
|
|
||||||
ncm := new(ncmMetaMusic)
|
|
||||||
ncm.logger = logger.With(zap.String("module", "ncmMetaMusic"))
|
|
||||||
return ncm
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ncmMetaMusic) GetAlbumImageURL() string {
|
func (m *ncmMetaMusic) GetAlbumImageURL() string {
|
||||||
return m.AlbumPic
|
return m.AlbumPic
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ncmMetaMusic) GetArtists() []string {
|
func (m *ncmMetaMusic) GetArtists() (artists []string) {
|
||||||
m.logger.Debug("ncm artists", zap.Any("artists", m.Artist))
|
for _, artist := range m.Artist {
|
||||||
|
for _, item := range artist {
|
||||||
var artists []string = nil
|
name, ok := item.(string)
|
||||||
if jsonArtists, ok := m.Artist.([][]string); ok {
|
if ok {
|
||||||
for _, artist := range jsonArtists {
|
|
||||||
for _, name := range artist {
|
|
||||||
artists = append(artists, name)
|
artists = append(artists, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if artist, ok := m.Artist.(string); ok {
|
|
||||||
// #78: artist is a string type.
|
|
||||||
// https://git.unlock-music.dev/um/cli/issues/78
|
|
||||||
artists = []string{artist}
|
|
||||||
} else {
|
|
||||||
m.logger.Warn("unexpected artist type", zap.Any("artists", m.Artist))
|
|
||||||
}
|
}
|
||||||
return artists
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ncmMetaMusic) GetTitle() string {
|
func (m *ncmMetaMusic) GetTitle() string {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.uber.org/zap"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@ -31,11 +30,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewDecoder(p *common.DecoderParams) common.Decoder {
|
func NewDecoder(p *common.DecoderParams) common.Decoder {
|
||||||
return &Decoder{rd: p.Reader, logger: p.Logger.With(zap.String("module", "ncm"))}
|
return &Decoder{rd: p.Reader}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
logger *zap.Logger
|
|
||||||
rd io.ReadSeeker // rd is the original file reader
|
rd io.ReadSeeker // rd is the original file reader
|
||||||
|
|
||||||
offset int
|
offset int
|
||||||
@ -76,7 +74,7 @@ func (d *Decoder) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := d.parseMeta(); err != nil {
|
if err := d.parseMeta(); err != nil {
|
||||||
return fmt.Errorf("parse meta failed: %w (raw json=%s)", err, string(d.metaRaw))
|
return fmt.Errorf("parse meta failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.cipher = newNcmCipher(keyData)
|
d.cipher = newNcmCipher(keyData)
|
||||||
@ -183,7 +181,7 @@ 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 = newNcmMetaMusic(d.logger)
|
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(ncmMetaDJ)
|
d.meta = new(ncmMetaDJ)
|
||||||
|
@ -5,10 +5,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -19,6 +15,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"unlock-music.dev/cli/algo/common"
|
"unlock-music.dev/cli/algo/common"
|
||||||
_ "unlock-music.dev/cli/algo/kgm"
|
_ "unlock-music.dev/cli/algo/kgm"
|
||||||
_ "unlock-music.dev/cli/algo/kwm"
|
_ "unlock-music.dev/cli/algo/kwm"
|
||||||
@ -28,13 +29,14 @@ import (
|
|||||||
_ "unlock-music.dev/cli/algo/xiami"
|
_ "unlock-music.dev/cli/algo/xiami"
|
||||||
_ "unlock-music.dev/cli/algo/ximalaya"
|
_ "unlock-music.dev/cli/algo/ximalaya"
|
||||||
"unlock-music.dev/cli/internal/ffmpeg"
|
"unlock-music.dev/cli/internal/ffmpeg"
|
||||||
|
"unlock-music.dev/cli/internal/logging"
|
||||||
"unlock-music.dev/cli/internal/sniff"
|
"unlock-music.dev/cli/internal/sniff"
|
||||||
"unlock-music.dev/cli/internal/utils"
|
"unlock-music.dev/cli/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AppVersion = "v0.2.8"
|
var AppVersion = "v0.2.8"
|
||||||
|
|
||||||
var logger = setupLogger(false) // TODO: inject logger to application, instead of using global logger
|
var logger, _ = logging.NewZapLogger() // TODO: inject logger to application, instead of using global logger
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
module, ok := debug.ReadBuildInfo()
|
module, ok := debug.ReadBuildInfo()
|
||||||
@ -53,7 +55,6 @@ func main() {
|
|||||||
&cli.StringFlag{Name: "qmc-mmkv-key", Aliases: []string{"key"}, Usage: "mmkv password (16 ascii chars)", Required: false},
|
&cli.StringFlag{Name: "qmc-mmkv-key", Aliases: []string{"key"}, Usage: "mmkv password (16 ascii chars)", Required: false},
|
||||||
&cli.BoolFlag{Name: "remove-source", Aliases: []string{"rs"}, Usage: "remove source file", Required: false, Value: false},
|
&cli.BoolFlag{Name: "remove-source", Aliases: []string{"rs"}, Usage: "remove source file", Required: false, Value: false},
|
||||||
&cli.BoolFlag{Name: "skip-noop", Aliases: []string{"n"}, Usage: "skip noop decoder", Required: false, Value: true},
|
&cli.BoolFlag{Name: "skip-noop", Aliases: []string{"n"}, Usage: "skip noop decoder", Required: false, Value: true},
|
||||||
&cli.BoolFlag{Name: "verbose", Aliases: []string{"V"}, Usage: "verbose logging", Required: false, Value: false},
|
|
||||||
&cli.BoolFlag{Name: "update-metadata", Usage: "update metadata & album art from network", Required: false, Value: false},
|
&cli.BoolFlag{Name: "update-metadata", Usage: "update metadata & album art from network", Required: false, Value: false},
|
||||||
&cli.BoolFlag{Name: "overwrite", Usage: "overwrite output file without asking", Required: false, Value: false},
|
&cli.BoolFlag{Name: "overwrite", Usage: "overwrite output file without asking", Required: false, Value: false},
|
||||||
&cli.BoolFlag{Name: "watch", Usage: "watch the input dir and process new files", Required: false, Value: false},
|
&cli.BoolFlag{Name: "watch", Usage: "watch the input dir and process new files", Required: false, Value: false},
|
||||||
@ -66,7 +67,6 @@ func main() {
|
|||||||
HideHelpCommand: true,
|
HideHelpCommand: true,
|
||||||
UsageText: "um [-o /path/to/output/dir] [--extra-flags] [-i] /path/to/input",
|
UsageText: "um [-o /path/to/output/dir] [--extra-flags] [-i] /path/to/input",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("run app failed", zap.Error(err))
|
logger.Fatal("run app failed", zap.Error(err))
|
||||||
@ -93,27 +93,7 @@ func printSupportedExtensions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLogger(verbose bool) *zap.Logger {
|
|
||||||
logConfig := zap.NewProductionEncoderConfig()
|
|
||||||
logConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
|
||||||
logConfig.EncodeTime = zapcore.RFC3339TimeEncoder
|
|
||||||
enabler := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
|
|
||||||
if verbose {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return level >= zapcore.InfoLevel
|
|
||||||
})
|
|
||||||
|
|
||||||
return zap.New(zapcore.NewCore(
|
|
||||||
zapcore.NewConsoleEncoder(logConfig),
|
|
||||||
os.Stdout,
|
|
||||||
enabler,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func appMain(c *cli.Context) (err error) {
|
func appMain(c *cli.Context) (err error) {
|
||||||
logger = setupLogger(c.Bool("verbose"))
|
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -175,7 +155,6 @@ func appMain(c *cli.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc := &processor{
|
proc := &processor{
|
||||||
logger: logger,
|
|
||||||
inputDir: inputDir,
|
inputDir: inputDir,
|
||||||
outputDir: output,
|
outputDir: output,
|
||||||
skipNoopDecoder: c.Bool("skip-noop"),
|
skipNoopDecoder: c.Bool("skip-noop"),
|
||||||
@ -198,7 +177,6 @@ func appMain(c *cli.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type processor struct {
|
type processor struct {
|
||||||
logger *zap.Logger
|
|
||||||
inputDir string
|
inputDir string
|
||||||
outputDir string
|
outputDir string
|
||||||
|
|
||||||
@ -428,7 +406,7 @@ func (p *processor) process(inputFile string, allDec []common.DecoderFactory) er
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := ffmpeg.UpdateMeta(ctx, outPath, params, logger); err != nil {
|
if err := ffmpeg.UpdateMeta(ctx, outPath, params); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.uber.org/zap"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -44,9 +43,9 @@ type UpdateMetadataParams struct {
|
|||||||
AlbumArtExt string // required if AlbumArt is not nil
|
AlbumArtExt string // required if AlbumArt is not nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateMeta(ctx context.Context, outPath string, params *UpdateMetadataParams, logger *zap.Logger) error {
|
func UpdateMeta(ctx context.Context, outPath string, params *UpdateMetadataParams) error {
|
||||||
if params.AudioExt == ".flac" {
|
if params.AudioExt == ".flac" {
|
||||||
return updateMetaFlac(ctx, outPath, params, logger.With(zap.String("module", "updateMetaFlac")))
|
return updateMetaFlac(ctx, outPath, params)
|
||||||
} else {
|
} else {
|
||||||
return updateMetaFFmpeg(ctx, outPath, params)
|
return updateMetaFFmpeg(ctx, outPath, params)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package ffmpeg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"go.uber.org/zap"
|
|
||||||
"mime"
|
"mime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ import (
|
|||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateMetaFlac(_ context.Context, outPath string, m *UpdateMetadataParams, logger *zap.Logger) error {
|
func updateMetaFlac(_ context.Context, outPath string, m *UpdateMetadataParams) error {
|
||||||
f, err := flac.ParseFile(m.Audio)
|
f, err := flac.ParseFile(m.Audio)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -63,18 +62,16 @@ func updateMetaFlac(_ context.Context, outPath string, m *UpdateMetadataParams,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.AlbumArt != nil {
|
if m.AlbumArt != nil {
|
||||||
coverMime := mime.TypeByExtension(m.AlbumArtExt)
|
|
||||||
logger.Debug("cover image mime detect", zap.String("mime", coverMime))
|
|
||||||
cover, err := flacpicture.NewFromImageData(
|
cover, err := flacpicture.NewFromImageData(
|
||||||
flacpicture.PictureTypeFrontCover,
|
flacpicture.PictureTypeFrontCover,
|
||||||
"Front cover",
|
"Front cover",
|
||||||
m.AlbumArt,
|
m.AlbumArt,
|
||||||
coverMime,
|
mime.TypeByExtension(m.AlbumArtExt),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("failed to create flac cover", zap.Error(err))
|
return err
|
||||||
} else {
|
}
|
||||||
coverBlock := cover.Marshal()
|
coverBlock := cover.Marshal()
|
||||||
f.Meta = append(f.Meta, &coverBlock)
|
f.Meta = append(f.Meta, &coverBlock)
|
||||||
|
|
||||||
@ -88,7 +85,6 @@ func updateMetaFlac(_ context.Context, outPath string, m *UpdateMetadataParams,
|
|||||||
f.Meta[coverIdx] = &coverBlock
|
f.Meta[coverIdx] = &coverBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return f.Save(outPath)
|
return f.Save(outPath)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user