You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
533 lines
15 KiB
533 lines
15 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"errors" |
|
"hash/crc32" |
|
"strconv" |
|
"strings" |
|
"time" |
|
|
|
"go-common/app/admin/main/videoup/model/archive" |
|
mngmdl "go-common/app/admin/main/videoup/model/manager" |
|
accApi "go-common/app/service/main/account/api" |
|
upsrpc "go-common/app/service/main/up/api/v1" |
|
"go-common/library/log" |
|
"go-common/library/sync/errgroup" |
|
xtime "go-common/library/time" |
|
|
|
"go-common/library/xstr" |
|
) |
|
|
|
//ERROR |
|
var ( |
|
ErrRPCEmpty = errors.New("rpc reply empty") |
|
) |
|
|
|
func (s *Service) archiveRound(c context.Context, a *archive.Archive, aid, mid int64, typeID int16, nowRound, newState int8, cancelMission bool) (round int8) { |
|
//非特殊分区私单定时发布时,稿件进入四审 |
|
//一个私单且定时发布的稿件 应该是先通过待审 传递到 私单四审 ,私单四审开放浏览后到达设置的定时时间最后再自动发布 |
|
if s.isPorder(a) && newState == archive.StateForbidUserDelay && !s.isAuditType(typeID) { |
|
round = archive.RoundReviewFlow |
|
return |
|
} |
|
//定时发布的付费稿件 投上来就是round24 admin提交不需要再走付费审核 |
|
|
|
//定时发布 |
|
if newState == archive.StateForbidAdminDelay || newState == archive.StateForbidUserDelay { |
|
round = nowRound |
|
return |
|
} |
|
var addit *archive.Addit |
|
//活动稿件(非私单且非付费) | pgc 稿件 up_from(1,5,6) 直接round 99 简单流程业务 |
|
if addit, _ = s.arc.Addit(c, aid); addit != nil && (addit.UpFrom == archive.UpFromPGC || addit.UpFrom == archive.UpFromSecretPGC || addit.UpFrom == archive.UpFromCoopera || (addit.MissionID > 0 && !s.isPorder(a) && !s.isUGCPay(a))) { |
|
if addit.UpFrom == archive.UpFromSecretPGC && newState == archive.StateForbidWait { |
|
//pgc 机密待审state=-1 不变更round |
|
round = nowRound |
|
return |
|
} |
|
if archive.NormalState(newState) { |
|
//pgc 生产组机密稿件(番剧、付费版权,严格要求时效和保密性) up_from=5 开放回查流程 90 |
|
if addit.UpFrom == archive.UpFromSecretPGC && nowRound < archive.RoundTriggerClick { |
|
//三查 |
|
round = archive.RoundTriggerClick |
|
return |
|
} |
|
} |
|
//pgc 生产组常规稿件(片包等其他内容) up_from=1 进三审 |
|
if addit.UpFrom == archive.UpFromPGC && nowRound < archive.RoundAuditThird { |
|
round = archive.RoundAuditThird |
|
return |
|
} |
|
//pgc 合作方嵌套,终结 |
|
if addit.UpFrom == archive.UpFromCoopera && nowRound < archive.RoundAuditThird { |
|
round = archive.RoundEnd |
|
return |
|
} |
|
round = archive.RoundEnd |
|
return |
|
} |
|
//其他稿件 (非定时,活动,pgc) |
|
if nowRound == archive.RoundAuditSecond { |
|
//二审阶段 |
|
if newState == archive.StateForbidWait { |
|
//1、非特殊分区私单进入私单四审;2、私单活动稿件进入私单四审 |
|
if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) { |
|
//私单四审 |
|
round = archive.RoundReviewFlow |
|
} else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) { |
|
//付费稿件 非特殊分区 非私单 |
|
round = archive.RoundAuditUGCPayFlow |
|
} else if s.isAuditType(typeID) || (addit != nil && addit.OrderID > 0) { |
|
//特殊分区 ,商单到三审 二审到三审 |
|
round = archive.RoundAuditThird |
|
} else { |
|
//不变 |
|
round = archive.RoundAuditSecond |
|
} |
|
} else if archive.NormalState(newState) { |
|
//回查控制 |
|
round = s.normalRound(c, aid, mid, typeID, nowRound, newState) |
|
} else if newState == archive.StateForbidFixed { |
|
//1、非特殊分区私单进入私单四审修复待审;2、私单+活动稿件进入私单四审修复待审 |
|
if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) { |
|
round = archive.RoundReviewFlow |
|
} else if s.isAuditType(typeID) && !(!cancelMission && addit.MissionID > 0) { |
|
//特殊分区 二审到三审 |
|
round = archive.RoundAuditThird |
|
} else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) { |
|
//付费稿件 非特殊分区 非私单 |
|
round = archive.RoundAuditUGCPayFlow |
|
} else { |
|
//不变 |
|
round = archive.RoundAuditSecond |
|
} |
|
} else { |
|
round = archive.RoundEnd |
|
} |
|
} else if nowRound == archive.RoundReviewFlow { |
|
//私单四审21 |
|
if archive.NormalState(newState) { |
|
if s.isAuditType(typeID) || addit.MissionID > 0 { |
|
round = archive.RoundEnd |
|
} else { |
|
round = s.normalRound(c, aid, mid, typeID, nowRound, newState) |
|
} |
|
} else { |
|
round = archive.RoundEnd |
|
} |
|
} else if nowRound == archive.RoundAuditUGCPayFlow { |
|
//付费待审 24 |
|
if archive.NormalState(newState) { |
|
if s.isAuditType(typeID) || addit.MissionID > 0 { |
|
round = archive.RoundEnd |
|
} else { |
|
round = s.normalRound(c, aid, mid, typeID, nowRound, newState) |
|
} |
|
} else { |
|
round = archive.RoundEnd |
|
} |
|
} else if nowRound == archive.RoundReviewFirst { |
|
//一查 |
|
if archive.NormalState(newState) { |
|
round = archive.RoundReviewFirstWaitTrigger |
|
} else { |
|
round = archive.RoundEnd |
|
} |
|
} else if nowRound == archive.RoundAuditThird { |
|
//三审 |
|
if s.isPorder(a) { |
|
//私单四审 |
|
round = archive.RoundReviewFlow |
|
} else if s.isUGCPay(a) { |
|
round = archive.RoundAuditUGCPayFlow |
|
} else { |
|
round = archive.RoundEnd |
|
} |
|
} else if nowRound == archive.RoundReviewSecond || nowRound == archive.RoundTriggerClick { |
|
//二查 三查 |
|
round = archive.RoundEnd |
|
} else { |
|
round = nowRound |
|
} |
|
return |
|
} |
|
|
|
//normalRound 回查逻辑 |
|
func (s *Service) normalRound(c context.Context, aid, mid int64, typeID int16, nowRound, newState int8) (round int8) { |
|
if s.isWhite(mid) || s.isBlack(mid) { |
|
round = archive.RoundReviewSecond |
|
} else if plf, _ := s.profile(c, mid); plf != nil && plf.Follower >= s.fansCache { |
|
//社区回查 粉丝阈值 |
|
round = archive.RoundReviewSecond |
|
} else if plf != nil && plf.Follower < s.fansCache && s.isRoundType(typeID) { |
|
//回查分区 |
|
round = archive.RoundReviewFirst // NOTE: if audit type, state must not open!!! so cannot execute here... |
|
} else { |
|
//点击量回查 |
|
round = archive.RoundReviewFirstWaitTrigger |
|
if plf == nil { |
|
log.Info("archive(%d) card(%d) is nil", aid, mid) |
|
} else { |
|
log.Info("archive(%d) card(%d) fans(%d) little than config(%d)", aid, mid, plf.Follower, s.fansCache) |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) hadPassed(c context.Context, aid int64) (had bool) { |
|
id, err := s.arc.GetFirstPassByAID(c, aid) |
|
if err != nil { |
|
log.Error("hadPassed s.arc.GetFirstPassByAID error(%v) aid(%d)", err, aid) |
|
return |
|
} |
|
|
|
had = id > 0 |
|
return |
|
} |
|
|
|
func (s *Service) isPorder(a *archive.Archive) bool { |
|
if a == nil { |
|
return false |
|
} |
|
return a.AttrVal(archive.AttrBitIsPorder) == archive.AttrYes |
|
} |
|
|
|
//ugc pay only |
|
func (s *Service) isUGCPay(a *archive.Archive) bool { |
|
if a == nil { |
|
return false |
|
} |
|
return a.AttrVal(archive.AttrBitUGCPay) == archive.AttrYes |
|
} |
|
|
|
func (s *Service) profile(c context.Context, mid int64) (card *accApi.ProfileStatReply, err error) { |
|
if card, err = s.accRPC.ProfileWithStat3(c, &accApi.MidReq{Mid: mid}); err != nil { |
|
log.Error("s.accRPC.ProfileWithStat3(%d) error(%v)", mid, err) |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) upCards(c context.Context, mids []int64) (p map[int64]*accApi.Card, err error) { |
|
p = make(map[int64]*accApi.Card) |
|
if len(mids) == 0 { |
|
return |
|
} |
|
var res *accApi.CardsReply |
|
if res, err = s.accRPC.Cards3(c, &accApi.MidsReq{Mids: mids}); err != nil { |
|
p = nil |
|
log.Error("s.accRPC.Cards3(%v) error(%v)", mids, err) |
|
return |
|
} |
|
p = res.Cards |
|
return |
|
} |
|
|
|
func (s *Service) archivePtime(c context.Context, aid int64, newState int8, newPtime xtime.Time) (ptime xtime.Time) { |
|
if newState >= archive.StateOpen { |
|
if !s.hadPassed(c, aid) { |
|
ptime = xtime.Time(time.Now().Unix()) |
|
return |
|
} |
|
} |
|
ptime = newPtime |
|
return |
|
} |
|
|
|
func (s *Service) archiveAttr(c context.Context, ap *archive.ArcParam, isExt bool) (attrs map[uint]int32, forbidAttrs map[string]map[uint]int32) { |
|
//批量和单个提交都需要补全对应属性值 |
|
|
|
attrs = make(map[uint]int32) |
|
attrs[archive.AttrBitNoRank] = ap.Attrs.NoRank |
|
attrs[archive.AttrBitNoDynamic] = ap.Attrs.NoDynamic |
|
attrs[archive.AttrBitNoWeb] = ap.Attrs.NoWeb |
|
attrs[archive.AttrBitNoMobile] = ap.Attrs.NoMobile |
|
attrs[archive.AttrBitNoSearch] = ap.Attrs.NoSearch |
|
attrs[archive.AttrBitOverseaLock] = ap.Attrs.OverseaLock |
|
attrs[archive.AttrBitNoRecommend] = ap.Attrs.NoRecommend |
|
attrs[archive.AttrBitNoReprint] = ap.Attrs.NoReprint |
|
attrs[archive.AttrBitHasHD5] = ap.Attrs.HasHD5 |
|
attrs[archive.AttrBitAllowBp] = ap.Attrs.AllowBp |
|
attrs[archive.AttrBitIsPorder] = ap.Attrs.IsPorder |
|
attrs[archive.AttrBitLimitArea] = ap.Attrs.LimitArea |
|
attrs[archive.AttrBitPushBlog] = ap.Attrs.PushBlog |
|
attrs[archive.AttrBitUGCPay] = ap.Attrs.UGCPay |
|
attrs[archive.AttrBitParentMode] = ap.Attrs.ParentMode |
|
// pgc |
|
attrs[archive.AttrBitIsMovie] = ap.Attrs.IsMovie |
|
attrs[archive.AttrBitBadgepay] = ap.Attrs.BadgePay |
|
attrs[archive.AttrBitIsBangumi] = ap.Attrs.IsBangumi |
|
attrs[archive.AttrBitIsPGC] = ap.Attrs.IsPGC |
|
if isExt { |
|
attrs[archive.AttrBitAllowTag] = ap.Attrs.AllowTag |
|
attrs[archive.AttrBitJumpURL] = ap.Attrs.JumpURL |
|
} |
|
forbidAttrs = make(map[string]map[uint]int32, 4) |
|
forbidAttrs[archive.ForbidRank] = map[uint]int32{ |
|
archive.ForbidRankMain: ap.Forbid.Rank.Main, |
|
archive.ForbidRankRecentArc: ap.Forbid.Rank.RecentArc, |
|
archive.ForbidRankAllArc: ap.Forbid.Rank.AllArc, |
|
} |
|
forbidAttrs[archive.ForbidDynamic] = map[uint]int32{ |
|
archive.ForbidDynamicMain: ap.Forbid.Dynamic.Main, |
|
} |
|
forbidAttrs[archive.ForbidRecommend] = map[uint]int32{ |
|
archive.ForbidRecommendMain: ap.Forbid.Recommend.Main, |
|
} |
|
forbidAttrs[archive.ForbidShow] = map[uint]int32{ |
|
archive.ForbidShowMain: ap.Forbid.Show.Main, |
|
archive.ForbidShowMobile: ap.Forbid.Show.Mobile, |
|
archive.ForbidShowWeb: ap.Forbid.Show.Web, |
|
archive.ForbidShowOversea: ap.Forbid.Show.Oversea, |
|
archive.ForbidShowOnline: ap.Forbid.Show.Online, |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) isAccess(c context.Context, aid int64) (wm bool) { |
|
var vs []*archive.Video |
|
if vs, _ = s.arc.NewVideosByAid(c, aid); len(vs) <= 0 { |
|
return |
|
} |
|
for _, v := range vs { |
|
if v.Status == 10000 { |
|
wm = true |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
// CheckArchive check typeid |
|
func (s *Service) CheckArchive(aps []*archive.ArcParam) bool { |
|
for _, ap := range aps { |
|
if ap.Aid == 0 || ap.UID == 0 { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
// CheckVideo check video |
|
func (s *Service) CheckVideo(vps []*archive.VideoParam) bool { |
|
for _, vp := range vps { |
|
if vp.ID == 0 || vp.Aid == 0 || vp.Filename == "" || vp.Cid == 0 || vp.UID == 0 { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
// CheckStaff check |
|
func (s *Service) CheckStaff(vps []*archive.StaffParam) bool { |
|
//允许为空 不允许为Nil |
|
if len(vps) == 0 { |
|
return true |
|
} |
|
for _, vp := range vps { |
|
if vp.MID == 0 || vp.Title == "" { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
// TypeTopParent get archive type's first level type |
|
func (s *Service) TypeTopParent(tid int16) (tp *archive.Type, err error) { |
|
if _, ok := s.typeCache[tid]; !ok { |
|
err = errors.New("archive type id not exist. id:" + strconv.Itoa(int(tid))) |
|
return |
|
} |
|
if s.typeCache[tid].PID == 0 { |
|
tp = s.typeCache[tid] |
|
} else { |
|
tp, err = s.TypeTopParent(s.typeCache[tid].PID) |
|
if err != nil { |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
//StringHandler handle two strings 以s1顺序为准 |
|
func StringHandler(s1 string, s2 string, delimiter string, subtraction bool) string { |
|
if strings.TrimSpace(s2) == "" { |
|
return s1 |
|
} |
|
|
|
var ( |
|
res []string |
|
duplicate []int |
|
) |
|
s1Arr := strings.Split(s1, delimiter) |
|
s2Arr := strings.Split(s2, delimiter) |
|
for _, s1Item := range s1Arr { |
|
dupIndex := -1 |
|
for k, s2Item := range s2Arr { |
|
if s1Item == s2Item { |
|
dupIndex = k |
|
break |
|
} |
|
} |
|
|
|
if dupIndex >= 0 && subtraction { |
|
continue |
|
} |
|
if dupIndex >= 0 { |
|
duplicate = append(duplicate, dupIndex) |
|
} |
|
res = append(res, s1Item) |
|
} |
|
|
|
if !subtraction { |
|
for k, s2Item := range s2Arr { |
|
s2Item = strings.TrimSpace(s2Item) |
|
if s2Item == "" { |
|
continue |
|
} |
|
add := true |
|
for _, dup := range duplicate { |
|
if k == dup { |
|
add = false |
|
break |
|
} |
|
} |
|
if add { |
|
res = append(res, s2Item) |
|
} |
|
} |
|
} |
|
return strings.Join(res, delimiter) |
|
} |
|
|
|
// SplitInts 去掉id字符串中的空白字符 |
|
func (s *Service) SplitInts(str string) ([]int64, error) { |
|
empties := []string{" ", "\n", "\t", "\r"} |
|
for _, v := range empties { |
|
str = strings.Replace(str, v, "", -1) |
|
} |
|
str = strings.Trim(str, ",") |
|
return xstr.SplitInts(str) |
|
} |
|
|
|
// coverURL convert cover url to full url. |
|
func coverURL(uri string) (cover string) { |
|
if uri == "" { |
|
cover = "http://static.hdslb.com/images/transparent.gif" |
|
return |
|
} |
|
cover = uri |
|
if strings.Index(uri, "http://") == 0 { |
|
return |
|
} |
|
if len(uri) >= 10 && uri[:10] == "/templets/" { |
|
return |
|
} |
|
if strings.HasPrefix(uri, "group1") { |
|
cover = "http://i0.hdslb.com/" + uri |
|
return |
|
} |
|
if pos := strings.Index(uri, "/uploads/"); pos != -1 && (pos == 0 || pos == 3) { |
|
cover = uri[pos+8:] |
|
} |
|
cover = strings.Replace(cover, "{IMG}", "", -1) |
|
cover = "http://i" + strconv.FormatInt(int64(crc32.ChecksumIEEE([]byte(cover)))%3, 10) + ".hdslb.com" + cover |
|
return |
|
} |
|
|
|
func (s *Service) upGroupMids(c context.Context, gid int64) (mids []int64, err error) { |
|
var ( |
|
total int |
|
maxps = 10000 |
|
req = &upsrpc.UpGroupMidsReq{ |
|
Pn: 1, |
|
GroupID: gid, |
|
Ps: maxps, |
|
} |
|
reply *upsrpc.UpGroupMidsReply |
|
) |
|
|
|
for { |
|
reply, err = s.upsRPC.UpGroupMids(c, req) |
|
if err == nil && (reply == nil || reply.Mids == nil) { |
|
err = ErrRPCEmpty |
|
} |
|
if err != nil { |
|
log.Error("UpGroupMids req(%+v) error(%v)", req, err) |
|
return |
|
} |
|
total = reply.Total |
|
mids = append(mids, reply.Mids...) |
|
if reply.Size() != maxps { |
|
break |
|
} |
|
req.Pn++ |
|
} |
|
log.Info("upGroupMids(%d) reply total(%d) len(%d)", gid, total, len(mids)) |
|
return |
|
} |
|
|
|
func (s *Service) upSpecial(c context.Context) (ups map[int8]map[int64]struct{}, err error) { |
|
var ( |
|
g errgroup.Group |
|
whitegroup, blackgroup, pgcgroup, ugcxgroup, policygroup, dangergroup, twoforbidgroup, pgcwhitegroup map[int64]struct{} |
|
) |
|
ups = make(map[int8]map[int64]struct{}) |
|
|
|
f := func(gid int8) (map[int64]struct{}, error) { |
|
group := make(map[int64]struct{}) |
|
mids, e := s.upGroupMids(c, int64(gid)) |
|
if e != nil { |
|
return group, e |
|
} |
|
for _, mid := range mids { |
|
group[mid] = struct{}{} |
|
} |
|
return group, nil |
|
} |
|
g.Go(func() error { |
|
whitegroup, err = f(mngmdl.UpperTypeWhite) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
blackgroup, err = f(mngmdl.UpperTypeBlack) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
pgcgroup, err = f(mngmdl.UpperTypePGC) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
ugcxgroup, err = f(mngmdl.UpperTypeUGCX) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
policygroup, err = f(mngmdl.UpperTypePolity) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
dangergroup, err = f(mngmdl.UpperTypeDanger) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
twoforbidgroup, err = f(mngmdl.UpperTypeTwoForbid) |
|
return err |
|
}) |
|
g.Go(func() error { |
|
pgcwhitegroup, err = f(mngmdl.UpperTypePGCWhite) |
|
return err |
|
}) |
|
if err = g.Wait(); err != nil { |
|
return |
|
} |
|
|
|
ups[mngmdl.UpperTypeWhite] = whitegroup |
|
ups[mngmdl.UpperTypeBlack] = blackgroup |
|
ups[mngmdl.UpperTypePGC] = pgcgroup |
|
ups[mngmdl.UpperTypeUGCX] = ugcxgroup |
|
ups[mngmdl.UpperTypePolity] = policygroup |
|
ups[mngmdl.UpperTypeDanger] = dangergroup |
|
ups[mngmdl.UpperTypeTwoForbid] = twoforbidgroup |
|
ups[mngmdl.UpperTypePGCWhite] = pgcwhitegroup |
|
return |
|
}
|
|
|