@@ -0,0 +1,723 @@
|
||||
package mediacontentser
|
||||
|
||||
import (
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/stderr"
|
||||
"91porn-server/models/v/mediamod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
"91porn-server/web/service/updownloadser"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"91porn-server/models/v/mediacontentmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type WebListReq struct {
|
||||
ID *string `form:"id" bson:"id,omitempty"` // ID
|
||||
Name *string `form:"name" bson:"name,omitempty"` // 名称
|
||||
Type *int `form:"type" bson:"type,omitempty"` // 类型 1:动漫,2:漫画
|
||||
Status *int `form:"status" bson:"status,omitempty"` // 状态
|
||||
IsActive *bool `form:"isActive" json:"isActive"` // 是否激活
|
||||
MID *string `form:"mId" json:"mId" bson:"mId" binding:"required"` // 媒体资源ID
|
||||
PageNumber uint64 `form:"pageNumber" json:"pageNumber" binding:"required,min=1"` // 当前页
|
||||
PageSize uint64 `form:"pageSize" json:"pageSize" binding:"required,min=1,max=100"` // 每页条数
|
||||
}
|
||||
type WebListRes struct {
|
||||
Total int64 `json:"total"`
|
||||
List []*mediacontentmod.MediaContent `json:"list"`
|
||||
}
|
||||
|
||||
func (q *WebListReq) Filter() bson.M {
|
||||
var query = bson.M{}
|
||||
if q.Name != nil {
|
||||
query["name"] = primitive.Regex{Pattern: *q.Name, Options: "i"}
|
||||
}
|
||||
if q.Status != nil {
|
||||
query["status"] = *q.Status
|
||||
}
|
||||
if q.MID != nil {
|
||||
mid, _ := primitive.ObjectIDFromHex(*q.MID)
|
||||
query["mediaId"] = mid
|
||||
}
|
||||
if q.Type != nil {
|
||||
query["type"] = *q.Type
|
||||
}
|
||||
if q.IsActive != nil {
|
||||
query["isActive"] = *q.IsActive
|
||||
}
|
||||
if q.ID != nil {
|
||||
id, _ := primitive.ObjectIDFromHex(*q.ID)
|
||||
query["_id"] = id
|
||||
}
|
||||
query["isDelete"] = false
|
||||
return query
|
||||
}
|
||||
func (q *WebListReq) Options() *options.FindOptions {
|
||||
return options.Find().SetSkip(int64((q.PageNumber - 1) * q.PageSize)).SetLimit(int64(q.PageSize)).SetSort(bson.M{"episodeNumber": 1})
|
||||
}
|
||||
|
||||
// GetList 获取列表
|
||||
func (q *WebListReq) GetList() (res *WebListRes, err error) {
|
||||
var out = &WebListRes{}
|
||||
count, err := mediacontentmod.QueryAllCount(q.Filter())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
out.List = []*mediacontentmod.MediaContent{}
|
||||
out.Total = 0
|
||||
return out, nil
|
||||
}
|
||||
out.Total = count
|
||||
out.List, err = mediacontentmod.QueryAllList(q.Filter(), q.Options())
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("mediacontentmod queryAllList error:%+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type WebCreateReq struct {
|
||||
MediaID primitive.ObjectID `json:"mediaId" form:"mediaId" binding:"required"` // 媒体资源ID
|
||||
MediaType string `json:"mediaType" form:"mediaType" binding:"required"` // 媒体类型
|
||||
EpisodeNumber uint `json:"episodeNumber" form:"episodeNumber" ` // 第几集
|
||||
ListenPermission int `json:"listenPermission" form:"listenPermission" ` // 收听权限 0:会员 1:金币购买 2:免费
|
||||
Price int64 `json:"price" form:"price" ` // 购买价格
|
||||
Cover string `json:"cover" form:"cover"` //封面
|
||||
Name string `json:"name" form:"name" ` // 章节名
|
||||
Text string `json:"text" form:"text" ` // 内容(小说专用)
|
||||
Md5 string `json:"md5" form:"md5" ` // 媒体md5
|
||||
SourceID string `json:"sourceID" form:"sourceID"` // 视频唯一id,对应文件服
|
||||
VideoUrl string `json:"videoUrl" form:"videoUrl" ` // 视频地址
|
||||
AudioUrl string `json:"audioUrl" form:"audioUrl"` // 有声小说地址
|
||||
UrlSet []string `json:"urlSet" form:"urlSet"` // 地址集(多个资源地址用 例如漫画)
|
||||
Filename string `json:"filename" form:"filename"` // 文件名称
|
||||
IsActive bool `json:"isActive" form:"isActive" ` // 是否激活
|
||||
PreviewEnabled bool `json:"previewEnabled" form:"previewEnabled"` // 是否允许试看
|
||||
PreviewStart int `json:"previewStart" form:"previewStart"` // 试看起始时间(秒)
|
||||
PreviewSeconds int `json:"previewSeconds" form:"previewSeconds"` // 试看时长(秒)
|
||||
}
|
||||
|
||||
const defaultDramaPreviewSeconds = 60
|
||||
|
||||
func normalizeDramaPreview(enabled bool, start, seconds int, playTime uint) (bool, int, int, error) {
|
||||
if !enabled {
|
||||
return false, 0, 0, nil
|
||||
}
|
||||
if start < 0 {
|
||||
return false, 0, 0, errors.New("试看起始时间不能小于0")
|
||||
}
|
||||
if seconds < 0 {
|
||||
return false, 0, 0, errors.New("试看时长不能小于0")
|
||||
}
|
||||
if seconds == 0 {
|
||||
seconds = defaultDramaPreviewSeconds
|
||||
}
|
||||
if playTime > 0 && uint64(start)+uint64(seconds) > uint64(playTime) {
|
||||
return false, 0, 0, errors.New("试看起始时间与时长之和不能超过视频总时长")
|
||||
}
|
||||
return true, start, seconds, nil
|
||||
}
|
||||
|
||||
func validateDramaEpisodeState(episodeNumber int, listenPermission int, price int64, name, videoURL, h265URL string, active bool, status int) error {
|
||||
if episodeNumber < 1 {
|
||||
return errors.New("剧集编号必须大于0")
|
||||
}
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return errors.New("剧集名称不能为空")
|
||||
}
|
||||
if listenPermission != 1 && listenPermission != 2 {
|
||||
return errors.New("短剧剧集listenPermission只支持1或2")
|
||||
}
|
||||
if listenPermission == 2 && price != 0 {
|
||||
return errors.New("免费剧集价格必须为0")
|
||||
}
|
||||
if listenPermission == 1 && price <= 0 {
|
||||
return errors.New("金币剧集价格必须大于0")
|
||||
}
|
||||
if active {
|
||||
if status != 1 {
|
||||
return errors.New("视频仍在转码,暂不能上架")
|
||||
}
|
||||
if strings.TrimSpace(videoURL) == "" && strings.TrimSpace(h265URL) == "" {
|
||||
return errors.New("剧集没有播放资源,暂不能上架")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureEpisodeNumberUnique(mediaID primitive.ObjectID, episodeNumber int, excludeID primitive.ObjectID) error {
|
||||
filter := bson.M{
|
||||
"mediaId": mediaID,
|
||||
"episodeNumber": episodeNumber,
|
||||
"isDelete": false,
|
||||
}
|
||||
if !excludeID.IsZero() {
|
||||
filter["_id"] = bson.M{"$ne": excludeID}
|
||||
}
|
||||
count, err := mediacontentmod.QueryAllCount(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("剧集编号已存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fileStatusToEpisodeStatus(status string) int {
|
||||
switch status {
|
||||
case vidmod.ConvertCompleted, vidmod.Completed:
|
||||
return 1
|
||||
case vidmod.FileUploadError, vidmod.MergeError, vidmod.ConvertError:
|
||||
return 2
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func mediaMetadataFromFs(id string) (vidmod.AwsPullResp, int, error) {
|
||||
resp, err := updownloadser.PullFileInfo(id)
|
||||
if err != nil {
|
||||
return vidmod.AwsPullResp{}, 0, err
|
||||
}
|
||||
status := fileStatusToEpisodeStatus(resp.Data.Status)
|
||||
return resp.Data, status, nil
|
||||
}
|
||||
|
||||
// Create 发布数据
|
||||
func (p *WebCreateReq) Create(manager string) (err error, vid primitive.ObjectID) {
|
||||
now := time.Now()
|
||||
media, err := mediamod.QueryMediaByID(bson.M{"_id": p.MediaID})
|
||||
if err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
if media == nil || media.ID.IsZero() {
|
||||
return errors.New("media info is nll"), primitive.ObjectID{}
|
||||
}
|
||||
if media.IsDelete || p.MediaType != media.MediaType {
|
||||
return errors.New("剧集mediaType与父媒体不一致"), primitive.ObjectID{}
|
||||
}
|
||||
p.Name = strings.TrimSpace(p.Name)
|
||||
|
||||
if p.MediaType == mediamod.MediaTypeVideo || p.MediaType == mediamod.MediaTypeDrama {
|
||||
vid, err = primitive.ObjectIDFromHex(p.SourceID)
|
||||
if err != nil || vid.IsZero() {
|
||||
return errors.New("sourceID不是有效的资源ID"), primitive.ObjectID{}
|
||||
}
|
||||
} else {
|
||||
vid = primitive.NewObjectID()
|
||||
}
|
||||
if err = ensureEpisodeNumberUnique(media.ID, int(p.EpisodeNumber), primitive.NilObjectID); err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
if media.MediaType == mediamod.MediaTypeDrama {
|
||||
if err = validateDramaEpisodeState(int(p.EpisodeNumber), p.ListenPermission, p.Price, p.Name, p.VideoUrl, "", false, 0); err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
if strings.TrimSpace(p.VideoUrl) == "" {
|
||||
return errors.New("短剧剧集必须提供videoUrl"), primitive.ObjectID{}
|
||||
}
|
||||
}
|
||||
previewEnabled, previewStart, previewSeconds := false, 0, 0
|
||||
if media.MediaType == mediamod.MediaTypeDrama {
|
||||
previewEnabled, previewStart, previewSeconds, err = normalizeDramaPreview(p.PreviewEnabled, p.PreviewStart, p.PreviewSeconds, 0)
|
||||
if err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
}
|
||||
mc := mediacontentmod.MediaContent{
|
||||
ID: vid,
|
||||
MediaID: p.MediaID,
|
||||
MediaType: media.MediaType,
|
||||
Cover: p.Cover,
|
||||
EpisodeNumber: int(p.EpisodeNumber),
|
||||
ListenPermission: p.ListenPermission,
|
||||
Price: p.Price,
|
||||
Name: p.Name,
|
||||
IsActive: p.IsActive,
|
||||
IsDelete: false,
|
||||
UpdatedAct: manager,
|
||||
UpdateTime: now,
|
||||
CreatedAt: now,
|
||||
PreviewEnabled: previewEnabled,
|
||||
PreviewStart: previewStart,
|
||||
PreviewSeconds: previewSeconds,
|
||||
}
|
||||
// 视频和短剧都使用视频资源。
|
||||
if media.MediaType == mediamod.MediaTypeVideo || media.MediaType == mediamod.MediaTypeDrama {
|
||||
mc.Md5 = p.Md5
|
||||
mc.VideoUrl = strings.TrimSpace(p.VideoUrl)
|
||||
mc.Status = 0
|
||||
if p.IsActive {
|
||||
metadata, status, metadataErr := mediaMetadataFromFs(vid.Hex())
|
||||
if metadataErr != nil {
|
||||
return errors.New("文件服务连接失败,暂不能上架剧集"), primitive.ObjectID{}
|
||||
}
|
||||
mc.Status = status
|
||||
mc.PlayTime = metadata.PlayTime
|
||||
mc.Weight = metadata.Width
|
||||
mc.Height = metadata.Height
|
||||
mc.MediaSize = int64(metadata.Size)
|
||||
if metadata.CheckSum != "" {
|
||||
mc.Md5 = metadata.CheckSum
|
||||
}
|
||||
mc.Ratio = metadata.Ratio
|
||||
if mc.Ratio == 0 && mc.Height > 0 {
|
||||
mc.Ratio = float64(mc.Weight) / float64(mc.Height)
|
||||
}
|
||||
if media.MediaType == mediamod.MediaTypeDrama {
|
||||
mc.PreviewEnabled, mc.PreviewStart, mc.PreviewSeconds, err = normalizeDramaPreview(mc.PreviewEnabled, mc.PreviewStart, mc.PreviewSeconds, mc.PlayTime)
|
||||
if err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
if err = validateDramaEpisodeState(mc.EpisodeNumber, mc.ListenPermission, mc.Price, mc.Name, mc.VideoUrl, mc.H265Url, true, mc.Status); err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 图集
|
||||
if media.MediaType == mediamod.MediaTypeImage {
|
||||
mc.UrlSet = p.UrlSet
|
||||
}
|
||||
// 小说
|
||||
if media.MediaType == mediamod.MediaTypeText {
|
||||
mc.AudioUrl = p.AudioUrl
|
||||
}
|
||||
|
||||
// 创建数据
|
||||
if _, err := mediacontentmod.Insert(nil, mc); err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
|
||||
err = OnMediaContentChange(media.ID, media.MediaType, true, mc.IsActive)
|
||||
if err != nil {
|
||||
return err, primitive.ObjectID{}
|
||||
}
|
||||
return nil, vid
|
||||
}
|
||||
|
||||
type WebUpdateReq struct {
|
||||
ID primitive.ObjectID `json:"id" binding:"required"`
|
||||
EpisodeNumber *int `json:"episodeNumber"` // 第几集
|
||||
ListenPermission *int `json:"listenPermission"` // 收听权限 0:会员 1:金币购买 2:免费
|
||||
Price *int64 `json:"price"` // 购买价格
|
||||
Name *string `json:"name"` // 章节名
|
||||
Cover *string `json:"cover"` // 封面
|
||||
Text *string `json:"text"` // 内容(小说专用)
|
||||
Md5 *string `json:"md5"` // 媒体md5
|
||||
VideoUrl *string `json:"videoUrl"` // 视频地址
|
||||
H265Url *string `json:"h265Url"` // H.265视频地址
|
||||
AudioUrl *string `json:"audioUrl"` // 有声小说地址
|
||||
UrlSet *[]string `json:"urlSet"` // 地址集(多个资源地址用 例如漫画)
|
||||
IsActive *bool `json:"isActive"` // 是否激活
|
||||
PreviewEnabled *bool `json:"previewEnabled"` // 是否允许试看
|
||||
PreviewStart *int `json:"previewStart"` // 试看起始时间(秒)
|
||||
PreviewSeconds *int `json:"previewSeconds"` // 试看时长(秒)
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (p *WebUpdateReq) Update(manager string) error {
|
||||
mediaContent, err := mediacontentmod.GetInfo(p.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mediaContent.ID.IsZero() {
|
||||
return errors.New("media content is null")
|
||||
}
|
||||
media, err := mediamod.GetInfo(mediaContent.MediaID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
next := mediaContent
|
||||
if p.EpisodeNumber != nil {
|
||||
next.EpisodeNumber = *p.EpisodeNumber
|
||||
}
|
||||
if p.ListenPermission != nil {
|
||||
next.ListenPermission = *p.ListenPermission
|
||||
}
|
||||
if p.Price != nil {
|
||||
next.Price = *p.Price
|
||||
}
|
||||
if p.Name != nil {
|
||||
next.Name = strings.TrimSpace(*p.Name)
|
||||
}
|
||||
if p.VideoUrl != nil {
|
||||
next.VideoUrl = strings.TrimSpace(*p.VideoUrl)
|
||||
}
|
||||
if p.H265Url != nil {
|
||||
next.H265Url = strings.TrimSpace(*p.H265Url)
|
||||
}
|
||||
if p.IsActive != nil {
|
||||
next.IsActive = *p.IsActive
|
||||
}
|
||||
if p.PreviewEnabled != nil {
|
||||
next.PreviewEnabled = *p.PreviewEnabled
|
||||
}
|
||||
if p.PreviewStart != nil {
|
||||
next.PreviewStart = *p.PreviewStart
|
||||
}
|
||||
if p.PreviewSeconds != nil {
|
||||
next.PreviewSeconds = *p.PreviewSeconds
|
||||
}
|
||||
var metadata *vidmod.AwsPullResp
|
||||
if next.IsActive && (media.MediaType == mediamod.MediaTypeVideo || media.MediaType == mediamod.MediaTypeDrama) && next.Status != 1 {
|
||||
loaded, status, metadataErr := mediaMetadataFromFs(mediaContent.ID.Hex())
|
||||
if metadataErr != nil {
|
||||
return errors.New("文件服务连接失败,暂不能上架剧集")
|
||||
}
|
||||
metadata = &loaded
|
||||
next.Status = status
|
||||
next.PlayTime = loaded.PlayTime
|
||||
next.Weight = loaded.Width
|
||||
next.Height = loaded.Height
|
||||
next.MediaSize = int64(loaded.Size)
|
||||
next.Ratio = loaded.Ratio
|
||||
if next.Ratio == 0 && next.Height > 0 {
|
||||
next.Ratio = float64(next.Weight) / float64(next.Height)
|
||||
}
|
||||
}
|
||||
if media.MediaType == mediamod.MediaTypeDrama {
|
||||
next.PreviewEnabled, next.PreviewStart, next.PreviewSeconds, err = normalizeDramaPreview(next.PreviewEnabled, next.PreviewStart, next.PreviewSeconds, next.PlayTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = validateDramaEpisodeState(next.EpisodeNumber, next.ListenPermission, next.Price, next.Name, next.VideoUrl, next.H265Url, next.IsActive, next.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ensureEpisodeNumberUnique(media.ID, next.EpisodeNumber, mediaContent.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
data := make(map[string]interface{})
|
||||
if p.EpisodeNumber != nil {
|
||||
data["episodeNumber"] = *p.EpisodeNumber
|
||||
}
|
||||
if p.ListenPermission != nil {
|
||||
data["listenPermission"] = *p.ListenPermission
|
||||
}
|
||||
if p.Price != nil {
|
||||
data["price"] = *p.Price
|
||||
}
|
||||
if p.Name != nil {
|
||||
data["name"] = next.Name
|
||||
}
|
||||
if p.Cover != nil {
|
||||
data["cover"] = *p.Cover
|
||||
}
|
||||
if p.Text != nil {
|
||||
data["text"] = *p.Text
|
||||
}
|
||||
if p.Md5 != nil {
|
||||
data["md5"] = *p.Md5
|
||||
}
|
||||
if p.VideoUrl != nil {
|
||||
data["videoUrl"] = next.VideoUrl
|
||||
}
|
||||
if p.H265Url != nil {
|
||||
data["h265Url"] = next.H265Url
|
||||
}
|
||||
if p.AudioUrl != nil {
|
||||
data["audioUrl"] = *p.AudioUrl
|
||||
}
|
||||
if p.UrlSet != nil {
|
||||
data["urlSet"] = *p.UrlSet
|
||||
}
|
||||
|
||||
if p.IsActive != nil {
|
||||
data["isActive"] = *p.IsActive
|
||||
}
|
||||
if media.MediaType == mediamod.MediaTypeDrama && (p.PreviewEnabled != nil || p.PreviewStart != nil || p.PreviewSeconds != nil) {
|
||||
data["previewEnabled"] = next.PreviewEnabled
|
||||
data["previewStart"] = next.PreviewStart
|
||||
data["previewSeconds"] = next.PreviewSeconds
|
||||
}
|
||||
if metadata != nil {
|
||||
data["playTime"] = metadata.PlayTime
|
||||
data["weight"] = metadata.Width
|
||||
data["height"] = metadata.Height
|
||||
data["mediaSize"] = metadata.Size
|
||||
data["status"] = next.Status
|
||||
data["ratio"] = next.Ratio
|
||||
if metadata.CheckSum != "" {
|
||||
data["md5"] = metadata.CheckSum
|
||||
}
|
||||
}
|
||||
|
||||
data["updatedAct"] = manager
|
||||
data["updateTime"] = time.Now()
|
||||
if _, err = mediacontentmod.UpdateByID(nil, p.ID, data); err != nil {
|
||||
return err
|
||||
}
|
||||
published := p.IsActive != nil && *p.IsActive && !mediaContent.IsActive
|
||||
err = OnMediaContentChange(media.ID, media.MediaType, false, published)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WebBatchUpdateReq struct {
|
||||
IDS []string `json:"ids" binding:"required"`
|
||||
IsActive *bool `json:"isActive"` // 是否激活
|
||||
Price *int64 `json:"price"` // 价格
|
||||
Permission *int `json:"permission"` // 收听权限 0:会员 1:金币购买 2:免费
|
||||
FreeEpisode *int `json:"freeEpisode"` // 前几集免费
|
||||
}
|
||||
|
||||
func (p *WebBatchUpdateReq) Filter() []primitive.ObjectID {
|
||||
ids, _ := p.ValidatedIDs()
|
||||
return ids
|
||||
}
|
||||
|
||||
func (p *WebBatchUpdateReq) ValidatedIDs() ([]primitive.ObjectID, error) {
|
||||
if len(p.IDS) == 0 || len(p.IDS) > 100 {
|
||||
return nil, errors.New("ids数量必须在1到100之间")
|
||||
}
|
||||
if p.IsActive == nil && p.Price == nil && p.Permission == nil && p.FreeEpisode == nil {
|
||||
return nil, errors.New("至少需要一个批量更新字段")
|
||||
}
|
||||
if p.FreeEpisode != nil && *p.FreeEpisode < 0 {
|
||||
return nil, errors.New("freeEpisode不能小于0")
|
||||
}
|
||||
ids := make([]primitive.ObjectID, 0, len(p.IDS))
|
||||
seen := make(map[primitive.ObjectID]struct{}, len(p.IDS))
|
||||
for _, raw := range p.IDS {
|
||||
id, err := primitive.ObjectIDFromHex(raw)
|
||||
if err != nil || id.IsZero() {
|
||||
return nil, errors.New("ids包含无效的剧集ID")
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (p *WebBatchUpdateReq) applyContentFields(content mediacontentmod.MediaContent) mediacontentmod.MediaContent {
|
||||
if p.IsActive != nil {
|
||||
content.IsActive = *p.IsActive
|
||||
}
|
||||
if p.Price != nil {
|
||||
content.Price = *p.Price
|
||||
}
|
||||
if p.Permission != nil {
|
||||
content.ListenPermission = *p.Permission
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (p *WebBatchUpdateReq) Update(manager string) error {
|
||||
ids, err := p.ValidatedIDs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contents, err := mediacontentmod.QueryAllList(bson.M{
|
||||
"_id": bson.M{"$in": ids},
|
||||
"isDelete": false,
|
||||
}, options.Find().SetLimit(int64(len(ids))))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(contents) != len(ids) {
|
||||
return errors.New("部分剧集不存在或已删除")
|
||||
}
|
||||
mediaID := contents[0].MediaID
|
||||
mediaType := contents[0].MediaType
|
||||
published := false
|
||||
for _, content := range contents {
|
||||
if content.MediaID != mediaID {
|
||||
return errors.New("批量操作的剧集必须属于同一部短剧")
|
||||
}
|
||||
next := p.applyContentFields(*content)
|
||||
if p.IsActive != nil && *p.IsActive && !content.IsActive {
|
||||
published = true
|
||||
}
|
||||
validateState := p.Price != nil || p.Permission != nil || (p.IsActive != nil && *p.IsActive)
|
||||
if validateState && mediaType == mediamod.MediaTypeDrama {
|
||||
if err = validateDramaEpisodeState(next.EpisodeNumber, next.ListenPermission, next.Price, next.Name, next.VideoUrl, next.H265Url, next.IsActive, next.Status); err != nil {
|
||||
return fmt.Errorf("第%d集:%w", content.EpisodeNumber, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
data := make(map[string]interface{})
|
||||
if p.IsActive != nil {
|
||||
data["isActive"] = *p.IsActive
|
||||
}
|
||||
if p.Price != nil {
|
||||
data["price"] = *p.Price
|
||||
}
|
||||
if p.Permission != nil {
|
||||
data["listenPermission"] = *p.Permission
|
||||
}
|
||||
data["updatedAct"] = manager
|
||||
data["updateTime"] = time.Now()
|
||||
|
||||
contentChanged := p.IsActive != nil || p.Price != nil || p.Permission != nil
|
||||
if contentChanged {
|
||||
if _, err := mediacontentmod.UpdateByIDS(nil, ids, data); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = OnMediaContentChange(mediaID, mediaType, false, published); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.FreeEpisode != nil {
|
||||
if _, err = mediamod.UpdateByID(nil, mediaID, map[string]interface{}{
|
||||
"freeEpisode": *p.FreeEpisode,
|
||||
"updatedAct": manager,
|
||||
"updateTime": time.Now(),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WebDeleteReq struct {
|
||||
ID primitive.ObjectID `json:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// Delete 删除数据
|
||||
func (p *WebDeleteReq) Delete() error {
|
||||
mediaContent, err := mediacontentmod.GetInfo(p.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mediacontentmod.DeleteByID(nil, p.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = OnMediaContentChange(mediaContent.MediaID, mediaContent.MediaType, false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OnMediaContentChange(mediaId primitive.ObjectID, mediaType string, contentAdded, published bool) (err error) {
|
||||
// 获取当前最小的章节,重新update
|
||||
defaultContent := mediamod.DefaultContent{}
|
||||
if mediaType == mediamod.MediaTypeImage {
|
||||
contentList, _, _, err := mediacontentmod.GetList(bson.M{"mediaId": mediaId, "isActive": true, "isDelete": false}, 0, 1, bson.D{{Key: "episodeNumber", Value: 1}, {Key: "createdAt", Value: 1}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(contentList) > 0 {
|
||||
defaultContent.Id = contentList[0].ID
|
||||
defaultContent.Name = contentList[0].Name
|
||||
defaultContent.UrlSet = contentList[0].UrlSet
|
||||
defaultContent.Cover = contentList[0].Cover
|
||||
}
|
||||
}
|
||||
// 子集总数
|
||||
count, err := mediacontentmod.QueryAllCount(bson.M{"mediaId": mediaId, "isActive": true, "isDelete": false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 获取子集免费章节总数
|
||||
freeCount, err := mediacontentmod.QueryAllCount(bson.M{"mediaId": mediaId, "listenPermission": 2, "isActive": true, "isDelete": false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contentsPrice, err := mediacontentmod.QueryContentsPrice(mediaId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
updateData := bson.M{
|
||||
"currentEpisode": count,
|
||||
"contentsPrice": contentsPrice,
|
||||
"freeEpisode": freeCount,
|
||||
"updateTime": time.Now(),
|
||||
"defaultContent": defaultContent, // 默认展示的子集内容,冗余一个字段,减少一次查询
|
||||
}
|
||||
now := time.Now()
|
||||
if contentAdded {
|
||||
updateData["contentUpdateTime"] = now
|
||||
}
|
||||
if published {
|
||||
updateData["latestPublishedAt"] = now
|
||||
}
|
||||
//修改当前父级的记录
|
||||
_, err = mediamod.UpdateByID(nil, mediaId, updateData)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ViewMediaFromFs 查看视频转码状态
|
||||
func ViewMediaFromFs(id string) (code stderr.Code, data interface{}) {
|
||||
resp, err := updownloadser.PullFileInfo(id)
|
||||
if err != nil {
|
||||
return stderr.ErrConnectToFs, nil
|
||||
}
|
||||
status := fileStatusToEpisodeStatus(resp.Data.Status)
|
||||
ratio := resp.Data.Ratio
|
||||
if ratio == 0 && resp.Data.Height > 0 {
|
||||
ratio = float64(resp.Data.Width) / float64(resp.Data.Height)
|
||||
}
|
||||
set := map[string]interface{}{
|
||||
"status": status,
|
||||
"playTime": resp.Data.PlayTime,
|
||||
"weight": resp.Data.Width,
|
||||
"height": resp.Data.Height,
|
||||
"mediaSize": int64(resp.Data.Size),
|
||||
"ratio": ratio,
|
||||
"updateTime": time.Now(),
|
||||
}
|
||||
if resp.Data.CheckSum != "" {
|
||||
set["md5"] = resp.Data.CheckSum
|
||||
}
|
||||
objId, _ := primitive.ObjectIDFromHex(id)
|
||||
if _, err = mediacontentmod.UpdateByID(nil, objId, set); err != nil {
|
||||
return stderr.ErrDbUpdateError, nil
|
||||
}
|
||||
back := make(map[string]interface{}, 10)
|
||||
back["playTime"] = resp.Data.PlayTime
|
||||
back["size"] = resp.Data.Size
|
||||
back["width"] = resp.Data.Width
|
||||
back["height"] = resp.Data.Height
|
||||
back["status"] = resp.Data.Status
|
||||
back["ratio"] = ratio
|
||||
fileName := resp.Data.Filename
|
||||
fieldNameFs := resp.Data.FieldNameFs
|
||||
back["fileName"] = filepath.Join(filepath.Dir(fieldNameFs), fileName)
|
||||
switch resp.Data.Status {
|
||||
case vidmod.UploadLoadingToFs:
|
||||
back["statusDesc"] = "正在上传中"
|
||||
case vidmod.UploadCompleted:
|
||||
back["statusDesc"] = "上传完成"
|
||||
case vidmod.FileUploadError:
|
||||
back["statusDesc"] = "上传错误"
|
||||
case vidmod.Merging:
|
||||
back["statusDesc"] = "正在合并中"
|
||||
case vidmod.MergeCompleted:
|
||||
back["statusDesc"] = "合并完成"
|
||||
case vidmod.MergeError:
|
||||
back["statusDesc"] = "合并失败"
|
||||
case vidmod.Converting:
|
||||
back["statusDesc"] = "正在转码中"
|
||||
case vidmod.ConvertError:
|
||||
back["statusDesc"] = "转码失败"
|
||||
case vidmod.ConvertCompleted, vidmod.Completed:
|
||||
back["statusDesc"] = "完成状态"
|
||||
}
|
||||
return stderr.Success, back
|
||||
}
|
||||
Reference in New Issue
Block a user