Files
huangguo_server/web/service/laosijiser/novel.go
T
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

315 lines
9.3 KiB
Go

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
}