Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
package search
import (
"91porn-server/app/proto"
"91porn-server/app/service/searcher"
"91porn-server/app/service/searcher/tagsearcher"
"91porn-server/app/service/searcher/tonesearcher"
"91porn-server/app/service/searcher/usersearcher"
"91porn-server/app/service/searcher/vidhkwsearcher"
"91porn-server/app/service/searcher/vidhotsearcher"
"91porn-server/app/service/searcher/vidpcountsearcher"
"91porn-server/app/service/searcher/vidrichsearcher"
"91porn-server/app/service/searcher/vidsearcher"
"91porn-server/app/service/vidhelpser"
"91porn-server/common"
"91porn-server/common/constant"
"91porn-server/common/log"
sli "91porn-server/common/slice"
"91porn-server/models/commod"
"91porn-server/models/v/tagmod"
"91porn-server/models/v/vidmod"
"errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
"strings"
"sync"
"time"
)
type (
NewsKeywordSearchReq struct {
Realm constant.RealmType `form:"realm" json:"realm" binding:"required"` // SP:长视频 SHORT:短视频 COVER:图文帖子 PIC:图集帖子 SEED_LINK:种子/黄油帖子
KeyWords []string `form:"keyWords" json:"keyWords" binding:"required"` // 关键字
SortType int `form:"sortType" json:"sortType"` // 1最多观看 2最新上架 3最多收藏
commod.Page
}
NewsKeywordSearchRep struct {
List any `json:"list"` // 数据列表(ACG和帖子不同格式)
TagID string `json:"tagID"` // 帖子搜索时附带的tagID
TagVidList []*vidmod.VideoInfo `json:"tagVidList"` // 搜索时tag相关的帖子
HasNext bool `json:"hasNext"` // 是否还有下一页
}
)
func (req *NewsKeywordSearchReq) Search(uid uint64) (rep NewsKeywordSearchRep, err error) {
var search searcher.Searcher
switch req.Realm {
case constant.SearchComplex:
search = vidrichsearcher.NewVidRichSearcher(uid)
case constant.SearchUser:
search = usersearcher.NewUserSearcher(uid)
case constant.SearchSP, constant.SearchShort, constant.SearchCover, constant.SearchPic:
search = vidsearcher.NewVidSearcher(uid, req.Realm, req.SortType)
case constant.SearchTag:
search = tagsearcher.NewTagSearcher(&uid)
default:
return rep, errors.New("search Realm is invaild")
}
kw := &searcher.Keyword{Word: strings.Join(req.KeyWords, "|")}
opt := (&searcher.Option{}).SetSkip(req.Skip64()).SetLimit(req.Limit64())
result, err := search.Search(kw, opt)
if err != nil {
return rep, err
}
rep.List = result.Data()
rep.HasNext = result.HasNext()
if req.Realm == constant.SearchSP || req.Realm == constant.SearchShort {
// 额外获取TAG相关信息
tagId, err := tagmod.GetTagIDByName(req.KeyWords[0])
if err != nil || tagId.IsZero() {
return rep, nil
}
// 6-最多收藏
limit := int64(4)
if req.Realm == constant.SearchShort {
limit = 6
}
filter := bson.M{"tags": tagId, "status": 1, "newsType": req.Realm}
sort := bson.D{{"collectCount", -1}, {"reviewAt", -1}}
opts := options.Find().SetLimit(limit).SetSort(sort)
tagVideos, _, err := vidmod.FindList(filter, opts)
if err != nil {
return rep, err
}
rep.TagID = tagId.Hex()
rep.TagVidList = vidhelpser.EncodeVideoInfoForSearch(uid, tagVideos)
}
return rep, nil
}
// GetHome
// 热点视屏 通过hOpt设置
// 最热视屏 通过hsOpt设置
// 音色入口 固定7个
func GetHome(uid uint64, hOpt, hsOpt searcher.Opter) Home {
//热点
vidHKWSearcher := vidhkwsearcher.NewVidHKWSearcher(uid, (&searcher.Option{}).SetLimit(1))
//最热视屏
vidHotSearcher := vidhotsearcher.NewVidHotSearcher(uid)
//音色
toneSearcher := tonesearcher.NewToneSearcher()
now := time.Now()
var (
home Home
sumDate = searcher.NewSumDate(now)
hVidRes, hsVidRes, toneRes searcher.Resulter
wg = sync.WaitGroup{}
)
wg.Add(3)
common.Go(func() { //热点
defer wg.Done()
res, err := vidHKWSearcher.Search(sumDate, hOpt)
if err != nil {
log.Error("vidHKWSearcher search faild!", log.E(err))
return
}
hVidRes = res
if res.Count() >= hOpt.Limit() { //查找出来的视屏数量足够 不用替换视屏
return
}
//查找出来的视屏数量不够,用最多播放视屏替换
res, err = vidpcountsearcher.NewVidPlayCountSearcher(uid).Search(nil, hOpt)
if err != nil {
log.Error("vidpcountsearcher search faild!", log.E(err))
return
}
hVidRes = res
})
common.Go(func() { //最热视屏
defer wg.Done()
res, err := vidHotSearcher.Search(nil, hsOpt)
if err != nil {
log.Error("vidHotSearcher search faild!", log.E(err))
//失败 返回原始搜索结果
return
}
hsVidRes = res
})
common.Go(func() { //音色
defer wg.Done()
res, err := toneSearcher.Search(nil, nil)
if err != nil {
log.Error("toneSearcher search faild!", log.E(err))
//失败 返回原始搜索结果
return
}
toneRes = res
})
wg.Wait()
//热点
if hVidRes != nil {
home.HVidList = hVidRes.Data().([]vidhkwsearcher.VideoRes)
}
//今日最热视屏
if hsVidRes != nil {
home.HSVidList = hsVidRes.Data().([]vidhotsearcher.VideoRes)
}
//音色
if toneRes != nil {
home.ToneList = toneRes.Data().([]tonesearcher.ToneRes)
}
return home
}
func GetWonderTagList(skip, limit int64) ([]vidmod.TagInfo, bool, error) {
limitEx1 := limit + 1
tags, err := tagmod.WonderTags(skip, limitEx1)
if err != nil {
return nil, false, err
}
hasNext := false
if len(tags) > int(limit) {
hasNext = true
tags = tags[:limit]
}
log.Debug("GetWonderTagList", log.Any("skip", skip), log.Any("limit", limit), log.Any("hasNext", hasNext))
return tags, hasNext, nil
}
func GetHotTag() ([]interface{}, error) {
tags, _, err := tagmod.GetTagListMostPlayed(commod.Page{
PageNumber: 1,
PageSize: 10,
})
if err != nil {
return nil, err
}
data := make([]interface{}, len(tags))
for i := range tags {
data[i] = proto.Tag{
ID: tags[i].ID,
Name: tags[i].TagName,
Hot: tags[i].TPlayCount,
}
}
sli.Shuffle(data)
return data, nil
}
+12
View File
@@ -0,0 +1,12 @@
package search
import (
"91porn-server/app/service/searcher"
"91porn-server/app/service/searcher/tonesearcher"
)
type Home struct {
HVidList []searcher.VideoRes `json:"hVidList"` //热点
HSVidList []searcher.VideoRes `json:"hsVidList"` //最热视屏(最多播放)
ToneList []tonesearcher.ToneRes `json:"toneList"` //音色
}