Files
MeBox/internal/service/downloads_organize_test.go
T
2026-06-24 12:45:23 +08:00

196 lines
6.0 KiB
Go

package service
import (
"os"
"path/filepath"
"testing"
"go.uber.org/zap"
"github.com/ShukeBta/MediaStationGo/internal/config"
"github.com/ShukeBta/MediaStationGo/internal/model"
)
func TestDownloadCompleteAutoOrganizesContentPath(t *testing.T) {
root := t.TempDir()
src := filepath.Join(root, "downloads", "国产剧", "狂飙.S01E01.2023.1080p.mkv")
dest := filepath.Join(root, "media")
if err := os.MkdirAll(filepath.Dir(src), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(src, []byte("episode"), 0o644); err != nil {
t.Fatal(err)
}
repos := newOrganizerTestRepo(t)
if err := repos.DB.AutoMigrate(&model.DownloadTask{}); err != nil {
t.Fatal(err)
}
for key, value := range map[string]string{
"organizer.auto_after_download": "true",
"organize.target_dir": dest,
"organize.transfer_mode": "copy",
} {
if err := repos.Setting.Set(t.Context(), key, value); err != nil {
t.Fatal(err)
}
}
org := NewOrganizerService(&config.Config{}, zap.NewNop(), repos)
svc := NewDownloadService(zap.NewNop(), repos, NewHub(zap.NewNop()), org)
svc.onTorrentComplete(t.Context(), QBitTorrent{
Hash: "done123",
Name: "狂飙.S01E01.2023.1080p",
Progress: 1,
SavePath: filepath.Join(root, "downloads", "国产剧"),
ContentPath: src,
})
want := filepath.Join(dest, "电视剧", "国产剧", "狂飙", "Season 01", "狂飙 - S01E01.mkv")
if _, err := os.Stat(want); err != nil {
t.Fatalf("auto organized file missing at %q: %v", want, err)
}
if _, err := os.Stat(src); err != nil {
t.Fatalf("copy mode should keep source: %v", err)
}
}
func TestDownloadCompleteAutoOrganizeUsesTaskMediaCategory(t *testing.T) {
root := t.TempDir()
src := filepath.Join(root, "downloads", "Motherhood.of.Taihang.S01E01.2026.1080p.mkv")
dest := filepath.Join(root, "media")
writeOrgFile(t, src, "episode")
repos := newOrganizerTestRepo(t)
if err := repos.DB.AutoMigrate(&model.DownloadTask{}); err != nil {
t.Fatal(err)
}
for key, value := range map[string]string{
"organizer.auto_after_download": "true",
"organize.target_dir": dest,
"organize.transfer_mode": "copy",
} {
if err := repos.Setting.Set(t.Context(), key, value); err != nil {
t.Fatal(err)
}
}
task := &model.DownloadTask{
UserID: "u1",
Source: "qbittorrent",
URL: "magnet:?xt=urn:btih:motherhood",
Title: "Motherhood.of.Taihang.S01E01.2026.1080p",
SavePath: filepath.Join(root, "downloads"),
MediaType: "tv",
MediaCategory: "国产剧",
Status: "completed",
Progress: 1,
}
if err := repos.Download.Create(t.Context(), task); err != nil {
t.Fatal(err)
}
org := NewOrganizerService(&config.Config{}, zap.NewNop(), repos)
svc := NewDownloadService(zap.NewNop(), repos, NewHub(zap.NewNop()), org)
svc.onTorrentComplete(t.Context(), QBitTorrent{
Hash: "done-category",
Name: "Motherhood.of.Taihang.S01E01.2026.1080p",
Progress: 1,
SavePath: filepath.Join(root, "downloads"),
ContentPath: src,
})
categoryRoot := filepath.Join(dest, "电视剧", "国产剧")
var organized string
err := filepath.WalkDir(categoryRoot, func(path string, entry os.DirEntry, err error) error {
if err != nil || entry.IsDir() {
return err
}
if filepath.Ext(path) == ".mkv" {
organized = path
}
return nil
})
if err != nil {
t.Fatalf("walk organized category: %v", err)
}
if organized == "" {
t.Fatalf("expected organized file under %q", categoryRoot)
}
wrongRoot := filepath.Join(dest, "电视剧", "Motherhood Of Taihang")
if _, err := os.Stat(wrongRoot); !os.IsNotExist(err) {
t.Fatalf("unexpected uncategorized organize root %q, err=%v", wrongRoot, err)
}
}
func TestDownloadCompleteOnlyReplacesExistingWhenTaskAllowsWash(t *testing.T) {
for _, tc := range []struct {
name string
allowWash bool
wantContent string
}{
{name: "wash disabled keeps existing", allowWash: false, wantContent: "inception-1080p"},
{name: "wash enabled replaces existing", allowWash: true, wantContent: "inception-2160p"},
} {
t.Run(tc.name, func(t *testing.T) {
root := t.TempDir()
src := filepath.Join(root, "downloads", "Inception 2010 2160p BluRay.mkv")
dest := filepath.Join(root, "media")
existing := filepath.Join(dest, "电影", "Inception (2010)", "Inception (2010).mkv")
writeOrgFile(t, src, "inception-2160p")
writeOrgFile(t, existing, "inception-1080p")
repos := newOrganizerTestRepo(t)
if err := repos.DB.AutoMigrate(&model.DownloadTask{}); err != nil {
t.Fatal(err)
}
for key, value := range map[string]string{
"organizer.auto_after_download": "true",
"organize.target_dir": dest,
"organize.transfer_mode": "copy",
} {
if err := repos.Setting.Set(t.Context(), key, value); err != nil {
t.Fatal(err)
}
}
if err := repos.Media.Upsert(t.Context(), &model.Media{
Title: "Inception",
Path: existing,
Year: 2010,
Container: "mkv",
Width: 1920,
Height: 1080,
}); err != nil {
t.Fatal(err)
}
if err := repos.Download.Create(t.Context(), &model.DownloadTask{
Source: "qbittorrent",
URL: "magnet:?xt=urn:btih:inception",
Title: "Inception 2010 2160p BluRay",
SavePath: filepath.Dir(src),
Status: "completed",
Progress: 1,
AllowExistingLibrary: tc.allowWash,
}); err != nil {
t.Fatal(err)
}
org := NewOrganizerService(&config.Config{}, zap.NewNop(), repos)
svc := NewDownloadService(zap.NewNop(), repos, NewHub(zap.NewNop()), org)
svc.onTorrentComplete(t.Context(), QBitTorrent{
Hash: "inception",
Name: "Inception 2010 2160p BluRay",
Progress: 1,
SavePath: filepath.Dir(src),
ContentPath: src,
})
got, err := os.ReadFile(existing)
if err != nil {
t.Fatal(err)
}
if string(got) != tc.wantContent {
t.Fatalf("existing content = %q, want %q", string(got), tc.wantContent)
}
})
}
}