feat: 添加动漫色情检测(WD Tagger v3),媒体库展示优化
- 新增 anime_nsfw 模块:WD Tagger v3 模型检测动漫/二次元图片 - 修复误判:当 general 评分最高时判定为安全,避免非动漫图误判 - 数据库存储四个 rating 原始分数(JSON),无需重扫即可查看 - 媒体库新增动漫色情检测列、文件路径列(支持一键复制) - 修复预览图加载占位符显示两个点的问题 - 移动文件按钮不再限制扫描完成后才显示
This commit is contained in:
@@ -49,6 +49,9 @@ type MediaInfo struct {
|
||||
TailMd5 string `xorm:"char(32) index('idx_fp') 'tail_md5'" json:"tailMd5"` // 文件尾 256KB 的 MD5(指纹用)
|
||||
NsfwScore float64 `xorm:"real 'nsfw_score'" json:"nsfwScore"` // NSFW 检测分 0~1(0 表示未检测或非图片)
|
||||
NsfwThreshold float64 `xorm:"real 'nsfw_threshold'" json:"nsfwThreshold"` // NSFW 判定阈值
|
||||
AnimeNsfwScore float64 `xorm:"real 'anime_nsfw_score'" json:"animeNsfwScore"` // 动漫 NSFW 检测分 0~1(0 表示未检测或非动漫)
|
||||
AnimeNsfwThreshold float64 `xorm:"real 'anime_nsfw_threshold'" json:"animeNsfwThreshold"` // 动漫 NSFW 判定阈值
|
||||
AnimeNsfwRatings string `xorm:"text 'anime_nsfw_ratings'" json:"animeNsfwRatings"` // WD Tagger 四个 rating 的 JSON(G/S/Q/E)
|
||||
ManualNsfw string `xorm:"varchar(1) 'manual_nsfw'" json:"manualNsfw"` // 手动标记是否色情:Y/N,默认 N
|
||||
CreatedAt time.Time `xorm:"created 'created_at'" json:"createdAt"` // 首次入库时间
|
||||
UpdatedAt time.Time `xorm:"updated 'updated_at'" json:"updatedAt"` // 最近更新时间
|
||||
@@ -190,6 +193,18 @@ func (s *Store) SaveScanLogs(entries []ScanLog) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// HasScanLog 检查是否有扫描记录(用于判断是否可以直接移动文件)。
|
||||
func (s *Store) HasScanLog() (bool, error) {
|
||||
if s == nil || s.engine == nil {
|
||||
return false, nil
|
||||
}
|
||||
total, err := s.engine.Count(new(ScanLog))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return total > 0, nil
|
||||
}
|
||||
|
||||
// ClearScanLog 清空全部续传记录。移动完成后调用。
|
||||
func (s *Store) ClearScanLog() error {
|
||||
if s == nil || s.engine == nil {
|
||||
@@ -220,6 +235,27 @@ func (s *Store) UpdateMediaFilePaths(moved map[string]string) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// AvgManualNsfwScore 计算 manual_nsfw='Y' 的记录的 nsfw_score 均值。
|
||||
func (s *Store) AvgManualNsfwScore() (float64, error) {
|
||||
if s == nil || s.engine == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var result struct {
|
||||
Avg float64 `xorm:"avg"`
|
||||
}
|
||||
has, err := s.engine.Table("media_info").
|
||||
Select("AVG(nsfw_score) as avg").
|
||||
Where("manual_nsfw = 'Y'").
|
||||
Get(&result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !has {
|
||||
return 0, nil
|
||||
}
|
||||
return result.Avg, nil
|
||||
}
|
||||
|
||||
// UpdateManualNsfw 更新单条记录的手动色情标记。
|
||||
func (s *Store) UpdateManualNsfw(id int64, value string) error {
|
||||
if s == nil || s.engine == nil {
|
||||
|
||||
Reference in New Issue
Block a user