show.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. package show
  2. import (
  3. "context"
  4. "fmt"
  5. "math/rand"
  6. "net/url"
  7. "strconv"
  8. "time"
  9. "go-common/app/interface/main/app-show/conf"
  10. "go-common/app/interface/main/app-show/model"
  11. "go-common/app/interface/main/app-show/model/show"
  12. "go-common/app/service/main/archive/api"
  13. "go-common/app/service/main/archive/model/archive"
  14. resource "go-common/app/service/main/resource/model"
  15. seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
  16. "go-common/library/log"
  17. "go-common/library/sync/errgroup"
  18. )
  19. const (
  20. _cnt = 4
  21. _initShowKey = "show_key_%d_%v"
  22. _initCardKey = "card_key_%d"
  23. _initlanguage = "hans"
  24. _bangumiSeasonID = 1
  25. _bangumiEpisodeID = 2
  26. )
  27. var (
  28. _emptyShow = []*show.Show{}
  29. _emptyItem = &show.Item{}
  30. _emptyShowItems = []*show.Item{}
  31. // ad
  32. _recommend = map[int8]string{
  33. model.PlatIPhone: "1508",
  34. model.PlatAndroid: "1515",
  35. model.PlatIPad: "1522",
  36. model.PlatIPhoneI: "1529",
  37. model.PlatAndroidG: "1543",
  38. model.PlatAndroidI: "1777",
  39. model.PlatIPadI: "1536",
  40. }
  41. _bangumiReids = map[int]struct{}{
  42. 167: struct{}{},
  43. }
  44. )
  45. // Display display show data.
  46. func (s *Service) Display(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
  47. device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
  48. res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, false, false, now)
  49. return
  50. }
  51. // RegionDisplay display region show data.
  52. func (s *Service) RegionDisplay(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
  53. device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
  54. res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, true, false, now)
  55. return
  56. }
  57. func (s *Service) Index(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
  58. device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
  59. res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, true, true, now)
  60. if cards := s.showCardDisplay(plat, build); len(cards) > 0 {
  61. cards = append(cards, res...)
  62. res = cards
  63. }
  64. return
  65. }
  66. // Display display show data.
  67. func (s *Service) showDisplay(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
  68. device, language, adExtra string, isTmp, isRegion, isIndex bool, now time.Time) (res []*show.Show) {
  69. var (
  70. bnr string
  71. banners map[int][]*resource.Banner
  72. showRec []*show.Item
  73. showLive []*show.Item
  74. isBangumi = false
  75. isRegionBanner = false
  76. ss []*show.Show
  77. resIDStr = _bannersPlat[plat]
  78. )
  79. if language == "" {
  80. language = _initlanguage
  81. }
  82. key := fmt.Sprintf(_initShowKey, plat, language)
  83. if (plat == model.PlatIPhone && build > 6050) || (plat == model.PlatAndroid && build > 512007) {
  84. ss = s.cacheBgEp[key]
  85. } else if ((mobiApp == "iphone" && build > 5600) || (mobiApp == "android" && build > 507000)) && isIndex {
  86. ss = s.cacheBg[key]
  87. } else {
  88. ss = s.cache[key]
  89. }
  90. if isTmp {
  91. ss = s.tempCache[key]
  92. }
  93. if len(ss) == 0 {
  94. res = _emptyShow
  95. return
  96. }
  97. res = make([]*show.Show, 0, len(ss))
  98. if (mobiApp == "iphone" && build > 4310) || (mobiApp == "android" && build > 502000) || isIndex {
  99. isBangumi = true
  100. }
  101. if (mobiApp == "iphone" && build > 4350) || (mobiApp == "android" && build > 503000) {
  102. isRegionBanner = true
  103. }
  104. g, ctx := errgroup.WithContext(c)
  105. g.Go(func() error {
  106. banners = s.resBanners(ctx, plat, build, mid, resIDStr, channel, ip, buvid, network, mobiApp, device, adExtra)
  107. return nil
  108. })
  109. if !isRegion {
  110. g.Go(func() error {
  111. showRec = s.getRecommend(ctx, mid, build, plat, buvid, network, mobiApp, device, ip)
  112. return nil
  113. })
  114. g.Go(func() error {
  115. showLive = s.getLive(ctx, mid, ak, ip, 0, now)
  116. return nil
  117. })
  118. }
  119. if err := g.Wait(); err != nil {
  120. log.Error("showDisplay errgroup.WithContext error(%v)", err)
  121. }
  122. for i, sw := range ss {
  123. if mobiApp == "white" && 101220 >= build && sw.Param == "165" { // 165 ad region
  124. continue
  125. } else if sw.Param != "165" || ((mobiApp != "iphone" || device != "pad") || build <= 3590) {
  126. if model.InvalidBuild(build, sw.Build, sw.Condition) {
  127. continue
  128. }
  129. }
  130. if sw.Type == "recommend" {
  131. if isRegion {
  132. continue
  133. }
  134. sw = s.dealRecommend(c, sw, plat, mid, build, buvid, network, mobiApp, device, ip, showRec)
  135. bnr = "0"
  136. } else if sw.Type == "live" {
  137. if isRegion {
  138. continue
  139. }
  140. sw = s.dealLive(c, sw, showLive)
  141. bnr = "65537"
  142. } else if sw.Type == "bangumi" {
  143. if ok := s.auditRegion(mobiApp, plat, build, "13"); ok {
  144. continue
  145. }
  146. if isRegion && isBangumi && !isRegionBanner {
  147. bnr = "-1"
  148. } else if isRegion && !isBangumi && !isRegionBanner {
  149. continue
  150. } else {
  151. bnr = "13"
  152. }
  153. } else {
  154. bnr = sw.Param
  155. if isRegion {
  156. if ok := s.auditRegion(mobiApp, plat, build, sw.Param); ok {
  157. continue
  158. }
  159. if !isRegionBanner {
  160. if sw.Param == "1" && !isBangumi {
  161. bnr = "-1"
  162. }
  163. if sw.Type == "topic" && i > 0 && (ss[i-1].Type == "bangumi" || ss[i-1].Type == "1") {
  164. continue
  165. }
  166. }
  167. }
  168. }
  169. sw.Banner = s.getBanners(c, plat, build, bnr, channel, ip, banners, isIndex)
  170. res = append(res, sw)
  171. }
  172. return
  173. }
  174. // showCardDisplay
  175. func (s *Service) showCardDisplay(plat int8, build int) (res []*show.Show) {
  176. var ss []*show.Show
  177. key := fmt.Sprintf(_initCardKey, plat)
  178. ss = s.cardCache[key]
  179. if len(ss) == 0 {
  180. res = _emptyShow
  181. return
  182. }
  183. res = []*show.Show{}
  184. for _, sw := range ss {
  185. if model.InvalidBuild(build, sw.Build, sw.Condition) {
  186. continue
  187. }
  188. tmp := &show.Show{}
  189. *tmp = *sw
  190. tmp.FillBuildURI(plat, build)
  191. res = append(res, tmp)
  192. }
  193. return
  194. }
  195. // Change change display show data.
  196. func (s *Service) Change(c context.Context, mid int64, build int, plat int8, rand int, buvid, ip, network, mobiApp, device string) (sis []*show.Item) {
  197. cnt := s.itemNum(plat)
  198. // first get recommend data.
  199. tmp := s.userRecommend(c, mid, build, plat, buvid, network, mobiApp, device, ip, cnt)
  200. if len(tmp) == cnt {
  201. sis = append(sis, tmp...)
  202. }
  203. if len(sis) < cnt {
  204. start := cnt * rand
  205. end := start + cnt
  206. rcLen := len(s.rcmmndCache)
  207. if rcLen < end {
  208. rand = 0
  209. start = cnt * rand
  210. end = start + cnt
  211. }
  212. if rcLen > end {
  213. sis = s.rcmmndCache[start:end]
  214. }
  215. }
  216. return
  217. }
  218. // RegionChange change show region data.
  219. func (s *Service) RegionChange(c context.Context, rid, rand int, plat int8, build int, mobiApp string) (sis []*show.Item) {
  220. if rand < 0 {
  221. rand = 0
  222. }
  223. var (
  224. cnt = 4
  225. pn = rand + 1
  226. isOsea = model.IsOverseas(plat)
  227. bangumiType = 0
  228. tmp []*show.Item
  229. )
  230. if (mobiApp == "iphone" && build > 5600) || (mobiApp == "android" && build > 507000) {
  231. if _, isBangumi := _bangumiReids[rid]; isBangumi {
  232. if (plat == model.PlatIPhone && build > 6050) || (plat == model.PlatAndroid && build > 512007) {
  233. bangumiType = _bangumiEpisodeID
  234. } else {
  235. bangumiType = _bangumiSeasonID
  236. }
  237. }
  238. }
  239. if model.IsIPad(plat) {
  240. cnt = 8
  241. }
  242. as, aids, err := s.dyn.RegionDynamic(c, rid, pn, cnt)
  243. if err != nil {
  244. log.Error("s.rcmmnd.RegionDynamic(%d, %d, %d) error(%v)", rid, pn, cnt, err)
  245. sis = []*show.Item{}
  246. return
  247. }
  248. if bangumiType != 0 {
  249. tmp = s.fromArchivesBangumiOsea(c, as, aids, isOsea, bangumiType)
  250. } else {
  251. tmp = s.fromArchivesOsea(as, isOsea)
  252. }
  253. sis = append(sis, tmp...)
  254. return
  255. }
  256. // BangumiChange change show bangumi data.
  257. func (s *Service) BangumiChange(c context.Context, rand int, plat int8) (sis []*show.Item) {
  258. if rand < 0 {
  259. rand = 0
  260. }
  261. rand = rand + 1
  262. var (
  263. cnt = 4
  264. )
  265. if model.IsIPad(plat) {
  266. cnt = 8
  267. }
  268. start := cnt * rand
  269. end := start + cnt
  270. if bgms, ok := s.bgmCache[plat]; ok {
  271. bcLen := len(bgms)
  272. if bcLen < end {
  273. rand = 0
  274. start = cnt * rand
  275. end = start + cnt
  276. }
  277. if bcLen > end {
  278. sis = bgms[start:end]
  279. }
  280. }
  281. return
  282. }
  283. // Dislike dislike show data
  284. func (s *Service) Dislike(c context.Context, mid int64, plat int8, id int64, buvid, mobiApp, device, gt, ip string) (si *show.Item) {
  285. var (
  286. cnt = 1
  287. changeAid string
  288. port string
  289. )
  290. // first get recommend data.
  291. tmp := s.userRecommend(c, mid, 0, plat, buvid, "", mobiApp, device, ip, cnt)
  292. if len(tmp) > 0 {
  293. si = tmp[0]
  294. port = "userRecommend"
  295. } else {
  296. si = s.rcmmndCache[0]
  297. port = "loadRcmmndCache"
  298. }
  299. if si != nil {
  300. changeAid = si.Param
  301. }
  302. if err := s.dbus.Pub(c, buvid, gt, id, mid); err != nil {
  303. log.Error("s.dbus.Pub(%s,%s,%d,%d) error(%v)", buvid, gt, id, mid, err)
  304. log.Error("dbus_Pub_dislike error mid:%v , dislike_aid:%v , change_aid:%v , interface_name:%v", mid, id, changeAid, port)
  305. return
  306. }
  307. log.Info("dbus_Pub_dislike success mid:%v , dislike_aid:%v , change_aid:%v , interface_name:%v", mid, id, changeAid, port)
  308. return
  309. }
  310. // Widget
  311. func (s *Service) Widget(c context.Context, plat int8) (res []*show.Item) {
  312. var (
  313. isOsea = model.IsOverseas(plat) //is overseas
  314. resCache []*show.Item
  315. randID int
  316. )
  317. if isOsea {
  318. resCache = s.rcmmndOseaCache
  319. } else {
  320. resCache = s.rcmmndCache
  321. }
  322. resCacheLen := len(resCache)
  323. if resCacheLen >= 3 {
  324. for {
  325. if len(res) >= 3 || len(resCache) == 0 {
  326. log.Info("Widget len 3")
  327. break
  328. }
  329. if randInt := rand.Intn(resCacheLen); randInt != randID && resCache[randInt] != nil {
  330. randID = randInt
  331. res = append(res, resCache[randInt])
  332. }
  333. }
  334. } else if resCacheLen > 0 {
  335. log.Info("Widget resCache")
  336. res = resCache
  337. } else {
  338. log.Info("Widget is null")
  339. res = _emptyShowItems
  340. }
  341. return
  342. }
  343. // LiveChange live change.
  344. func (s *Service) LiveChange(c context.Context, mid int64, ak, ip string, rand int, now time.Time) (sis []*show.Item) {
  345. return s.getLive(c, mid, ak, ip, rand, now)
  346. }
  347. // dealRecommend deal recommend.
  348. func (s *Service) dealRecommend(c context.Context, sw *show.Show, plat int8, mid int64, build int, buvid, network, mobiApp, device, ipaddr string, showRec []*show.Item) (rs *show.Show) {
  349. cnt := s.itemNum(plat)
  350. sis := make([]*show.Item, 0, cnt)
  351. // first get recommend data.
  352. if len(showRec) == cnt {
  353. sis = append(sis, showRec...)
  354. }
  355. // if recommend data not enough, get from @hetongzi.
  356. if len(sis) < cnt {
  357. rcLen := len(s.rcmmndCache)
  358. if rcLen < cnt {
  359. sis = s.rcmmndCache[0:rcLen]
  360. } else {
  361. sis = s.rcmmndCache[0:cnt]
  362. }
  363. if rcLen > 0 {
  364. sis = s.adVideo(c, mid, build, plat, buvid, network, mobiApp, device, ipaddr, sis)
  365. }
  366. }
  367. if len(sis) == 0 {
  368. sis = []*show.Item{}
  369. }
  370. rs = &show.Show{
  371. Head: sw.Head,
  372. Body: sis,
  373. }
  374. return
  375. }
  376. // getRecommend user recommend data
  377. func (s *Service) getRecommend(c context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string) (sis []*show.Item) {
  378. cnt := s.itemNum(plat)
  379. // first get recommend data.
  380. sis = s.userRecommend(c, mid, build, plat, buvid, network, mobiApp, device, ipaddr, cnt)
  381. return
  382. }
  383. // userRecommend user recommend data.
  384. func (s *Service) userRecommend(ctx context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string, cnt int) (sis []*show.Item) {
  385. // get redis seed whether or not hit
  386. if !s.rcmmndOn {
  387. return
  388. }
  389. var (
  390. key = buvid
  391. i int
  392. aids []int64
  393. rcs []*rcmmndCfg
  394. err error
  395. )
  396. if mid > 0 {
  397. key = strconv.FormatInt(mid, 10)
  398. }
  399. if key == "" {
  400. return
  401. }
  402. Retry:
  403. for i = 0; i < 2; i++ {
  404. if aids, err = s.dao.PopRcmmndCache(ctx, key, cnt); err != nil {
  405. log.Error("s.dao.PopRcmmndCache(%d) error(%v)", key, err)
  406. return
  407. }
  408. if len(aids) < cnt {
  409. break
  410. }
  411. for _, aid := range aids {
  412. if _, ok := s.blackCache[aid]; ok {
  413. continue Retry
  414. }
  415. }
  416. var isOsea = model.IsOverseas(plat)
  417. if sis = s.fromAidsOsea(ctx, aids, isOsea); len(sis) < cnt {
  418. log.Warn("recommend aids(%v) get from archive have not normal(%v)", aids, sis)
  419. continue Retry
  420. }
  421. return
  422. }
  423. // if i==2, mean retry two counts, else if i<2, means break and recommend not enough.
  424. if i == 2 {
  425. return
  426. }
  427. if host := s.rcmmndHost(mid); host != "" {
  428. rcs, aids = s.apiRecommend(ctx, plat, key, host, mid)
  429. }
  430. var (
  431. clen = len(rcs)
  432. caids = make([]int64, 0, cnt)
  433. fill = cnt - clen
  434. )
  435. if clen+len(aids) < cnt {
  436. return
  437. }
  438. if cnt < clen {
  439. fill = 0
  440. }
  441. for _, rc := range rcs {
  442. if rc.Goto == "" || rc.Goto == model.GotoAv {
  443. caids = append(caids, rc.Aid)
  444. if len(caids) == cnt {
  445. break
  446. }
  447. }
  448. }
  449. if fill > 0 {
  450. caids = append(caids, aids[:fill]...)
  451. }
  452. if aids = aids[fill:]; len(aids) >= cnt {
  453. select {
  454. case s.rcmmndCh <- recommend{key: key, aids: aids[fill:]}:
  455. default:
  456. log.Warn("recommendProc chan full")
  457. }
  458. }
  459. var isOsea = model.IsOverseas(plat) //is overseas
  460. if sis = s.fromAidsOsea(ctx, caids, isOsea); len(sis) < clen { // NOTE: if cnt=1 means dislike change one
  461. for {
  462. var (
  463. over = cnt - len(sis)
  464. start = 0
  465. )
  466. if over == 0 || start+over > len(aids) {
  467. break
  468. }
  469. if tmp := s.fromAidsOsea(ctx, aids[start:over], isOsea); len(tmp) > 0 {
  470. sis = append(sis, tmp...)
  471. }
  472. }
  473. return
  474. }
  475. for i, rc := range rcs {
  476. if rc.Goto != "" && rc.Goto != model.GotoAv {
  477. sis[i].Param = strconv.FormatInt(rc.Aid, 10)
  478. sis[i].Goto = rc.Goto
  479. sis[i].URI = model.FillURI(rc.Goto, sis[i].Param, nil)
  480. }
  481. if rc.Title != "" {
  482. sis[i].Title = rc.Title
  483. }
  484. if rc.Cover != "" {
  485. sis[i].Cover = rc.Cover
  486. }
  487. }
  488. sis = s.adVideo(ctx, mid, build, plat, buvid, network, mobiApp, device, ipaddr, sis)
  489. return
  490. }
  491. // rcmmndHost get recommend host
  492. func (s *Service) rcmmndHost(mid int64) (host string) {
  493. // if mid=0, let host is 1: base recommend
  494. yu := mid % 20
  495. g := s.rcmmndGroup[yu]
  496. if hosts, ok := s.rcmmndHosts[g]; ok {
  497. if len(hosts) == 1 {
  498. host = hosts[0]
  499. } else {
  500. host = hosts[rand.Intn(len(hosts))]
  501. }
  502. }
  503. return
  504. }
  505. // apiRecommend get recommend fron big data.
  506. func (s *Service) apiRecommend(ctx context.Context, plat int8, key, host string, mid int64) (rcs []*rcmmndCfg, aids []int64) {
  507. var (
  508. uri string
  509. recURL = conf.Conf.Host.Data + "/mobile/home/%s"
  510. )
  511. uri = fmt.Sprintf(recURL, key)
  512. params := url.Values{}
  513. params.Set("plat", strconv.Itoa(int(plat)))
  514. params.Set("v2", "1")
  515. var res struct {
  516. Code int `json:"code"`
  517. Data []int64 `json:"data"`
  518. Configs []*rcmmndCfg `json:"config"`
  519. }
  520. if err := s.client.Post(ctx, uri, "", params, &res); err != nil {
  521. log.Error("recommend url(%s) error(%v)", uri+"?"+params.Encode(), err)
  522. return
  523. }
  524. if res.Code != 0 {
  525. log.Error("url(%s) res code(%d) or res.result(%v,%v)", uri, res.Code, res.Data, res.Configs)
  526. return
  527. }
  528. aids = res.Data
  529. rcs = res.Configs
  530. return
  531. }
  532. // itemNum get item number by plat.
  533. func (s *Service) itemNum(plat int8) int {
  534. // cnt is items number
  535. cnt := 6
  536. if plat == model.PlatAndroid || plat == model.PlatAndroidI || plat == model.PlatAndroidG {
  537. cnt = 4
  538. } else if plat == model.PlatIPad || plat == model.PlatIPadI {
  539. cnt = 8
  540. } else if plat == model.PlatAndroidTV {
  541. cnt = 16
  542. }
  543. return cnt
  544. }
  545. // dealLive dela live data
  546. func (s *Service) dealLive(c context.Context, sw *show.Show, sis []*show.Item) (rs *show.Show) {
  547. rs = &show.Show{
  548. Head: sw.Head,
  549. Body: sis,
  550. Ext: sw.Ext,
  551. }
  552. return
  553. }
  554. // getLive get lives: feed, moe, hot.
  555. func (s *Service) getLive(c context.Context, mid int64, ak, ip string, rand int, now time.Time) (sis []*show.Item) {
  556. const (
  557. _halfCnt = 2
  558. )
  559. sis = make([]*show.Item, _cnt) // _cnt=4 [0,1,2,3]: 0 1 feed and hot, 2 3 moe and hot
  560. feed, err := s.lv.Feed(c, mid, ak, ip, now)
  561. if err != nil {
  562. log.Error("s.live.Feed(%d) error(%d)", mid, err)
  563. }
  564. var have int
  565. // get two feed
  566. if feed != nil {
  567. for i := 0; i < _halfCnt && i < len(feed.Lives); i++ {
  568. si := &show.Item{}
  569. si.FromLive(feed.Lives[i])
  570. sis[i] = si
  571. have++
  572. }
  573. }
  574. // get two moe
  575. fdCnt := have
  576. start := _halfCnt * rand
  577. if len(s.liveMoeCache) < start+_halfCnt {
  578. start = 0
  579. }
  580. index := _halfCnt
  581. MOENEXT:
  582. for _, l := range s.liveMoeCache[start:] {
  583. for i := 0; i < fdCnt; i++ {
  584. if sis[i].Param == l.Param {
  585. continue MOENEXT
  586. }
  587. }
  588. sis[index] = l
  589. index++
  590. have++
  591. if index >= _cnt {
  592. break
  593. }
  594. }
  595. // if feed and moe not enough, get hot
  596. yu := _cnt - have
  597. if yu > 0 {
  598. start := yu * rand
  599. if len(s.liveHotCache) < start+yu {
  600. start = 0
  601. }
  602. var nilI int
  603. HOTNEXT:
  604. for _, l := range s.liveHotCache[start:] {
  605. nilI = -1
  606. for i := len(sis) - 1; i >= 0; i-- {
  607. if sis[i] == nil {
  608. nilI = i
  609. } else if sis[i].Param == l.Param {
  610. continue HOTNEXT
  611. }
  612. }
  613. if nilI != -1 {
  614. sis[nilI] = l
  615. have++
  616. } else {
  617. return
  618. }
  619. }
  620. }
  621. if have < _cnt {
  622. for k, v := range sis {
  623. if v == nil {
  624. sis[k] = _emptyItem
  625. }
  626. }
  627. }
  628. return
  629. }
  630. // fromArchives return region show items from archive archives.
  631. func (s *Service) fromArchivesPB(as []*api.Arc) (sis, sisOsea []*show.Item) {
  632. var asLen = len(as)
  633. if asLen == 0 {
  634. sis = []*show.Item{}
  635. return
  636. }
  637. sis = make([]*show.Item, 0, asLen)
  638. for _, a := range as {
  639. i := &show.Item{}
  640. i.FromArchivePB(a)
  641. if a.AttrVal(archive.AttrBitOverseaLock) == 0 {
  642. sisOsea = append(sisOsea, i)
  643. }
  644. sis = append(sis, i)
  645. }
  646. return
  647. }
  648. // fromArchivesBangumi aid to sid
  649. func (s *Service) fromArchivesBangumi(c context.Context, as []*api.Arc, aids []int64, sids map[int32]*seasongrpc.CardInfoProto, bangumiType int) (sis, sisOsea []*show.Item) {
  650. var (
  651. asLen = len(as)
  652. err error
  653. // bangumi
  654. )
  655. if asLen == 0 {
  656. sis = []*show.Item{}
  657. return
  658. }
  659. if sids == nil {
  660. if sids, err = s.fromSeasonID(c, aids); err != nil {
  661. log.Error("s.fromSeasonID error(%v)", err)
  662. return
  663. }
  664. }
  665. sis = make([]*show.Item, 0, asLen)
  666. for _, a := range as {
  667. i := &show.Item{}
  668. if sid, ok := sids[int32(a.Aid)]; ok && sid.SeasonId != 0 {
  669. i.FromArchivePBBangumi(a, sid, bangumiType)
  670. } else {
  671. i.FromArchivePB(a)
  672. }
  673. sis = append(sis, i)
  674. if a.AttrVal(archive.AttrBitOverseaLock) == 0 {
  675. sisOsea = append(sisOsea, i)
  676. }
  677. }
  678. return
  679. }
  680. // fromArchivesOsea isOverseas
  681. func (s *Service) fromArchivesOsea(as []*api.Arc, isOsea bool) (sis []*show.Item) {
  682. tmp, tmpOsea := s.fromArchivesPB(as)
  683. if isOsea {
  684. sis = tmpOsea
  685. } else {
  686. sis = tmp
  687. }
  688. return
  689. }
  690. // fromArchivesOsea isOverseas
  691. func (s *Service) fromArchivesBangumiOsea(c context.Context, as []*api.Arc, aids []int64, isOsea bool, bangumiType int) (sis []*show.Item) {
  692. tmp, tmpOsea := s.fromArchivesBangumi(c, as, aids, nil, bangumiType)
  693. if isOsea {
  694. sis = tmpOsea
  695. } else {
  696. sis = tmp
  697. }
  698. return
  699. }
  700. // fromAids get Aids.
  701. func (s *Service) fromAids(ctx context.Context, aids []int64) (sis, sisOsea []*show.Item) {
  702. as, err := s.arc.ArchivesPB(ctx, aids)
  703. if err != nil {
  704. log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
  705. return
  706. }
  707. if len(as) == 0 {
  708. log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
  709. return
  710. }
  711. sis = make([]*show.Item, 0, len(aids))
  712. for _, aid := range aids {
  713. var isOverseas int32
  714. si := &show.Item{}
  715. si.Goto = model.GotoAv
  716. si.Param = strconv.FormatInt(aid, 10)
  717. si.URI = model.FillURI(si.Goto, si.Param, nil)
  718. if v, ok := as[aid]; ok {
  719. isOverseas = v.AttrVal(archive.AttrBitOverseaLock)
  720. si.Danmaku = int(v.Stat.Danmaku)
  721. si.Play = int(v.Stat.View)
  722. si.Title = v.Title
  723. si.Duration = v.Duration
  724. si.Rname = v.TypeName
  725. si.Name = v.Author.Name
  726. si.Like = int(v.Stat.Like)
  727. si.Cover = model.CoverURL(v.Pic)
  728. }
  729. if isOverseas == 0 {
  730. sisOsea = append(sisOsea, si)
  731. }
  732. sis = append(sis, si)
  733. }
  734. return
  735. }
  736. // fromCardAids get Aids.
  737. func (s *Service) fromCardAids(ctx context.Context, aids []int64) (sis map[int64]*show.Item) {
  738. as, err := s.arc.ArchivesPB(ctx, aids)
  739. if err != nil {
  740. log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
  741. return
  742. }
  743. if len(as) == 0 {
  744. log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
  745. return
  746. }
  747. sis = map[int64]*show.Item{}
  748. for _, aid := range aids {
  749. si := &show.Item{}
  750. si.Goto = model.GotoAv
  751. si.Param = strconv.FormatInt(aid, 10)
  752. si.URI = model.FillURI(si.Goto, si.Param, nil)
  753. if v, ok := as[aid]; ok {
  754. if !v.IsNormal() {
  755. continue
  756. }
  757. si.Danmaku = int(v.Stat.Danmaku)
  758. si.Play = int(v.Stat.View)
  759. si.Title = v.Title
  760. si.Duration = v.Duration
  761. if region, ok := s.reRegionCache[int(v.TypeID)]; ok {
  762. si.Desc = region.Name
  763. si.Reid = region.Rid
  764. }
  765. si.Rid = int(v.TypeID)
  766. si.Rname = v.TypeName
  767. si.Name = v.Author.Name
  768. si.Like = int(v.Stat.Like)
  769. si.Cover = model.CoverURL(v.Pic)
  770. }
  771. sis[aid] = si
  772. }
  773. return
  774. }
  775. // fromRankAids
  776. func (s *Service) fromRankAids(ctx context.Context, aids []int64, scores map[int64]int64, as map[int64]*api.Arc) (sis, sisOsea []*show.Item) {
  777. var (
  778. aid int64
  779. arc *api.Arc
  780. ok bool
  781. )
  782. for _, aid = range aids {
  783. if arc, ok = as[aid]; ok {
  784. i := &show.Item{}
  785. if region, ok := s.reRegionCache[int(arc.TypeID)]; ok {
  786. i.Desc = region.Name
  787. }
  788. i.FromArchiveRank(arc, scores)
  789. if arc.AttrVal(archive.AttrBitOverseaLock) == 0 {
  790. sisOsea = append(sisOsea, i)
  791. }
  792. sis = append(sis, i)
  793. }
  794. }
  795. return
  796. }
  797. // fromAids get Aids.
  798. func (s *Service) fromBgAids(ctx context.Context, aids []int64, sids map[int32]*seasongrpc.CardInfoProto, bangumiType int) (sis, sisOsea, sisbg, sisbgOsea, sisbgep, sisbgepOsea []*show.Item) {
  799. var (
  800. err error
  801. )
  802. as, err := s.arc.ArchivesPB(ctx, aids)
  803. if err != nil {
  804. log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
  805. return
  806. }
  807. if len(as) == 0 {
  808. log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
  809. return
  810. }
  811. sis = make([]*show.Item, 0, len(aids))
  812. if sids == nil {
  813. if sids, err = s.fromSeasonID(ctx, aids); err != nil {
  814. log.Error("s.fromSeasonID error(%v)", err)
  815. return
  816. }
  817. }
  818. for _, aid := range aids {
  819. var isOverseas int32
  820. si := &show.Item{}
  821. sibg := &show.Item{}
  822. sibgep := &show.Item{}
  823. if v, ok := as[aid]; ok {
  824. isOverseas = v.AttrVal(archive.AttrBitOverseaLock)
  825. if sid, ok := sids[int32(aid)]; ok && sid.SeasonId != 0 {
  826. sibg.FromArchivePBBangumi(v, sid, _bangumiSeasonID)
  827. sibgep.FromArchivePBBangumi(v, sid, _bangumiEpisodeID)
  828. } else {
  829. sibg.FromArchivePB(v)
  830. sibgep.FromArchivePB(v)
  831. }
  832. si.FromArchivePB(v)
  833. if isOverseas == 0 {
  834. sisOsea = append(sisOsea, si)
  835. sisbgOsea = append(sisbgOsea, sibg)
  836. sisbgepOsea = append(sisbgepOsea, sibg)
  837. }
  838. sis = append(sis, si)
  839. sisbg = append(sisbg, sibg)
  840. sisbgep = append(sisbgep, sibgep)
  841. }
  842. }
  843. return
  844. }
  845. // fromSeasonID
  846. func (s *Service) fromSeasonID(c context.Context, arcAids []int64) (seasonID map[int32]*seasongrpc.CardInfoProto, err error) {
  847. if seasonID, err = s.bgm.CardsByAids(c, arcAids); err != nil {
  848. log.Error("s.bgm.Seasonid CardsByAids %v", err)
  849. }
  850. return
  851. }
  852. // isOverseas
  853. func (s *Service) fromAidsOsea(ctx context.Context, aids []int64, isOsea bool) (sis []*show.Item) {
  854. tmp, tmpOsea := s.fromAids(ctx, aids)
  855. if isOsea {
  856. sis = tmpOsea
  857. } else {
  858. sis = tmp
  859. }
  860. return
  861. }
  862. // adVideo
  863. func (s *Service) adVideo(ctx context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string, sis []*show.Item) (res []*show.Item) {
  864. var cpmsis map[int]*show.Item
  865. if resID, ok := _recommend[plat]; ok {
  866. cpmsis = s.cpmRecommend(ctx, mid, build, buvid, resID, network, mobiApp, device, ipaddr)
  867. }
  868. for rank, ad := range cpmsis {
  869. if len(sis) >= rank {
  870. if ad.IsAdReplace {
  871. sis[rank-1] = ad
  872. } else {
  873. sis[rank-1].IsAdLoc = true
  874. sis[rank-1].IsAd = ad.IsAd
  875. sis[rank-1].CmMark = ad.CmMark
  876. sis[rank-1].SrcId = ad.SrcId
  877. sis[rank-1].RequestId = ad.RequestId
  878. sis[rank-1].ClientIp = ad.ClientIp
  879. }
  880. }
  881. }
  882. res = sis
  883. return
  884. }