package service
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/truewhile/MeBox/internal/model"
)
func TestWriteMediaNFOUsesMappedDestinationPath(t *testing.T) {
root := t.TempDir()
t.Setenv("MEBOX_MEDIA_DIR", root)
t.Setenv("MEBOX_MEDIA_CONTAINER_DIR", "/media")
mediaPath := filepath.Join(root, "电影", "测试电影.mkv")
if err := os.MkdirAll(filepath.Dir(mediaPath), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(mediaPath, []byte("media"), 0o644); err != nil {
t.Fatal(err)
}
got, err := WriteMediaNFO(&model.Media{
Title: "测试电影",
Path: "/media/电影/测试电影.mkv",
Year: 2026,
})
if err != nil {
t.Fatal(err)
}
want := filepath.Join(root, "电影", "测试电影.nfo")
if got != want {
t.Fatalf("nfo path = %q, want %q", got, want)
}
if _, err := os.Stat(want); err != nil {
t.Fatal(err)
}
}
func TestWriteMediaNFOUsesEpisodeTitleForEpisodeDetails(t *testing.T) {
root := t.TempDir()
mediaPath := filepath.Join(root, "剧集", "间谍过家家", "Season 02", "间谍过家家 - S02E01.mkv")
if err := os.MkdirAll(filepath.Dir(mediaPath), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(mediaPath, []byte("media"), 0o644); err != nil {
t.Fatal(err)
}
got, err := WriteMediaNFO(&model.Media{
Title: "间谍过家家",
OriginalName: "SPY×FAMILY",
EpisodeTitle: "任务代号: 猫",
Path: mediaPath,
SeasonNum: 2,
EpisodeNum: 1,
})
if err != nil {
t.Fatal(err)
}
body, err := os.ReadFile(got)
if err != nil {
t.Fatal(err)
}
text := string(body)
if !strings.Contains(text, "
任务代号: 猫") || !strings.Contains(text, "间谍过家家") {
t.Fatalf("episode nfo did not keep episode/show titles separate:\n%s", text)
}
}
func TestWriteMediaNFOAdultTitleWithCode(t *testing.T) {
root := t.TempDir()
mediaPath := filepath.Join(root, "成人", "IPZZ-090-测试成人影片", "IPZZ-090.mp4")
if err := os.MkdirAll(filepath.Dir(mediaPath), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(mediaPath, []byte("media"), 0o644); err != nil {
t.Fatal(err)
}
got, err := WriteMediaNFO(&model.Media{
Title: "测试成人影片",
OriginalName: "IPZZ-090",
Path: mediaPath,
NSFW: true,
})
if err != nil {
t.Fatal(err)
}
body, err := os.ReadFile(got)
if err != nil {
t.Fatal(err)
}
text := string(body)
if !strings.Contains(text, "IPZZ-090-测试成人影片") {
t.Fatalf("expected title with code at front in adult nfo, got:\n%s", text)
}
if !strings.Contains(text, "IPZZ-090") {
t.Fatalf("expected originaltitle with code, got:\n%s", text)
}
}
func TestWriteMediaNFORoundTripsExternalUniqueIDs(t *testing.T) {
root := t.TempDir()
mediaPath := filepath.Join(root, "云下载", "sivr-270", "sivr-270-1.strm")
if err := os.MkdirAll(filepath.Dir(mediaPath), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(mediaPath, []byte("strm"), 0o644); err != nil {
t.Fatal(err)
}
dst, err := WriteMediaNFO(&model.Media{
Title: "SIVR-270-河北彩花",
OriginalName: "SIVR-270",
Path: mediaPath,
Year: 2023,
NSFW: true,
DoubanID: "SIVR-270",
TheTVDBID: "JavBus",
})
if err != nil {
t.Fatal(err)
}
body, err := os.ReadFile(dst)
if err != nil {
t.Fatal(err)
}
text := string(body)
// 成人条目把番号/provider 借用存在 douban/thetvdb 两列;sidecar 必须把它们
// 带回来,否则「在线刮削 → 写 NFO → 重扫读 NFO」之后同一部片会被按不同
// 分组键拆成多张卡。
for _, want := range []string{
`SIVR-270`,
`JavBus`,
} {
if !strings.Contains(text, want) {
t.Fatalf("sidecar missing %s, got:\n%s", want, text)
}
}
meta, err := ReadLocalMetadata(mediaPath, "", false)
if err != nil {
t.Fatal(err)
}
if meta == nil || meta.DoubanID != "SIVR-270" || meta.TheTVDBID != "JavBus" {
t.Fatalf("external ids did not round trip: %#v", meta)
}
}