413 lines
11 KiB
Go
413 lines
11 KiB
Go
package main_test
|
|
|
|
import (
|
|
"context"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"slices"
|
|
"testing"
|
|
|
|
main "gitea/show-ingestion"
|
|
)
|
|
|
|
func TestRunChoosesOne(t *testing.T) {
|
|
ind := t.TempDir()
|
|
outd := t.TempDir()
|
|
|
|
for _, given := range []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",
|
|
} {
|
|
ioutil.WriteFile(path.Join(ind, given), []byte{}, os.ModePerm)
|
|
}
|
|
|
|
want := map[string]bool{
|
|
"Australian_Survivor_S12E11.mkv": false,
|
|
"Australian_Survivor_S12E12.mkv": false,
|
|
}
|
|
|
|
if err := main.RunWith(context.Background(),
|
|
outd,
|
|
ind,
|
|
[]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",
|
|
},
|
|
main.Fields{
|
|
Title: "Australian_Survivor",
|
|
},
|
|
func(outf, inf string) error {
|
|
want[path.Base(outf)] = true
|
|
return nil
|
|
},
|
|
); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for k, v := range want {
|
|
if !v {
|
|
t.Errorf("did not mv_n_ln(outf=%s)", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunWith(t *testing.T) {
|
|
cases := map[string]struct {
|
|
given []string
|
|
patterns []string
|
|
overrides main.Fields
|
|
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: main.Fields{
|
|
Title: "Australian_Survivor",
|
|
},
|
|
want: []string{
|
|
"Australian_Survivor_S12E11.mkv",
|
|
"Australian_Survivor_S12E12.mkv",
|
|
},
|
|
},
|
|
"hard w group": {
|
|
given: []string{
|
|
"[Yameii] Dr. Stone - S04E12 [English Dub] [CR WEB-DL 720p] [F6EF1948].mkv",
|
|
},
|
|
patterns: []string{
|
|
main.PatternGroupTitleHyphenSE,
|
|
},
|
|
want: []string{
|
|
"Dr_Stone_S04E12.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",
|
|
},
|
|
patterns: []string{
|
|
`^\[[^\]]*\] (?P<title>.*) - (?<episode>[0-9]*)`,
|
|
},
|
|
overrides: main.Fields{
|
|
Season: "01",
|
|
},
|
|
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.RunWith(context.Background(), outd, ind, c.patterns, c.overrides, main.RealMvNLn); err != nil {
|
|
t.Fatal("err on first run:", err)
|
|
} else if err := main.RunWith(context.Background(), outd, ind, c.patterns, c.overrides, main.RealMvNLn); err != nil {
|
|
t.Fatal("err on second run:", 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 {
|
|
t.Logf("%s", entry.Name())
|
|
if !slices.Contains(c.want, path.Base(entry.Name())) {
|
|
t.Errorf("unexpected %s", entry.Name())
|
|
}
|
|
if !entry.Type().IsRegular() {
|
|
t.Errorf("non-regular file %s in out: %v", entry.Name(), entry.Type())
|
|
}
|
|
}
|
|
}
|
|
|
|
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 _, err := os.Stat(inf); err != nil {
|
|
t.Errorf("%s no longer in ind: %v", inf, err)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRecursive(t *testing.T) {
|
|
webhooks := []string{}
|
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPut {
|
|
t.Errorf("unexpected webhook method %s", r.Method)
|
|
}
|
|
if r.URL.User.String() != "" {
|
|
t.Errorf("unexpected auth on url %s", r.URL.String())
|
|
}
|
|
if u, p, _ := r.BasicAuth(); u != "u" || p != "p" {
|
|
t.Errorf("webhook didnt translate u:p to basic auth")
|
|
}
|
|
b, _ := ioutil.ReadAll(r.Body)
|
|
t.Logf("%s { %s }", r.URL.String(), b)
|
|
webhooks = append(webhooks, string(b))
|
|
}))
|
|
t.Cleanup(s.Close)
|
|
t.Cleanup(func() {
|
|
t.Logf("webhooks: %+v", webhooks)
|
|
if len(webhooks) == 0 {
|
|
t.Errorf("expected webhook calls but got none")
|
|
}
|
|
deduped := slices.Clone(webhooks)
|
|
slices.Sort(deduped)
|
|
slices.Compact(deduped)
|
|
if len(deduped) != len(webhooks) {
|
|
t.Errorf("expected no duplicate webhooks but got %+v", webhooks)
|
|
}
|
|
})
|
|
|
|
u, _ := url.Parse(s.URL)
|
|
u.User = url.UserPassword("u", "p")
|
|
main.WebhookOnRecursiveMiss = u.String()
|
|
main.WebhookOnRecursiveMissCacheD = t.TempDir()
|
|
t.Cleanup(func() {
|
|
main.WebhookOnRecursiveMiss = ""
|
|
main.WebhookOnRecursiveMissCacheD = ""
|
|
})
|
|
|
|
was, _ := os.Getwd()
|
|
t.Cleanup(func() { os.Chdir(was) })
|
|
os.Chdir(t.TempDir())
|
|
|
|
outd := t.TempDir()
|
|
os.MkdirAll(path.Join(outd, "A"), os.ModePerm)
|
|
|
|
// use config
|
|
write("./showA/.show-ingestion.yaml", `{
|
|
"c": {
|
|
"title": "A",
|
|
"season": "A",
|
|
"episode": "A"
|
|
},
|
|
"p": [".*"],
|
|
"o": "`+outd+`/A"
|
|
}`)
|
|
write("./showA/file.a")
|
|
|
|
// parse files and const wins
|
|
write("./showB/.show-ingestion.yaml", `{
|
|
"o": "`+outd+`/B_{{.Title}}_{{.Season}}_{{.Episode}}",
|
|
"p": [],
|
|
"c": {"title": "TITLE"}
|
|
}`)
|
|
write("./showB/title S01E02.b")
|
|
|
|
// use file pattern
|
|
write("./dirA/showC/.show-ingestion.yaml", `{
|
|
"o": "`+outd+`/C",
|
|
"p": ["^(?P<title>.) (?P<season>.) (?P<episode>.)"]
|
|
}`)
|
|
write("./dirA/showC/t s e.c")
|
|
|
|
// dry run
|
|
write("./dirA/showD/.show-ingestion.yaml", `{
|
|
"o": "`+outd+`/D",
|
|
"d": true
|
|
}`)
|
|
write("./dirA/showD/title S02E04.d")
|
|
|
|
// not configured
|
|
os.MkdirAll("./dirB/showE", os.ModePerm)
|
|
write("./dirB/showE/title S03E06.e")
|
|
|
|
// defaults
|
|
write("./dirA/showF/.show-ingestion.yaml", `{
|
|
"o": "`+outd+`/F"
|
|
}`)
|
|
write("./dirA/showF/[Yameii] Dr. Stone - S04E12 [English Dub] [CR WEB-DL 720p] [F6EF1948].mkv")
|
|
|
|
if err := main.Recursive(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
} else if err := main.Recursive(context.Background()); err != nil {
|
|
t.Fatalf("failed second run: %v", err)
|
|
}
|
|
|
|
exists(t, path.Join(outd, "A", "A_SAEA.a"))
|
|
exists(t, path.Join(outd, "B_TITLE_01_02", "TITLE_S01E02.b"))
|
|
exists(t, path.Join(outd, "C", "t_SsEe.c"))
|
|
notExists(t, path.Join(outd, "D", "title_S02E04.d"))
|
|
notExists(t, path.Join(outd, "title_S03E06.e"))
|
|
exists(t, path.Join(outd, "F", "Dr_Stone_S04E12.mkv"))
|
|
notExists(t, path.Join(outd, "F", "[Yameii]_Dr_Stone_-_S04E12.mkv"))
|
|
}
|
|
|
|
func write(f string, b ...string) {
|
|
if len(b) == 0 {
|
|
b = append(b, "")
|
|
}
|
|
|
|
os.MkdirAll(path.Dir(f), os.ModePerm)
|
|
os.WriteFile(f, []byte(b[0]), os.ModePerm)
|
|
}
|
|
|
|
func exists(t *testing.T, p string) {
|
|
if _, err := os.Stat(p); os.IsNotExist(err) {
|
|
d := path.Dir(path.Dir(p))
|
|
t.Errorf("expected %s of %s (%+v)", path.Base(p), d, ls(d))
|
|
}
|
|
}
|
|
|
|
func notExists(t *testing.T, p string) {
|
|
if _, err := os.Stat(p); !os.IsNotExist(err) {
|
|
d := path.Dir(path.Dir(p))
|
|
t.Errorf("unexpected %s of %s (%+v)", path.Base(p), d, ls(d))
|
|
}
|
|
}
|
|
|
|
func ls(d string) []string {
|
|
result := []string{}
|
|
entries, _ := os.ReadDir(d)
|
|
for _, entry := range entries {
|
|
p := path.Join(d, entry.Name())
|
|
if entry.IsDir() {
|
|
result = append(result, ls(p)...)
|
|
} else {
|
|
result = append(result, p)
|
|
}
|
|
}
|
|
slices.Sort(result)
|
|
return result
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
cases := map[string]struct {
|
|
pattern string
|
|
want main.Fields
|
|
}{
|
|
"[SubsPlease] Tokidoki Bosotto Russia-go de Dereru Tonari no Alya-san - 01 (720p) [A12844D5].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Tokidoki Bosotto Russia-go de Dereru Tonari no Alya-san",
|
|
Season: "",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"Survivor.AU.S12E11.1080p.HEVC.x265-MeGusta[EZTVx.to].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Survivor.AU",
|
|
Season: "12",
|
|
Episode: "11",
|
|
},
|
|
},
|
|
"DAN DA DAN (2024) S01E01v2 (1080p WEB-DL H264 AAC DDP 2.0 Dual-Audio) [MALD].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "DAN DA DAN (2024)",
|
|
Season: "01",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"ZENSHU.S01E01.1080p.AMZN.WEB-DL.MULTi.DDP2.0.H.264.MSubs-ToonsHub.mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "ZENSHU",
|
|
Season: "01",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"[Yameii] My Hero Academia - S07E08 [English Dub] [CR WEB-DL 720p] [DE5FFC3E].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "My Hero Academia",
|
|
Season: "07",
|
|
Episode: "08",
|
|
},
|
|
},
|
|
"Ranma1-2.2024.S01E03.Because.Theres.Someone.He.Likes.1080p.NF.WEB-DL.AAC2.0.H.264-VARYG.mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Ranma1-2.2024",
|
|
Season: "01",
|
|
Episode: "03",
|
|
},
|
|
},
|
|
"[Yameii] The Apothecary Diaries - S02E03 [English Dub] [CR WEB-DL 720p] [FD3E7434].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "The Apothecary Diaries",
|
|
Season: "02",
|
|
Episode: "03",
|
|
},
|
|
},
|
|
"The.Dinner.Table.Detective.S01E01.Welcome.to.the.murderous.party.File.1.1080p.AMZN.WEB-DL.DDP2.0.H.264-VARYG.mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "The.Dinner.Table.Detective",
|
|
Season: "01",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"[Reza] Wistoria Wand and Sword - S01E01.mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Wistoria Wand and Sword",
|
|
Season: "01",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"[EMBER] Ao no Hako - 01.mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Ao no Hako",
|
|
Season: "",
|
|
Episode: "01",
|
|
},
|
|
},
|
|
"Niehime to Kemono no Ou - 12 [darkflux].mkv": {
|
|
pattern: main.PatternGroupTitleHyphenSE,
|
|
want: main.Fields{
|
|
Title: "Niehime to Kemono no Ou",
|
|
Season: "",
|
|
Episode: "12",
|
|
},
|
|
},
|
|
}
|
|
|
|
for f, d := range cases {
|
|
c := d
|
|
t.Run(f, func(t *testing.T) {
|
|
got, _ := main.Parse(f, c.pattern)
|
|
if got != c.want {
|
|
t.Errorf("expected \n\t%+v but got \n\t%+v", c.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|