166 lines
3.8 KiB
Go
166 lines
3.8 KiB
Go
|
package process
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/akamensky/argparse"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
"gitlab.com/ChaotiCryptidz/musicutil/types"
|
||
|
"gitlab.com/ChaotiCryptidz/musicutil/utils"
|
||
|
"gitlab.com/ChaotiCryptidz/musicutil/utils/ascii_reduce"
|
||
|
"gitlab.com/ChaotiCryptidz/musicutil/utils/tag_cache"
|
||
|
)
|
||
|
|
||
|
type ProcessCommandArgs struct {
|
||
|
Source *string
|
||
|
DryRun *bool
|
||
|
}
|
||
|
|
||
|
func RegisterProcessCommand(parser *argparse.Parser) (*argparse.Command, *ProcessCommandArgs) {
|
||
|
cmd := parser.NewCommand("process", "")
|
||
|
|
||
|
arguments := &ProcessCommandArgs{}
|
||
|
arguments.Source = cmd.String("s", "src", &argparse.Options{
|
||
|
Required: true,
|
||
|
Validate: func(args []string) error {
|
||
|
fileInfo, err := os.Stat(args[0])
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Source does not exist")
|
||
|
}
|
||
|
|
||
|
if !fileInfo.IsDir() {
|
||
|
return fmt.Errorf("Source is not a directory")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
},
|
||
|
})
|
||
|
|
||
|
arguments.DryRun = cmd.Flag("", "dry-run", &argparse.Options{})
|
||
|
|
||
|
return cmd, arguments
|
||
|
}
|
||
|
|
||
|
type ProcessCommand struct {
|
||
|
Args *ProcessCommandArgs
|
||
|
Files []*types.File
|
||
|
TagCache *tag_cache.TagCache
|
||
|
}
|
||
|
|
||
|
func NewProcessCommand(args *ProcessCommandArgs) *ProcessCommand {
|
||
|
return &ProcessCommand{
|
||
|
Args: args,
|
||
|
Files: make([]*types.File, 0),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *ProcessCommand) Run() {
|
||
|
log.Info().Str("dir", *c.Args.Source).Msg("Processing")
|
||
|
|
||
|
c.TagCache = tag_cache.NewTagCache(*c.Args.Source)
|
||
|
defer c.TagCache.Close()
|
||
|
c.scan_for_music()
|
||
|
c.load_tag_information()
|
||
|
c.rename_files()
|
||
|
}
|
||
|
|
||
|
func (c *ProcessCommand) scan_for_music() {
|
||
|
log.Info().Msg("Scanning For Music")
|
||
|
files, err := utils.ScanForMusic(*c.Args.Source)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
c.Files = files
|
||
|
}
|
||
|
|
||
|
func (c *ProcessCommand) load_tag_information() {
|
||
|
log.Info().Msg("Load Tag Information")
|
||
|
|
||
|
for _, file := range c.Files {
|
||
|
if cached_tags, ok := c.TagCache.IsCached(file); !ok {
|
||
|
log.Info().Str("file", file.JoinFilename()).Msg("Loading Tags")
|
||
|
|
||
|
tags, err := utils.ExtractTags(file)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
file.Tags = tags
|
||
|
c.TagCache.AddToCache(file, tags)
|
||
|
} else {
|
||
|
log.Info().Str("file", file.JoinFilename()).Msg("Loading Tags From Cache")
|
||
|
file.Tags = cached_tags
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// returns the new file so if renamed,
|
||
|
// any step after it is ran can operate on file
|
||
|
// if dry run then returns orig file without changed filename
|
||
|
func (c *ProcessCommand) rename_file(file *types.File) *types.File {
|
||
|
title := file.Tags.Title
|
||
|
artist := file.Tags.Artist
|
||
|
|
||
|
replace_char := "_"
|
||
|
|
||
|
// Step 1: Remove Newlines
|
||
|
title = strings.ReplaceAll(title, "\n", "")
|
||
|
artist = strings.ReplaceAll(artist, "\n", "")
|
||
|
|
||
|
// Step 2: Strip ASCII
|
||
|
title = ascii_reduce.Reduce(title, replace_char)
|
||
|
artist = ascii_reduce.Reduce(artist, replace_char)
|
||
|
|
||
|
// Step 3: Remove File Seperators
|
||
|
title = strings.ReplaceAll(title, "\\", replace_char)
|
||
|
title = strings.ReplaceAll(title, "/", replace_char)
|
||
|
artist = strings.ReplaceAll(artist, "\\", replace_char)
|
||
|
artist = strings.ReplaceAll(artist, "/", replace_char)
|
||
|
|
||
|
// Step 4: Join Filename
|
||
|
filename := fmt.Sprintf("%s - %s", artist, title)
|
||
|
|
||
|
if filename == file.Filename {
|
||
|
return file
|
||
|
}
|
||
|
|
||
|
// Step 5: Make new File with filename set
|
||
|
new_file := file.DeepCopy()
|
||
|
if !*c.Args.DryRun {
|
||
|
new_file.Filename = filename
|
||
|
}
|
||
|
|
||
|
// Step 6: Rename File
|
||
|
log.Info().
|
||
|
Str("old", file.Filename).
|
||
|
Str("new", filename).
|
||
|
Msg("Renaming File")
|
||
|
|
||
|
if !*c.Args.DryRun {
|
||
|
if _, err := os.Stat(new_file.JoinPathTo()); err == nil {
|
||
|
log.Fatal().
|
||
|
Str("old", file.JoinFilename()).
|
||
|
Str("new", new_file.JoinFilename()).
|
||
|
Msg("Refusing to rename files, please retag to be distinct")
|
||
|
}
|
||
|
|
||
|
err := os.Rename(file.JoinPathTo(), new_file.JoinPathTo())
|
||
|
if err != nil {
|
||
|
log.Fatal().Err(err).Msg("Failed to rename file")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new_file
|
||
|
}
|
||
|
|
||
|
func (c *ProcessCommand) rename_files() {
|
||
|
log.Info().Msg("Renaming Files")
|
||
|
|
||
|
for _, file := range c.Files {
|
||
|
c.rename_file(file)
|
||
|
}
|
||
|
|
||
|
}
|