295 lines
10 KiB
Go
295 lines
10 KiB
Go
package srv_videoinfo
|
|
|
|
import (
|
|
"context"
|
|
"math/rand"
|
|
"strings"
|
|
"time"
|
|
"videoweb/pub/common/log"
|
|
"videoweb/pub/common/playletcache"
|
|
"videoweb/pub/common/slugx"
|
|
"videoweb/pub/common/srvdef"
|
|
"videoweb/pub/common/utils"
|
|
"videoweb/pub/models/playletchaptermod"
|
|
"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"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
func videoSyncKey(media proxy.MediaResp) string {
|
|
if !media.MediaSourceId.IsZero() {
|
|
return media.MediaSourceId.Hex()
|
|
}
|
|
return media.Id.Hex()
|
|
}
|
|
|
|
func buildVideoSyncFilter(media proxy.MediaResp) bson.M {
|
|
keys := []string{media.Id.Hex()}
|
|
if !media.MediaSourceId.IsZero() {
|
|
msid := media.MediaSourceId.Hex()
|
|
if msid != keys[0] {
|
|
keys = append(keys, msid)
|
|
}
|
|
}
|
|
or := make([]bson.M, 0, len(keys)*2)
|
|
for _, key := range keys {
|
|
or = append(or,
|
|
bson.M{videoinformationmod.FN.VideoInformation.Video.FileId: key},
|
|
bson.M{videoinformationmod.FN.VideoInformation.SyncId: key},
|
|
)
|
|
}
|
|
return bson.M{"$or": or}
|
|
}
|
|
|
|
func IsPlayletMedia(ctx context.Context, media proxy.MediaResp) bool {
|
|
return playletchaptermod.IsLinkedMedia(ctx, media.IsPlaylet, media.PlayletKeys()...)
|
|
}
|
|
|
|
func SyncOneVideo(ctx context.Context, media proxy.MediaResp) *srvdef.SrvErr {
|
|
if IsPlayletMedia(ctx, media) {
|
|
log.Info("VideoSync skip playlet media", log.Any("mediaId", media.Id.Hex()), log.Any("mediaSourceId", media.MediaSourceId.Hex()))
|
|
return nil
|
|
}
|
|
// 同步时不再自动写 video_taginfo,标签由后台统一标签绑定维护
|
|
syncKey := videoSyncKey(media)
|
|
filter := buildVideoSyncFilter(media)
|
|
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 serr
|
|
}
|
|
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,
|
|
MediaTypes: []int64{1},
|
|
Status: true,
|
|
Sort: 0,
|
|
UpdatedAt: time.Now(),
|
|
CreatedAt: time.Now(),
|
|
}
|
|
createrExists := func(s string) bool {
|
|
doc, _ := videocreatermod.FindOneVideoCreaterInfo(ctx, slugx.Filter(
|
|
videocreatermod.FN.VideoCreaterInfo.Slug, videocreatermod.FN.VideoCreaterInfo.Id, s, 0))
|
|
return doc != nil
|
|
}
|
|
if serr = slugx.Ensure(&creater.Slug, utils.SlugSourceFromKeywordsOrTitle(nil, creater.Name), createrExists); serr != nil {
|
|
return serr
|
|
}
|
|
serr = videocreatermod.InsertOneVideoCreaterInfo(ctx, creater)
|
|
if serr != nil {
|
|
log.Error("VideoSync.InsertOneVideoCreaterInfo", log.Any("media", media), log.E(serr))
|
|
return serr
|
|
}
|
|
} else {
|
|
isFind := false
|
|
for _, v := range creater.MediaTypes {
|
|
if v == 1 {
|
|
isFind = true
|
|
}
|
|
}
|
|
if !isFind {
|
|
mediaTypes := append(creater.MediaTypes, 1)
|
|
_ = videocreatermod.UpdateOneVideoCreaterInfo(ctx, bson.M{videocreatermod.FN.VideoCreaterInfo.Id: creater.Id}, bson.M{
|
|
"$set": bson.M{videocreatermod.FN.VideoCreaterInfo.MediaTypes: mediaTypes},
|
|
})
|
|
}
|
|
}
|
|
videoInfo.CreatorId = creater.Id
|
|
videoInfo.CreatorName = creater.Name
|
|
}
|
|
videoInfo.IndexNow = 0
|
|
applyDefaultFakeFlow(&videoInfo.Fake, rand.New(rand.NewSource(time.Now().UnixNano())))
|
|
exists := func(s string) bool {
|
|
doc, _ := videoinformationmod.FindOneVideoInformation(ctx, slugx.Filter(
|
|
videoinformationmod.FN.VideoInformation.Slug, videoinformationmod.FN.VideoInformation.Id, s, 0))
|
|
return doc != nil
|
|
}
|
|
if serr = slugx.Ensure(&videoInfo.Slug, utils.SlugSourceFromKeywordsOrTitle(videoInfo.Keyworld, videoInfo.Title), exists); serr != nil {
|
|
return serr
|
|
}
|
|
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 {
|
|
mediaNodeMap := make(map[string]videoinformationmod.Node, len(media.Nodes))
|
|
for _, node := range media.Nodes {
|
|
if node.NodeId != "" {
|
|
mediaNodeMap[node.NodeId] = node
|
|
}
|
|
}
|
|
// 更新节点里面图片水印 以本地视频列表的节点为主
|
|
for _, node := range videoInfo.Nodes {
|
|
if mediaNode, ok := mediaNodeMap[node.NodeId]; ok {
|
|
node.Images = mediaNode.Images
|
|
}
|
|
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.IssuedBrand: media.IssuedBrand,
|
|
videoinformationmod.FN.VideoInformation.IssuedAt: media.IssuedAt,
|
|
}
|
|
for k, v := range defaultFakeFlowSetDoc(rand.New(rand.NewSource(time.Now().UnixNano()))) {
|
|
setDoc[k] = v
|
|
}
|
|
setDoc[videoinformationmod.FN.VideoInformation.SyncId] = syncKey
|
|
if len(media.FieldNameFs) > 0 {
|
|
video := videoinformationmod.VideoInfo{
|
|
TaskId: media.TaskID,
|
|
FileId: syncKey,
|
|
Url: media.FieldNameFs,
|
|
Cover: media.CoverImg,
|
|
Height: media.Height,
|
|
Width: media.Width,
|
|
VideoTime: media.VideoTime,
|
|
}
|
|
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
|
|
}
|
|
if preMp4 := strings.TrimSpace(media.PreMp4FileNameFs); preMp4 != "" {
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.PreMp4FileNameFs] = preMp4
|
|
}
|
|
if unencryptedPreMp4 := strings.TrimSpace(media.UnencryptedPreMp4); unencryptedPreMp4 != "" {
|
|
setDoc[videoinformationmod.FN.VideoInformation.Video.UnencryptedPreMp4] = unencryptedPreMp4
|
|
}
|
|
if videoInfo.Slug == "" {
|
|
exists := func(s string) bool {
|
|
doc, _ := videoinformationmod.FindOneVideoInformation(ctx, slugx.Filter(
|
|
videoinformationmod.FN.VideoInformation.Slug, videoinformationmod.FN.VideoInformation.Id, s, videoInfo.Id))
|
|
return doc != nil
|
|
}
|
|
slug := ""
|
|
if serr = slugx.Ensure(&slug, utils.SlugSourceFromKeywordsOrTitle(media.Keyworld, videoInfo.Title), exists); serr != nil {
|
|
return serr
|
|
}
|
|
setDoc[videoinformationmod.FN.VideoInformation.Slug] = slug
|
|
}
|
|
serr = videoinformationmod.UpdateOneVideoInformation(ctx, bson.M{videoinformationmod.FN.VideoInformation.Id: videoInfo.Id}, bson.M{"$set": setDoc})
|
|
if serr != nil {
|
|
return serr
|
|
}
|
|
}
|
|
playletcache.ClearHomeCache()
|
|
_ = syncNodeVideo(ctx, media)
|
|
return nil
|
|
}
|
|
|
|
// syncNodeVideo 同步节点里的视频
|
|
func syncNodeVideo(ctx context.Context, media proxy.MediaResp) *srvdef.SrvErr {
|
|
mediaID := videoSyncKey(media)
|
|
nodeIDs := []string{mediaID}
|
|
if !media.MediaSourceId.IsZero() {
|
|
msid := media.MediaSourceId.Hex()
|
|
if msid != mediaID {
|
|
nodeIDs = append(nodeIDs, msid)
|
|
}
|
|
}
|
|
if media.Id.Hex() != mediaID && media.Id.Hex() != "" {
|
|
nodeIDs = append(nodeIDs, media.Id.Hex())
|
|
}
|
|
filter := bson.M{"nodes.nodeId": bson.M{"$in": nodeIDs}}
|
|
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 {
|
|
writeModels := make([]mongo.WriteModel, 0, len(videoInfo))
|
|
now := time.Now()
|
|
// 更新视频路径
|
|
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 == mediaID || containsString(nodeIDs, v.FileId) {
|
|
node.Videos[j].Url = media.FieldNameFs
|
|
isFind = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if isFind {
|
|
video.Nodes[i] = node
|
|
break
|
|
}
|
|
}
|
|
if isFind {
|
|
writeModels = append(writeModels, mongo.NewUpdateOneModel().
|
|
SetFilter(bson.M{videoinformationmod.FN.VideoInformation.Id: video.Id}).
|
|
SetUpdate(bson.M{"$set": bson.M{
|
|
videoinformationmod.FN.VideoInformation.UpdatedAt: now,
|
|
videoinformationmod.FN.VideoInformation.Nodes: video.Nodes,
|
|
}}))
|
|
}
|
|
}
|
|
}
|
|
if len(writeModels) > 0 {
|
|
_, serr = videoinformationmod.BulkWriteVideoInformation(ctx, writeModels, options.BulkWrite().SetOrdered(false))
|
|
if serr != nil {
|
|
log.Warn("syncNodeVideo BulkWriteVideoInformation failed", log.Any("filter", filter), log.E(serr))
|
|
return serr
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func containsString(list []string, target string) bool {
|
|
for _, item := range list {
|
|
if item == target {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|