go-common/app/admin/main/videoup/service/extra_func.go
2019-04-22 18:49:16 +08:00

534 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}