123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- // Go CLI tool to extract things from filenames and call external commands. Just because doing it with sed/awk/grep is too cumbersome!
- //
- // Licensed under a MIT license (https://gwyneth-llewelyn.mit-license.org/)
- package main
- import (
- "fmt"
- "regexp"
- "os/exec"
- // "strings"
- "github.com/karrick/godirwalk"
- "github.com/karrick/golf" // flag replacement library
- )
- // instantiate a few global variables, to avoid memory leaks.
- var (
- digit, artist, song int // indexes inside the searched string with matched content.
- dirPath string // path where the files are
- mp4tags string // path to mp4tags executable
- recursive bool // if set, walks through directories recursively
- help bool // if set, show usage
- )
- func main() {
- // read flags, if any
- golf.StringVarP(&dirPath, 'd', "dir", ".", "Directory to read from")
- golf.StringVarP(&mp4tags, 'm', "mp4tags", "/usr/local/bin/mp4tags", "Path to `mp4tags` executable")
- golf.BoolVarP(&recursive, 'r', "recursive", false, "Traverse directory structure recursively")
- golf.BoolVarP(&help, 'h', "help", false, "show command usage")
- golf.Parse()
- if help {
- golf.Usage()
- return
- }
- // check of we can run mp4tags:
- path, err := exec.LookPath(mp4tags) // also search under the $PATH shell
- if err != nil {
- panic(fmt.Sprintf("couldn't find executable `mp4tags` at %q, error was: %s", mp4tags, err))
- }
- fmt.Printf("`mp4tags` is available at %s\n", path)
- fmt.Printf("Now entering directory %q (recursive: %t)...\n\n", dirPath, recursive)
- // prepare a regexp
- re := regexp.MustCompile(`\/(?P<digit>\d\d)\s+(?P<artist>[^-]*)\s+-\s+(?P<song>[^-]*)\.m4a`)
- err = godirwalk.Walk(dirPath, &godirwalk.Options{
- Callback: func(osPathname string, de *godirwalk.Dirent) error {
- // skip directories/symlinks to directories (if not in recursive mode)
- isDir, dirErr := de.IsDirOrSymlinkToDir();
- if isDir && !recursive {
- if dirErr == nil {
- // return godirwalk.SkipThis
- return nil
- }
- fmt.Printf("error when trying to access directory/symlink %q: %s",
- osPathname, dirErr)
- return nil
- }
- matches := re.FindStringSubmatch(osPathname)
- howManyMatches := len(matches)
- //
- // if howManyMatches > 0 {
- // fmt.Printf("Attempting to parse %q, found %d matches\n",
- // osPathname,
- // howManyMatches)
- // }
- digit = re.SubexpIndex("digit")
- artist = re.SubexpIndex("artist")
- song = re.SubexpIndex("song")
- if howManyMatches > 2 && digit >= 0 && artist >= 0 && song >= 0 {
- fmt.Printf("Song %s --> Artist: %q Song: %q -->",
- matches[digit],
- matches[artist],
- matches[song])
- // Call mp4tags with the proper tags
- cmd := exec.Command(mp4tags, "-artist", matches[artist], "-song", matches[song], osPathname)
- stdoutStderr, err := cmd.CombinedOutput()
- if err != nil {
- fmt.Printf("error while running %q: %q \n", mp4tags, err)
- return nil
- }
- fmt.Printf("✅ %s\n", stdoutStderr)
- return nil
- }
- if howManyMatches <= 0 {
- fmt.Printf("The filename %q is not in the proper format (skipping)...\n", osPathname)
- return nil
- }
- fmt.Printf("The filename %q does not match anything at all!\n", osPathname)
- //return godirwalk.SkipThis
- return nil
- },
- Unsorted: false, // (optional) set true for faster yet non-deterministic enumeration (see godoc)
- })
- if err != nil {
- fmt.Printf("sorry, got error %s", err)
- }
- }
|