package main import ( "context" "fmt" "maps" "os" "os/signal" "path" "regexp" "strings" "syscall" ) func main() { ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT) defer can() if err := Run(ctx, os.Args[1], os.Args[2], os.Args[3:], nil, ); err != nil { panic(err) } } func Run(ctx context.Context, outd, ind string, patterns []string, overrides map[string]string) error { entries, err := os.ReadDir(ind) if err != nil { return err } for _, entry := range entries { if err := one(ctx, outd, path.Join(ind, entry.Name()), patterns, overrides); err != nil { return err } } return nil } func one(ctx context.Context, outd, inf string, patterns []string, overrides map[string]string) error { f := path.Base(inf) for _, pattern := range patterns { re := regexp.MustCompile(pattern) if !re.MatchString(f) { continue } found := maps.Clone(overrides) groupNames := re.SubexpNames() groups := re.FindStringSubmatch(f) for i := 1; i < len(groupNames); i++ { k := groupNames[i] v := groups[i] found[k] = v } if found["title"] == "" || found["season"] == "" || found["episode"] == "" { continue } found["title"] = strings.Join(strings.Fields(found["title"]), "_") if err := mvNLn(ctx, outd, inf, found["title"], found["season"], found["episode"]); err != nil { return err } return nil } return nil } func mvNLn(ctx context.Context, outd, inf string, title, season, episode string) error { outf := path.Join(outd, fmt.Sprintf("%s_S%sE%s%s", title, season, episode, path.Ext(inf))) if err := os.Rename(inf, outf); err != nil { return err } return os.Symlink(outf, inf) }