main
Bel LaPointe 2025-04-04 17:11:36 -06:00
parent bff2bd6d2e
commit 61569b0515
2 changed files with 159 additions and 4 deletions

60
main.go
View File

@ -2,7 +2,12 @@ package main
import (
"context"
"fmt"
"maps"
"os"
"os/signal"
"path"
"regexp"
"syscall"
)
@ -10,11 +15,62 @@ func main() {
ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
defer can()
if err := Run(ctx); err != nil {
if err := Run(ctx,
os.Args[1],
os.Args[2],
os.Args[3:],
nil,
); err != nil {
panic(err)
}
}
func Run(ctx context.Context) error {
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
}
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)
}

View File

@ -2,13 +2,112 @@ package main_test
import (
"context"
"io/fs"
"io/ioutil"
"os"
"path"
"slices"
"testing"
main "gitea/show-ingestion"
)
func TestRun(t *testing.T) {
if err := main.Run(context.Background()); err != nil {
cases := map[string]struct {
given []string
patterns []string
overrides map[string]string
want []string
}{
"empty": {},
"fallback survivor": {
given: []string{
"Survivor.AU.S12E11.1080p.HEVC.x265-MeGusta[EZTVx.to].mkv",
"Survivor.AU.S12E11.720p.HEVC.x265-MeGusta[EZTVx.to].mkv",
"Survivor.AU.S12E12.720p.HEVC.x265-MeGusta[EZTVx.to].mkv",
},
patterns: []string{
".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",
},
overrides: map[string]string{
"title": "Australian_Survivor",
},
want: []string{
"Australian_Survivor_S12E11.mkv",
"Australian_Survivor_S12E12.mkv",
},
},
"easy w group": {
given: []string{
"[SubsPlease] Tokidoki Bosotto Russia-go de Dereru Tonari no Alya-san - 01 (720p) [A12844D5].mkv",
"[SubsPlease] Tokidoki Bosotto Russia-go de Dereru Tonari no Alya-san - 02 (720p) [2608F490].mkv",
},
want: []string{
"Tokidoki_Bosotto_Russia-go_de_Dereru_Tonari_no_Alya-san_S01E01.mkv",
"Tokidoki_Bosotto_Russia-go_de_Dereru_Tonari_no_Alya-san_S01E02.mkv",
},
},
}
for name, d := range cases {
c := d
t.Run(name, func(t *testing.T) {
ind := t.TempDir()
for _, f := range c.given {
ioutil.WriteFile(path.Join(ind, f), []byte{}, os.ModePerm)
}
outd := t.TempDir()
if err := main.Run(context.Background(), outd, ind, c.patterns, c.overrides); err != nil {
t.Fatal(err)
}
for _, f := range c.want {
if stat, err := os.Stat(path.Join(outd, f)); os.IsNotExist(err) {
t.Errorf("expected %s", f)
} else if !stat.Mode().IsRegular() {
t.Errorf("%s not a regular file: %v", f, 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())
}
if stat, err := entry.Info(); err != nil {
t.Errorf("cant read info of %s: %v", entry.Name(), err)
} 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())
}
}
}
if entries, err := os.ReadDir(ind); err != nil {
t.Error("failed to list indir: %w", err)
} else {
for _, entry := range entries {
inf := path.Join(ind, entry.Name())
if stat, err := os.Stat(inf); err != nil {
t.Errorf("%s no longer in ind: %v", inf, err)
} else if stat.Mode() != fs.ModeSymlink {
t.Errorf("%s not replaced with symlink: %v", inf, stat.Mode())entry.Name(),
}
}
}
})
}
}