573 lines
15 KiB
Go
573 lines
15 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go-common/app/interface/main/web/model"
|
|
arcmdl "go-common/app/service/main/archive/api"
|
|
"go-common/library/log"
|
|
)
|
|
|
|
const (
|
|
_rankIndexLen = 8
|
|
_rankLen = 100
|
|
_rankRegionLen = 10
|
|
_rankOtherLimit = 10
|
|
_avType = "av"
|
|
)
|
|
|
|
var (
|
|
_emptyRankArchive = make([]*model.RankArchive, 0)
|
|
)
|
|
|
|
// Ranking get ranking data.
|
|
func (s *Service) Ranking(c context.Context, rid int16, rankType, day, arcType int) (res *model.RankData, err error) {
|
|
var (
|
|
rankArc *model.RankNew
|
|
addCache = true
|
|
)
|
|
if res, err = s.dao.RankingCache(c, rid, rankType, day, arcType); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if res != nil && len(res.List) > 0 {
|
|
return
|
|
}
|
|
if rankArc, err = s.dao.Ranking(c, rid, rankType, day, arcType); err != nil {
|
|
err = nil
|
|
} else if rankArc != nil && len(rankArc.List) > s.c.Rule.MinRankCount {
|
|
res = &model.RankData{Note: rankArc.Note}
|
|
if res.List, err = s.fmtRankArcs(c, rankArc.List, _rankLen); err != nil {
|
|
err = nil
|
|
} else if len(res.List) > 0 {
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRankingCache(c, rid, rankType, day, arcType, res)
|
|
})
|
|
}
|
|
return
|
|
}
|
|
} else {
|
|
log.Error("s.dao.RankingNew(%d,%d,%d) len(aids) (%d)", rid, day, arcType, len(rankArc.List))
|
|
}
|
|
res, err = s.dao.RankingBakCache(c, rid, rankType, day, arcType)
|
|
if res == nil || len(res.List) == 0 {
|
|
res = &model.RankData{List: _emptyRankArchive}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RankingIndex get index ranking data
|
|
func (s *Service) RankingIndex(c context.Context, day int) (res []*model.IndexArchive, err error) {
|
|
var (
|
|
addCache = true
|
|
rs []*model.NewArchive
|
|
arcs map[int64]*arcmdl.Arc
|
|
)
|
|
if res, err = s.dao.RankingIndexCache(c, day); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if len(res) > 0 {
|
|
return
|
|
}
|
|
if rs, err = s.dao.RankingIndex(c, day); err != nil {
|
|
err = nil
|
|
} else if len(rs) > s.c.Rule.MinRankIndexCount {
|
|
if arcs, err = s.fillArcs(c, rs); err != nil {
|
|
err = nil
|
|
} else if len(arcs) > 0 {
|
|
res = fmtIndexArcs(rs, arcs)
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRankingIndexCache(c, day, res)
|
|
})
|
|
}
|
|
return
|
|
}
|
|
} else {
|
|
log.Error("s.dao.RankingIndexCache(%d) len(aids) (%d)", day, len(res))
|
|
}
|
|
if res, err = s.dao.RankingIndexBakCache(c, day); err != nil {
|
|
return
|
|
}
|
|
if len(res) == 0 {
|
|
res = []*model.IndexArchive{}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RankingRegion get region ranking data
|
|
func (s *Service) RankingRegion(c context.Context, rid int16, day, original int) (res []*model.RegionArchive, err error) {
|
|
var (
|
|
addCache = true
|
|
rs []*model.NewArchive
|
|
arcs map[int64]*arcmdl.Arc
|
|
)
|
|
defer func() {
|
|
if len(res) > 0 {
|
|
s.fmtRegionStats(c, res)
|
|
}
|
|
}()
|
|
if res, err = s.dao.RankingRegionCache(c, rid, day, original); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if len(res) > 0 {
|
|
return
|
|
}
|
|
if rs, err = s.dao.RankingRegion(c, rid, day, original); err != nil {
|
|
err = nil
|
|
} else if len(rs) > s.c.Rule.MinRankRegionCount {
|
|
if arcs, err = s.fillArcs(c, rs); err != nil {
|
|
err = nil
|
|
} else if len(arcs) > 0 {
|
|
res = fmtRegionArcs(rs, arcs)
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRankingRegionCache(c, rid, day, original, res)
|
|
})
|
|
}
|
|
return
|
|
}
|
|
} else {
|
|
log.Error("s.dao.RankingRegion(%d,%d,%d) len(aids) (%d)", rid, day, original, len(rs))
|
|
}
|
|
res, err = s.dao.RankingRegionBakCache(c, rid, day, original)
|
|
if len(res) == 0 {
|
|
res = []*model.RegionArchive{}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RankingRecommend get rank recommend data.
|
|
func (s *Service) RankingRecommend(c context.Context, rid int16) (res []*model.IndexArchive, err error) {
|
|
var (
|
|
addCache = true
|
|
rs []*model.NewArchive
|
|
arcs map[int64]*arcmdl.Arc
|
|
)
|
|
if res, err = s.dao.RankingRecommendCache(c, rid); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if len(res) > 0 {
|
|
return
|
|
}
|
|
if rs, err = s.dao.RankingRecommend(c, rid); err != nil {
|
|
err = nil
|
|
} else if len(rs) > s.c.Rule.MinRankRecCount {
|
|
if arcs, err = s.fillArcs(c, rs); err != nil {
|
|
err = nil
|
|
} else if len(arcs) > 0 {
|
|
res = fmtIndexArcs(rs, arcs)
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRankingRecommendCache(c, rid, res)
|
|
})
|
|
}
|
|
return
|
|
}
|
|
} else {
|
|
log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
|
|
}
|
|
res, err = s.dao.RankingRecommendBakCache(c, rid)
|
|
if len(res) == 0 {
|
|
res = []*model.IndexArchive{}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RankingTag get tag ranking data
|
|
func (s *Service) RankingTag(c context.Context, rid int16, tagID int64) (res []*model.TagArchive, err error) {
|
|
var (
|
|
addCache = true
|
|
tagArcs []*model.NewArchive
|
|
arcsReply *arcmdl.ArcsReply
|
|
)
|
|
defer func() {
|
|
s.fmtTagStats(c, res)
|
|
}()
|
|
if res, err = s.dao.RankingTagCache(c, rid, tagID); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if len(res) > 0 {
|
|
return
|
|
}
|
|
if tagArcs, err = s.dao.RankingTag(c, rid, tagID); err != nil {
|
|
err = nil
|
|
} else if len(tagArcs) > s.c.Rule.MinRankTagCount {
|
|
var aids []int64
|
|
for _, v := range tagArcs {
|
|
aids = append(aids, v.Aid)
|
|
}
|
|
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
|
|
err = nil
|
|
} else if len(arcsReply.Arcs) > 0 {
|
|
res = fmtTagArchives(tagArcs, arcsReply.Arcs)
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRankingTagCache(c, rid, tagID, res)
|
|
})
|
|
}
|
|
}
|
|
return
|
|
} else {
|
|
log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
|
|
}
|
|
res, err = s.dao.RankingTagBakCache(c, rid, tagID)
|
|
if len(res) == 0 {
|
|
res = []*model.TagArchive{}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RegionCustom region custom data
|
|
func (s *Service) RegionCustom(c context.Context) (res []*model.Custom, err error) {
|
|
var (
|
|
addCache = true
|
|
aids []int64
|
|
arcsReply *arcmdl.ArcsReply
|
|
)
|
|
if res, err = s.dao.RegionCustomCache(c); err != nil {
|
|
err = nil
|
|
addCache = false
|
|
} else if len(res) > 0 {
|
|
return
|
|
}
|
|
if res, err = s.dao.RegionCustom(c); err != nil {
|
|
log.Error("s.dao.RegionCustom error(%v)", err)
|
|
res = []*model.Custom{}
|
|
return
|
|
} else if len(res) > 0 {
|
|
for _, item := range res {
|
|
if item.Type == _avType && item.Aid > 0 {
|
|
aids = append(aids, item.Aid)
|
|
}
|
|
}
|
|
if len(aids) > 0 {
|
|
archivesArgLog("RegionCustom", aids)
|
|
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
|
|
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
|
|
err = nil
|
|
} else {
|
|
for _, v := range res {
|
|
if arc, ok := arcsReply.Arcs[v.Aid]; ok && v.Type == _avType {
|
|
v.Pic = arc.Pic
|
|
v.Title = arc.Title
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if addCache {
|
|
s.cache.Do(c, func(c context.Context) {
|
|
s.dao.SetRegionCustomCache(c, res)
|
|
})
|
|
}
|
|
return
|
|
}
|
|
res, err = s.dao.RegionCustomBakCache(c)
|
|
if len(res) == 0 {
|
|
res = []*model.Custom{}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *Service) fillArcs(c context.Context, rankArchives []*model.NewArchive) (res map[int64]*arcmdl.Arc, err error) {
|
|
var (
|
|
aids []int64
|
|
arcsReply *arcmdl.ArcsReply
|
|
)
|
|
for _, arc := range rankArchives {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
aids = append(aids, arc.Aid)
|
|
}
|
|
archivesArgLog("fillArcs", aids)
|
|
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
|
|
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
res = arcsReply.Arcs
|
|
return
|
|
}
|
|
|
|
func fmtRegionArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.RegionArchive) {
|
|
for _, arc := range aids {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
if len(res) > _rankRegionLen {
|
|
break
|
|
}
|
|
if _, ok := arcs[arc.Aid]; !ok {
|
|
continue
|
|
}
|
|
regionArchive := &model.RegionArchive{
|
|
Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
|
|
Typename: arcs[arc.Aid].TypeName,
|
|
Title: arcs[arc.Aid].Title,
|
|
Play: fmtArcView(arcs[arc.Aid]),
|
|
Review: arcs[arc.Aid].Stat.Reply,
|
|
VideoReview: arcs[arc.Aid].Stat.Danmaku,
|
|
Favorites: arcs[arc.Aid].Stat.Fav,
|
|
Mid: arcs[arc.Aid].Author.Mid,
|
|
Author: arcs[arc.Aid].Author.Name,
|
|
Description: arcs[arc.Aid].Desc,
|
|
Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
|
|
Pic: arcs[arc.Aid].Pic,
|
|
Coins: arcs[arc.Aid].Stat.Coin,
|
|
Duration: fmtDuration(arcs[arc.Aid].Duration),
|
|
Pts: arc.Score,
|
|
Rights: arcs[arc.Aid].Rights,
|
|
}
|
|
res = append(res, regionArchive)
|
|
}
|
|
return
|
|
}
|
|
|
|
func fmtIndexArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.IndexArchive) {
|
|
var (
|
|
typeName string
|
|
ok bool
|
|
)
|
|
for _, arc := range aids {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
if len(res) > _rankIndexLen {
|
|
break
|
|
}
|
|
if _, ok = arcs[arc.Aid]; !ok {
|
|
continue
|
|
}
|
|
if typeName, ok = model.RecSpecTypeName[arcs[arc.Aid].TypeID]; !ok {
|
|
typeName = arcs[arc.Aid].TypeName
|
|
}
|
|
indexArchive := &model.IndexArchive{
|
|
Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
|
|
Typename: typeName,
|
|
Title: arcs[arc.Aid].Title,
|
|
Play: fmtArcView(arcs[arc.Aid]),
|
|
Review: arcs[arc.Aid].Stat.Reply,
|
|
VideoReview: arcs[arc.Aid].Stat.Danmaku,
|
|
Favorites: arcs[arc.Aid].Stat.Fav,
|
|
Mid: arcs[arc.Aid].Author.Mid,
|
|
Author: arcs[arc.Aid].Author.Name,
|
|
Description: arcs[arc.Aid].Desc,
|
|
Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
|
|
Pic: arcs[arc.Aid].Pic,
|
|
Coins: arcs[arc.Aid].Stat.Coin,
|
|
Duration: fmtDuration(arcs[arc.Aid].Duration),
|
|
Rights: arcs[arc.Aid].Rights,
|
|
}
|
|
res = append(res, indexArchive)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *Service) fmtRankArcs(c context.Context, rankArchives []*model.RankNewArchive, arcLen int) (res []*model.RankArchive, err error) {
|
|
var (
|
|
aids []int64
|
|
arcsReply *arcmdl.ArcsReply
|
|
)
|
|
for _, arc := range rankArchives {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
aids = append(aids, arc.Aid)
|
|
if len(arc.Others) > 0 {
|
|
i := 0
|
|
for _, a := range arc.Others {
|
|
if a == nil {
|
|
continue
|
|
}
|
|
aids = append(aids, a.Aid)
|
|
i++
|
|
if i >= _rankOtherLimit {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
archivesArgLog("fmtRankArcs", aids)
|
|
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
|
|
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
for _, arc := range rankArchives {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
if len(res) > arcLen {
|
|
break
|
|
}
|
|
if _, ok := arcsReply.Arcs[arc.Aid]; !ok {
|
|
continue
|
|
}
|
|
var coin, danmu int32
|
|
if arc.RankStat == nil {
|
|
coin = arcsReply.Arcs[arc.Aid].Stat.Coin
|
|
danmu = arcsReply.Arcs[arc.Aid].Stat.Danmaku
|
|
} else {
|
|
coin = arc.RankStat.Coin
|
|
danmu = arc.RankStat.Danmu
|
|
arcsReply.Arcs[arc.Aid].Stat.View = arc.RankStat.Play
|
|
}
|
|
rankArchive := &model.RankArchive{
|
|
Aid: strconv.FormatInt(arcsReply.Arcs[arc.Aid].Aid, 10),
|
|
Author: arcsReply.Arcs[arc.Aid].Author.Name,
|
|
Coins: coin,
|
|
Duration: fmtDuration(arcsReply.Arcs[arc.Aid].Duration),
|
|
Mid: arcsReply.Arcs[arc.Aid].Author.Mid,
|
|
Pic: arcsReply.Arcs[arc.Aid].Pic,
|
|
Play: fmtArcView(arcsReply.Arcs[arc.Aid]),
|
|
Pts: arc.Score,
|
|
Title: arcsReply.Arcs[arc.Aid].Title,
|
|
VideoReview: danmu,
|
|
Rights: arcsReply.Arcs[arc.Aid].Rights,
|
|
}
|
|
if len(arc.Others) > 0 {
|
|
for _, a := range arc.Others {
|
|
if a == nil {
|
|
continue
|
|
}
|
|
if _, ok := arcsReply.Arcs[a.Aid]; !ok {
|
|
continue
|
|
}
|
|
archive := &model.Other{
|
|
Aid: a.Aid,
|
|
Play: fmtArcView(arcsReply.Arcs[a.Aid]),
|
|
VideoReview: arcsReply.Arcs[a.Aid].Stat.Danmaku,
|
|
Coins: arcsReply.Arcs[a.Aid].Stat.Coin,
|
|
Pts: a.Score,
|
|
Title: arcsReply.Arcs[a.Aid].Title,
|
|
Pic: arcsReply.Arcs[a.Aid].Pic,
|
|
Duration: fmtDuration(arcsReply.Arcs[a.Aid].Duration),
|
|
Rights: arcsReply.Arcs[a.Aid].Rights,
|
|
}
|
|
rankArchive.Others = append(rankArchive.Others, archive)
|
|
}
|
|
}
|
|
res = append(res, rankArchive)
|
|
}
|
|
return
|
|
}
|
|
|
|
// fmtRegionStats get real time region archive stat
|
|
func (s *Service) fmtRegionStats(c context.Context, res []*model.RegionArchive) {
|
|
var (
|
|
aids []int64
|
|
aid int64
|
|
err error
|
|
statsReply *arcmdl.StatsReply
|
|
)
|
|
for _, arc := range res {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
|
|
continue
|
|
}
|
|
aids = append(aids, aid)
|
|
}
|
|
if len(aids) == 0 {
|
|
return
|
|
}
|
|
if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
|
|
log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
arcStats := statsReply.Stats
|
|
for _, arc := range res {
|
|
if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
|
|
continue
|
|
}
|
|
if arcStat, ok := arcStats[aid]; ok {
|
|
arc.Play = arcStat.View
|
|
arc.VideoReview = arcStat.Danmaku
|
|
arc.Favorites = arcStat.Fav
|
|
arc.Coins = arcStat.Coin
|
|
}
|
|
}
|
|
}
|
|
|
|
func fmtTagArchives(tagArcs []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.TagArchive) {
|
|
for _, tagArc := range tagArcs {
|
|
if arc, ok := arcs[tagArc.Aid]; ok {
|
|
res = append(res, &model.TagArchive{
|
|
Title: arc.Title,
|
|
Author: arc.Author.Name,
|
|
Description: arc.Desc,
|
|
Pic: arc.Pic,
|
|
Play: strconv.FormatInt(int64(arc.Stat.View), 10),
|
|
Favorites: strconv.FormatInt(int64(arc.Stat.Fav), 10),
|
|
Mid: strconv.FormatInt(arc.Author.Mid, 10),
|
|
Review: strconv.FormatInt(int64(arc.Stat.Reply), 10),
|
|
CreatedAt: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
|
|
VideoReview: strconv.FormatInt(int64(arc.Stat.Danmaku), 10),
|
|
Coins: strconv.FormatInt(int64(arc.Stat.Coin), 10),
|
|
Duration: strconv.FormatInt(arc.Duration, 10),
|
|
Aid: arc.Aid,
|
|
Pts: tagArc.Score,
|
|
Rights: arc.Rights,
|
|
})
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// fmtTagStats get real time tag archive stat
|
|
func (s *Service) fmtTagStats(c context.Context, res []*model.TagArchive) {
|
|
var (
|
|
aids []int64
|
|
err error
|
|
statsReply *arcmdl.StatsReply
|
|
)
|
|
for _, arc := range res {
|
|
if arc == nil {
|
|
continue
|
|
}
|
|
aids = append(aids, arc.Aid)
|
|
}
|
|
if len(aids) == 0 {
|
|
return
|
|
}
|
|
if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
|
|
log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
arcStats := statsReply.Stats
|
|
for _, arc := range res {
|
|
if arcStat, ok := arcStats[arc.Aid]; ok {
|
|
arc.Play = strconv.FormatInt(int64(arcStat.View), 10)
|
|
arc.VideoReview = strconv.FormatInt(int64(arcStat.Danmaku), 10)
|
|
arc.Favorites = strconv.FormatInt(int64(arcStat.Fav), 10)
|
|
arc.Coins = strconv.FormatInt(int64(arcStat.Coin), 10)
|
|
}
|
|
}
|
|
}
|
|
|
|
func fmtDuration(duration int64) (du string) {
|
|
if duration == 0 {
|
|
du = "00:00"
|
|
} else {
|
|
var min, sec string
|
|
min = strconv.Itoa(int(duration / 60))
|
|
if int(duration%60) < 10 {
|
|
sec = "0" + strconv.Itoa(int(duration%60))
|
|
} else {
|
|
sec = strconv.Itoa(int(duration % 60))
|
|
}
|
|
du = min + ":" + sec
|
|
}
|
|
return
|
|
}
|
|
|
|
func fmtArcView(a *arcmdl.Arc) interface{} {
|
|
var view interface{} = a.Stat.View
|
|
if a.Access > 0 {
|
|
view = "--"
|
|
}
|
|
return view
|
|
}
|