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
+266
View File
@@ -0,0 +1,266 @@
package laosijiser
import (
"91porn-server/common"
"91porn-server/common/laosiji"
"91porn-server/common/log"
"91porn-server/models/v/mediacontentmod"
"91porn-server/models/v/mediamod"
"91porn-server/web/service/vidser"
"context"
"errors"
"fmt"
"strconv"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func ComicsSearch(ctx context.Context, param laosiji.ComicsSearchListReq) (resp laosiji.ComicsSearchListResp, err error) {
comicsResp, err := laosiji.ComicsSearch(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
//是否导入
lsjIds := make([]string, 0)
for _, v := range comicsResp.Data {
lsjIds = append(lsjIds, v.Id)
}
comicsList, _ := mediamod.GetListByLsjIds(lsjIds)
// 处理域名
resp = laosiji.ComicsSearchListResp{
Data: make([]laosiji.ComicsSearchInfo, 0),
Total: comicsResp.Total,
Current_page: comicsResp.Current_page,
Page_size: comicsResp.Page_size,
Last_page: comicsResp.Last_page,
}
for _, comicsInfo := range comicsResp.Data {
//comicsInfo.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, comicsInfo.Img)
comicsInfo.Img = common.JoinUrlPath("laosiji", comicsInfo.Img)
for _, comicsIn := range comicsList {
if comicsIn.LsjId == comicsInfo.Id {
comicsInfo.IsAdd = true
continue
}
}
resp.Data = append(resp.Data, comicsInfo)
}
return resp, nil
}
func ComicsDetail(ctx context.Context, param laosiji.ComicsDetailReq) (resp laosiji.ComicsDetailResp, serr error) {
resp, serr = laosiji.ComicsDetail(ctx, param)
if serr != nil {
log.Error("MovieSearch", log.E(serr))
return
}
// 处理域名
//resp.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Img)
resp.Img = common.JoinUrlPath("laosiji", resp.Img)
if resp.Chapter != nil && len(resp.Chapter) > 0 {
for i, cha := range resp.Chapter {
if len(cha.Img) > 0 {
//resp.Chapter[i].Img = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Chapter[i].Img)
resp.Chapter[i].Img = common.JoinUrlPath("laosiji", resp.Chapter[i].Img)
}
if cha.Content != nil && len(cha.Content) > 0 {
for y, content := range cha.Content {
//resp.Chapter[i].Content[y].F = common.JoinUrlPath(laosiji.IMAGEYUAN, content.F)
resp.Chapter[i].Content[y].F = common.JoinUrlPath("laosiji", content.F)
}
}
}
}
return
}
func ComicsAddList(ctx context.Context, param laosiji.ComicsSyncReq, manager string) (hits []vidser.SensitiveHit, err error) {
if param.Ids == nil || len(param.Ids) <= 0 {
return
}
// 批量查询所有详情
comicsDetails := make([]laosiji.ComicsDetailResp, 0)
for _, id := range param.Ids {
var comicsDetail laosiji.ComicsDetailResp
req := laosiji.ComicsDetailReq{
Id: id,
}
comicsDetail, err = laosiji.ComicsDetail(ctx, req)
if err != nil {
log.Warn("ComicsAddList laosiji.ComicsDetail failed", log.Any("id", id), log.E(err))
continue
}
// 处理域名
//comicsDetail.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, comicsDetail.Img)
comicsDetail.Img = common.JoinUrlPath("laosiji", comicsDetail.Img)
if comicsDetail.Chapter != nil && len(comicsDetail.Chapter) > 0 {
for i, cha := range comicsDetail.Chapter {
if len(cha.Img) > 0 {
comicsDetail.Chapter[i].Img = common.JoinUrlPath("laosiji", comicsDetail.Chapter[i].Img)
}
if cha.Content != nil && len(cha.Content) > 0 {
for y, content := range cha.Content {
comicsDetail.Chapter[i].Content[y].F = common.JoinUrlPath("laosiji", content.F)
}
}
}
}
comicsDetails = append(comicsDetails, comicsDetail)
}
if len(comicsDetails) <= 0 {
log.Warn("ComicsAddList laosiji.ComicsDetailResp len is 0")
err = errors.New("laosiji.ComicsDetailResp len is 0")
return
}
// 批量处理标签
tags := make(map[string]struct{})
for _, comicsDetail := range comicsDetails {
if comicsDetail.Tags != nil && len(comicsDetail.Tags) > 0 {
for _, tag := range comicsDetail.Tags {
tags[tag.Name] = struct{}{}
}
}
}
tagMaps := make(map[string]primitive.ObjectID)
if len(tags) > 0 {
tagList := make([]string, 0)
for k, _ := range tags {
tagList = append(tagList, k)
}
tagMaps, err = checkInsertMediaTag(tagList, 2)
if err != nil {
log.Error("ComicsAdd checkInsertMediaTag failed", log.E(err))
return
}
}
terms := vidser.LoadEnabledSensitiveTerms()
hits = make([]vidser.SensitiveHit, 0)
failedIds := make([]string, 0)
for _, comicsDetail := range comicsDetails {
hit, oneErr := syncOneComics(comicsDetail, tagMaps, manager, terms)
if oneErr != nil {
log.Warn("ComicsAdd syncOneComics 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 {
err = errors.New(fmt.Sprintf("需要同步%d部漫画,失败%d,失败Id[%s]", len(param.Ids), len(failedIds), strings.Join(failedIds, ",")))
}
return
}
func syncOneComics(comicsDetail laosiji.ComicsDetailResp, tagMaps map[string]primitive.ObjectID, manager string, terms []string) (*vidser.SensitiveHit, error) {
now := time.Now()
mediaTemp, err := mediamod.GetListByLsjId(comicsDetail.Id)
if err != nil {
log.Warn("syncOneComics GetListByLsjId failed", log.Any("id", comicsDetail.Id), log.Any("err", err))
return nil, err
}
if !mediaTemp.ID.IsZero() {
return nil, nil
}
mediaTemp = mediamod.Media{
ID: primitive.NewObjectID(),
LsjId: comicsDetail.Id,
Title: comicsDetail.Name,
HorizontalCover: comicsDetail.Img,
VerticalCover: comicsDetail.Img,
Tags: make([]primitive.ObjectID, 0),
TagDetails: make([]mediamod.TagDetail, 0),
Summary: comicsDetail.Description,
FreeEpisode: 0,
CurrentEpisode: 0,
MediaType: mediamod.MediaTypeImage,
Kind: 5,
PermissionIconHide: false,
Permission: 2,
Price: 0,
ContentsPrice: 0,
Status: 1,
CreatedAt: now,
UpdateTime: now,
UpdatedAct: manager,
}
mediaTemp.TotalEpisode, _ = strconv.Atoi(comicsDetail.Chapter_count)
mediaTemp.UpdateStatus, _ = strconv.Atoi(comicsDetail.Update_status)
mediaTemp.Price, _ = strconv.ParseInt(comicsDetail.Money, 10, 64)
if mediaTemp.Price > 0 {
mediaTemp.Permission = 1
}
//if mediaTemp.UpdateStatus == 1 {
// mediaTemp.UpdatedDesc = fmt.Sprintf("已完结%d话", mediaTemp.TotalEpisode)
//} else {
// mediaTemp.UpdatedDesc = fmt.Sprintf("更新至%d话", mediaTemp.TotalEpisode)
//}
for _, tag := range comicsDetail.Tags {
if v, ok := tagMaps[tag.Name]; ok {
mediaTemp.TagDetails = append(mediaTemp.TagDetails, mediamod.TagDetail{
Id: v,
Name: tag.Name,
})
mediaTemp.Tags = append(mediaTemp.Tags, v)
}
}
contents := make([]mediacontentmod.MediaContent, 0)
if len(comicsDetail.Chapter) > 0 {
for i, chapter := range comicsDetail.Chapter {
mediaContent := mediacontentmod.MediaContent{
ID: primitive.NewObjectID(),
MediaID: mediaTemp.ID,
EpisodeNumber: i + 1,
ListenPermission: mediaTemp.Permission,
Price: mediaTemp.Price,
Name: fmt.Sprintf("第%d话", i+1),
Text: "",
Md5: "",
VideoUrl: "",
UrlSet: make([]string, 0),
Status: 1,
IsActive: true,
UpdatedAct: manager,
CreatedAt: now,
UpdateTime: now,
HashId: chapter.Id,
}
mediaContent.Height, _ = strconv.Atoi(chapter.Content[0].H)
mediaContent.Weight, _ = strconv.Atoi(chapter.Content[0].W)
if chapter.Content != nil && len(chapter.Content) > 0 {
for _, content := range chapter.Content {
mediaContent.UrlSet = append(mediaContent.UrlSet, content.F)
}
}
contents = append(contents, mediaContent)
}
}
mediaTemp.CurrentEpisode = len(contents)
// 敏感词命中 → 强制下架(Status=0)
hit := vidser.CheckTextHits(terms, comicsDetail.Id, mediaTemp.Title, mediaTemp.Summary, "")
if hit != nil {
mediaTemp.Status = 0
log.Warn("syncOneComics sensitive hit, forced offline",
log.Any("sourceId", hit.SourceID),
log.Any("title", hit.Title),
log.Any("detail", hit.Detail))
}
_, err = mediamod.Insert(nil, mediaTemp)
if err != nil {
log.Warn("syncOneComics InsertMedia failed", log.Any("media", mediaTemp.ID), log.E(err))
return nil, err
}
if len(contents) > 0 {
_ = mediacontentmod.InsetBatch(nil, contents)
}
return hit, nil
}
+207
View File
@@ -0,0 +1,207 @@
package laosijiser
import (
"91porn-server/common/laosiji"
"91porn-server/common/log"
"91porn-server/models/v/mediacontentmod"
"91porn-server/models/v/mediamod"
"91porn-server/models/v/mediatagmod"
"91porn-server/web/service/vidser"
"errors"
"fmt"
"strconv"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func checkInsertMediaTag(names []string, typ int) (data map[string]primitive.ObjectID, err error) {
data, err = mediatagmod.FindOneTagByNames(names, typ)
if err != nil {
log.Error("checkInsertMediaTag FindOneTagByiNames failed", log.Any("tags", names), log.E(err))
return
}
insertTags := make([]mediatagmod.MediaTag, 0)
for _, tag := range names {
if _, ok := data[tag]; !ok {
insertTag := mediatagmod.MediaTag{
ID: primitive.NewObjectID(),
Type: typ,
Name: tag,
Active: true,
Sort: 0,
IsDiscovery: false,
CreatedAt: time.Now(),
}
insertTags = append(insertTags, insertTag)
data[tag] = insertTag.ID
}
}
if len(insertTags) > 0 {
err = mediatagmod.InsertMany(nil, insertTags)
if err != nil {
log.Warn("checkInsertMediaTag InsertMany failed", log.Any("tags", insertTags), log.E(err))
return
}
}
return
}
func syncCartoonList(movieDetails []laosiji.MovieDetailResp, tags map[string]struct{}, manager string, terms []string) ([]vidser.SensitiveHit, error) {
hits := make([]vidser.SensitiveHit, 0)
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 = checkInsertMediaTag(tagList, 1)
if err != nil {
log.Error("syncCartoonList checkInsertVidTags failed", log.E(err))
return hits, err
}
}
failedIds := make([]string, 0)
for _, movieDetail := range movieDetails {
hit, oneErr := syncOneCartoon(movieDetail, tagMaps, manager, terms)
if oneErr != nil {
log.Warn("syncCartoonList syncOneCartoon failed", log.Any("id", movieDetail.Id), log.E(oneErr))
failedIds = append(failedIds, movieDetail.Id)
continue
}
if hit != nil {
hits = append(hits, *hit)
}
}
if len(failedIds) > 0 {
return hits, errors.New(fmt.Sprintf("需要同步%d部动漫,失败%d,失败Id[%s]", len(movieDetails), len(failedIds), strings.Join(failedIds, ",")))
}
return hits, nil
}
func syncOneCartoon(movieDetail laosiji.MovieDetailResp, tagMaps map[string]primitive.ObjectID, manager string, terms []string) (*vidser.SensitiveHit, error) {
now := time.Now()
mediaTemp, err := mediamod.GetListByLsjId(movieDetail.Id)
if err != nil {
log.Warn("syncOneCartoon GetListByLsjId failed", log.Any("id", movieDetail.Id), log.Any("err", err))
return nil, err
}
if !mediaTemp.ID.IsZero() {
return nil, syncExistingCartoonH265(mediaTemp.ID, movieDetail.Links, manager)
}
mediaTemp = mediamod.Media{
ID: primitive.NewObjectID(),
LsjId: movieDetail.Id,
Title: movieDetail.Name,
HorizontalCover: movieDetail.Img_x,
VerticalCover: movieDetail.Img_y,
Tags: make([]primitive.ObjectID, 0),
TagDetails: make([]mediamod.TagDetail, 0),
Summary: movieDetail.Description,
MediaType: mediamod.MediaTypeVideo,
Kind: 1,
PermissionIconHide: false,
Permission: 2,
Status: 1,
CreatedAt: now,
UpdateTime: now,
UpdatedAct: manager,
Anchor: movieDetail.Director,
}
mediaTemp.UpdateStatus, _ = strconv.Atoi(movieDetail.Update_status)
//if mediaTemp.UpdateStatus == 1 {
// mediaTemp.UpdatedDesc = fmt.Sprintf("已完结%d话", mediaTemp.TotalEpisode)
//} else {
// mediaTemp.UpdatedDesc = fmt.Sprintf("更新至%d话", mediaTemp.TotalEpisode)
//}
for _, tag := range movieDetail.Tags {
if v, ok := tagMaps[tag.Name]; ok {
mediaTemp.TagDetails = append(mediaTemp.TagDetails, mediamod.TagDetail{
Id: v,
Name: tag.Name,
})
mediaTemp.Tags = append(mediaTemp.Tags, v)
}
}
contents := make([]mediacontentmod.MediaContent, 0)
if len(movieDetail.Links) > 0 {
for i, chapter := range movieDetail.Links {
mediaContent := mediacontentmod.MediaContent{
ID: primitive.NewObjectID(),
MediaID: mediaTemp.ID,
EpisodeNumber: i + 1,
ListenPermission: mediaTemp.Permission,
Price: mediaTemp.Price,
Name: chapter.Name,
VideoUrl: chapter.M3u8_url,
H265Url: strings.TrimSpace(chapter.Hevc_m3u8_url),
UrlSet: make([]string, 0),
Status: 1,
IsActive: true,
UpdatedAct: manager,
CreatedAt: now,
UpdateTime: now,
HashId: chapter.Id,
}
contents = append(contents, mediaContent)
}
}
mediaTemp.CurrentEpisode = len(contents)
mediaTemp.TotalEpisode = mediaTemp.CurrentEpisode
// 敏感词命中 → 强制下架(Status=0)
hit := vidser.CheckTextHits(terms, movieDetail.Id, mediaTemp.Title, mediaTemp.Summary, "")
if hit != nil {
mediaTemp.Status = 0
log.Warn("syncOneCartoon sensitive hit, forced offline",
log.Any("sourceId", hit.SourceID),
log.Any("title", hit.Title),
log.Any("detail", hit.Detail))
}
_, err = mediamod.Insert(nil, mediaTemp)
if err != nil {
log.Warn("syncOneCartoon InsertMedia failed", log.Any("media", mediaTemp.ID), log.E(err))
return nil, err
}
if len(contents) > 0 {
_ = mediacontentmod.InsetBatch(nil, contents)
}
return hit, nil
}
// syncExistingCartoonH265 允许重复导入老司机动漫时回填历史章节的 H.265 地址。
// 只接受上游非空地址,不改动现有 H.264 地址,也不会用空值覆盖已入库资源。
func syncExistingCartoonH265(mediaID primitive.ObjectID, links []laosiji.LinkInfo, manager string) error {
updatedIDs := make([]primitive.ObjectID, 0)
for _, chapter := range links {
h265URL := strings.TrimSpace(chapter.Hevc_m3u8_url)
if h265URL == "" || strings.TrimSpace(chapter.Id) == "" {
continue
}
content, err := mediacontentmod.GetInfoByHashId(mediaID, chapter.Id)
if err == mediacontentmod.MediaContentNotFound {
continue
}
if err != nil {
return err
}
if strings.TrimSpace(content.H265Url) == h265URL {
continue
}
if _, err = mediacontentmod.UpdateByID(nil, content.ID, map[string]interface{}{
"h265Url": h265URL,
"updatedAct": manager,
"updateTime": time.Now(),
}); err != nil {
return err
}
updatedIDs = append(updatedIDs, content.ID)
}
return nil
}
+314
View File
@@ -0,0 +1,314 @@
package laosijiser
import (
"91porn-server/common"
"91porn-server/common/crypt"
"91porn-server/common/httputil"
"91porn-server/common/laosiji"
"91porn-server/common/log"
"91porn-server/models/v/mediacontentmod"
"91porn-server/models/v/mediamod"
"91porn-server/web/webg"
"context"
"errors"
"fmt"
"io/ioutil"
"strconv"
"strings"
"sync"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func NovelSearch(ctx context.Context, param laosiji.NovelSearchListReq) (resp laosiji.NovelSearchListResp, err error) {
novelResp, err := laosiji.NovelSearch(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
resp = laosiji.NovelSearchListResp{
Data: make([]laosiji.NovelSearchInfo, 0),
Total: novelResp.Total,
Current_page: novelResp.Current_page,
Page_size: novelResp.Page_size,
Last_page: novelResp.Last_page,
}
//是否导入
taskIds := make([]string, 0)
for _, v := range novelResp.Data {
taskIds = append(taskIds, v.Id)
}
novelList, _ := mediamod.GetListByLsjIds(taskIds)
// 处理域名
for _, novelInfo := range novelResp.Data {
//novelInfo.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, novelInfo.Img)
novelInfo.Img = common.JoinUrlPath("laosiji", novelInfo.Img)
for _, novelIn := range novelList {
if novelIn.LsjId == novelInfo.Id {
novelInfo.IsAdd = true
continue
}
}
resp.Data = append(resp.Data, novelInfo)
}
return
}
func NovelDetail(ctx context.Context, param laosiji.NovelDetailReq) (resp laosiji.NovelDetailResp, err error) {
resp, err = laosiji.NovelDetail(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
// 处理域名
//resp.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Img)
resp.Img = common.JoinUrlPath("laosiji", resp.Img)
if resp.Chapter != nil && len(resp.Chapter) > 0 {
for i, cha := range resp.Chapter {
if len(cha.Img) > 0 {
//resp.Chapter[i].Img = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Chapter[i].Img)
resp.Chapter[i].Img = common.JoinUrlPath("laosiji", resp.Chapter[i].Img)
}
if len(cha.Content) > 0 {
if cha.Is_audio == "y" {
resp.Chapter[i].Content = common.JoinUrlPath("laosiji/m3m", resp.Chapter[i].Content)
} else {
resp.Chapter[i].Content = common.JoinUrlPath("laosiji", resp.Chapter[i].Content)
}
}
}
}
return
}
func NovelAddList(ctx context.Context, param laosiji.NovelAddListReq, manager string) (err error) {
if param.Ids == nil || len(param.Ids) <= 0 {
return
}
novelDetails := make([]laosiji.NovelDetailResp, 0)
for _, id := range param.Ids {
var novelDetail laosiji.NovelDetailResp
req := laosiji.NovelDetailReq{
Id: id,
}
novelDetail, err = laosiji.NovelDetail(ctx, req)
if err != nil {
log.Warn("NovelAddList laosiji.NovelDetail failed", log.Any("id", id), log.E(err))
continue
}
// 处理域名
//novelDetail.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, novelDetail.Img)
novelDetail.Img = common.JoinUrlPath("laosiji/", novelDetail.Img)
if novelDetail.Chapter != nil && len(novelDetail.Chapter) > 0 {
for i, cha := range novelDetail.Chapter {
if len(cha.Img) > 0 {
novelDetail.Chapter[i].Img = common.JoinUrlPath("laosiji/", novelDetail.Chapter[i].Img)
}
if len(cha.Content) > 0 {
if cha.Is_audio == "y" {
return errors.New("暂不支持有声小说!!")
//novelDetail.Chapter[i].Content = common.JoinUrlPath("laosiji/m3m", novelDetail.Chapter[i].Content)
} else {
novelDetail.Chapter[i].Content = common.JoinUrlPath("laosiji", novelDetail.Chapter[i].Content)
}
}
}
}
novelDetails = append(novelDetails, novelDetail)
}
if len(novelDetails) <= 0 {
log.Warn("NovelAddList laosiji.NovelDetailResp len is 0")
err = errors.New("laosiji.NovelDetailResp len is 0")
return
}
// 批量处理标签
tagMaps := make(map[string]primitive.ObjectID)
tagList := make([]string, 0) // 减少重复循环
tagList2 := make([]string, 0) // 减少重复循环
tagTmpMap := map[int]map[string]any{ // 区分类别和去重
3: make(map[string]any), // 文本
4: make(map[string]any), // 有声
}
for _, comicsDetail := range novelDetails {
for _, tag := range comicsDetail.Tags {
if len(comicsDetail.Chapter) > 0 && comicsDetail.Chapter[0].Is_audio == "y" {
if _, ok := tagTmpMap[4][tag.Name]; !ok {
tagTmpMap[4][tag.Name] = nil
tagList = append(tagList, tag.Name)
}
} else {
if _, ok := tagTmpMap[3][tag.Name]; !ok {
tagTmpMap[3][tag.Name] = nil
tagList2 = append(tagList, tag.Name)
}
}
}
}
if len(tagTmpMap[3]) > 0 {
tagMaps, err = checkInsertMediaTag(tagList, 3)
if err != nil {
log.Error("NovelAddList checkInsertMediaTag failed", log.E(err))
return err
}
}
if len(tagTmpMap[4]) > 0 {
tagMaps2, err := checkInsertMediaTag(tagList2, 4)
if err != nil {
log.Error("NovelAddList checkInsertMediaTag failed", log.E(err))
return err
}
for k, id := range tagMaps2 {
tagMaps[k] = id
}
}
failedIds := make([]string, 0)
wg := sync.WaitGroup{}
for index, _ := range novelDetails {
wg.Add(1)
common.GoParam(index, func(i int) {
defer wg.Done()
comicsDetail := novelDetails[i]
err = syncOneNovel(comicsDetail, tagMaps, manager)
if err != nil {
log.Warn("NovelAddList syncOneNovel failed", log.Any("id", comicsDetail.Id), log.E(err))
failedIds = append(failedIds, comicsDetail.Id)
}
})
}
wg.Wait()
if len(failedIds) > 0 {
err = errors.New(fmt.Sprintf("需要同步%d部小说,失败%d,失败Id[%s]", len(param.Ids), len(failedIds), strings.Join(failedIds, ",")))
}
return
}
func syncOneNovel(novelDetail laosiji.NovelDetailResp, tagMaps map[string]primitive.ObjectID, manager string) error {
now := time.Now()
mediaTemp, err := mediamod.GetListByLsjId(novelDetail.Id)
if err != nil {
log.Warn("syncOneNovel GetListByLsjId failed", log.Any("id", novelDetail.Id), log.Any("err", err))
return err
}
if !mediaTemp.ID.IsZero() {
return nil
}
mediaTemp = mediamod.Media{
ID: primitive.NewObjectID(),
LsjId: novelDetail.Id,
Title: novelDetail.Name,
HorizontalCover: novelDetail.Img,
VerticalCover: novelDetail.Img,
Tags: make([]primitive.ObjectID, 0),
TagDetails: make([]mediamod.TagDetail, 0),
Summary: novelDetail.Description,
FreeEpisode: 0,
CurrentEpisode: 0,
MediaType: mediamod.MediaTypeText,
Kind: 7,
Anchor: novelDetail.Author,
PermissionIconHide: false,
Permission: 2,
Price: 0,
ContentsPrice: 0,
Status: 1,
CreatedAt: now,
UpdateTime: now,
UpdatedAct: manager,
}
isAudo := false
mediaTemp.TotalEpisode, _ = strconv.Atoi(novelDetail.Chapter_count)
mediaTemp.UpdateStatus, _ = strconv.Atoi(novelDetail.Update_status)
mediaTemp.Price, _ = strconv.ParseInt(novelDetail.Money, 10, 64)
if mediaTemp.Price > 0 {
mediaTemp.Permission = 1
}
//if mediaTemp.UpdateStatus == 1 {
// mediaTemp.UpdatedDesc = fmt.Sprintf("已完结%d话", mediaTemp.TotalEpisode)
//} else {
// mediaTemp.UpdatedDesc = fmt.Sprintf("更新至%d话", mediaTemp.TotalEpisode)
//}
for _, tag := range novelDetail.Tags {
if v, ok := tagMaps[tag.Name]; ok {
mediaTemp.TagDetails = append(mediaTemp.TagDetails, mediamod.TagDetail{
Id: v,
Name: tag.Name,
})
mediaTemp.Tags = append(mediaTemp.Tags, v)
}
}
contents := make([]mediacontentmod.MediaContent, 0)
if len(novelDetail.Chapter) > 0 {
for i, chapter := range novelDetail.Chapter {
mediaContent := mediacontentmod.MediaContent{
ID: primitive.NewObjectID(),
MediaID: mediaTemp.ID,
EpisodeNumber: i + 1,
ListenPermission: mediaTemp.Permission,
Price: mediaTemp.Price,
Name: fmt.Sprintf("第%d章", i+1),
UrlSet: make([]string, 0),
Status: 1,
IsActive: true,
Author: mediaTemp.Anchor,
IsDelete: false,
UpdatedAct: manager,
CreatedAt: now,
UpdateTime: now,
HashId: chapter.Id,
}
if chapter.Is_audio == "y" {
mediaContent.AudioUrl = chapter.Content
isAudo = true
} else {
content, err := textNovelContent(chapter.Content)
if err != nil {
log.Warn("syncOneNovel textNovelContent failed", log.Any("err", err))
return err
}
mediaContent.Text = content
}
contents = append(contents, mediaContent)
}
}
if isAudo {
mediaTemp.MediaSubType = 1
}
_, err = mediamod.Insert(nil, mediaTemp)
if err != nil {
log.Warn("syncOneNovel InsertMedia failed", log.Any("media", mediaTemp.ID), log.E(err))
return err
}
if len(contents) > 0 {
_ = mediacontentmod.InsetBatch(nil, contents)
}
return nil
}
func textNovelContent(url string) (string, error) {
decKey := "525202f9149e061d"
path := fmt.Sprintf("%s/%s", webg.Conf.URL.LaoSiJiTSCdn, url)
resp, err := httputil.DefaultClientGet(path, make(map[string]string))
if err != nil {
log.Warn("textNovelContent http client get failed", log.Any("url", path), log.Any("err", err))
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Warn("textNovelContent read response body failed", log.Any("err", err))
return "", err
}
b := crypt.AESECBDecrypt(body, []byte(decKey))
return string(b), nil
}
+34
View File
@@ -0,0 +1,34 @@
package laosijiser
import (
"91porn-server/common/crypt"
"91porn-server/common/httputil"
"91porn-server/common/log"
"fmt"
"io/ioutil"
"testing"
)
func TestNovelDetail(t *testing.T) {
url := "laosiji/media/novel/cbd/cbd5b05ea5677797958895694211582c.bnc"
key := "525202f9149e061d"
domain := "https://tssdaa.hlvwcn.cn"
//req, err := http.NewRequest("GET", url, nil)
//if err != nil {
// t.Fatal(err)
// return
//}
resp, err := httputil.ClientGet(30, fmt.Sprintf("%s/%s", domain, url), make(map[string]string))
if err != nil {
log.Warn("http client get failed", log.Any("err", err))
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Warn("read response body failed", log.Any("err", err))
return
}
b := crypt.AESECBDecrypt(body, []byte(key))
log.Info(string(b))
}
+229
View File
@@ -0,0 +1,229 @@
package laosijiser
import (
"91porn-server/common"
"91porn-server/common/laosiji"
"91porn-server/common/log"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"91porn-server/web/service/vidser"
"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 PostSearch(ctx context.Context, param laosiji.PostSearchListReq) (resp laosiji.PostSearchListResp, err error) {
postResp, err := laosiji.PostSearch(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
resp = laosiji.PostSearchListResp{
Data: make([]laosiji.PostSearchInfo, 0),
Total: postResp.Total,
Current_page: postResp.Current_page,
Page_size: postResp.Page_size,
Last_page: postResp.Last_page,
}
//是否导入
taskIds := make([]string, 0)
for _, v := range postResp.Data {
taskIds = append(taskIds, v.Id)
}
postList, _ := vidmod.GetList(bson.M{"sourceID": bson.M{"$in": taskIds}})
// 处理域名
for _, postInfo := range postResp.Data {
//postInfo.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, postInfo.Img)
postInfo.Img = common.JoinUrlPath("laosiji", postInfo.Img)
for _, postIn := range postList {
if postIn.SourceID == postInfo.Id {
postInfo.IsAdd = true
continue
}
}
resp.Data = append(resp.Data, postInfo)
}
return resp, nil
}
func PostDetail(ctx context.Context, param laosiji.PostDetailReq) (resp laosiji.PostDetailResp, err error) {
resp, err = laosiji.PostDetail(ctx, param)
if err != nil {
log.Error("MovieSearch", log.E(err))
return
}
// 处理域名
//resp.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, resp.Img)
resp.Img = common.JoinUrlPath("laosiji", resp.Img)
if resp.Files != nil && len(resp.Files) > 0 {
for i, file := range resp.Files {
if len(file.Image) > 0 {
//resp.Files[i].Image = common.JoinUrlPath(laosiji.IMAGEYUAN, file.Image)
resp.Files[i].Image = common.JoinUrlPath("laosiji", file.Image)
}
if len(file.Video_link) > 0 {
resp.Files[i].Video_link = common.JoinUrlPath(laosiji.APIUrl+"/m3m", file.Video_link)
}
}
}
return
}
func PostAddList(ctx context.Context, param laosiji.PostAddListReq, manager string) (hits []vidser.SensitiveHit, err error) {
if param.Ids == nil || len(param.Ids) <= 0 {
return
}
// 批量查询所有详情
postDetails := make([]laosiji.PostDetailResp, 0)
for _, id := range param.Ids {
var postDetail laosiji.PostDetailResp
req := laosiji.PostDetailReq{
Id: id,
}
postDetail, err = laosiji.PostDetail(ctx, req)
if err != nil {
log.Warn("PostAddList laosiji.PostDetail failed", log.Any("id", id), log.E(err))
continue
}
//postDetail.Img = common.JoinUrlPath(laosiji.IMAGEYUAN, postDetail.Img)
postDetail.Img = common.JoinUrlPath("laosiji", postDetail.Img)
if postDetail.Files != nil && len(postDetail.Files) > 0 {
for i, file := range postDetail.Files {
if len(file.Image) > 0 {
postDetail.Files[i].Image = common.JoinUrlPath("laosiji", file.Image)
}
if len(file.Video_link) > 0 {
postDetail.Files[i].Video_link = common.JoinUrlPath("laosiji/m3m/", file.Video_link)
}
}
}
postDetails = append(postDetails, postDetail)
}
if len(postDetails) <= 0 {
log.Warn("PostAddList laosiji.PostDetailResp len is 0")
err = errors.New("laosiji.PostDetailResp len is 0")
return
}
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
}
terms := vidser.LoadEnabledSensitiveTerms()
hits = make([]vidser.SensitiveHit, 0)
failedIds := make([]string, 0)
for _, postDetail := range postDetails {
hit, oneErr := addOnePost(postDetail, nil, users, manager, terms)
if oneErr != nil {
log.Warn("PostAddList addOnePost failed", log.Any("id", postDetail.Id), log.E(oneErr))
failedIds = append(failedIds, postDetail.Id)
continue
}
if hit != nil {
hits = append(hits, *hit)
}
}
if len(failedIds) > 0 {
err = errors.New(fmt.Sprintf("需要同步%d个帖子,失败%d,失败Id[%s]", len(param.Ids), len(failedIds), strings.Join(failedIds, ",")))
}
return
}
func addOnePost(postDetail laosiji.PostDetailResp, tagMaps map[string]primitive.ObjectID, upUsers []*usermod.User, manager string, terms []string) (*vidser.SensitiveHit, error) {
//
// 有的帖子是图文节点 前端格式不支持 这里屏蔽
//
if len(postDetail.Files) == 0 {
return nil, nil
}
now := time.Now()
postList, err := vidmod.GetList(bson.M{"sourceID": bson.M{"$in": []string{postDetail.Id}}})
if err != nil {
log.Warn("addOnePost GetList failed", log.Any("id", postDetail.Id), log.E(err))
return nil, err
}
if postList != nil && len(postList) > 0 {
return nil, nil
}
postInfo := vidmod.VideoModel{
ID: primitive.NewObjectID(),
NewsType: vidmod.COVER,
Title: postDetail.Title,
Content: postDetail.Content,
Tags: make([]primitive.ObjectID, 0),
MimeType: "video/mp4",
Cover: postDetail.Img,
CoverThumb: postDetail.Img,
SeriesCover: make([]string, 0),
Via: "laosiji",
Status: vidmod.CheckPass,
Location: primitive.ObjectID{},
NewUpdatedAt: "laosiji",
ReviewAt: now,
CreatedAt: now,
UpdatedAt: now,
ReviewAccount: manager,
SourceID: postDetail.Id,
VerticalCover: postDetail.Img,
}
postInfo.SeriesNum, _ = strconv.Atoi(postDetail.Img_count)
postInfo.Coins, _ = strconv.ParseInt(postDetail.Money, 10, 64)
uIndex := rand.Intn(len(upUsers))
u := upUsers[uIndex]
postInfo.PublisherID = u.UID
//if postInfo.Coins > 0 {
// postInfo.Permission = 1
//} else {
// postInfo.Permission = 2
// postInfo.FreeArea = true
// postInfo.FreeAreaDate = now
//}
//节点 处理
if postDetail.Files != nil && len(postDetail.Files) > 0 {
for _, file := range postDetail.Files {
if file.Type == "image" {
if len(file.Image) > 0 {
postInfo.SeriesCover = append(postInfo.SeriesCover, file.Image)
}
}
if file.Type == "video" {
postInfo.SourceURL = file.Video_link
postInfo.PlayTime = 1
postInfo.Filename = file.Tips
postInfo.SourceID = postDetail.Id
}
}
}
if postDetail.Rich_content != nil && len(postDetail.Rich_content) > 0 {
for _, file := range postDetail.Rich_content {
postInfo.RichText += fmt.Sprintf("%s\n", file)
}
}
// 敏感词命中 → 强制为待审核(WaitingCheck=0),写库后由后台逐条告警
hit := vidser.CheckTextHits(terms, postDetail.Id, postInfo.Title, postInfo.Content, postInfo.RichText)
if hit != nil {
postInfo.Status = vidmod.WaitingCheck
log.Warn("addOnePost sensitive hit, forced offline",
log.Any("sourceId", hit.SourceID),
log.Any("title", hit.Title),
log.Any("detail", hit.Detail))
}
if _, err = vidmod.InsertBase(postInfo); err != nil {
return nil, err
}
return hit, nil
}
+338
View File
@@ -0,0 +1,338 @@
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
}
+53
View File
@@ -0,0 +1,53 @@
package laosijiser
import (
"testing"
"91porn-server/common/laosiji"
)
func TestMovieH265SourceURL(t *testing.T) {
tests := []struct {
name string
links []laosiji.LinkInfo
want string
}{
{
name: "empty",
links: []laosiji.LinkInfo{
{Hevc_m3u8_url: " "},
},
},
{
name: "does not mix a later episode with first H264 link",
links: []laosiji.LinkInfo{
{Hevc_m3u8_url: ""},
{Hevc_m3u8_url: "https://cdn.example.com/m3m/movie/hevc.m3u8?token=ignored"},
{Hevc_m3u8_url: "other.m3u8"},
},
},
{
name: "first link normalized",
links: []laosiji.LinkInfo{
{Hevc_m3u8_url: "https://cdn.example.com/m3m/movie/hevc.m3u8?token=ignored"},
{Hevc_m3u8_url: "other.m3u8"},
},
want: "laosiji/m3m/movie/hevc.m3u8",
},
{
name: "already normalized",
links: []laosiji.LinkInfo{
{Hevc_m3u8_url: "laosiji/rk130/hevc/movie/index.m3u8"},
},
want: "laosiji/rk130/hevc/movie/index.m3u8",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := movieH265SourceURL(test.links); got != test.want {
t.Fatalf("movieH265SourceURL() = %q, want %q", got, test.want)
}
})
}
}