slide.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. package service
  2. import (
  3. "context"
  4. "strconv"
  5. "strings"
  6. "go-common/app/interface/openplatform/article/model"
  7. "go-common/library/log"
  8. )
  9. var (
  10. _slideCount = 20
  11. _left = 0
  12. _right = 1
  13. )
  14. // var _slideRecommends = 2
  15. // ViewList .
  16. func (s *Service) ViewList(c context.Context, aid int64, buvid string, from string, ip string, build int, plat int8, mid int64) (pre int64, next int64) {
  17. var (
  18. cid int64
  19. res *model.Article
  20. err error
  21. arts = &model.ArticleViewList{From: from, Buvid: buvid, Plat: plat, Build: build, Mid: mid}
  22. )
  23. if res, err = s.Article(c, aid); err != nil {
  24. res = nil
  25. return
  26. }
  27. if res == nil {
  28. res = nil
  29. return
  30. }
  31. if strings.Contains(from, "_") {
  32. fs := strings.Split(from, "_")
  33. if len(fs) < 2 {
  34. return
  35. }
  36. cid, _ = strconv.ParseInt(fs[1], 10, 64)
  37. switch fs[0] {
  38. case "category":
  39. //分区 天马
  40. if cid == 0 {
  41. arts.From = "recommend"
  42. pre, next = s.listFromRecommends(c, aid, arts)
  43. // arts.From = "skyhorse"
  44. // pre, next = s.listFromSkyHorseEx(c, aid, cid, arts, int64(res.PublishTime), res.Author.Mid)
  45. } else {
  46. arts.From = "default"
  47. pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
  48. }
  49. case "rank":
  50. //排行榜
  51. pre, next = s.listFromRank(c, aid, cid, arts, ip)
  52. case "readlist":
  53. //文集
  54. pre, next = s.listFromReadList(c, aid, arts)
  55. default:
  56. //default
  57. arts.From = "default"
  58. pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
  59. }
  60. } else {
  61. switch from {
  62. // case "mainCard":
  63. // //天马
  64. // arts.From = "skyhorse"
  65. // pre, next = s.listFromSkyHorseEx(c, aid, 0, arts, int64(res.PublishTime), res.Author.Mid)
  66. case "favorite":
  67. // TODO
  68. pre, next = s.validFavsList(c, aid, arts, true)
  69. case "records":
  70. // TODO
  71. // pre, next = 0, 0
  72. // pre, next = s.historyCursor(c, aid, arts, true)
  73. case "readlist":
  74. //文集
  75. pre, next = s.listFromReadList(c, aid, arts)
  76. case "articleSlide":
  77. //滑动
  78. pre, next, arts = s.listFromCache(c, aid, arts.Buvid)
  79. default:
  80. //作者其他的文章
  81. arts.From = "default"
  82. pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
  83. }
  84. }
  85. s.dao.AddCacheListArtsId(c, buvid, arts)
  86. return
  87. }
  88. // func (s *Service) listFromSkyHorseEx(c context.Context, aid int64, cid int64, arts *model.ArticleViewList, pt int64, authorMid int64) (pre int64, next int64) {
  89. // pre, next = s.listFromSkyHorse(c, aid, cid, arts)
  90. // if pre == 0 && next == 0 {
  91. // arts.From = "default"
  92. // pre, next = s.listByAuthor(c, aid, authorMid, pt, arts)
  93. // }
  94. // return
  95. // }
  96. func (s *Service) listFromCache(c context.Context, aid int64, buvid string) (pre int64, next int64, arts *model.ArticleViewList) {
  97. var (
  98. res *model.Article
  99. err error
  100. position = -1
  101. )
  102. if arts, err = s.dao.CacheListArtsId(c, buvid); err != nil {
  103. log.Error("s.dao.CacheListArtsId, error(%+v)", err)
  104. return
  105. }
  106. if arts == nil || arts.Aids == nil {
  107. return
  108. }
  109. for i, id := range arts.Aids {
  110. if id == aid {
  111. position = i
  112. break
  113. }
  114. }
  115. if position == -1 {
  116. return
  117. }
  118. switch arts.From {
  119. case "recommend":
  120. if position == 0 {
  121. if len(arts.Aids) > 1 {
  122. next = arts.Aids[1]
  123. }
  124. pre = s.newRecommend(c, arts, _left)
  125. // pre = s.newSkyHorse(c, arts, _left)
  126. arts.Position = position
  127. return
  128. }
  129. if position == len(arts.Aids)-1 {
  130. if len(arts.Aids) > 1 {
  131. pre = arts.Aids[len(arts.Aids)-2]
  132. }
  133. next = s.newRecommend(c, arts, _right)
  134. // next = s.newSkyHorse(c, arts, _right)
  135. arts.Position = position
  136. return
  137. }
  138. case "default":
  139. if position == 0 || position == len(arts.Aids)-1 {
  140. if res, err = s.Article(c, aid); err != nil || res == nil {
  141. return
  142. }
  143. pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
  144. arts.Position = position
  145. return
  146. }
  147. next = arts.Aids[position-1]
  148. pre = arts.Aids[position+1]
  149. return
  150. case "records":
  151. return
  152. // if position == len(arts.Aids)-1 {
  153. // if position > 0 {
  154. // pre = arts.Aids[position-1]
  155. // }
  156. // _, next = s.historyCursor(c, aid, arts, false)
  157. // return
  158. // }
  159. case "favorite":
  160. if position == len(arts.Aids)-1 {
  161. if position > 0 {
  162. pre = arts.Aids[position-1]
  163. }
  164. _, next = s.validFavsList(c, aid, arts, false)
  165. return
  166. }
  167. }
  168. if position > 0 {
  169. pre = arts.Aids[position-1]
  170. }
  171. if position < len(arts.Aids)-1 {
  172. next = arts.Aids[position+1]
  173. }
  174. return
  175. }
  176. func (s *Service) listFromReadList(c context.Context, aid int64, arts *model.ArticleViewList) (pre int64, next int64) {
  177. var (
  178. listID int64
  179. list *model.List
  180. artsMetas []*model.ListArtMeta
  181. ok bool
  182. )
  183. lists, err := s.dao.ArtsList(c, []int64{aid})
  184. if err != nil {
  185. log.Error("s.dao.ArtsList, error(%+v)", err)
  186. return
  187. }
  188. if list, ok = lists[aid]; !ok {
  189. return
  190. }
  191. listID = list.ID
  192. if artsMetas, err = s.dao.ListArts(c, listID); err != nil {
  193. log.Error("s.dao.ListArts, error(%+v)", err)
  194. return
  195. }
  196. if artsMetas == nil {
  197. return
  198. }
  199. for i, art := range artsMetas {
  200. if art.ID == aid {
  201. arts.Position = i
  202. }
  203. arts.Aids = append(arts.Aids, art.ID)
  204. }
  205. if arts.Position > 0 {
  206. pre = artsMetas[arts.Position-1].ID
  207. }
  208. if arts.Position < len(artsMetas)-1 {
  209. next = artsMetas[arts.Position+1].ID
  210. }
  211. return
  212. }
  213. func (s *Service) listByAuthor(c context.Context, aid int64, mid int64, pt int64, arts *model.ArticleViewList) (pre int64, next int64) {
  214. var (
  215. beforeAids, afterAids, tmpAids []int64
  216. aidTimes [][2]int64
  217. exist bool
  218. j int
  219. err error
  220. metas map[int64]*model.Meta
  221. aids []int64
  222. addCache = true
  223. position = -1
  224. )
  225. if exist, err = s.dao.ExpireUpperCache(c, mid); err != nil {
  226. addCache = false
  227. err = nil
  228. } else if exist {
  229. if beforeAids, afterAids, err = s.dao.MoreArtsCaches(c, mid, int64(pt), _slideCount); err != nil {
  230. addCache = false
  231. exist = false
  232. }
  233. if len(beforeAids)+len(afterAids) == 0 {
  234. return
  235. }
  236. for i := len(beforeAids) - 1; i >= 0; i-- {
  237. tmpAids = append(tmpAids, beforeAids[i])
  238. }
  239. tmpAids = append(tmpAids, aid)
  240. tmpAids = append(tmpAids, afterAids...)
  241. } else {
  242. if aidTimes, err = s.dao.UpperPassed(c, mid); err != nil {
  243. log.Error("s.dao.UpperPassed, error(%+v)", err)
  244. return
  245. }
  246. if addCache {
  247. cache.Save(func() {
  248. s.dao.AddUpperCaches(context.TODO(), map[int64][][2]int64{mid: aidTimes})
  249. })
  250. }
  251. for i := len(aidTimes) - 1; i >= 0; i-- {
  252. aidTime := aidTimes[i]
  253. tmpAids = append(tmpAids, aidTime[0])
  254. }
  255. }
  256. if metas, err = s.ArticleMetas(c, tmpAids); err != nil {
  257. log.Error("s.ArticleMetas, error(%+v)", err)
  258. return
  259. }
  260. //过滤禁止显示的稿件
  261. filterNoDistributeArtsMap(metas)
  262. if len(metas) == 0 {
  263. return
  264. }
  265. for _, id := range tmpAids {
  266. if _, ok := metas[id]; !ok {
  267. continue
  268. }
  269. if id == aid {
  270. position = j
  271. }
  272. j++
  273. aids = append(aids, id)
  274. }
  275. if position == -1 {
  276. return
  277. }
  278. if position > 0 {
  279. next = aids[position-1]
  280. }
  281. if position < len(aids)-1 {
  282. pre = aids[position+1]
  283. }
  284. arts.Position = position
  285. arts.Aids = aids
  286. return
  287. }
  288. func (s *Service) listFromRank(c context.Context, aid int64, cid int64, arts *model.ArticleViewList, ip string) (pre int64, next int64) {
  289. var (
  290. exist bool
  291. err error
  292. aids []int64
  293. rank model.RankResp
  294. addCache = true
  295. position = -1
  296. )
  297. s.dao.DelCacheListArtsId(c, arts.Buvid)
  298. if !s.ranksMap[cid] {
  299. return
  300. }
  301. if exist, err = s.dao.ExpireRankCache(c, cid); err != nil {
  302. addCache = false
  303. err = nil
  304. }
  305. if exist {
  306. if rank, err = s.dao.RankCache(c, cid); err != nil {
  307. exist = false
  308. err = nil
  309. addCache = false
  310. }
  311. } else {
  312. if rank, err = s.dao.Rank(c, cid, ip); err != nil {
  313. if rank, err = s.dao.RankCache(c, cid); err != nil {
  314. log.Error("s.dao.RankCache, error(%+v)", err)
  315. return
  316. }
  317. } else {
  318. if addCache && len(rank.List) > 0 {
  319. cache.Save(func() {
  320. s.dao.AddRankCache(context.TODO(), cid, rank)
  321. })
  322. }
  323. }
  324. }
  325. if len(rank.List) == 0 {
  326. return
  327. }
  328. for i, a := range rank.List {
  329. aids = append(aids, a.Aid)
  330. if a.Aid == aid {
  331. position = i
  332. }
  333. }
  334. if position == -1 {
  335. return
  336. }
  337. arts.Position = position
  338. arts.Aids = aids
  339. if position > 0 {
  340. pre = aids[position-1]
  341. }
  342. if position < len(aids)-1 {
  343. next = aids[position+1]
  344. }
  345. return
  346. }
  347. // func (s *Service) listFromSkyHorse(c context.Context, aid int64, cid int64, arts *model.ArticleViewList) (pre int64, next int64) {
  348. // var (
  349. // beforeAids, afterAids, tmpAids, aids []int64
  350. // err error
  351. // position = -1
  352. // half = _slideRecommends / 2
  353. // )
  354. // if tmpAids, err = s.filterAidsFromSkyHorse(c, aid, arts, _slideRecommends); err != nil || len(tmpAids) == 0 {
  355. // return
  356. // }
  357. // if len(tmpAids) < half {
  358. // half = len(tmpAids) / 2
  359. // }
  360. // beforeAids = make([]int64, half)
  361. // afterAids = make([]int64, len(tmpAids)-half)
  362. // copy(beforeAids, tmpAids[:half])
  363. // copy(afterAids, tmpAids[half:])
  364. // position = half
  365. // aids = append([]int64{}, beforeAids...)
  366. // aids = append(aids, aid)
  367. // aids = append(aids, afterAids...)
  368. // arts.Position = position
  369. // arts.Aids = aids
  370. // if len(beforeAids) > 0 {
  371. // pre = beforeAids[len(beforeAids)-1]
  372. // }
  373. // if len(afterAids) > 0 {
  374. // next = afterAids[0]
  375. // }
  376. // return
  377. // }
  378. // func (s *Service) newSkyHorse(c context.Context, arts *model.ArticleViewList, side int) (aid int64) {
  379. // var (
  380. // aids []int64
  381. // err error
  382. // )
  383. // if aids, err = s.filterAidsFromSkyHorse(c, arts.Aids[arts.Position], arts, _slideRecommends/2); err != nil || len(aids) == 0 {
  384. // return
  385. // }
  386. // aids = uniqIDs(aids, arts.Aids)
  387. // if len(aids) == 0 {
  388. // return
  389. // }
  390. // if side == _left {
  391. // aid = aids[len(aids)-1]
  392. // arts.Aids = append(aids, arts.Aids...)
  393. // arts.Position += len(aids)
  394. // } else {
  395. // aid = aids[0]
  396. // arts.Aids = append(arts.Aids, aids...)
  397. // }
  398. // return
  399. // }
  400. // func (s *Service) filterAidsFromSkyHorse(c context.Context, aid int64, arts *model.ArticleViewList, size int) (aids []int64, err error) {
  401. // var (
  402. // tmpIds []int64
  403. // sky *model.SkyHorseResp
  404. // metas map[int64]*model.Meta
  405. // )
  406. // if sky, err = s.dao.SkyHorse(c, arts.Mid, arts.Build, arts.Buvid, arts.Plat, size); err != nil {
  407. // return
  408. // }
  409. // if len(sky.Data) == 0 {
  410. // return
  411. // }
  412. // for _, item := range sky.Data {
  413. // tmpIds = append(tmpIds, item.ID)
  414. // }
  415. // if metas, err = s.ArticleMetas(c, tmpIds); err != nil {
  416. // log.Error("s.ArticleMetas, error(%+v)", err)
  417. // return
  418. // }
  419. // //过滤禁止显示的稿件
  420. // filterNoDistributeArtsMap(metas)
  421. // filterNoRegionArts(metas)
  422. // if len(metas) == 0 {
  423. // return
  424. // }
  425. // for _, meta := range metas {
  426. // if meta.ID == aid {
  427. // continue
  428. // }
  429. // aids = append(aids, meta.ID)
  430. // }
  431. // return
  432. // }
  433. func (s *Service) validFavsList(c context.Context, aid int64, arts *model.ArticleViewList, ok bool) (pre int64, next int64) {
  434. arts.Position++
  435. var (
  436. favs []*model.Favorite
  437. err error
  438. page = &model.Page{Total: arts.Position*_slideCount + 1}
  439. )
  440. for ok && page.Total > arts.Position*_slideCount {
  441. if favs, page, err = s.Favs(c, arts.Mid, 0, arts.Position, _slideCount, ""); err != nil {
  442. return
  443. }
  444. for _, fav := range favs {
  445. if !fav.Valid {
  446. continue
  447. }
  448. arts.Aids = append(arts.Aids, fav.ID)
  449. }
  450. for i, id := range arts.Aids {
  451. if id != aid {
  452. continue
  453. }
  454. if i > 0 {
  455. pre = arts.Aids[i-1]
  456. }
  457. if i < len(arts.Aids)-1 {
  458. next = arts.Aids[i+1]
  459. ok = false
  460. }
  461. }
  462. arts.Position++
  463. }
  464. if next > 0 {
  465. return
  466. }
  467. ok = true
  468. for ok && page.Total > arts.Position*_slideCount {
  469. if favs, page, err = s.Favs(c, arts.Mid, 0, arts.Position, _slideCount, ""); err != nil {
  470. return
  471. }
  472. for _, fav := range favs {
  473. if !fav.Valid {
  474. continue
  475. }
  476. if next == 0 {
  477. next = fav.ID
  478. }
  479. ok = false
  480. arts.Aids = append(arts.Aids, fav.ID)
  481. }
  482. arts.Position++
  483. }
  484. return
  485. }
  486. // func (s *Service) historyCursor(c context.Context, aid int64, arts *model.ArticleViewList, ok bool) (pre int64, next int64) {
  487. // var (
  488. // res []*history.Resource
  489. // err error
  490. // viewAt = int64(arts.Position)
  491. // aids []int64
  492. // )
  493. // for ok {
  494. // arg := &history.ArgCursor{Mid: arts.Mid, Businesses: []string{"article", "article-list"}, Ps: _slideCount, ViewAt: viewAt}
  495. // if res, err = s.hisRPC.HistoryCursor(c, arg); err != nil || len(res) < 2 {
  496. // return
  497. // }
  498. // for _, r := range res {
  499. // viewAt = r.Unix
  500. // id := r.Oid
  501. // if r.TP == history.TypeCorpus {
  502. // id = r.Cid
  503. // }
  504. // aids = append(aids, id)
  505. // }
  506. // for i, id := range aids {
  507. // if id != aid {
  508. // continue
  509. // }
  510. // ok = false
  511. // if i > 0 {
  512. // pre = aids[i-1]
  513. // }
  514. // if i < len(aids)-1 {
  515. // next = aids[i+1]
  516. // }
  517. // }
  518. // arts.Aids = append(arts.Aids, aids...)
  519. // arts.Position = int(viewAt)
  520. // }
  521. // if next > 0 {
  522. // return
  523. // }
  524. // arg := &history.ArgCursor{Mid: arts.Mid, Businesses: []string{"article", "article-list"}, Ps: _slideCount, ViewAt: viewAt}
  525. // if res, err = s.hisRPC.HistoryCursor(c, arg); err != nil || len(res) == 0 {
  526. // return
  527. // }
  528. // for _, r := range res {
  529. // viewAt = r.Unix
  530. // id := r.Oid
  531. // if r.TP == history.TypeCorpus {
  532. // id = r.Cid
  533. // }
  534. // if next == 0 {
  535. // next = id
  536. // }
  537. // arts.Aids = append(arts.Aids, id)
  538. // }
  539. // arts.Position = int(viewAt)
  540. // return
  541. // }
  542. func (s *Service) listFromRecommends(c context.Context, aid int64, arts *model.ArticleViewList) (pre int64, next int64) {
  543. recommends := s.genRecommendArtFromPool(s.RecommendsMap[_recommendCategory], _slideCount)
  544. tmpAids, _ := s.dealRecommends(recommends)
  545. var aids []int64
  546. for _, id := range tmpAids {
  547. if id != aid {
  548. aids = append(aids, id)
  549. }
  550. }
  551. if len(aids) == 0 {
  552. return
  553. }
  554. if len(aids) == 1 {
  555. next = aids[0]
  556. arts.Aids = append([]int64{aid}, aids[0])
  557. return
  558. }
  559. half := len(aids) / 2
  560. beforeAids := make([]int64, half)
  561. afterAids := make([]int64, len(aids)-half)
  562. copy(beforeAids, aids[:half])
  563. copy(afterAids, aids[half:])
  564. aids = append([]int64{}, beforeAids...)
  565. aids = append(aids, aid)
  566. aids = append(aids, afterAids...)
  567. arts.Position = half
  568. arts.Aids = aids
  569. pre = arts.Aids[half-1]
  570. next = arts.Aids[half+1]
  571. return
  572. }
  573. func (s *Service) newRecommend(c context.Context, arts *model.ArticleViewList, side int) (res int64) {
  574. var (
  575. m = make(map[int64]bool)
  576. nids []int64
  577. )
  578. recommends := s.genRecommendArtFromPool(s.RecommendsMap[_recommendCategory], _slideCount)
  579. aids, _ := s.dealRecommends(recommends)
  580. if len(aids) == 0 {
  581. return
  582. }
  583. for _, aid := range arts.Aids {
  584. m[aid] = true
  585. }
  586. for _, aid := range aids {
  587. if !m[aid] {
  588. nids = append(nids, aid)
  589. }
  590. }
  591. if len(nids) == 0 {
  592. return
  593. }
  594. if side == _left {
  595. res = nids[len(nids)-1]
  596. arts.Aids = append(nids, arts.Aids...)
  597. }
  598. if side == _right {
  599. res = nids[0]
  600. arts.Aids = append(arts.Aids, nids...)
  601. }
  602. return
  603. }