args are OUTD IND {} patterns..

main
bel 2025-04-04 22:28:38 -06:00
parent 81d1ce1dde
commit 805e666230
2 changed files with 46 additions and 36 deletions

52
main.go
View File

@ -2,8 +2,8 @@ package main
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"maps"
"os" "os"
"os/signal" "os/signal"
"path" "path"
@ -12,26 +12,38 @@ import (
"syscall" "syscall"
) )
type Fields struct {
Title string
Season string
Episode string
}
func main() { func main() {
ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT) ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
defer can() defer can()
var overrides Fields
json.Unmarshal([]byte(os.Args[3]), &overrides)
if err := Run(ctx, if err := Run(ctx,
os.Args[1], os.Args[1],
os.Args[2], os.Args[2],
os.Args[3:], os.Args[4:],
nil, overrides,
); err != nil { ); err != nil {
panic(err) panic(err)
} }
} }
func Run(ctx context.Context, outd, ind string, patterns []string, overrides map[string]string) error { func Run(ctx context.Context, outd, ind string, patterns []string, overrides Fields) error {
entries, err := os.ReadDir(ind) entries, err := os.ReadDir(ind)
if err != nil { if err != nil {
return err return err
} }
for _, entry := range entries { for _, entry := range entries {
if !entry.Type().IsRegular() {
continue
}
if err := one(ctx, outd, path.Join(ind, entry.Name()), patterns, overrides); err != nil { if err := one(ctx, outd, path.Join(ind, entry.Name()), patterns, overrides); err != nil {
return err return err
} }
@ -39,7 +51,7 @@ func Run(ctx context.Context, outd, ind string, patterns []string, overrides map
return nil return nil
} }
func one(ctx context.Context, outd, inf string, patterns []string, overrides map[string]string) error { func one(ctx context.Context, outd, inf string, patterns []string, overrides Fields) error {
f := path.Base(inf) f := path.Base(inf)
for _, pattern := range patterns { for _, pattern := range patterns {
re := regexp.MustCompile(pattern) re := regexp.MustCompile(pattern)
@ -47,30 +59,38 @@ func one(ctx context.Context, outd, inf string, patterns []string, overrides map
continue continue
} }
found := maps.Clone(overrides) found := overrides
groupNames := re.SubexpNames() groupNames := re.SubexpNames()
groups := re.FindStringSubmatch(f) groups := re.FindStringSubmatch(f)
for i := 1; i < len(groupNames); i++ { for i := 1; i < len(groupNames); i++ {
k := groupNames[i]
v := groups[i] v := groups[i]
found[k] = v switch groupNames[i] {
case "title":
found.Title = v
case "season":
found.Season = v
case "episode":
found.Episode = v
default:
return fmt.Errorf("unexpected capture group %q", groupNames[i])
}
} }
if found["title"] == "" || found["season"] == "" || found["episode"] == "" { if found.Title == "" || found.Season == "" || found.Episode == "" {
continue continue
} }
found["title"] = strings.Join(strings.Fields(found["title"]), "_") found.Title = strings.Join(strings.Fields(found.Title), "_")
if err := mvNLn(ctx, outd, inf, found["title"], found["season"], found["episode"]); err != nil { return mvNLn(ctx, outd, inf, found)
return err
}
return nil
} }
return nil return nil
} }
func mvNLn(ctx context.Context, outd, inf string, title, season, episode string) error { func mvNLn(ctx context.Context, outd, inf string, fields Fields) error {
outf := path.Join(outd, fmt.Sprintf("%s_S%sE%s%s", title, season, episode, path.Ext(inf))) outf := path.Join(outd, fmt.Sprintf("%s_S%sE%s%s", fields.Title, fields.Season, fields.Episode, path.Ext(inf)))
if _, err := os.Stat(outf); err == nil {
return nil // fmt.Errorf("conflict: %s already exists", path.Base(outf))
}
if err := os.Rename(inf, outf); err != nil { if err := os.Rename(inf, outf); err != nil {
return err return err
} }

View File

@ -15,7 +15,7 @@ func TestRun(t *testing.T) {
cases := map[string]struct { cases := map[string]struct {
given []string given []string
patterns []string patterns []string
overrides map[string]string overrides main.Fields
want []string want []string
}{ }{
"empty": {}, "empty": {},
@ -29,8 +29,8 @@ func TestRun(t *testing.T) {
".urvivor.[Aa][Uu].*[sS](?P<season>[0-9]+)[eE](?P<episode>[0-9]*).*1080.*MeGusta", ".urvivor.[Aa][Uu].*[sS](?P<season>[0-9]+)[eE](?P<episode>[0-9]*).*1080.*MeGusta",
".urvivor.[Aa][Uu].*[sS](?P<season>[0-9]+)[eE](?P<episode>[0-9]*).*720.*MeGusta", ".urvivor.[Aa][Uu].*[sS](?P<season>[0-9]+)[eE](?P<episode>[0-9]*).*720.*MeGusta",
}, },
overrides: map[string]string{ overrides: main.Fields{
"title": "Australian_Survivor", Title: "Australian_Survivor",
}, },
want: []string{ want: []string{
"Australian_Survivor_S12E11.mkv", "Australian_Survivor_S12E11.mkv",
@ -45,8 +45,8 @@ func TestRun(t *testing.T) {
patterns: []string{ patterns: []string{
`^\[[^\]]*\] (?P<title>.*) - (?<episode>[0-9]*)`, `^\[[^\]]*\] (?P<title>.*) - (?<episode>[0-9]*)`,
}, },
overrides: map[string]string{ overrides: main.Fields{
"season": "01", Season: "01",
}, },
want: []string{ want: []string{
"Tokidoki_Bosotto_Russia-go_de_Dereru_Tonari_no_Alya-san_S01E01.mkv", "Tokidoki_Bosotto_Russia-go_de_Dereru_Tonari_no_Alya-san_S01E01.mkv",
@ -65,7 +65,9 @@ func TestRun(t *testing.T) {
outd := t.TempDir() outd := t.TempDir()
if err := main.Run(context.Background(), outd, ind, c.patterns, c.overrides); err != nil { if err := main.Run(context.Background(), outd, ind, c.patterns, c.overrides); err != nil {
t.Fatal(err) t.Fatal("err on first run:", err)
} else if err := main.Run(context.Background(), outd, ind, c.patterns, c.overrides); err != nil {
t.Fatal("err on second run:", err)
} }
for _, f := range c.want { for _, f := range c.want {
@ -84,20 +86,8 @@ func TestRun(t *testing.T) {
if !slices.Contains(c.want, path.Base(entry.Name())) { if !slices.Contains(c.want, path.Base(entry.Name())) {
t.Errorf("unexpected %s", entry.Name()) t.Errorf("unexpected %s", entry.Name())
} }
if stat, err := entry.Info(); err != nil { if !entry.Type().IsRegular() {
t.Errorf("cant read info of %s: %v", entry.Name(), err) t.Errorf("non-regular file %s in out: %v", entry.Name(), entry.Type())
} else if !stat.Mode().IsRegular() {
t.Errorf("non-regular file %s in out: %v", entry.Name(), stat.Mode())
}
}
}
if entries, err := os.ReadDir(outd); err != nil {
t.Error("failed to list outdir: %w", err)
} else {
for _, entry := range entries {
if !slices.Contains(c.want, path.Base(entry.Name())) {
t.Errorf("unexpected %s", entry.Name())
} }
} }
} }