Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
212 lines
7.3 KiB
Go
212 lines
7.3 KiB
Go
package srv_videoinfo
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
"videoweb/pub/common/log"
|
|
"videoweb/pub/common/srvdef"
|
|
"videoweb/pub/models/videocreatermod"
|
|
"videoweb/pub/models/videoinformationmod"
|
|
"videoweb/pub/mongos"
|
|
"videoweb/pub/storage/proxy"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
func SyncOneVideo(ctx context.Context, media proxy.MediaResp) *srvdef.SrvErr {
|
|
filter := bson.M{
|
|
"$or": []bson.M{
|
|
{videoinformationmod.FN.VideoInformation.Video.FileId: media.Id.Hex()},
|
|
{videoinformationmod.FN.VideoInformation.SyncId: media.Id.Hex()},
|
|
},
|
|
}
|
|
videoInfo, serr := videoinformationmod.FindOneVideoInformation(ctx, filter)
|
|
if serr != nil {
|
|
// 新加入的视频
|
|
if serr.Code == srvdef.ErrNoData {
|
|
videoInfo = media.ToVideoInfo()
|
|
if videoInfo == nil {
|
|
log.Error("VideoSync FindOneVideoInformation", log.Any("MediaId", media.Id))
|
|
return srvdef.New(srvdef.ErrNoData, "videoInfo is nil")
|
|
}
|
|
videoInfo.IndexNow = 0
|
|
if len(media.Publish) > 0 {
|
|
creater, serr := videocreatermod.FindOneVideoCreaterInfo(ctx, bson.M{
|
|
videocreatermod.FN.VideoCreaterInfo.Name: media.Publish,
|
|
})
|
|
if serr != nil && serr.Code != srvdef.ErrNoData {
|
|
log.Error("VideoSync.FindOneVideoCreaterInfo", log.Any("media", media), log.E(serr))
|
|
return serr
|
|
}
|
|
if creater == nil {
|
|
createrId := mongos.Lid.VideoCreator.Get()
|
|
creater = &videocreatermod.VideoCreaterInfo{
|
|
Id: createrId,
|
|
Name: media.Publish,
|
|
Status: true,
|
|
Sort: 0,
|
|
UpdatedAt: time.Now(),
|
|
CreatedAt: time.Now(),
|
|
}
|
|
serr = videocreatermod.InsertOneVideoCreaterInfo(ctx, creater)
|
|
if serr != nil {
|
|
log.Error("VideoSync.InsertOneVideoCreaterInfo", log.Any("media", media), log.E(serr))
|
|
return serr
|
|
}
|
|
}
|
|
videoInfo.CreatorId = creater.Id
|
|
videoInfo.CreatorName = creater.Name
|
|
}
|
|
serr = videoinformationmod.InsertOneVideoInformation(ctx, videoInfo)
|
|
if serr != nil {
|
|
log.Error("VideoSync InsertOneVideoInformation", log.Any("videoInfo", videoInfo), log.E(serr))
|
|
return serr
|
|
}
|
|
} else {
|
|
log.Error("VideoSync FindOneVideoInformation", log.Any("filter", filter), log.E(serr))
|
|
return serr
|
|
}
|
|
} else {
|
|
// 更新资源
|
|
nodes := make([]videoinformationmod.Node, 0)
|
|
if videoInfo != nil {
|
|
// 更新节点里面图片水印 以本地视频列表的节点为主
|
|
for _, node := range videoInfo.Nodes {
|
|
isFind := false
|
|
if len(node.NodeId) > 0 {
|
|
for _, v := range media.Nodes {
|
|
if node.NodeId == v.NodeId {
|
|
isFind = true
|
|
node.Images = v.Images
|
|
nodes = append(nodes, node)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !isFind {
|
|
nodes = append(nodes, node)
|
|
}
|
|
}
|
|
} else {
|
|
nodes = media.Nodes
|
|
}
|
|
setDoc := bson.M{
|
|
videoinformationmod.FN.VideoInformation.Nodes: nodes,
|
|
videoinformationmod.FN.VideoInformation.Keyworld: media.Keyworld,
|
|
videoinformationmod.FN.VideoInformation.FirstTag: media.FirstTag,
|
|
videoinformationmod.FN.VideoInformation.SecondTags: media.SecondTags,
|
|
videoinformationmod.FN.VideoInformation.CoverImg: media.CoverImg,
|
|
videoinformationmod.FN.VideoInformation.UnencryptedImage: media.UnencryptedImage,
|
|
}
|
|
if len(media.FieldNameFs) > 0 {
|
|
video := videoinformationmod.VideoInfo{
|
|
TaskId: media.TaskID,
|
|
FileId: media.Id.Hex(),
|
|
Url: media.FieldNameFs,
|
|
Cover: media.CoverImg,
|
|
Height: media.Height,
|
|
Width: media.Width,
|
|
VideoTime: media.VideoTime,
|
|
UnencryptedPreMp4: media.UnencryptedPreMp4,
|
|
PreMp4FileNameFs: media.PreMp4FileNameFs,
|
|
}
|
|
if !strings.HasSuffix(video.Url, ".m3u8") {
|
|
video.Url += ".m3u8"
|
|
}
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.TaskId] = video.TaskId
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.FileId] = video.FileId
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.Url] = video.Url
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.Cover] = video.Cover
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.Height] = video.Height
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.Width] = video.Width
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.VideoTime] = video.VideoTime
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.UnencryptedPreMp4] = video.UnencryptedPreMp4
|
|
}
|
|
serr = videoinformationmod.UpdateOneVideoInformation(ctx, bson.M{videoinformationmod.FN.VideoInformation.Id: videoInfo.Id}, bson.M{"$set": setDoc})
|
|
if serr != nil {
|
|
return serr
|
|
}
|
|
}
|
|
_ = syncNodeVideo(ctx, media)
|
|
return nil
|
|
}
|
|
|
|
// SyncUnencryptedOne 仅补齐单条资源的 UnencryptedImage / UnencryptedPreMp4 字段。
|
|
// 源数据对应字段为空时跳过该字段(避免覆盖本地已有值);本地无对应资源时直接返回。
|
|
// 幂等:可重复执行,用于历史数据补齐。
|
|
func SyncUnencryptedOne(ctx context.Context, media proxy.MediaResp) *srvdef.SrvErr {
|
|
if media.UnencryptedImage == "" && media.UnencryptedPreMp4 == "" {
|
|
return nil
|
|
}
|
|
filter := bson.M{videoinformationmod.FN.VideoInformation.Video.FileId: media.Id.Hex()}
|
|
videoInfo, serr := videoinformationmod.FindOneVideoInformation(ctx, filter)
|
|
if serr != nil {
|
|
return serr
|
|
}
|
|
setDoc := bson.M{}
|
|
if media.UnencryptedImage != "" {
|
|
setDoc[videoinformationmod.FN.VideoInformation.UnencryptedImage] = media.UnencryptedImage
|
|
}
|
|
// 仅当源端有主视频文件时,才补 Video.UnencryptedPreMp4(避免向空的 Video 子结构写字段)
|
|
if media.UnencryptedPreMp4 != "" && len(media.FieldNameFs) > 0 {
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.UnencryptedPreMp4] = media.UnencryptedPreMp4
|
|
}
|
|
if len(setDoc) == 0 {
|
|
return nil
|
|
}
|
|
return videoinformationmod.UpdateOneVideoInformation(ctx,
|
|
bson.M{videoinformationmod.FN.VideoInformation.Id: videoInfo.Id},
|
|
bson.M{"$set": setDoc})
|
|
}
|
|
|
|
// syncNodeVideo 同步节点里的视频
|
|
func syncNodeVideo(ctx context.Context, media proxy.MediaResp) *srvdef.SrvErr {
|
|
filter := bson.M{"nodes.nodeId": media.Id.Hex()}
|
|
opts := &options.FindOptions{}
|
|
opts.SetLimit(100)
|
|
videoInfo, serr := videoinformationmod.FindManyVideoInformations(ctx, filter, opts)
|
|
if serr != nil {
|
|
log.Warn("syncNodeVideo", log.Any("filter", filter), log.E(serr))
|
|
return serr
|
|
}
|
|
if !strings.HasSuffix(media.FieldNameFs, ".m3u8") {
|
|
media.FieldNameFs += ".m3u8"
|
|
}
|
|
if len(videoInfo) > 0 {
|
|
// 更新视频路径
|
|
for _, video := range videoInfo {
|
|
if video.Nodes != nil && len(video.Nodes) > 0 {
|
|
isFind := false
|
|
for i, node := range video.Nodes {
|
|
if node.Videos != nil && len(node.Videos) > 0 {
|
|
for j, v := range node.Videos {
|
|
if v.FileId == media.Id.Hex() {
|
|
node.Videos[j].Url = media.FieldNameFs
|
|
isFind = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if isFind {
|
|
video.Nodes[i] = node
|
|
break
|
|
}
|
|
}
|
|
if isFind {
|
|
serr = videoinformationmod.UpdateOneVideoInformation(ctx, bson.M{videoinformationmod.FN.VideoInformation.Id: video.Id}, bson.M{"$set": bson.M{
|
|
videoinformationmod.FN.VideoInformation.UpdatedAt: time.Now(),
|
|
videoinformationmod.FN.VideoInformation.Nodes: video.Nodes,
|
|
}})
|
|
if serr != nil {
|
|
log.Warn("syncNodeVideo UpdateOneVideoInformation failed", log.Any("filter", filter), log.E(serr))
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|