package contentreviewser import ( "91porn-server/common/log" "91porn-server/models/v/contentreviewmod" "91porn-server/models/v/mediacontentmod" "91porn-server/models/v/mediamod" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) // acgScanner ACG 扫描策略:每个 Media 可能产生 1 个 ACG_MEDIA + N 个 ACG_CONTENT 命中 // 仅匹配 title / summary / 章节名 / 章节内容(不检测 tag) type acgScanner struct{} func (s *acgScanner) CountTotal() (int64, error) { return mediamod.CountForReview() } func (s *acgScanner) ScanBatch(taskID, lastID primitive.ObjectID, terms []string) (*ScanResult, error) { batch, err := mediamod.FindForReviewBatch(lastID, scanBatchSize) if err != nil { return nil, err } if len(batch) == 0 { return &ScanResult{Done: true}, nil } issues := make([]*contentreviewmod.ReviewIssue, 0) for _, m := range batch { issues = append(issues, collectMediaIssues(taskID, m, terms)...) } return &ScanResult{ Issues: issues, Checked: int64(len(batch)), NextID: batch[len(batch)-1].ID, }, nil } // collectMediaIssues 检测一个 Media 自身及其全部 MediaContent func collectMediaIssues(taskID primitive.ObjectID, m *mediamod.Media, terms []string) []*contentreviewmod.ReviewIssue { out := make([]*contentreviewmod.ReviewIssue, 0) mb := newIssueBuilder(taskID, contentreviewmod.IssueTargetACGMedia, m.ID). MatchTitle("标题", m.Title, terms). MatchContent("内容", m.Summary, terms) if mb.HasHits() { out = append(out, mb.Build()) } contents, err := mediacontentmod.QueryAllList(bson.M{"mediaId": m.ID, "isActive": true}) if err != nil { log.Warn("query media contents fail", log.Any("mid", m.ID), log.E(err)) return out } for _, c := range contents { cb := newIssueBuilder(taskID, contentreviewmod.IssueTargetACGContent, c.ID). WithMediaID(m.ID). MatchTitle("章节名", c.Name, terms). MatchContent("章节内容", c.Text, terms) if cb.HasHits() { out = append(out, cb.Build()) } } return out }