refactor scraper query helpers by responsibility

This commit is contained in:
ShukeBta
2026-06-26 20:51:42 +08:00
parent ba5262b648
commit a158039a13
3 changed files with 302 additions and 292 deletions
+159
View File
@@ -0,0 +1,159 @@
package service
import "strings"
func mediaFolderTitle(mediaPath, libraryRoot string) string {
dir := parentSlashPath(mediaPath)
root := comparableLibraryRoot(libraryRoot)
for depth := 0; depth < 5 && dir != ""; depth++ {
if root != "" && sameSlashPath(dir, root) {
return libraryRootTitle(libraryRoot)
}
base := pathBaseSlash(dir)
if base == "" || base == "." {
return ""
}
if isTechnicalMediaFolder(base) || strictSeasonFolderMatched(base) {
dir = parentSlashPath(dir)
continue
}
if isGenericMediaCategoryFolder(base) {
return ""
}
title, _ := CleanQuery(base)
if title == "" {
title = strings.TrimSpace(base)
}
return strings.TrimSpace(title)
}
return ""
}
func isTechnicalMediaFolder(name string) bool {
key := strings.ToLower(strings.TrimSpace(name))
compact := strings.NewReplacer(" ", "", "_", "", ".", "", "-", "").Replace(key)
switch compact {
case "bdmv", "stream", "certificate", "videots", "audiots",
"subs", "subtitles", "subtitle", "sample", "samples",
"extra", "extras", "featurette", "featurettes":
return true
default:
return numberedTechnicalFolder(compact, "disc") ||
numberedTechnicalFolder(compact, "disk") ||
numberedTechnicalFolder(compact, "cd") ||
numberedTechnicalFolder(compact, "dvd") ||
numberedTechnicalFolder(compact, "part")
}
}
func numberedTechnicalFolder(value, prefix string) bool {
if !strings.HasPrefix(value, prefix) || len(value) == len(prefix) {
return false
}
for _, r := range value[len(prefix):] {
if r < '0' || r > '9' {
return false
}
}
return true
}
func cleanSlashPath(value string) string {
value = strings.TrimSpace(strings.ReplaceAll(value, "\\", "/"))
return strings.TrimRight(value, "/")
}
func comparableLibraryRoot(libraryRoot string) string {
if info, ok := ParseCloudLibraryMount(libraryRoot); ok {
if strings.TrimSpace(info.DisplayDir) == "" {
return "cloud://" + info.Provider
}
return "cloud://" + info.Provider + "/" + info.DisplayDir
}
return cleanSlashPath(libraryRoot)
}
func sameSlashPath(a, b string) bool {
return strings.EqualFold(cleanSlashPath(a), cleanSlashPath(b))
}
func parentSlashPath(value string) string {
value = cleanSlashPath(value)
if value == "" {
return ""
}
idx := strings.LastIndex(value, "/")
if idx < 0 {
return ""
}
return strings.TrimRight(value[:idx], "/")
}
func seriesFolderTitle(mediaPath, libraryRoot string) string {
dir := parentSlashPath(mediaPath)
if strictSeasonFolderMatched(pathBaseSlash(dir)) {
dir = parentSlashPath(dir)
}
if root := comparableLibraryRoot(libraryRoot); root != "" && sameSlashPath(dir, root) {
return libraryRootTitle(libraryRoot)
}
base := pathBaseSlash(dir)
if base == "" || base == "." {
return ""
}
if isGenericMediaCategoryFolder(base) || isTechnicalMediaFolder(base) || strictSeasonFolderMatched(base) {
return ""
}
return base
}
func libraryRootTitle(libraryRoot string) string {
base := ""
if info, ok := ParseCloudLibraryMount(libraryRoot); ok {
base = pathBaseSlash(info.DisplayDir)
} else {
base = pathBaseSlash(libraryRoot)
}
if base == "" || base == "." || isGenericMediaCategoryFolder(base) || isTechnicalMediaFolder(base) || strictSeasonFolderMatched(base) {
return ""
}
return base
}
func isGenericMediaCategoryFolder(name string) bool {
key := strings.ToLower(strings.TrimSpace(name))
key = strings.Trim(key, `\/`)
switch key {
case "",
"电影", "movies", "movie",
"电视剧", "剧集", "tv", "shows", "series",
"动漫", "动画", "anime", "bangumi",
"国产剧", "国剧", "大陆剧", "国产电视剧",
"欧美剧", "欧美电视剧",
"日韩剧", "日剧", "韩剧",
"华语电影", "国产电影", "大陆电影",
"外语电影", "欧美电影", "日韩电影",
"动画电影", "动漫电影",
"国漫", "国产动漫", "日番", "日漫", "日本动漫", "日本动画", "欧美动漫", "欧美动画", "西方动画",
"综艺", "真人秀",
"纪录片", "纪录",
"儿童", "少儿",
"成人", "番号", "9kg",
"未分类", "uncategorized":
return true
default:
return false
}
}
func strictSeasonFolder(name string) int {
if season, ok := seasonFromDir(name); ok {
return season
}
return 0
}
func strictSeasonFolderMatched(name string) bool {
_, ok := seasonFromDir(name)
return ok
}