Files
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

339 lines
11 KiB
Go

package laosijiser
import (
"91porn-server/common"
"91porn-server/common/constant/redisconst"
"91porn-server/common/laosiji"
"91porn-server/common/log"
"91porn-server/models/v/mediamod"
"91porn-server/models/v/tagmod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"91porn-server/web/service/vidser"
"91porn-server/web/webg"
"context"
"errors"
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
func MovieSearch(ctx context.Context, param laosiji.MovieSearchReq) (resp laosiji.MovieSearchResp, err error) {
var yuanresp laosiji.MovieSearchResp
yuanresp, err = laosiji.MovieSearch(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
//是否导入
taskIds := make([]string, 0)
for _, v := range yuanresp.Data {
taskIds = append(taskIds, v.Id)
}
resp = laosiji.MovieSearchResp{
Data: make([]laosiji.MovieInfo, 0),
Total: yuanresp.Total,
Current_page: yuanresp.Current_page,
Page_size: yuanresp.Page_size,
Last_page: yuanresp.Last_page,
}
if param.Position == "guochan" || param.Position == "av" || param.Position == "douyin" || param.Position == "dark" {
videoList, _ := vidmod.GetList(bson.M{"sourceID": bson.M{"$in": taskIds}})
// 处理域名
for _, movieInfo := range yuanresp.Data {
//movieInfo.Img_x = common.JoinUrlPath(laosiji.IMAGEYUAN, movieInfo.Img_x)
//movieInfo.Img_y = common.JoinUrlPath(laosiji.IMAGEYUAN, movieInfo.Img_y)
movieInfo.Img_x = common.JoinUrlPath("laosiji", movieInfo.Img_x)
movieInfo.Img_y = common.JoinUrlPath("laosiji", movieInfo.Img_y)
for _, videoInfo := range videoList {
if videoInfo.SourceID == movieInfo.Id {
movieInfo.IsAdd = true
continue
}
}
resp.Data = append(resp.Data, movieInfo)
}
} else if param.Position == "cartoon" {
mediaList, _ := mediamod.GetListByLsjIds(taskIds)
for _, movieInfo := range yuanresp.Data {
//movieInfo.Img_x = common.JoinUrlPath(laosiji.IMAGEYUAN, movieInfo.Img_x)
//movieInfo.Img_y = common.JoinUrlPath(laosiji.IMAGEYUAN, movieInfo.Img_y)
movieInfo.Img_x = common.JoinUrlPath("laosiji", movieInfo.Img_x)
movieInfo.Img_y = common.JoinUrlPath("laosiji", movieInfo.Img_y)
for _, videoInfo := range mediaList {
if videoInfo.LsjId == movieInfo.Id {
movieInfo.IsAdd = true
continue
}
}
resp.Data = append(resp.Data, movieInfo)
}
} else {
err = errors.New("该资源暂不支持")
}
return resp, nil
}
func MovieDetail(ctx context.Context, param laosiji.MovieDetailReq) (resp laosiji.MovieDetailResp, err error) {
resp, err = laosiji.MovieDetail(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
// 处理域名
//resp.Img_x = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Img_x)
//resp.Img_y = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Img_y)
resp.Img_x = common.JoinUrlPath("laosiji", resp.Img_x)
resp.Img_y = common.JoinUrlPath("laosiji", resp.Img_y)
for key, value := range resp.Preview_images {
//resp.Preview_images[key] = common.JoinUrlPath(laosiji.IMAGEYUAN, value)
resp.Preview_images[key] = common.JoinUrlPath("laosiji", value)
}
for key, value := range resp.Links {
resp.Links[key].M3u8_url = laosiji.MovieM3u8OriginURL(value.M3u8_url)
resp.Links[key].Preview_m3u8_url = laosiji.MovieM3u8OriginURL(value.Preview_m3u8_url)
resp.Links[key].Hevc_m3u8_url = laosiji.MovieM3u8OriginURL(value.Hevc_m3u8_url)
}
return resp, nil
}
func MovieAddList(ctx context.Context, param laosiji.MovieAddListReq, manager string) ([]vidser.SensitiveHit, error) {
if param.Ids == nil || len(param.Ids) <= 0 {
return nil, nil
}
movieDetails := make([]laosiji.MovieDetailResp, 0)
for _, id := range param.Ids {
var movieDetail laosiji.MovieDetailResp
req := laosiji.MovieDetailReq{
Id: id,
}
movieDetail, err := laosiji.MovieDetail(ctx, req)
if err != nil {
log.Warn("MovieAddList laosiji.MovieDetail failed", log.Any("id", id), log.E(err))
continue
}
for i, linkInfo := range movieDetail.Links {
linkInfo.M3u8_url = laosiji.MovieM3u8SourcePath(linkInfo.M3u8_url)
linkInfo.Preview_m3u8_url = laosiji.MovieM3u8SourcePath(linkInfo.Preview_m3u8_url)
linkInfo.Hevc_m3u8_url = laosiji.MovieM3u8SourcePath(linkInfo.Hevc_m3u8_url)
movieDetail.Links[i] = linkInfo
}
if len(movieDetail.Img_y) > 0 {
movieDetail.Img_y = common.JoinUrlPath("laosiji/", movieDetail.Img_y)
}
if len(movieDetail.Img_x) > 0 {
movieDetail.Img_x = common.JoinUrlPath("laosiji/", movieDetail.Img_x)
}
movieDetails = append(movieDetails, movieDetail)
}
if len(movieDetails) <= 0 {
log.Warn("MovieAddList laosiji.MovieDetailResp len is 0")
return nil, errors.New("laosiji.MovieDetailResp len is 0")
}
// 批量处理标签
tags := make(map[string]struct{})
for _, comicsDetail := range movieDetails {
if comicsDetail.Tags != nil && len(comicsDetail.Tags) > 0 {
for _, tag := range comicsDetail.Tags {
tags[tag.Name] = struct{}{}
}
}
}
terms := vidser.LoadEnabledSensitiveTerms()
hits := make([]vidser.SensitiveHit, 0)
if param.Position == "cartoon" {
return syncCartoonList(movieDetails, tags, manager, terms)
} else if param.Position == "av" || param.Position == "guochan" || param.Position == "douyin" || param.Position == "dark" {
tagMaps := make(map[string]primitive.ObjectID)
var err error
if len(tags) > 0 {
tagList := make([]string, 0)
for k, _ := range tags {
tagList = append(tagList, k)
}
tagMaps, err = checkInsertVidTags(tagList)
if err != nil {
log.Error("MovieAddList checkInsertVidTags failed", log.E(err))
return hits, err
}
}
users, err := usermod.FindMany(bson.M{"uid": bson.M{"$gt": 300000}}, &options.FindOptions{}, 0, 300)
if err != nil {
log.Warn("PostAddList FindManyUser failed", log.E(err))
return hits, err
}
failedIds := make([]string, 0)
for _, comicsDetail := range movieDetails {
hit, oneErr := syncOneMovie(comicsDetail, tagMaps, users, manager, terms)
if oneErr != nil {
log.Warn("MovieAddList syncOneMovie failed", log.Any("id", comicsDetail.Id), log.E(oneErr))
failedIds = append(failedIds, comicsDetail.Id)
continue
}
if hit != nil {
hits = append(hits, *hit)
}
}
if len(failedIds) > 0 {
return hits, errors.New(fmt.Sprintf("需要同步%d部资源,失败%d,失败Id[%s]", len(param.Ids), len(failedIds), strings.Join(failedIds, ",")))
}
return hits, nil
}
return hits, errors.New("该资源暂不支持")
}
func syncOneMovie(movieDetail laosiji.MovieDetailResp, tags map[string]primitive.ObjectID, upUsers []*usermod.User, manager string, terms []string) (*vidser.SensitiveHit, error) {
now := time.Now()
postList, err := vidmod.GetList(bson.M{"sourceID": bson.M{"$in": []string{movieDetail.Id}}})
if err != nil {
log.Warn("syncOneMovie GetList failed", log.Any("id", movieDetail.Id), log.E(err))
return nil, err
}
if postList != nil && len(postList) > 0 {
h265URL := movieH265SourceURL(movieDetail.Links)
if h265URL == "" {
return nil, nil
}
video := postList[0]
if err = vidmod.MarkH265Success(video.ID, h265URL); err != nil {
return nil, err
}
if webg.Redis != nil {
cacheKey := fmt.Sprintf(redisconst.VideoInfoKey(), video.ID.Hex())
if _, err = webg.Redis.Del(cacheKey); err != nil {
log.Warn("syncOneMovie clear video cache failed",
log.Any("id", video.ID),
log.Any("cacheKey", cacheKey),
log.E(err))
return nil, err
}
}
return nil, nil
}
vidInfo := vidmod.VideoModel{
ID: primitive.NewObjectID(),
Title: movieDetail.Name,
Content: movieDetail.Description,
Tags: make([]primitive.ObjectID, 0),
MimeType: "video/mp4",
SeriesCover: make([]string, 0),
Via: "laosiji",
Status: vidmod.CheckPass,
Location: primitive.ObjectID{},
Actor: movieDetail.Actor,
NewUpdatedAt: "laosiji",
ReviewAt: now,
CreatedAt: now,
UpdatedAt: now,
ReviewAccount: manager,
VerticalCover: movieDetail.Img_y,
}
if movieDetail.Img_type == "short" && len(movieDetail.Img_y) > 0 {
vidInfo.NewsType = vidmod.SHORT
vidInfo.Cover = movieDetail.Img_y
vidInfo.CoverThumb = movieDetail.Img_y
vidInfo.Direction = "vertical"
} else {
vidInfo.NewsType = vidmod.SP
vidInfo.Cover = movieDetail.Img_x
vidInfo.CoverThumb = movieDetail.Img_x
vidInfo.Direction = "horizontal"
}
playTime, _ := strconv.Atoi(movieDetail.Duration)
vidInfo.PlayTime = uint(playTime)
uIndex := rand.Intn(len(upUsers))
u := upUsers[uIndex]
vidInfo.PublisherID = u.UID
if movieDetail.Links != nil && len(movieDetail.Links) > 0 {
vidInfo.SourceURL = movieDetail.Links[0].M3u8_url
vidInfo.Filename = movieDetail.Links[0].Name
vidInfo.PreviewURL = movieDetail.Links[0].Preview_m3u8_url
vidInfo.H265Url = movieH265SourceURL(movieDetail.Links)
if vidInfo.H265Url != "" {
vidInfo.H265Status = vidmod.H265StatusSuccess
}
}
vidInfo.SourceID = movieDetail.Id
if movieDetail.Tags != nil && len(movieDetail.Tags) > 0 {
for _, tag := range movieDetail.Tags {
if k, ok := tags[tag.Name]; ok {
vidInfo.Tags = append(vidInfo.Tags, k)
}
}
}
// 敏感词命中 → 强制为待审核(WaitingCheck=0)
hit := vidser.CheckTextHits(terms, movieDetail.Id, vidInfo.Title, vidInfo.Content, "")
if hit != nil {
vidInfo.Status = vidmod.WaitingCheck
log.Warn("syncOneMovie sensitive hit, forced offline",
log.Any("sourceId", hit.SourceID),
log.Any("title", hit.Title),
log.Any("detail", hit.Detail))
}
if vidInfo.H265Url == "" && vidInfo.SourceURL != "" && vidInfo.Status == vidmod.CheckPass && vidInfo.NewsType == vidmod.SP {
vidInfo.H265Status = vidmod.H265StatusQueued
vidInfo.H265QueuedAt = now
}
if _, err = vidmod.InsertBase(vidInfo); err != nil {
return nil, err
}
return hit, nil
}
// movieH265SourceURL 返回首个播放链接对应的 H.265 地址。
// syncOneMovie 的 H.264 也固定使用 links[0],不能拿后续分集的 H.265 与首集混用。
func movieH265SourceURL(links []laosiji.LinkInfo) string {
if len(links) == 0 {
return ""
}
return laosiji.MovieM3u8SourcePath(links[0].Hevc_m3u8_url)
}
func checkInsertVidTags(names []string) (data map[string]vidmod.ObjectID, err error) {
data = make(map[string]vidmod.ObjectID)
tags, err := tagmod.FindOneTagByNames(names)
if err != nil {
log.Warn("checkInsertVidTags tagmod.FindOneTagByNames", log.E(err), log.Any("name", names))
return
}
for _, tag := range tags {
data[tag.TagName] = tag.ID
}
insertTags := make([]tagmod.Tag, 0)
for _, tag := range tags {
if _, ok := data[tag.TagName]; !ok {
insertTag := tagmod.Tag{
ID: primitive.NewObjectID(),
TagName: tag.TagName,
IsActive: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
insertTags = append(insertTags, insertTag)
data[tag.TagName] = insertTag.ID
}
}
if len(insertTags) > 0 {
err = tagmod.InsertMany(insertTags)
if err != nil {
log.Warn("checkInsertVidTags InsertMany failed", log.Any("tags", insertTags), log.E(err))
return
}
}
return
}