mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-12 08:16:37 +08:00
fix(media): 修复emby电影库混入剧集/特别篇识别/剧集合集 + 新增手动编辑元数据
emby 兼容层(hills/yamby 等客户端): - 电影库不再混入剧集:filterLikelyEpisodicPathsFromMovieQuery 按路径 特征(Season/S0x/Specials/电视剧/日番/国漫等)剔除误入电影库的剧集 - itemPayload 改用 mediaShouldBeEpisode:有季集号且(属剧集库或路径像剧集) 才标记为 Episode,修正电影库里剧集被当成 Movie 特别篇识别: - episode_parser 新增 patSpecialSeason,识别 S0/Season 0/Specials/SP/OVA/ OAD/番外/特别篇/特典 文件夹 → 第0季;seasonFromParents 返回 found 标志, 区分"明确第0季"与"未识别默认第1季" - emby seasonDir 正则同步支持 Specials/SP/OVA/特别篇 等 剧集合集: - groupSeries 抽出 isSeriesCard,卡片链接按是否剧集判定,修复剧集卡片 跳转;每集分离的根因(季集号/分组key)随入库识别修复一并改善 手动编辑元数据(自采集视频无TMDB信息时可自定义封面/标题/简介/分类): - 新增 MediaService.UpdateMetadata + PATCH /media/:id/metadata(需admin) - 前端 MetadataEditDialog 接入 LibraryPage 与 MediaDetailPage 其他:scanner/scraper/nfo/local+cloud_metadata/adult 元数据识别配套改进; .gitignore 忽略本地 .dev-cache/.dev-data 运行产物。
This commit is contained in:
@@ -67,6 +67,7 @@ func (s *ScraperService) ManualSearch(ctx context.Context, media *model.Media, q
|
||||
Source: source,
|
||||
MediaType: typ,
|
||||
Title: match.Title,
|
||||
OriginalName: match.OriginalName,
|
||||
Overview: match.Overview,
|
||||
PosterURL: match.PosterURL,
|
||||
BackdropURL: match.BackdropURL,
|
||||
@@ -77,9 +78,18 @@ func (s *ScraperService) ManualSearch(ctx context.Context, media *model.Media, q
|
||||
DoubanID: match.DoubanID,
|
||||
TheTVDBID: match.TheTVDBID,
|
||||
SubscribeKeyword: buildSubscribeKeyword(match.Title, match.Year),
|
||||
Languages: match.Languages,
|
||||
Countries: match.Countries,
|
||||
Genres: match.Genres,
|
||||
NSFW: match.NSFW,
|
||||
})
|
||||
}
|
||||
|
||||
if provider == "all" || provider == "adult" {
|
||||
for _, match := range s.manualAdultMatches(ctx, media, query) {
|
||||
add("adult", "adult", match)
|
||||
}
|
||||
}
|
||||
if provider == "all" || provider == "tmdb" {
|
||||
for _, match := range s.manualTMDbMatches(ctx, query, year, mediaType) {
|
||||
typ := mediaType
|
||||
@@ -165,6 +175,10 @@ func (s *ScraperService) manualRequestMatch(ctx context.Context, req ManualScrap
|
||||
return mergeManualRequestIntoMatch(match, req), nil
|
||||
}
|
||||
}
|
||||
case source == "adult":
|
||||
if match := s.manualAdultMatch(ctx, firstText(req.OriginalName, req.Title)); match != nil {
|
||||
return mergeManualRequestIntoMatch(match, req), nil
|
||||
}
|
||||
}
|
||||
return fallback()
|
||||
}
|
||||
@@ -180,18 +194,52 @@ func (s *ScraperService) manualTMDbMatches(ctx context.Context, query string, ye
|
||||
}
|
||||
out := make([]*Match, 0, 2)
|
||||
if mediaType == "" || mediaType == "movie" {
|
||||
if match, err := s.tmdb.SearchMovie(ctx, query, year); err == nil && match != nil {
|
||||
out = append(out, match)
|
||||
if matches, err := s.tmdb.SearchMovieCandidates(ctx, query, year); err == nil {
|
||||
out = append(out, matches...)
|
||||
}
|
||||
}
|
||||
if mediaType == "" || mediaType == "tv" || mediaType == "anime" || mediaType == "variety" {
|
||||
if match, err := s.tmdb.SearchTV(ctx, query, year); err == nil && match != nil {
|
||||
if matches, err := s.tmdb.SearchTVCandidates(ctx, query, year); err == nil {
|
||||
out = append(out, matches...)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *ScraperService) manualAdultMatches(ctx context.Context, media *model.Media, query string) []*Match {
|
||||
candidates := []string{query}
|
||||
if media != nil {
|
||||
candidates = append(candidates, media.Path, media.OriginalName, media.Title)
|
||||
}
|
||||
out := make([]*Match, 0, 1)
|
||||
seen := map[string]struct{}{}
|
||||
for _, candidate := range candidates {
|
||||
code := normalizeAdultCode(candidate)
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[code]; ok {
|
||||
continue
|
||||
}
|
||||
seen[code] = struct{}{}
|
||||
if match := s.manualAdultMatch(ctx, code); match != nil {
|
||||
out = append(out, match)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *ScraperService) manualAdultMatch(ctx context.Context, code string) *Match {
|
||||
if s.adult == nil || !s.adult.Enabled() {
|
||||
return nil
|
||||
}
|
||||
match, err := s.adult.Search(ctx, code)
|
||||
if err != nil || match == nil {
|
||||
return nil
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
func (s *ScraperService) manualTMDbMatchByID(ctx context.Context, id int, mediaType string) *Match {
|
||||
if s.tmdb == nil || !s.tmdb.Enabled() || id <= 0 {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user