239 lines
7.3 KiB
Go
239 lines
7.3 KiB
Go
package shareser
|
|
|
|
import (
|
|
"91porn-server/app/appg"
|
|
"91porn-server/app/service/versionser"
|
|
"91porn-server/models/v/mediacontentmod"
|
|
"91porn-server/models/v/mediamod"
|
|
"91porn-server/models/v/moduleconfmod"
|
|
"91porn-server/models/v/sourcemod"
|
|
"context"
|
|
"fmt"
|
|
"math/rand"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
|
|
"91porn-server/common/log"
|
|
"91porn-server/common/stderr"
|
|
"91porn-server/models/e/sharemod"
|
|
"91porn-server/models/v/vidmod"
|
|
|
|
"github.com/skip2/go-qrcode"
|
|
)
|
|
|
|
// GeneratorQrCode 生成二维码
|
|
func GeneratorQrCode(uid uint64, content, videoID string) (code stderr.Code, data interface{}) {
|
|
return GeneratorQrCodeContext(context.Background(), uid, content, videoID, "")
|
|
}
|
|
|
|
// GeneratorQrCodeContext 生成二维码,并按分享事件幂等累计短视频推荐分。
|
|
func GeneratorQrCodeContext(
|
|
ctx context.Context,
|
|
uid uint64,
|
|
content, videoID, eventID string,
|
|
) (code stderr.Code, data interface{}) {
|
|
return generatorQrCodeContextWithScore(
|
|
ctx,
|
|
uid,
|
|
content,
|
|
videoID,
|
|
eventID,
|
|
func(
|
|
ctx context.Context,
|
|
uid uint64,
|
|
videoID primitive.ObjectID,
|
|
eventID string,
|
|
now time.Time,
|
|
) error {
|
|
return incrementRecommendShareOnce(
|
|
ctx, appg.Redis, uid, videoID, eventID, now,
|
|
)
|
|
},
|
|
)
|
|
}
|
|
|
|
// GeneratorDramaQrCodeContext 生成短剧分享二维码并幂等累计分享互动分。
|
|
func GeneratorDramaQrCodeContext(
|
|
ctx context.Context,
|
|
uid uint64,
|
|
content, mediaID, contentID, eventID string,
|
|
) (code stderr.Code, data interface{}) {
|
|
id, err := primitive.ObjectIDFromHex(mediaID)
|
|
if err != nil {
|
|
return stderr.ErrParamError, ""
|
|
}
|
|
media, err := mediamod.GetInfo(id)
|
|
if err != nil || media.ID.IsZero() || media.MediaType != mediamod.MediaTypeDrama || media.Status != 1 || media.IsDelete {
|
|
return stderr.ErrParamError, ""
|
|
}
|
|
if contentID != "" {
|
|
cid, parseErr := primitive.ObjectIDFromHex(contentID)
|
|
if parseErr != nil {
|
|
return stderr.ErrParamError, ""
|
|
}
|
|
episode, episodeErr := mediacontentmod.GetInfo(cid, true)
|
|
if episodeErr != nil || episode.MediaID != id || episode.MediaType != mediamod.MediaTypeDrama || episode.IsDelete {
|
|
return stderr.ErrParamError, ""
|
|
}
|
|
}
|
|
return generatorQrCodeContextWithScore(
|
|
ctx, uid, content, mediaID, eventID,
|
|
func(ctx context.Context, uid uint64, mediaID primitive.ObjectID, eventID string, now time.Time) error {
|
|
return incrementRecommendShareOnceWith(
|
|
ctx, appg.Redis, uid, mediaID, eventID, now,
|
|
func(_ context.Context, id primitive.ObjectID) error {
|
|
return mediamod.IncreaseCountShareByID(id, 1)
|
|
},
|
|
)
|
|
},
|
|
)
|
|
}
|
|
|
|
type recommendShareScoreFunc func(
|
|
context.Context,
|
|
uint64,
|
|
primitive.ObjectID,
|
|
string,
|
|
time.Time,
|
|
) error
|
|
|
|
func generatorQrCodeContextWithScore(
|
|
ctx context.Context,
|
|
uid uint64,
|
|
content, videoID, eventID string,
|
|
score recommendShareScoreFunc,
|
|
) (code stderr.Code, data interface{}) {
|
|
tmp := strconv.FormatUint(uid, 10)
|
|
url := content + "&share=true&shareuid=" + tmp
|
|
png, err := qrcode.Encode(url, qrcode.Medium, 256)
|
|
if err != nil {
|
|
e := fmt.Sprintf("GeneratorQrCode error: uid(%d), content(%s), err(%+v)\n", uid, content, err)
|
|
log.Error(e)
|
|
return stderr.ErrNetWorkBusy, ""
|
|
}
|
|
if id, parseErr := primitive.ObjectIDFromHex(videoID); parseErr == nil && score != nil {
|
|
if incErr := score(ctx, uid, id, eventID, time.Now()); incErr != nil {
|
|
// 二维码已经生成,推荐统计是旁路能力;瞬时 Redis/Mongo
|
|
// 故障不能破坏旧分享主流程,失败通过日志和监控告警。
|
|
log.Error("increment recommend share failed", log.E(incErr), log.Any("videoID", videoID))
|
|
}
|
|
}
|
|
return stderr.Success, sharemod.VShareResp{QrCode: png}
|
|
}
|
|
|
|
// GetShareCnt 获取视频分享次数
|
|
func GetShareCnt(videoID string) (code stderr.Code, data interface{}) {
|
|
cnt, err := vidmod.GetShareCount(videoID)
|
|
if err != nil {
|
|
return stderr.ErrNetWorkBusy, ""
|
|
}
|
|
data = sharemod.VShareCntResp{VidelID: videoID, Cnt: cnt}
|
|
return stderr.Success, data
|
|
}
|
|
|
|
// Info 获取分享的视频信息以及推荐列表
|
|
func Info(id primitive.ObjectID, sysType string) (*sharemod.List, *stderr.CustomErr) {
|
|
video, err := vidmod.GetByIDFromRedis(id.Hex())
|
|
if err != nil {
|
|
return nil, stderr.NewCustomErr(stderr.ErrDbQueryError, err.Error(), "查找视频失败")
|
|
}
|
|
if video.ID.IsZero() {
|
|
return nil, stderr.NewCustomErr(stderr.Failure, "视频未找到", "视频未找到")
|
|
}
|
|
blockedModules, err := moduleconfmod.BlockedOutsideSearchModuleIDs([]string{video.MID}, time.Now())
|
|
if err != nil {
|
|
return nil, stderr.NewCustomErr(stderr.ErrDbQueryError, err.Error(), "查找视频失败")
|
|
}
|
|
if _, blocked := blockedModules[video.MID]; blocked {
|
|
return nil, stderr.NewCustomErr(stderr.CodeEmptyData, "视频未找到", "视频未找到")
|
|
}
|
|
var picUrl, landUrl string
|
|
_, pl := sourcemod.PingList()
|
|
if len(pl) > 0 {
|
|
for _, v := range pl {
|
|
if v == nil {
|
|
continue
|
|
}
|
|
if landUrl != "" && picUrl != "" {
|
|
break
|
|
}
|
|
if v.Type == sourcemod.Image && len(v.Domain) > 0 {
|
|
picUrl = v.Domain[rand.Intn(len(v.Domain))].Url
|
|
continue
|
|
}
|
|
if v.Type == sourcemod.ShareURL && len(v.Domain) > 0 {
|
|
landUrl = v.Domain[rand.Intn(len(v.Domain))].Url
|
|
}
|
|
}
|
|
}
|
|
vsis, err := vidmod.GetShareListFromRedis()
|
|
if err != nil {
|
|
return nil, stderr.NewCustomErr(stderr.ErrDbQueryError, err.Error(), "查询分享视频推荐列表失败")
|
|
}
|
|
vsis, err = filterShareRecommendations(vsis)
|
|
if err != nil {
|
|
return nil, stderr.NewCustomErr(stderr.ErrDbQueryError, err.Error(), "查询分享视频推荐列表失败")
|
|
}
|
|
ver, _, _, _, _, _, err := versionser.AdvVersionAnnounThreeServer("1.0.1", sysType)
|
|
if err != nil {
|
|
log.Error("查询版本信息失败", log.E(err))
|
|
return nil, stderr.NewCustomErr(stderr.Failure, err.Error(), "查询下载链接失败")
|
|
}
|
|
if len(ver.DownloadLink) == 0 {
|
|
return nil, stderr.NewCustomErr(stderr.Failure, "", "无有效的app下载地址")
|
|
}
|
|
l := sharemod.List{
|
|
Title: video.Title,
|
|
Cover: video.Cover,
|
|
SourceUrl: video.SourceURL,
|
|
LandUrl: landUrl,
|
|
PicUrl: picUrl,
|
|
Tags: []string{"暗网幼女", "人兽重口", "校园霸凌", "灌醉迷奸", "处女破处", "捉奸现场", "疯狂孕妇", "黑鬼草人妻",
|
|
"缅北禁区", "全家乱操", "黑料吃瓜", "摄像破解", "群P激战", "AI换脸", "SM调教", "反差母狗"},
|
|
DownloadUrl: ver.DownloadLink[0],
|
|
List: vsis,
|
|
}
|
|
return &l, nil
|
|
}
|
|
|
|
func filterShareRecommendations(items []vidmod.ShareInfo) ([]vidmod.ShareInfo, error) {
|
|
if len(items) == 0 {
|
|
return items, nil
|
|
}
|
|
ids := make([]primitive.ObjectID, 0, len(items))
|
|
for _, item := range items {
|
|
ids = append(ids, item.ID)
|
|
}
|
|
videos, err := vidmod.GetVideosByIDs(ids)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
excludedModules, err := moduleconfmod.ExcludedVideoModuleIDs(time.Now(), true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
excludedSet := make(map[string]struct{}, len(excludedModules))
|
|
for _, moduleID := range excludedModules {
|
|
excludedSet[moduleID] = struct{}{}
|
|
}
|
|
excludedVideos := make(map[primitive.ObjectID]struct{})
|
|
for _, video := range videos {
|
|
if video == nil {
|
|
continue
|
|
}
|
|
if _, excluded := excludedSet[video.MID]; excluded {
|
|
excludedVideos[video.ID] = struct{}{}
|
|
}
|
|
}
|
|
filtered := make([]vidmod.ShareInfo, 0, len(items))
|
|
for _, item := range items {
|
|
if _, excluded := excludedVideos[item.ID]; excluded {
|
|
continue
|
|
}
|
|
filtered = append(filtered, item)
|
|
}
|
|
return filtered, nil
|
|
}
|