优化兼容性

This commit is contained in:
truewhile
2026-10-11 23:44:11 +08:00
parent 3c30c64a39
commit 079b3ff063
23 changed files with 1246 additions and 142 deletions
@@ -0,0 +1,82 @@
package service
import (
"strings"
"testing"
"github.com/truewhile/MeBox/internal/model"
)
// TestLikelyEpisodicPathSQLNormalisesSeparator 守住剧集路径判定的转义差异。
//
// 此前 embyLikelyEpisodicPathSQL 会额外生成一份反斜杠模式
// (strings.ReplaceAll(pattern, "/", `\`))。PostgreSQL 的 LIKE 默认就把反斜杠
// 当转义符,模式结尾的 `\%` 被解析成「字面百分号」而不是「反斜杠 + 通配符」,
// 那些模式在 PostgreSQL 下永不命中;SQLite 没有默认转义符所以一直正常。
// 现在统一在 SQL 里把分隔符归一化成 '/',模式本身不再含反斜杠。
func TestLikelyEpisodicPathSQLNormalisesSeparator(t *testing.T) {
clause, args := embyLikelyEpisodicPathSQL()
if !strings.Contains(clause, "REPLACE(media.path") {
t.Fatalf("clause no longer normalises the path separator:\n%s", clause)
}
if got := strings.Count(clause, "LIKE ?"); got != len(args) {
t.Fatalf("clause has %d placeholders but %d args:\n%s", got, len(args), clause)
}
for _, arg := range args {
pattern, ok := arg.(string)
if !ok {
t.Fatalf("unexpected pattern type %T", arg)
}
if strings.Contains(pattern, `\`) {
t.Fatalf("pattern %q still contains a backslash; PostgreSQL's LIKE would treat it as an escape character", pattern)
}
if !strings.Contains(pattern, "/") {
t.Fatalf("pattern %q lost its separator", pattern)
}
}
}
// TestFilterLikelyEpisodicPathsHandlesWindowsStylePaths 验证反斜杠路径(Windows
// 宿主机入库的媒体)仍然被判成剧集并从电影库查询里排除。
func TestFilterLikelyEpisodicPathsHandlesWindowsStylePaths(t *testing.T) {
db := newServiceTestDB(t)
episodic := model.Media{
Base: model.Base{ID: "ep-1"},
Path: `D:\Media\国产剧\我的剧\Season 1\我的剧 - S01E01.mkv`,
SeasonNum: 1,
EpisodeNum: 1,
}
movie := model.Media{
Base: model.Base{ID: "mv-1"},
Path: `D:\Media\电影\某电影\某电影.mkv`,
}
if err := db.Create(&episodic).Error; err != nil {
t.Fatal(err)
}
if err := db.Create(&movie).Error; err != nil {
t.Fatal(err)
}
q := filterLikelyEpisodicPathsFromMovieQuery(
db.Model(&model.Media{}).Where("season_num > 0 OR episode_num > 0"),
)
var rows []model.Media
if err := q.Find(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) != 0 {
t.Fatalf("windows-style episodic path was not excluded, got %d rows", len(rows))
}
// 反证:电影类型的行必须保留。
var kept []model.Media
keepQ := filterLikelyEpisodicPathsFromMovieQuery(
db.Model(&model.Media{}).Where("path LIKE ?", `D:\Media\电影\%`),
)
if err := keepQ.Find(&kept).Error; err != nil {
t.Fatal(err)
}
if len(kept) != 1 || kept[0].ID != "mv-1" {
t.Fatalf("plain movie row was dropped from the movie query: %+v", kept)
}
}