index2.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. package channel
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "sync"
  8. "time"
  9. cdm "go-common/app/interface/main/app-card/model"
  10. cardm "go-common/app/interface/main/app-card/model/card"
  11. "go-common/app/interface/main/app-card/model/card/audio"
  12. "go-common/app/interface/main/app-card/model/card/bangumi"
  13. "go-common/app/interface/main/app-card/model/card/live"
  14. "go-common/app/interface/main/app-card/model/card/operate"
  15. shopping "go-common/app/interface/main/app-card/model/card/show"
  16. "go-common/app/interface/main/app-channel/model"
  17. "go-common/app/interface/main/app-channel/model/card"
  18. "go-common/app/interface/main/app-channel/model/feed"
  19. tag "go-common/app/interface/main/tag/model"
  20. article "go-common/app/interface/openplatform/article/model"
  21. account "go-common/app/service/main/account/model"
  22. "go-common/app/service/main/archive/model/archive"
  23. relation "go-common/app/service/main/relation/model"
  24. episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
  25. seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
  26. "go-common/library/log"
  27. "go-common/library/sync/errgroup"
  28. farm "github.com/dgryski/go-farm"
  29. )
  30. const (
  31. _fTypeOperation = "operation"
  32. _fTypeRecommend = "recommend"
  33. )
  34. // Index channel index
  35. func (s *Service) Index2(c context.Context, mid, channelID, idx int64, plat int8, mobiApp, device, buvid, channelName, ip string,
  36. build, loginEvent, displayID, qn, fnver, fnval int, pull bool, now time.Time) (res *feed.Show2, err error) {
  37. var (
  38. aiCards []*card.Card
  39. requestCnt = 10
  40. isIpad = plat == model.PlatIPad
  41. topic cardm.Handler
  42. item []cardm.Handler
  43. channelResource *tag.ChannelResource
  44. topChannel, isRec int
  45. infocs []*feed.Item
  46. )
  47. if isIpad {
  48. requestCnt = 20
  49. }
  50. if channelID > 0 {
  51. channelName = ""
  52. }
  53. g, ctx := errgroup.WithContext(c)
  54. g.Go(func() (err error) {
  55. if channelResource, err = s.tg.Resources(ctx, plat, channelID, mid, channelName, buvid, build, requestCnt, loginEvent, displayID); err != nil {
  56. log.Error("index s.tg.Resources error(%v)", err)
  57. return
  58. }
  59. if channelResource != nil {
  60. aids := channelResource.Oids
  61. for _, aid := range aids {
  62. t := &card.Card{
  63. Type: model.GotoAv,
  64. Value: aid,
  65. FromType: _fTypeRecommend,
  66. }
  67. aiCards = append(aiCards, t)
  68. }
  69. if channelResource.Failover {
  70. isRec = 0
  71. } else {
  72. isRec = 1
  73. }
  74. if channelResource.IsChannel {
  75. topChannel = 1
  76. } else {
  77. topChannel = 0
  78. }
  79. }
  80. return
  81. })
  82. g.Go(func() (err error) {
  83. var t *tag.ChannelDetail
  84. if t, err = s.tg.ChannelDetail(c, mid, channelID, channelName, s.isOverseas(plat)); err != nil {
  85. log.Error("s.tag.ChannelDetail(%d, %d, %s) error(%v)", mid, channelID, channelName, err)
  86. return
  87. }
  88. channelID = t.Tag.ID
  89. channelName = t.Tag.Name
  90. return
  91. })
  92. err = g.Wait()
  93. //infoc
  94. infoc := &feedInfoc{
  95. mobiApp: mobiApp,
  96. device: device,
  97. build: strconv.Itoa(build),
  98. now: now.Format("2006-01-02 15:04:05"),
  99. pull: strconv.FormatBool(pull),
  100. loginEvent: strconv.Itoa(loginEvent),
  101. channelID: strconv.FormatInt(channelID, 10),
  102. channelName: channelName,
  103. mid: strconv.FormatInt(mid, 10),
  104. buvid: buvid,
  105. displayID: strconv.Itoa(displayID),
  106. isRec: strconv.Itoa(isRec),
  107. topChannel: strconv.Itoa(topChannel),
  108. ServerCode: "0",
  109. }
  110. //infoc
  111. if err != nil {
  112. log.Error("RankUser errgroup.WithContext error(%v)", err)
  113. res = &feed.Show2{
  114. Feed: []cardm.Handler{},
  115. }
  116. infoc.Items = []*feed.Item{}
  117. infoc.ServerCode = err.Error()
  118. s.infoc(infoc)
  119. return
  120. }
  121. var (
  122. tmps = []*card.Card{}
  123. )
  124. if loginEvent == 1 || loginEvent == 2 {
  125. if cards, ok := s.cardCache[channelID]; ok {
  126. isShowCard := s.isShowOperationCards(c, buvid, channelID, cards, now)
  127. for _, c := range cards {
  128. if !isShowCard && c.Type != model.GotoTopstick {
  129. continue
  130. }
  131. t := &card.Card{}
  132. *t = *c
  133. t.FromType = _fTypeOperation
  134. tmps = append(tmps, t)
  135. }
  136. tmps = append(tmps, aiCards...)
  137. } else {
  138. tmps = aiCards
  139. }
  140. } else {
  141. tmps = aiCards
  142. }
  143. topic, item, infocs, err = s.dealItem2(c, mid, idx, channelID, plat, build, buvid, ip, mobiApp, pull, qn, fnver, fnval, now, tmps)
  144. res = &feed.Show2{
  145. Topic: topic,
  146. Feed: item,
  147. }
  148. infoc.Items = infocs
  149. s.infoc(infoc)
  150. return
  151. }
  152. // dealItem
  153. func (s *Service) dealItem2(c context.Context, mid, idx, channelID int64, plat int8, build int, buvid, ip, mobiApp string, pull bool,
  154. qn, fnver, fnval int, now time.Time, cards []*card.Card) (top cardm.Handler, is []cardm.Handler, infocs []*feed.Item, err error) {
  155. if len(cards) == 0 {
  156. is = []cardm.Handler{}
  157. return
  158. }
  159. var (
  160. aids, shopIDs, audioIDs, sids, roomIDs, metaIDs []int64
  161. upIDs, tids, rmUpIDs, mtUpIDs, avUpIDs, avUpCountIDs []int64
  162. seasonIDs, epIDs []int32
  163. am map[int64]*archive.ArchiveWithPlayer
  164. tagm map[int64]*tag.Tag
  165. rm map[int64]*live.Room
  166. sm map[int64]*bangumi.Season
  167. metam map[int64]*article.Meta
  168. shopm map[int64]*shopping.Shopping
  169. audiom map[int64]*audio.Audio
  170. cardAids = map[int64]struct{}{}
  171. ac map[int64]*account.Card
  172. statm map[int64]*relation.Stat
  173. isAtten map[int64]int8
  174. upAvCount = map[int64]int{}
  175. channelCards []*card.Card
  176. seasonm map[int32]*seasongrpc.CardInfoProto
  177. epidsCards map[int32]*episodegrpc.EpisodeCardsProto
  178. // key
  179. _initCardPlatKey = "card_platkey_%d_%d"
  180. )
  181. specialm := map[int64]*operate.Card{}
  182. convergem := map[int64]*operate.Card{}
  183. downloadm := map[int64]*operate.Card{}
  184. followm := map[int64]*operate.Card{}
  185. liveUpm := map[int64][]*live.Card{}
  186. cardSet := map[int64]*operate.Card{}
  187. LOOP:
  188. for _, card := range cards {
  189. key := fmt.Sprintf(_initCardPlatKey, plat, card.ID)
  190. if cardPlat, ok := s.cardPlatCache[key]; ok {
  191. for _, l := range cardPlat {
  192. if model.InvalidBuild(build, l.Build, l.Condition) {
  193. continue LOOP
  194. }
  195. }
  196. } else if card.FromType == _fTypeOperation {
  197. continue LOOP
  198. }
  199. channelCards = append(channelCards, card)
  200. switch card.Type {
  201. case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv:
  202. if card.Value != 0 {
  203. aids = append(aids, card.Value)
  204. cardAids[card.Value] = struct{}{}
  205. }
  206. case model.GotoLive, model.GotoPlayerLive:
  207. if card.Value != 0 {
  208. roomIDs = append(roomIDs, card.Value)
  209. }
  210. case model.GotoBangumi:
  211. if card.Value != 0 {
  212. sids = append(sids, card.Value)
  213. }
  214. case model.GotoPGC:
  215. if card.Value != 0 {
  216. epIDs = append(epIDs, int32(card.Value))
  217. }
  218. case model.GotoConverge:
  219. if card.Value != 0 {
  220. cardm, aid, roomID, metaID := s.convergeCard2(c, 3, card.Value)
  221. for id, card := range cardm {
  222. convergem[id] = card
  223. }
  224. aids = append(aids, aid...)
  225. roomIDs = append(roomIDs, roomID...)
  226. metaIDs = append(metaIDs, metaID...)
  227. }
  228. case model.GotoGameDownload, model.GotoGameDownloadS:
  229. if card.Value != 0 {
  230. cardm := s.downloadCard(c, card.Value)
  231. for id, card := range cardm {
  232. downloadm[id] = card
  233. }
  234. }
  235. case model.GotoArticle, model.GotoArticleS:
  236. if card.Value != 0 {
  237. metaIDs = append(metaIDs, card.Value)
  238. }
  239. case model.GotoShoppingS:
  240. if card.Value != 0 {
  241. shopIDs = append(shopIDs, card.Value)
  242. }
  243. case model.GotoAudio:
  244. if card.Value != 0 {
  245. audioIDs = append(audioIDs, card.Value)
  246. }
  247. case model.GotoChannelRcmd:
  248. cardm, aid, tid := s.channelRcmdCard(c, card.Value)
  249. for id, card := range cardm {
  250. followm[id] = card
  251. }
  252. aids = append(aids, aid...)
  253. tids = append(tids, tid...)
  254. case model.GotoLiveUpRcmd:
  255. if card.Value != 0 {
  256. cardm, upID := s.liveUpRcmdCard(c, card.Value)
  257. for id, card := range cardm {
  258. liveUpm[id] = card
  259. }
  260. upIDs = append(upIDs, upID...)
  261. }
  262. case model.GotoSubscribe:
  263. if card.Value != 0 {
  264. cardm, upID, tid := s.subscribeCard(c, card.Value)
  265. for id, card := range cardm {
  266. followm[id] = card
  267. }
  268. upIDs = append(upIDs, upID...)
  269. tids = append(tids, tid...)
  270. }
  271. case model.GotoSpecial, model.GotoSpecialS:
  272. cardm := s.specialCard(c, card.Value)
  273. for id, card := range cardm {
  274. specialm[id] = card
  275. }
  276. case model.GotoTopstick:
  277. cardm := s.topstickCard(c, card.Value)
  278. for id, card := range cardm {
  279. specialm[id] = card
  280. }
  281. case model.GotoPgcsRcmd:
  282. cardm, ssid := s.cardSetChange(c, card.Value)
  283. seasonIDs = append(seasonIDs, ssid...)
  284. for id, card := range cardm {
  285. cardSet[id] = card
  286. }
  287. case model.GotoUpRcmdS:
  288. if card.Value != 0 {
  289. avUpCountIDs = append(avUpCountIDs, card.Value)
  290. }
  291. }
  292. }
  293. g, ctx := errgroup.WithContext(c)
  294. if len(aids) != 0 {
  295. g.Go(func() (err error) {
  296. if am, err = s.ArchivesWithPlayer(ctx, aids, qn, mobiApp, fnver, fnval, build); err != nil {
  297. return
  298. }
  299. for _, a := range am {
  300. avUpIDs = append(avUpIDs, a.Author.Mid)
  301. }
  302. return
  303. })
  304. }
  305. if len(tids) != 0 {
  306. g.Go(func() (err error) {
  307. if tagm, err = s.tg.InfoByIDs(ctx, mid, tids); err != nil {
  308. log.Error("%+v", err)
  309. err = nil
  310. }
  311. return
  312. })
  313. }
  314. if len(roomIDs) != 0 {
  315. g.Go(func() (err error) {
  316. if rm, err = s.lv.AppMRoom(ctx, roomIDs); err != nil {
  317. log.Error("%+v", err)
  318. err = nil
  319. }
  320. for _, r := range rm {
  321. rmUpIDs = append(rmUpIDs, r.UID)
  322. }
  323. return
  324. })
  325. }
  326. if len(sids) != 0 {
  327. g.Go(func() (err error) {
  328. if sm, err = s.bgm.Seasons(ctx, sids, now); err != nil {
  329. log.Error("%+v", err)
  330. err = nil
  331. }
  332. return
  333. })
  334. }
  335. if len(seasonIDs) != 0 {
  336. g.Go(func() (err error) {
  337. if seasonm, err = s.bgm.CardsInfoReply(ctx, seasonIDs); err != nil {
  338. log.Error("%+v", err)
  339. err = nil
  340. }
  341. return
  342. })
  343. }
  344. if len(epIDs) != 0 {
  345. g.Go(func() (err error) {
  346. if epidsCards, err = s.bgm.EpidsCardsInfoReply(ctx, epIDs); err != nil {
  347. log.Error("%+v", err)
  348. err = nil
  349. }
  350. return
  351. })
  352. }
  353. if len(metaIDs) != 0 {
  354. g.Go(func() (err error) {
  355. if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
  356. log.Error("%+v", err)
  357. err = nil
  358. }
  359. for _, meta := range metam {
  360. if meta.Author != nil {
  361. mtUpIDs = append(mtUpIDs, meta.Author.Mid)
  362. }
  363. }
  364. return
  365. })
  366. }
  367. if len(shopIDs) != 0 {
  368. g.Go(func() (err error) {
  369. if shopm, err = s.sp.Card(ctx, shopIDs); err != nil {
  370. log.Error("%+v", err)
  371. err = nil
  372. }
  373. return
  374. })
  375. }
  376. if len(audioIDs) != 0 {
  377. g.Go(func() (err error) {
  378. if audiom, err = s.audio.Audios(ctx, audioIDs); err != nil {
  379. log.Error("%+v", err)
  380. err = nil
  381. }
  382. return
  383. })
  384. }
  385. if len(avUpCountIDs) != 0 {
  386. var mutex sync.Mutex
  387. for _, upid := range avUpCountIDs {
  388. var (
  389. tmpupid = upid
  390. )
  391. g.Go(func() (err error) {
  392. var cnt int
  393. if cnt, err = s.arc.UpCount2(ctx, tmpupid); err != nil {
  394. log.Error("%+v", err)
  395. err = nil
  396. }
  397. mutex.Lock()
  398. upAvCount[tmpupid] = cnt
  399. mutex.Unlock()
  400. return
  401. })
  402. }
  403. }
  404. if err = g.Wait(); err != nil {
  405. log.Error("%+v", err)
  406. return
  407. }
  408. upIDs = append(upIDs, avUpIDs...)
  409. upIDs = append(upIDs, rmUpIDs...)
  410. upIDs = append(upIDs, mtUpIDs...)
  411. upIDs = append(upIDs, avUpCountIDs...)
  412. g, ctx = errgroup.WithContext(c)
  413. if len(upIDs) != 0 {
  414. g.Go(func() (err error) {
  415. if ac, err = s.acc.Cards3(ctx, upIDs); err != nil {
  416. log.Error("%+v", err)
  417. err = nil
  418. }
  419. return
  420. })
  421. g.Go(func() (err error) {
  422. if statm, err = s.rel.Stats(ctx, upIDs); err != nil {
  423. log.Error("%+v", err)
  424. err = nil
  425. }
  426. return
  427. })
  428. if mid != 0 {
  429. g.Go(func() error {
  430. isAtten = s.acc.IsAttention(ctx, upIDs, mid)
  431. return nil
  432. })
  433. }
  434. }
  435. if err = g.Wait(); err != nil {
  436. log.Error("%+v", err)
  437. return
  438. }
  439. for _, card := range channelCards {
  440. var (
  441. r = card.CardToAiChange()
  442. main interface{}
  443. )
  444. switch r.Goto {
  445. case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer:
  446. r.HideButton = true
  447. }
  448. h := cardm.Handle(plat, cdm.CardGt(r.Goto), "", cdm.ColumnSvrSingle, r, tagm, isAtten, statm, ac)
  449. if h == nil {
  450. continue
  451. }
  452. op := &operate.Card{}
  453. op.From(cdm.CardGt(r.Goto), r.ID, 0, plat, build)
  454. switch r.Goto {
  455. case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer:
  456. op.ShowUGCPay = true
  457. if a, ok := am[r.ID]; ok && (a.AttrVal(archive.AttrBitOverseaLock) == 0 || !model.IsOverseas(plat)) {
  458. main = am
  459. }
  460. op.Switch = cdm.SwitchCooperationHide
  461. case model.GotoLive, model.GotoPlayerLive:
  462. main = rm
  463. case model.GotoBangumi:
  464. main = sm
  465. case model.GotoPGC:
  466. main = epidsCards
  467. case model.GotoSpecial, model.GotoSpecialS, model.GotoTopstick:
  468. op = specialm[r.ID]
  469. case model.GotoGameDownload, model.GotoGameDownloadS:
  470. op = downloadm[r.ID]
  471. case model.GotoArticle, model.GotoArticleS:
  472. main = metam
  473. case model.GotoShoppingS:
  474. main = shopm
  475. case model.GotoAudio:
  476. main = audiom
  477. case model.GotoChannelRcmd:
  478. main = am
  479. op = followm[r.ID]
  480. case model.GotoSubscribe:
  481. op = followm[r.ID]
  482. case model.GotoLiveUpRcmd:
  483. main = liveUpm
  484. case model.GotoConverge:
  485. main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoLive: rm, cdm.GotoArticle: metam}
  486. op = convergem[r.ID]
  487. case model.GotoPgcsRcmd:
  488. main = seasonm
  489. op = cardSet[r.ID]
  490. case model.GotoUpRcmdS:
  491. op.Limit = upAvCount[r.ID]
  492. }
  493. h.From(main, op)
  494. if h.Get() == nil {
  495. continue
  496. }
  497. h.Get().FromType = card.FromType
  498. if h.Get().Right {
  499. switch card.FromType {
  500. case _fTypeOperation:
  501. h.Get().ThreePointWatchLater()
  502. case _fTypeRecommend:
  503. h.Get().ThreePointChannel()
  504. }
  505. switch r.Goto {
  506. case model.GotoTopstick:
  507. top = h
  508. default:
  509. is = append(is, h)
  510. }
  511. }
  512. // infoc
  513. tinfo := &feed.Item{
  514. Goto: card.Type,
  515. Param: strconv.FormatInt(card.Value, 10),
  516. URI: h.Get().URI,
  517. FromType: card.FromType,
  518. }
  519. infocs = append(infocs, tinfo)
  520. }
  521. rl := len(is)
  522. if rl == 0 {
  523. is = []cardm.Handler{}
  524. return
  525. }
  526. if idx == 0 {
  527. idx = now.Unix()
  528. }
  529. for i, h := range is {
  530. if pull {
  531. h.Get().Idx = idx + int64(rl-i)
  532. } else {
  533. h.Get().Idx = idx - int64(i+1)
  534. }
  535. }
  536. return
  537. }
  538. // ArchivesWithPlayer archives witch player
  539. func (s *Service) ArchivesWithPlayer(c context.Context, aids []int64, qn int, platform string, fnver, fnval, build int) (res map[int64]*archive.ArchiveWithPlayer, err error) {
  540. if res, err = s.arc.ArchivesWithPlayer(c, aids, qn, platform, fnver, fnval, build); err != nil {
  541. log.Error("%+v", err)
  542. }
  543. if len(res) != 0 {
  544. return
  545. }
  546. am, err := s.arc.Archives(c, aids)
  547. if err != nil {
  548. return
  549. }
  550. if len(am) == 0 {
  551. return
  552. }
  553. res = make(map[int64]*archive.ArchiveWithPlayer, len(am))
  554. for aid, a := range am {
  555. res[aid] = &archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(a)}
  556. }
  557. return
  558. }
  559. // isShowOperationCards is show operation cards by buvid
  560. func (s *Service) isShowOperationCards(c context.Context, buvid string, channelID int64, cards []*card.Card, now time.Time) (isShow bool) {
  561. var (
  562. md5, mcmd5 string
  563. )
  564. g, ctx := errgroup.WithContext(c)
  565. g.Go(func() (err error) {
  566. if mcmd5, err = s.cd.ChannelCardCache(ctx, buvid, channelID); err != nil {
  567. isShow = true
  568. return
  569. }
  570. return nil
  571. })
  572. g.Go(func() (err error) {
  573. md5 = s.hashCards(cards)
  574. return nil
  575. })
  576. g.Wait()
  577. if md5 != mcmd5 {
  578. isShow = true
  579. s.cd.AddChannelCardCache(c, buvid, md5, channelID, now)
  580. }
  581. return
  582. }
  583. func (s *Service) hashCards(v []*card.Card) string {
  584. bs, err := json.Marshal(v)
  585. if err != nil {
  586. log.Error("json.Marshal error(%v)", err)
  587. return ""
  588. }
  589. return strconv.FormatUint(farm.Hash64(bs), 10)
  590. }