extra_func.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. package service
  2. import (
  3. "context"
  4. "errors"
  5. "hash/crc32"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "go-common/app/admin/main/videoup/model/archive"
  10. mngmdl "go-common/app/admin/main/videoup/model/manager"
  11. accApi "go-common/app/service/main/account/api"
  12. upsrpc "go-common/app/service/main/up/api/v1"
  13. "go-common/library/log"
  14. "go-common/library/sync/errgroup"
  15. xtime "go-common/library/time"
  16. "go-common/library/xstr"
  17. )
  18. //ERROR
  19. var (
  20. ErrRPCEmpty = errors.New("rpc reply empty")
  21. )
  22. func (s *Service) archiveRound(c context.Context, a *archive.Archive, aid, mid int64, typeID int16, nowRound, newState int8, cancelMission bool) (round int8) {
  23. //非特殊分区私单定时发布时,稿件进入四审
  24. //一个私单且定时发布的稿件 应该是先通过待审 传递到 私单四审 ,私单四审开放浏览后到达设置的定时时间最后再自动发布
  25. if s.isPorder(a) && newState == archive.StateForbidUserDelay && !s.isAuditType(typeID) {
  26. round = archive.RoundReviewFlow
  27. return
  28. }
  29. //定时发布的付费稿件 投上来就是round24 admin提交不需要再走付费审核
  30. //定时发布
  31. if newState == archive.StateForbidAdminDelay || newState == archive.StateForbidUserDelay {
  32. round = nowRound
  33. return
  34. }
  35. var addit *archive.Addit
  36. //活动稿件(非私单且非付费) | pgc 稿件 up_from(1,5,6) 直接round 99 简单流程业务
  37. 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))) {
  38. if addit.UpFrom == archive.UpFromSecretPGC && newState == archive.StateForbidWait {
  39. //pgc 机密待审state=-1 不变更round
  40. round = nowRound
  41. return
  42. }
  43. if archive.NormalState(newState) {
  44. //pgc 生产组机密稿件(番剧、付费版权,严格要求时效和保密性) up_from=5 开放回查流程 90
  45. if addit.UpFrom == archive.UpFromSecretPGC && nowRound < archive.RoundTriggerClick {
  46. //三查
  47. round = archive.RoundTriggerClick
  48. return
  49. }
  50. }
  51. //pgc 生产组常规稿件(片包等其他内容) up_from=1 进三审
  52. if addit.UpFrom == archive.UpFromPGC && nowRound < archive.RoundAuditThird {
  53. round = archive.RoundAuditThird
  54. return
  55. }
  56. //pgc 合作方嵌套,终结
  57. if addit.UpFrom == archive.UpFromCoopera && nowRound < archive.RoundAuditThird {
  58. round = archive.RoundEnd
  59. return
  60. }
  61. round = archive.RoundEnd
  62. return
  63. }
  64. //其他稿件 (非定时,活动,pgc)
  65. if nowRound == archive.RoundAuditSecond {
  66. //二审阶段
  67. if newState == archive.StateForbidWait {
  68. //1、非特殊分区私单进入私单四审;2、私单活动稿件进入私单四审
  69. if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) {
  70. //私单四审
  71. round = archive.RoundReviewFlow
  72. } else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) {
  73. //付费稿件 非特殊分区 非私单
  74. round = archive.RoundAuditUGCPayFlow
  75. } else if s.isAuditType(typeID) || (addit != nil && addit.OrderID > 0) {
  76. //特殊分区 ,商单到三审 二审到三审
  77. round = archive.RoundAuditThird
  78. } else {
  79. //不变
  80. round = archive.RoundAuditSecond
  81. }
  82. } else if archive.NormalState(newState) {
  83. //回查控制
  84. round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
  85. } else if newState == archive.StateForbidFixed {
  86. //1、非特殊分区私单进入私单四审修复待审;2、私单+活动稿件进入私单四审修复待审
  87. if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) {
  88. round = archive.RoundReviewFlow
  89. } else if s.isAuditType(typeID) && !(!cancelMission && addit.MissionID > 0) {
  90. //特殊分区 二审到三审
  91. round = archive.RoundAuditThird
  92. } else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) {
  93. //付费稿件 非特殊分区 非私单
  94. round = archive.RoundAuditUGCPayFlow
  95. } else {
  96. //不变
  97. round = archive.RoundAuditSecond
  98. }
  99. } else {
  100. round = archive.RoundEnd
  101. }
  102. } else if nowRound == archive.RoundReviewFlow {
  103. //私单四审21
  104. if archive.NormalState(newState) {
  105. if s.isAuditType(typeID) || addit.MissionID > 0 {
  106. round = archive.RoundEnd
  107. } else {
  108. round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
  109. }
  110. } else {
  111. round = archive.RoundEnd
  112. }
  113. } else if nowRound == archive.RoundAuditUGCPayFlow {
  114. //付费待审 24
  115. if archive.NormalState(newState) {
  116. if s.isAuditType(typeID) || addit.MissionID > 0 {
  117. round = archive.RoundEnd
  118. } else {
  119. round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
  120. }
  121. } else {
  122. round = archive.RoundEnd
  123. }
  124. } else if nowRound == archive.RoundReviewFirst {
  125. //一查
  126. if archive.NormalState(newState) {
  127. round = archive.RoundReviewFirstWaitTrigger
  128. } else {
  129. round = archive.RoundEnd
  130. }
  131. } else if nowRound == archive.RoundAuditThird {
  132. //三审
  133. if s.isPorder(a) {
  134. //私单四审
  135. round = archive.RoundReviewFlow
  136. } else if s.isUGCPay(a) {
  137. round = archive.RoundAuditUGCPayFlow
  138. } else {
  139. round = archive.RoundEnd
  140. }
  141. } else if nowRound == archive.RoundReviewSecond || nowRound == archive.RoundTriggerClick {
  142. //二查 三查
  143. round = archive.RoundEnd
  144. } else {
  145. round = nowRound
  146. }
  147. return
  148. }
  149. //normalRound 回查逻辑
  150. func (s *Service) normalRound(c context.Context, aid, mid int64, typeID int16, nowRound, newState int8) (round int8) {
  151. if s.isWhite(mid) || s.isBlack(mid) {
  152. round = archive.RoundReviewSecond
  153. } else if plf, _ := s.profile(c, mid); plf != nil && plf.Follower >= s.fansCache {
  154. //社区回查 粉丝阈值
  155. round = archive.RoundReviewSecond
  156. } else if plf != nil && plf.Follower < s.fansCache && s.isRoundType(typeID) {
  157. //回查分区
  158. round = archive.RoundReviewFirst // NOTE: if audit type, state must not open!!! so cannot execute here...
  159. } else {
  160. //点击量回查
  161. round = archive.RoundReviewFirstWaitTrigger
  162. if plf == nil {
  163. log.Info("archive(%d) card(%d) is nil", aid, mid)
  164. } else {
  165. log.Info("archive(%d) card(%d) fans(%d) little than config(%d)", aid, mid, plf.Follower, s.fansCache)
  166. }
  167. }
  168. return
  169. }
  170. func (s *Service) hadPassed(c context.Context, aid int64) (had bool) {
  171. id, err := s.arc.GetFirstPassByAID(c, aid)
  172. if err != nil {
  173. log.Error("hadPassed s.arc.GetFirstPassByAID error(%v) aid(%d)", err, aid)
  174. return
  175. }
  176. had = id > 0
  177. return
  178. }
  179. func (s *Service) isPorder(a *archive.Archive) bool {
  180. if a == nil {
  181. return false
  182. }
  183. return a.AttrVal(archive.AttrBitIsPorder) == archive.AttrYes
  184. }
  185. //ugc pay only
  186. func (s *Service) isUGCPay(a *archive.Archive) bool {
  187. if a == nil {
  188. return false
  189. }
  190. return a.AttrVal(archive.AttrBitUGCPay) == archive.AttrYes
  191. }
  192. func (s *Service) profile(c context.Context, mid int64) (card *accApi.ProfileStatReply, err error) {
  193. if card, err = s.accRPC.ProfileWithStat3(c, &accApi.MidReq{Mid: mid}); err != nil {
  194. log.Error("s.accRPC.ProfileWithStat3(%d) error(%v)", mid, err)
  195. }
  196. return
  197. }
  198. func (s *Service) upCards(c context.Context, mids []int64) (p map[int64]*accApi.Card, err error) {
  199. p = make(map[int64]*accApi.Card)
  200. if len(mids) == 0 {
  201. return
  202. }
  203. var res *accApi.CardsReply
  204. if res, err = s.accRPC.Cards3(c, &accApi.MidsReq{Mids: mids}); err != nil {
  205. p = nil
  206. log.Error("s.accRPC.Cards3(%v) error(%v)", mids, err)
  207. return
  208. }
  209. p = res.Cards
  210. return
  211. }
  212. func (s *Service) archivePtime(c context.Context, aid int64, newState int8, newPtime xtime.Time) (ptime xtime.Time) {
  213. if newState >= archive.StateOpen {
  214. if !s.hadPassed(c, aid) {
  215. ptime = xtime.Time(time.Now().Unix())
  216. return
  217. }
  218. }
  219. ptime = newPtime
  220. return
  221. }
  222. func (s *Service) archiveAttr(c context.Context, ap *archive.ArcParam, isExt bool) (attrs map[uint]int32, forbidAttrs map[string]map[uint]int32) {
  223. //批量和单个提交都需要补全对应属性值
  224. attrs = make(map[uint]int32)
  225. attrs[archive.AttrBitNoRank] = ap.Attrs.NoRank
  226. attrs[archive.AttrBitNoDynamic] = ap.Attrs.NoDynamic
  227. attrs[archive.AttrBitNoWeb] = ap.Attrs.NoWeb
  228. attrs[archive.AttrBitNoMobile] = ap.Attrs.NoMobile
  229. attrs[archive.AttrBitNoSearch] = ap.Attrs.NoSearch
  230. attrs[archive.AttrBitOverseaLock] = ap.Attrs.OverseaLock
  231. attrs[archive.AttrBitNoRecommend] = ap.Attrs.NoRecommend
  232. attrs[archive.AttrBitNoReprint] = ap.Attrs.NoReprint
  233. attrs[archive.AttrBitHasHD5] = ap.Attrs.HasHD5
  234. attrs[archive.AttrBitAllowBp] = ap.Attrs.AllowBp
  235. attrs[archive.AttrBitIsPorder] = ap.Attrs.IsPorder
  236. attrs[archive.AttrBitLimitArea] = ap.Attrs.LimitArea
  237. attrs[archive.AttrBitPushBlog] = ap.Attrs.PushBlog
  238. attrs[archive.AttrBitUGCPay] = ap.Attrs.UGCPay
  239. attrs[archive.AttrBitParentMode] = ap.Attrs.ParentMode
  240. // pgc
  241. attrs[archive.AttrBitIsMovie] = ap.Attrs.IsMovie
  242. attrs[archive.AttrBitBadgepay] = ap.Attrs.BadgePay
  243. attrs[archive.AttrBitIsBangumi] = ap.Attrs.IsBangumi
  244. attrs[archive.AttrBitIsPGC] = ap.Attrs.IsPGC
  245. if isExt {
  246. attrs[archive.AttrBitAllowTag] = ap.Attrs.AllowTag
  247. attrs[archive.AttrBitJumpURL] = ap.Attrs.JumpURL
  248. }
  249. forbidAttrs = make(map[string]map[uint]int32, 4)
  250. forbidAttrs[archive.ForbidRank] = map[uint]int32{
  251. archive.ForbidRankMain: ap.Forbid.Rank.Main,
  252. archive.ForbidRankRecentArc: ap.Forbid.Rank.RecentArc,
  253. archive.ForbidRankAllArc: ap.Forbid.Rank.AllArc,
  254. }
  255. forbidAttrs[archive.ForbidDynamic] = map[uint]int32{
  256. archive.ForbidDynamicMain: ap.Forbid.Dynamic.Main,
  257. }
  258. forbidAttrs[archive.ForbidRecommend] = map[uint]int32{
  259. archive.ForbidRecommendMain: ap.Forbid.Recommend.Main,
  260. }
  261. forbidAttrs[archive.ForbidShow] = map[uint]int32{
  262. archive.ForbidShowMain: ap.Forbid.Show.Main,
  263. archive.ForbidShowMobile: ap.Forbid.Show.Mobile,
  264. archive.ForbidShowWeb: ap.Forbid.Show.Web,
  265. archive.ForbidShowOversea: ap.Forbid.Show.Oversea,
  266. archive.ForbidShowOnline: ap.Forbid.Show.Online,
  267. }
  268. return
  269. }
  270. func (s *Service) isAccess(c context.Context, aid int64) (wm bool) {
  271. var vs []*archive.Video
  272. if vs, _ = s.arc.NewVideosByAid(c, aid); len(vs) <= 0 {
  273. return
  274. }
  275. for _, v := range vs {
  276. if v.Status == 10000 {
  277. wm = true
  278. return
  279. }
  280. }
  281. return
  282. }
  283. // CheckArchive check typeid
  284. func (s *Service) CheckArchive(aps []*archive.ArcParam) bool {
  285. for _, ap := range aps {
  286. if ap.Aid == 0 || ap.UID == 0 {
  287. return false
  288. }
  289. }
  290. return true
  291. }
  292. // CheckVideo check video
  293. func (s *Service) CheckVideo(vps []*archive.VideoParam) bool {
  294. for _, vp := range vps {
  295. if vp.ID == 0 || vp.Aid == 0 || vp.Filename == "" || vp.Cid == 0 || vp.UID == 0 {
  296. return false
  297. }
  298. }
  299. return true
  300. }
  301. // CheckStaff check
  302. func (s *Service) CheckStaff(vps []*archive.StaffParam) bool {
  303. //允许为空 不允许为Nil
  304. if len(vps) == 0 {
  305. return true
  306. }
  307. for _, vp := range vps {
  308. if vp.MID == 0 || vp.Title == "" {
  309. return false
  310. }
  311. }
  312. return true
  313. }
  314. // TypeTopParent get archive type's first level type
  315. func (s *Service) TypeTopParent(tid int16) (tp *archive.Type, err error) {
  316. if _, ok := s.typeCache[tid]; !ok {
  317. err = errors.New("archive type id not exist. id:" + strconv.Itoa(int(tid)))
  318. return
  319. }
  320. if s.typeCache[tid].PID == 0 {
  321. tp = s.typeCache[tid]
  322. } else {
  323. tp, err = s.TypeTopParent(s.typeCache[tid].PID)
  324. if err != nil {
  325. return
  326. }
  327. }
  328. return
  329. }
  330. //StringHandler handle two strings 以s1顺序为准
  331. func StringHandler(s1 string, s2 string, delimiter string, subtraction bool) string {
  332. if strings.TrimSpace(s2) == "" {
  333. return s1
  334. }
  335. var (
  336. res []string
  337. duplicate []int
  338. )
  339. s1Arr := strings.Split(s1, delimiter)
  340. s2Arr := strings.Split(s2, delimiter)
  341. for _, s1Item := range s1Arr {
  342. dupIndex := -1
  343. for k, s2Item := range s2Arr {
  344. if s1Item == s2Item {
  345. dupIndex = k
  346. break
  347. }
  348. }
  349. if dupIndex >= 0 && subtraction {
  350. continue
  351. }
  352. if dupIndex >= 0 {
  353. duplicate = append(duplicate, dupIndex)
  354. }
  355. res = append(res, s1Item)
  356. }
  357. if !subtraction {
  358. for k, s2Item := range s2Arr {
  359. s2Item = strings.TrimSpace(s2Item)
  360. if s2Item == "" {
  361. continue
  362. }
  363. add := true
  364. for _, dup := range duplicate {
  365. if k == dup {
  366. add = false
  367. break
  368. }
  369. }
  370. if add {
  371. res = append(res, s2Item)
  372. }
  373. }
  374. }
  375. return strings.Join(res, delimiter)
  376. }
  377. // SplitInts 去掉id字符串中的空白字符
  378. func (s *Service) SplitInts(str string) ([]int64, error) {
  379. empties := []string{" ", "\n", "\t", "\r"}
  380. for _, v := range empties {
  381. str = strings.Replace(str, v, "", -1)
  382. }
  383. str = strings.Trim(str, ",")
  384. return xstr.SplitInts(str)
  385. }
  386. // coverURL convert cover url to full url.
  387. func coverURL(uri string) (cover string) {
  388. if uri == "" {
  389. cover = "http://static.hdslb.com/images/transparent.gif"
  390. return
  391. }
  392. cover = uri
  393. if strings.Index(uri, "http://") == 0 {
  394. return
  395. }
  396. if len(uri) >= 10 && uri[:10] == "/templets/" {
  397. return
  398. }
  399. if strings.HasPrefix(uri, "group1") {
  400. cover = "http://i0.hdslb.com/" + uri
  401. return
  402. }
  403. if pos := strings.Index(uri, "/uploads/"); pos != -1 && (pos == 0 || pos == 3) {
  404. cover = uri[pos+8:]
  405. }
  406. cover = strings.Replace(cover, "{IMG}", "", -1)
  407. cover = "http://i" + strconv.FormatInt(int64(crc32.ChecksumIEEE([]byte(cover)))%3, 10) + ".hdslb.com" + cover
  408. return
  409. }
  410. func (s *Service) upGroupMids(c context.Context, gid int64) (mids []int64, err error) {
  411. var (
  412. total int
  413. maxps = 10000
  414. req = &upsrpc.UpGroupMidsReq{
  415. Pn: 1,
  416. GroupID: gid,
  417. Ps: maxps,
  418. }
  419. reply *upsrpc.UpGroupMidsReply
  420. )
  421. for {
  422. reply, err = s.upsRPC.UpGroupMids(c, req)
  423. if err == nil && (reply == nil || reply.Mids == nil) {
  424. err = ErrRPCEmpty
  425. }
  426. if err != nil {
  427. log.Error("UpGroupMids req(%+v) error(%v)", req, err)
  428. return
  429. }
  430. total = reply.Total
  431. mids = append(mids, reply.Mids...)
  432. if reply.Size() != maxps {
  433. break
  434. }
  435. req.Pn++
  436. }
  437. log.Info("upGroupMids(%d) reply total(%d) len(%d)", gid, total, len(mids))
  438. return
  439. }
  440. func (s *Service) upSpecial(c context.Context) (ups map[int8]map[int64]struct{}, err error) {
  441. var (
  442. g errgroup.Group
  443. whitegroup, blackgroup, pgcgroup, ugcxgroup, policygroup, dangergroup, twoforbidgroup, pgcwhitegroup map[int64]struct{}
  444. )
  445. ups = make(map[int8]map[int64]struct{})
  446. f := func(gid int8) (map[int64]struct{}, error) {
  447. group := make(map[int64]struct{})
  448. mids, e := s.upGroupMids(c, int64(gid))
  449. if e != nil {
  450. return group, e
  451. }
  452. for _, mid := range mids {
  453. group[mid] = struct{}{}
  454. }
  455. return group, nil
  456. }
  457. g.Go(func() error {
  458. whitegroup, err = f(mngmdl.UpperTypeWhite)
  459. return err
  460. })
  461. g.Go(func() error {
  462. blackgroup, err = f(mngmdl.UpperTypeBlack)
  463. return err
  464. })
  465. g.Go(func() error {
  466. pgcgroup, err = f(mngmdl.UpperTypePGC)
  467. return err
  468. })
  469. g.Go(func() error {
  470. ugcxgroup, err = f(mngmdl.UpperTypeUGCX)
  471. return err
  472. })
  473. g.Go(func() error {
  474. policygroup, err = f(mngmdl.UpperTypePolity)
  475. return err
  476. })
  477. g.Go(func() error {
  478. dangergroup, err = f(mngmdl.UpperTypeDanger)
  479. return err
  480. })
  481. g.Go(func() error {
  482. twoforbidgroup, err = f(mngmdl.UpperTypeTwoForbid)
  483. return err
  484. })
  485. g.Go(func() error {
  486. pgcwhitegroup, err = f(mngmdl.UpperTypePGCWhite)
  487. return err
  488. })
  489. if err = g.Wait(); err != nil {
  490. return
  491. }
  492. ups[mngmdl.UpperTypeWhite] = whitegroup
  493. ups[mngmdl.UpperTypeBlack] = blackgroup
  494. ups[mngmdl.UpperTypePGC] = pgcgroup
  495. ups[mngmdl.UpperTypeUGCX] = ugcxgroup
  496. ups[mngmdl.UpperTypePolity] = policygroup
  497. ups[mngmdl.UpperTypeDanger] = dangergroup
  498. ups[mngmdl.UpperTypeTwoForbid] = twoforbidgroup
  499. ups[mngmdl.UpperTypePGCWhite] = pgcwhitegroup
  500. return
  501. }