mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 20:46:37 +08:00
feat: 实现智能分类功能
- 配置模型扩展(OrganizerConfig:smart_classify + categories) - 数据模型扩展(Media:languages/countries/genres 字段) - TMDbProvider 增强(GetDetails 方法获取扩展元数据) - Scraper 服务增强(保存 languages/countries/genres 到数据库) - Organizer 智能分类逻辑(根据元数据自动分类到子目录) - 前端 SettingsPage 添加智能分类开关 - 后端支持从数据库读取 organizer.smart_classify 设置 Task #90-94 完成,Task #95 部分完成
This commit is contained in:
@@ -154,6 +154,34 @@ func (s *ScraperService) EnrichOne(ctx context.Context, m *model.Media) error {
|
||||
if match.BangumiID > 0 {
|
||||
updates["bangumi_id"] = match.BangumiID
|
||||
}
|
||||
|
||||
// Fetch extended metadata (languages, countries, genres) from TMDb
|
||||
if match.TMDbID > 0 && s.tmdb != nil && s.tmdb.Enabled() {
|
||||
mediaType := s.determineMediaType(lib, match)
|
||||
details, err := s.tmdb.GetDetails(ctx, match.TMDbID, mediaType)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to get details from tmdb",
|
||||
zap.Int("tmdb_id", match.TMDbID),
|
||||
zap.String("type", mediaType),
|
||||
zap.Error(err))
|
||||
} else if details != nil {
|
||||
if len(details.Languages) > 0 {
|
||||
updates["languages"] = strings.Join(details.Languages, ",")
|
||||
}
|
||||
if len(details.Countries) > 0 {
|
||||
updates["countries"] = strings.Join(details.Countries, ",")
|
||||
}
|
||||
if len(details.Genres) > 0 {
|
||||
updates["genres"] = strings.Join(details.Genres, ",")
|
||||
}
|
||||
s.log.Debug("enrich: saved extended metadata",
|
||||
zap.String("media_id", m.ID),
|
||||
zap.Strings("languages", details.Languages),
|
||||
zap.Strings("countries", details.Countries),
|
||||
zap.Strings("genres", details.Genres))
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.repo.DB.Model(&model.Media{}).Where("id = ?", m.ID).
|
||||
Updates(updates).Error; err != nil {
|
||||
return err
|
||||
@@ -242,3 +270,19 @@ func (s *ScraperService) AnyEnabled() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// determineMediaType returns "tv" for TV shows and "movie" for movies.
|
||||
// It uses the library type as the primary signal.
|
||||
func (s *ScraperService) determineMediaType(lib *model.Library, match *Match) string {
|
||||
if lib != nil {
|
||||
switch lib.Type {
|
||||
case "tv", "anime":
|
||||
return "tv"
|
||||
}
|
||||
}
|
||||
// Fallback: if Bangumi ID is present, treat as TV/anime
|
||||
if match != nil && match.BangumiID > 0 {
|
||||
return "tv"
|
||||
}
|
||||
return "movie"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user