ranking.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. package service
  2. import (
  3. "context"
  4. "strconv"
  5. "time"
  6. "go-common/app/interface/main/web/model"
  7. arcmdl "go-common/app/service/main/archive/api"
  8. "go-common/library/log"
  9. )
  10. const (
  11. _rankIndexLen = 8
  12. _rankLen = 100
  13. _rankRegionLen = 10
  14. _rankOtherLimit = 10
  15. _avType = "av"
  16. )
  17. var (
  18. _emptyRankArchive = make([]*model.RankArchive, 0)
  19. )
  20. // Ranking get ranking data.
  21. func (s *Service) Ranking(c context.Context, rid int16, rankType, day, arcType int) (res *model.RankData, err error) {
  22. var (
  23. rankArc *model.RankNew
  24. addCache = true
  25. )
  26. if res, err = s.dao.RankingCache(c, rid, rankType, day, arcType); err != nil {
  27. err = nil
  28. addCache = false
  29. } else if res != nil && len(res.List) > 0 {
  30. return
  31. }
  32. if rankArc, err = s.dao.Ranking(c, rid, rankType, day, arcType); err != nil {
  33. err = nil
  34. } else if rankArc != nil && len(rankArc.List) > s.c.Rule.MinRankCount {
  35. res = &model.RankData{Note: rankArc.Note}
  36. if res.List, err = s.fmtRankArcs(c, rankArc.List, _rankLen); err != nil {
  37. err = nil
  38. } else if len(res.List) > 0 {
  39. if addCache {
  40. s.cache.Do(c, func(c context.Context) {
  41. s.dao.SetRankingCache(c, rid, rankType, day, arcType, res)
  42. })
  43. }
  44. return
  45. }
  46. } else {
  47. log.Error("s.dao.RankingNew(%d,%d,%d) len(aids) (%d)", rid, day, arcType, len(rankArc.List))
  48. }
  49. res, err = s.dao.RankingBakCache(c, rid, rankType, day, arcType)
  50. if res == nil || len(res.List) == 0 {
  51. res = &model.RankData{List: _emptyRankArchive}
  52. }
  53. return
  54. }
  55. // RankingIndex get index ranking data
  56. func (s *Service) RankingIndex(c context.Context, day int) (res []*model.IndexArchive, err error) {
  57. var (
  58. addCache = true
  59. rs []*model.NewArchive
  60. arcs map[int64]*arcmdl.Arc
  61. )
  62. if res, err = s.dao.RankingIndexCache(c, day); err != nil {
  63. err = nil
  64. addCache = false
  65. } else if len(res) > 0 {
  66. return
  67. }
  68. if rs, err = s.dao.RankingIndex(c, day); err != nil {
  69. err = nil
  70. } else if len(rs) > s.c.Rule.MinRankIndexCount {
  71. if arcs, err = s.fillArcs(c, rs); err != nil {
  72. err = nil
  73. } else if len(arcs) > 0 {
  74. res = fmtIndexArcs(rs, arcs)
  75. if addCache {
  76. s.cache.Do(c, func(c context.Context) {
  77. s.dao.SetRankingIndexCache(c, day, res)
  78. })
  79. }
  80. return
  81. }
  82. } else {
  83. log.Error("s.dao.RankingIndexCache(%d) len(aids) (%d)", day, len(res))
  84. }
  85. if res, err = s.dao.RankingIndexBakCache(c, day); err != nil {
  86. return
  87. }
  88. if len(res) == 0 {
  89. res = []*model.IndexArchive{}
  90. }
  91. return
  92. }
  93. // RankingRegion get region ranking data
  94. func (s *Service) RankingRegion(c context.Context, rid int16, day, original int) (res []*model.RegionArchive, err error) {
  95. var (
  96. addCache = true
  97. rs []*model.NewArchive
  98. arcs map[int64]*arcmdl.Arc
  99. )
  100. defer func() {
  101. if len(res) > 0 {
  102. s.fmtRegionStats(c, res)
  103. }
  104. }()
  105. if res, err = s.dao.RankingRegionCache(c, rid, day, original); err != nil {
  106. err = nil
  107. addCache = false
  108. } else if len(res) > 0 {
  109. return
  110. }
  111. if rs, err = s.dao.RankingRegion(c, rid, day, original); err != nil {
  112. err = nil
  113. } else if len(rs) > s.c.Rule.MinRankRegionCount {
  114. if arcs, err = s.fillArcs(c, rs); err != nil {
  115. err = nil
  116. } else if len(arcs) > 0 {
  117. res = fmtRegionArcs(rs, arcs)
  118. if addCache {
  119. s.cache.Do(c, func(c context.Context) {
  120. s.dao.SetRankingRegionCache(c, rid, day, original, res)
  121. })
  122. }
  123. return
  124. }
  125. } else {
  126. log.Error("s.dao.RankingRegion(%d,%d,%d) len(aids) (%d)", rid, day, original, len(rs))
  127. }
  128. res, err = s.dao.RankingRegionBakCache(c, rid, day, original)
  129. if len(res) == 0 {
  130. res = []*model.RegionArchive{}
  131. }
  132. return
  133. }
  134. // RankingRecommend get rank recommend data.
  135. func (s *Service) RankingRecommend(c context.Context, rid int16) (res []*model.IndexArchive, err error) {
  136. var (
  137. addCache = true
  138. rs []*model.NewArchive
  139. arcs map[int64]*arcmdl.Arc
  140. )
  141. if res, err = s.dao.RankingRecommendCache(c, rid); err != nil {
  142. err = nil
  143. addCache = false
  144. } else if len(res) > 0 {
  145. return
  146. }
  147. if rs, err = s.dao.RankingRecommend(c, rid); err != nil {
  148. err = nil
  149. } else if len(rs) > s.c.Rule.MinRankRecCount {
  150. if arcs, err = s.fillArcs(c, rs); err != nil {
  151. err = nil
  152. } else if len(arcs) > 0 {
  153. res = fmtIndexArcs(rs, arcs)
  154. if addCache {
  155. s.cache.Do(c, func(c context.Context) {
  156. s.dao.SetRankingRecommendCache(c, rid, res)
  157. })
  158. }
  159. return
  160. }
  161. } else {
  162. log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
  163. }
  164. res, err = s.dao.RankingRecommendBakCache(c, rid)
  165. if len(res) == 0 {
  166. res = []*model.IndexArchive{}
  167. }
  168. return
  169. }
  170. // RankingTag get tag ranking data
  171. func (s *Service) RankingTag(c context.Context, rid int16, tagID int64) (res []*model.TagArchive, err error) {
  172. var (
  173. addCache = true
  174. tagArcs []*model.NewArchive
  175. arcsReply *arcmdl.ArcsReply
  176. )
  177. defer func() {
  178. s.fmtTagStats(c, res)
  179. }()
  180. if res, err = s.dao.RankingTagCache(c, rid, tagID); err != nil {
  181. err = nil
  182. addCache = false
  183. } else if len(res) > 0 {
  184. return
  185. }
  186. if tagArcs, err = s.dao.RankingTag(c, rid, tagID); err != nil {
  187. err = nil
  188. } else if len(tagArcs) > s.c.Rule.MinRankTagCount {
  189. var aids []int64
  190. for _, v := range tagArcs {
  191. aids = append(aids, v.Aid)
  192. }
  193. if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
  194. err = nil
  195. } else if len(arcsReply.Arcs) > 0 {
  196. res = fmtTagArchives(tagArcs, arcsReply.Arcs)
  197. if addCache {
  198. s.cache.Do(c, func(c context.Context) {
  199. s.dao.SetRankingTagCache(c, rid, tagID, res)
  200. })
  201. }
  202. }
  203. return
  204. } else {
  205. log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
  206. }
  207. res, err = s.dao.RankingTagBakCache(c, rid, tagID)
  208. if len(res) == 0 {
  209. res = []*model.TagArchive{}
  210. }
  211. return
  212. }
  213. // RegionCustom region custom data
  214. func (s *Service) RegionCustom(c context.Context) (res []*model.Custom, err error) {
  215. var (
  216. addCache = true
  217. aids []int64
  218. arcsReply *arcmdl.ArcsReply
  219. )
  220. if res, err = s.dao.RegionCustomCache(c); err != nil {
  221. err = nil
  222. addCache = false
  223. } else if len(res) > 0 {
  224. return
  225. }
  226. if res, err = s.dao.RegionCustom(c); err != nil {
  227. log.Error("s.dao.RegionCustom error(%v)", err)
  228. res = []*model.Custom{}
  229. return
  230. } else if len(res) > 0 {
  231. for _, item := range res {
  232. if item.Type == _avType && item.Aid > 0 {
  233. aids = append(aids, item.Aid)
  234. }
  235. }
  236. if len(aids) > 0 {
  237. archivesArgLog("RegionCustom", aids)
  238. if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
  239. log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
  240. err = nil
  241. } else {
  242. for _, v := range res {
  243. if arc, ok := arcsReply.Arcs[v.Aid]; ok && v.Type == _avType {
  244. v.Pic = arc.Pic
  245. v.Title = arc.Title
  246. }
  247. }
  248. }
  249. }
  250. if addCache {
  251. s.cache.Do(c, func(c context.Context) {
  252. s.dao.SetRegionCustomCache(c, res)
  253. })
  254. }
  255. return
  256. }
  257. res, err = s.dao.RegionCustomBakCache(c)
  258. if len(res) == 0 {
  259. res = []*model.Custom{}
  260. }
  261. return
  262. }
  263. func (s *Service) fillArcs(c context.Context, rankArchives []*model.NewArchive) (res map[int64]*arcmdl.Arc, err error) {
  264. var (
  265. aids []int64
  266. arcsReply *arcmdl.ArcsReply
  267. )
  268. for _, arc := range rankArchives {
  269. if arc == nil {
  270. continue
  271. }
  272. aids = append(aids, arc.Aid)
  273. }
  274. archivesArgLog("fillArcs", aids)
  275. if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
  276. log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
  277. return
  278. }
  279. res = arcsReply.Arcs
  280. return
  281. }
  282. func fmtRegionArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.RegionArchive) {
  283. for _, arc := range aids {
  284. if arc == nil {
  285. continue
  286. }
  287. if len(res) > _rankRegionLen {
  288. break
  289. }
  290. if _, ok := arcs[arc.Aid]; !ok {
  291. continue
  292. }
  293. regionArchive := &model.RegionArchive{
  294. Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
  295. Typename: arcs[arc.Aid].TypeName,
  296. Title: arcs[arc.Aid].Title,
  297. Play: fmtArcView(arcs[arc.Aid]),
  298. Review: arcs[arc.Aid].Stat.Reply,
  299. VideoReview: arcs[arc.Aid].Stat.Danmaku,
  300. Favorites: arcs[arc.Aid].Stat.Fav,
  301. Mid: arcs[arc.Aid].Author.Mid,
  302. Author: arcs[arc.Aid].Author.Name,
  303. Description: arcs[arc.Aid].Desc,
  304. Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
  305. Pic: arcs[arc.Aid].Pic,
  306. Coins: arcs[arc.Aid].Stat.Coin,
  307. Duration: fmtDuration(arcs[arc.Aid].Duration),
  308. Pts: arc.Score,
  309. Rights: arcs[arc.Aid].Rights,
  310. }
  311. res = append(res, regionArchive)
  312. }
  313. return
  314. }
  315. func fmtIndexArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.IndexArchive) {
  316. var (
  317. typeName string
  318. ok bool
  319. )
  320. for _, arc := range aids {
  321. if arc == nil {
  322. continue
  323. }
  324. if len(res) > _rankIndexLen {
  325. break
  326. }
  327. if _, ok = arcs[arc.Aid]; !ok {
  328. continue
  329. }
  330. if typeName, ok = model.RecSpecTypeName[arcs[arc.Aid].TypeID]; !ok {
  331. typeName = arcs[arc.Aid].TypeName
  332. }
  333. indexArchive := &model.IndexArchive{
  334. Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
  335. Typename: typeName,
  336. Title: arcs[arc.Aid].Title,
  337. Play: fmtArcView(arcs[arc.Aid]),
  338. Review: arcs[arc.Aid].Stat.Reply,
  339. VideoReview: arcs[arc.Aid].Stat.Danmaku,
  340. Favorites: arcs[arc.Aid].Stat.Fav,
  341. Mid: arcs[arc.Aid].Author.Mid,
  342. Author: arcs[arc.Aid].Author.Name,
  343. Description: arcs[arc.Aid].Desc,
  344. Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
  345. Pic: arcs[arc.Aid].Pic,
  346. Coins: arcs[arc.Aid].Stat.Coin,
  347. Duration: fmtDuration(arcs[arc.Aid].Duration),
  348. Rights: arcs[arc.Aid].Rights,
  349. }
  350. res = append(res, indexArchive)
  351. }
  352. return
  353. }
  354. func (s *Service) fmtRankArcs(c context.Context, rankArchives []*model.RankNewArchive, arcLen int) (res []*model.RankArchive, err error) {
  355. var (
  356. aids []int64
  357. arcsReply *arcmdl.ArcsReply
  358. )
  359. for _, arc := range rankArchives {
  360. if arc == nil {
  361. continue
  362. }
  363. aids = append(aids, arc.Aid)
  364. if len(arc.Others) > 0 {
  365. i := 0
  366. for _, a := range arc.Others {
  367. if a == nil {
  368. continue
  369. }
  370. aids = append(aids, a.Aid)
  371. i++
  372. if i >= _rankOtherLimit {
  373. break
  374. }
  375. }
  376. }
  377. }
  378. archivesArgLog("fmtRankArcs", aids)
  379. if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
  380. log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
  381. return
  382. }
  383. for _, arc := range rankArchives {
  384. if arc == nil {
  385. continue
  386. }
  387. if len(res) > arcLen {
  388. break
  389. }
  390. if _, ok := arcsReply.Arcs[arc.Aid]; !ok {
  391. continue
  392. }
  393. var coin, danmu int32
  394. if arc.RankStat == nil {
  395. coin = arcsReply.Arcs[arc.Aid].Stat.Coin
  396. danmu = arcsReply.Arcs[arc.Aid].Stat.Danmaku
  397. } else {
  398. coin = arc.RankStat.Coin
  399. danmu = arc.RankStat.Danmu
  400. arcsReply.Arcs[arc.Aid].Stat.View = arc.RankStat.Play
  401. }
  402. rankArchive := &model.RankArchive{
  403. Aid: strconv.FormatInt(arcsReply.Arcs[arc.Aid].Aid, 10),
  404. Author: arcsReply.Arcs[arc.Aid].Author.Name,
  405. Coins: coin,
  406. Duration: fmtDuration(arcsReply.Arcs[arc.Aid].Duration),
  407. Mid: arcsReply.Arcs[arc.Aid].Author.Mid,
  408. Pic: arcsReply.Arcs[arc.Aid].Pic,
  409. Play: fmtArcView(arcsReply.Arcs[arc.Aid]),
  410. Pts: arc.Score,
  411. Title: arcsReply.Arcs[arc.Aid].Title,
  412. VideoReview: danmu,
  413. Rights: arcsReply.Arcs[arc.Aid].Rights,
  414. }
  415. if len(arc.Others) > 0 {
  416. for _, a := range arc.Others {
  417. if a == nil {
  418. continue
  419. }
  420. if _, ok := arcsReply.Arcs[a.Aid]; !ok {
  421. continue
  422. }
  423. archive := &model.Other{
  424. Aid: a.Aid,
  425. Play: fmtArcView(arcsReply.Arcs[a.Aid]),
  426. VideoReview: arcsReply.Arcs[a.Aid].Stat.Danmaku,
  427. Coins: arcsReply.Arcs[a.Aid].Stat.Coin,
  428. Pts: a.Score,
  429. Title: arcsReply.Arcs[a.Aid].Title,
  430. Pic: arcsReply.Arcs[a.Aid].Pic,
  431. Duration: fmtDuration(arcsReply.Arcs[a.Aid].Duration),
  432. Rights: arcsReply.Arcs[a.Aid].Rights,
  433. }
  434. rankArchive.Others = append(rankArchive.Others, archive)
  435. }
  436. }
  437. res = append(res, rankArchive)
  438. }
  439. return
  440. }
  441. // fmtRegionStats get real time region archive stat
  442. func (s *Service) fmtRegionStats(c context.Context, res []*model.RegionArchive) {
  443. var (
  444. aids []int64
  445. aid int64
  446. err error
  447. statsReply *arcmdl.StatsReply
  448. )
  449. for _, arc := range res {
  450. if arc == nil {
  451. continue
  452. }
  453. if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
  454. continue
  455. }
  456. aids = append(aids, aid)
  457. }
  458. if len(aids) == 0 {
  459. return
  460. }
  461. if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
  462. log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
  463. return
  464. }
  465. arcStats := statsReply.Stats
  466. for _, arc := range res {
  467. if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
  468. continue
  469. }
  470. if arcStat, ok := arcStats[aid]; ok {
  471. arc.Play = arcStat.View
  472. arc.VideoReview = arcStat.Danmaku
  473. arc.Favorites = arcStat.Fav
  474. arc.Coins = arcStat.Coin
  475. }
  476. }
  477. }
  478. func fmtTagArchives(tagArcs []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.TagArchive) {
  479. for _, tagArc := range tagArcs {
  480. if arc, ok := arcs[tagArc.Aid]; ok {
  481. res = append(res, &model.TagArchive{
  482. Title: arc.Title,
  483. Author: arc.Author.Name,
  484. Description: arc.Desc,
  485. Pic: arc.Pic,
  486. Play: strconv.FormatInt(int64(arc.Stat.View), 10),
  487. Favorites: strconv.FormatInt(int64(arc.Stat.Fav), 10),
  488. Mid: strconv.FormatInt(arc.Author.Mid, 10),
  489. Review: strconv.FormatInt(int64(arc.Stat.Reply), 10),
  490. CreatedAt: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
  491. VideoReview: strconv.FormatInt(int64(arc.Stat.Danmaku), 10),
  492. Coins: strconv.FormatInt(int64(arc.Stat.Coin), 10),
  493. Duration: strconv.FormatInt(arc.Duration, 10),
  494. Aid: arc.Aid,
  495. Pts: tagArc.Score,
  496. Rights: arc.Rights,
  497. })
  498. }
  499. }
  500. return
  501. }
  502. // fmtTagStats get real time tag archive stat
  503. func (s *Service) fmtTagStats(c context.Context, res []*model.TagArchive) {
  504. var (
  505. aids []int64
  506. err error
  507. statsReply *arcmdl.StatsReply
  508. )
  509. for _, arc := range res {
  510. if arc == nil {
  511. continue
  512. }
  513. aids = append(aids, arc.Aid)
  514. }
  515. if len(aids) == 0 {
  516. return
  517. }
  518. if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
  519. log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
  520. return
  521. }
  522. arcStats := statsReply.Stats
  523. for _, arc := range res {
  524. if arcStat, ok := arcStats[arc.Aid]; ok {
  525. arc.Play = strconv.FormatInt(int64(arcStat.View), 10)
  526. arc.VideoReview = strconv.FormatInt(int64(arcStat.Danmaku), 10)
  527. arc.Favorites = strconv.FormatInt(int64(arcStat.Fav), 10)
  528. arc.Coins = strconv.FormatInt(int64(arcStat.Coin), 10)
  529. }
  530. }
  531. }
  532. func fmtDuration(duration int64) (du string) {
  533. if duration == 0 {
  534. du = "00:00"
  535. } else {
  536. var min, sec string
  537. min = strconv.Itoa(int(duration / 60))
  538. if int(duration%60) < 10 {
  539. sec = "0" + strconv.Itoa(int(duration%60))
  540. } else {
  541. sec = strconv.Itoa(int(duration % 60))
  542. }
  543. du = min + ":" + sec
  544. }
  545. return
  546. }
  547. func fmtArcView(a *arcmdl.Arc) interface{} {
  548. var view interface{} = a.Stat.View
  549. if a.Access > 0 {
  550. view = "--"
  551. }
  552. return view
  553. }