go-common/app/interface/openplatform/article/service/slide.go
2019-04-22 18:49:16 +08:00

625 lines
15 KiB
Go

package service
import (
"context"
"strconv"
"strings"
"go-common/app/interface/openplatform/article/model"
"go-common/library/log"
)
var (
_slideCount = 20
_left = 0
_right = 1
)
// var _slideRecommends = 2
// ViewList .
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) {
var (
cid int64
res *model.Article
err error
arts = &model.ArticleViewList{From: from, Buvid: buvid, Plat: plat, Build: build, Mid: mid}
)
if res, err = s.Article(c, aid); err != nil {
res = nil
return
}
if res == nil {
res = nil
return
}
if strings.Contains(from, "_") {
fs := strings.Split(from, "_")
if len(fs) < 2 {
return
}
cid, _ = strconv.ParseInt(fs[1], 10, 64)
switch fs[0] {
case "category":
//分区 天马
if cid == 0 {
arts.From = "recommend"
pre, next = s.listFromRecommends(c, aid, arts)
// arts.From = "skyhorse"
// pre, next = s.listFromSkyHorseEx(c, aid, cid, arts, int64(res.PublishTime), res.Author.Mid)
} else {
arts.From = "default"
pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
}
case "rank":
//排行榜
pre, next = s.listFromRank(c, aid, cid, arts, ip)
case "readlist":
//文集
pre, next = s.listFromReadList(c, aid, arts)
default:
//default
arts.From = "default"
pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
}
} else {
switch from {
// case "mainCard":
// //天马
// arts.From = "skyhorse"
// pre, next = s.listFromSkyHorseEx(c, aid, 0, arts, int64(res.PublishTime), res.Author.Mid)
case "favorite":
// TODO
pre, next = s.validFavsList(c, aid, arts, true)
case "records":
// TODO
// pre, next = 0, 0
// pre, next = s.historyCursor(c, aid, arts, true)
case "readlist":
//文集
pre, next = s.listFromReadList(c, aid, arts)
case "articleSlide":
//滑动
pre, next, arts = s.listFromCache(c, aid, arts.Buvid)
default:
//作者其他的文章
arts.From = "default"
pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
}
}
s.dao.AddCacheListArtsId(c, buvid, arts)
return
}
// func (s *Service) listFromSkyHorseEx(c context.Context, aid int64, cid int64, arts *model.ArticleViewList, pt int64, authorMid int64) (pre int64, next int64) {
// pre, next = s.listFromSkyHorse(c, aid, cid, arts)
// if pre == 0 && next == 0 {
// arts.From = "default"
// pre, next = s.listByAuthor(c, aid, authorMid, pt, arts)
// }
// return
// }
func (s *Service) listFromCache(c context.Context, aid int64, buvid string) (pre int64, next int64, arts *model.ArticleViewList) {
var (
res *model.Article
err error
position = -1
)
if arts, err = s.dao.CacheListArtsId(c, buvid); err != nil {
log.Error("s.dao.CacheListArtsId, error(%+v)", err)
return
}
if arts == nil || arts.Aids == nil {
return
}
for i, id := range arts.Aids {
if id == aid {
position = i
break
}
}
if position == -1 {
return
}
switch arts.From {
case "recommend":
if position == 0 {
if len(arts.Aids) > 1 {
next = arts.Aids[1]
}
pre = s.newRecommend(c, arts, _left)
// pre = s.newSkyHorse(c, arts, _left)
arts.Position = position
return
}
if position == len(arts.Aids)-1 {
if len(arts.Aids) > 1 {
pre = arts.Aids[len(arts.Aids)-2]
}
next = s.newRecommend(c, arts, _right)
// next = s.newSkyHorse(c, arts, _right)
arts.Position = position
return
}
case "default":
if position == 0 || position == len(arts.Aids)-1 {
if res, err = s.Article(c, aid); err != nil || res == nil {
return
}
pre, next = s.listByAuthor(c, aid, res.Author.Mid, int64(res.PublishTime), arts)
arts.Position = position
return
}
next = arts.Aids[position-1]
pre = arts.Aids[position+1]
return
case "records":
return
// if position == len(arts.Aids)-1 {
// if position > 0 {
// pre = arts.Aids[position-1]
// }
// _, next = s.historyCursor(c, aid, arts, false)
// return
// }
case "favorite":
if position == len(arts.Aids)-1 {
if position > 0 {
pre = arts.Aids[position-1]
}
_, next = s.validFavsList(c, aid, arts, false)
return
}
}
if position > 0 {
pre = arts.Aids[position-1]
}
if position < len(arts.Aids)-1 {
next = arts.Aids[position+1]
}
return
}
func (s *Service) listFromReadList(c context.Context, aid int64, arts *model.ArticleViewList) (pre int64, next int64) {
var (
listID int64
list *model.List
artsMetas []*model.ListArtMeta
ok bool
)
lists, err := s.dao.ArtsList(c, []int64{aid})
if err != nil {
log.Error("s.dao.ArtsList, error(%+v)", err)
return
}
if list, ok = lists[aid]; !ok {
return
}
listID = list.ID
if artsMetas, err = s.dao.ListArts(c, listID); err != nil {
log.Error("s.dao.ListArts, error(%+v)", err)
return
}
if artsMetas == nil {
return
}
for i, art := range artsMetas {
if art.ID == aid {
arts.Position = i
}
arts.Aids = append(arts.Aids, art.ID)
}
if arts.Position > 0 {
pre = artsMetas[arts.Position-1].ID
}
if arts.Position < len(artsMetas)-1 {
next = artsMetas[arts.Position+1].ID
}
return
}
func (s *Service) listByAuthor(c context.Context, aid int64, mid int64, pt int64, arts *model.ArticleViewList) (pre int64, next int64) {
var (
beforeAids, afterAids, tmpAids []int64
aidTimes [][2]int64
exist bool
j int
err error
metas map[int64]*model.Meta
aids []int64
addCache = true
position = -1
)
if exist, err = s.dao.ExpireUpperCache(c, mid); err != nil {
addCache = false
err = nil
} else if exist {
if beforeAids, afterAids, err = s.dao.MoreArtsCaches(c, mid, int64(pt), _slideCount); err != nil {
addCache = false
exist = false
}
if len(beforeAids)+len(afterAids) == 0 {
return
}
for i := len(beforeAids) - 1; i >= 0; i-- {
tmpAids = append(tmpAids, beforeAids[i])
}
tmpAids = append(tmpAids, aid)
tmpAids = append(tmpAids, afterAids...)
} else {
if aidTimes, err = s.dao.UpperPassed(c, mid); err != nil {
log.Error("s.dao.UpperPassed, error(%+v)", err)
return
}
if addCache {
cache.Save(func() {
s.dao.AddUpperCaches(context.TODO(), map[int64][][2]int64{mid: aidTimes})
})
}
for i := len(aidTimes) - 1; i >= 0; i-- {
aidTime := aidTimes[i]
tmpAids = append(tmpAids, aidTime[0])
}
}
if metas, err = s.ArticleMetas(c, tmpAids); err != nil {
log.Error("s.ArticleMetas, error(%+v)", err)
return
}
//过滤禁止显示的稿件
filterNoDistributeArtsMap(metas)
if len(metas) == 0 {
return
}
for _, id := range tmpAids {
if _, ok := metas[id]; !ok {
continue
}
if id == aid {
position = j
}
j++
aids = append(aids, id)
}
if position == -1 {
return
}
if position > 0 {
next = aids[position-1]
}
if position < len(aids)-1 {
pre = aids[position+1]
}
arts.Position = position
arts.Aids = aids
return
}
func (s *Service) listFromRank(c context.Context, aid int64, cid int64, arts *model.ArticleViewList, ip string) (pre int64, next int64) {
var (
exist bool
err error
aids []int64
rank model.RankResp
addCache = true
position = -1
)
s.dao.DelCacheListArtsId(c, arts.Buvid)
if !s.ranksMap[cid] {
return
}
if exist, err = s.dao.ExpireRankCache(c, cid); err != nil {
addCache = false
err = nil
}
if exist {
if rank, err = s.dao.RankCache(c, cid); err != nil {
exist = false
err = nil
addCache = false
}
} else {
if rank, err = s.dao.Rank(c, cid, ip); err != nil {
if rank, err = s.dao.RankCache(c, cid); err != nil {
log.Error("s.dao.RankCache, error(%+v)", err)
return
}
} else {
if addCache && len(rank.List) > 0 {
cache.Save(func() {
s.dao.AddRankCache(context.TODO(), cid, rank)
})
}
}
}
if len(rank.List) == 0 {
return
}
for i, a := range rank.List {
aids = append(aids, a.Aid)
if a.Aid == aid {
position = i
}
}
if position == -1 {
return
}
arts.Position = position
arts.Aids = aids
if position > 0 {
pre = aids[position-1]
}
if position < len(aids)-1 {
next = aids[position+1]
}
return
}
// func (s *Service) listFromSkyHorse(c context.Context, aid int64, cid int64, arts *model.ArticleViewList) (pre int64, next int64) {
// var (
// beforeAids, afterAids, tmpAids, aids []int64
// err error
// position = -1
// half = _slideRecommends / 2
// )
// if tmpAids, err = s.filterAidsFromSkyHorse(c, aid, arts, _slideRecommends); err != nil || len(tmpAids) == 0 {
// return
// }
// if len(tmpAids) < half {
// half = len(tmpAids) / 2
// }
// beforeAids = make([]int64, half)
// afterAids = make([]int64, len(tmpAids)-half)
// copy(beforeAids, tmpAids[:half])
// copy(afterAids, tmpAids[half:])
// position = half
// aids = append([]int64{}, beforeAids...)
// aids = append(aids, aid)
// aids = append(aids, afterAids...)
// arts.Position = position
// arts.Aids = aids
// if len(beforeAids) > 0 {
// pre = beforeAids[len(beforeAids)-1]
// }
// if len(afterAids) > 0 {
// next = afterAids[0]
// }
// return
// }
// func (s *Service) newSkyHorse(c context.Context, arts *model.ArticleViewList, side int) (aid int64) {
// var (
// aids []int64
// err error
// )
// if aids, err = s.filterAidsFromSkyHorse(c, arts.Aids[arts.Position], arts, _slideRecommends/2); err != nil || len(aids) == 0 {
// return
// }
// aids = uniqIDs(aids, arts.Aids)
// if len(aids) == 0 {
// return
// }
// if side == _left {
// aid = aids[len(aids)-1]
// arts.Aids = append(aids, arts.Aids...)
// arts.Position += len(aids)
// } else {
// aid = aids[0]
// arts.Aids = append(arts.Aids, aids...)
// }
// return
// }
// func (s *Service) filterAidsFromSkyHorse(c context.Context, aid int64, arts *model.ArticleViewList, size int) (aids []int64, err error) {
// var (
// tmpIds []int64
// sky *model.SkyHorseResp
// metas map[int64]*model.Meta
// )
// if sky, err = s.dao.SkyHorse(c, arts.Mid, arts.Build, arts.Buvid, arts.Plat, size); err != nil {
// return
// }
// if len(sky.Data) == 0 {
// return
// }
// for _, item := range sky.Data {
// tmpIds = append(tmpIds, item.ID)
// }
// if metas, err = s.ArticleMetas(c, tmpIds); err != nil {
// log.Error("s.ArticleMetas, error(%+v)", err)
// return
// }
// //过滤禁止显示的稿件
// filterNoDistributeArtsMap(metas)
// filterNoRegionArts(metas)
// if len(metas) == 0 {
// return
// }
// for _, meta := range metas {
// if meta.ID == aid {
// continue
// }
// aids = append(aids, meta.ID)
// }
// return
// }
func (s *Service) validFavsList(c context.Context, aid int64, arts *model.ArticleViewList, ok bool) (pre int64, next int64) {
arts.Position++
var (
favs []*model.Favorite
err error
page = &model.Page{Total: arts.Position*_slideCount + 1}
)
for ok && page.Total > arts.Position*_slideCount {
if favs, page, err = s.Favs(c, arts.Mid, 0, arts.Position, _slideCount, ""); err != nil {
return
}
for _, fav := range favs {
if !fav.Valid {
continue
}
arts.Aids = append(arts.Aids, fav.ID)
}
for i, id := range arts.Aids {
if id != aid {
continue
}
if i > 0 {
pre = arts.Aids[i-1]
}
if i < len(arts.Aids)-1 {
next = arts.Aids[i+1]
ok = false
}
}
arts.Position++
}
if next > 0 {
return
}
ok = true
for ok && page.Total > arts.Position*_slideCount {
if favs, page, err = s.Favs(c, arts.Mid, 0, arts.Position, _slideCount, ""); err != nil {
return
}
for _, fav := range favs {
if !fav.Valid {
continue
}
if next == 0 {
next = fav.ID
}
ok = false
arts.Aids = append(arts.Aids, fav.ID)
}
arts.Position++
}
return
}
// func (s *Service) historyCursor(c context.Context, aid int64, arts *model.ArticleViewList, ok bool) (pre int64, next int64) {
// var (
// res []*history.Resource
// err error
// viewAt = int64(arts.Position)
// aids []int64
// )
// for ok {
// arg := &history.ArgCursor{Mid: arts.Mid, Businesses: []string{"article", "article-list"}, Ps: _slideCount, ViewAt: viewAt}
// if res, err = s.hisRPC.HistoryCursor(c, arg); err != nil || len(res) < 2 {
// return
// }
// for _, r := range res {
// viewAt = r.Unix
// id := r.Oid
// if r.TP == history.TypeCorpus {
// id = r.Cid
// }
// aids = append(aids, id)
// }
// for i, id := range aids {
// if id != aid {
// continue
// }
// ok = false
// if i > 0 {
// pre = aids[i-1]
// }
// if i < len(aids)-1 {
// next = aids[i+1]
// }
// }
// arts.Aids = append(arts.Aids, aids...)
// arts.Position = int(viewAt)
// }
// if next > 0 {
// return
// }
// arg := &history.ArgCursor{Mid: arts.Mid, Businesses: []string{"article", "article-list"}, Ps: _slideCount, ViewAt: viewAt}
// if res, err = s.hisRPC.HistoryCursor(c, arg); err != nil || len(res) == 0 {
// return
// }
// for _, r := range res {
// viewAt = r.Unix
// id := r.Oid
// if r.TP == history.TypeCorpus {
// id = r.Cid
// }
// if next == 0 {
// next = id
// }
// arts.Aids = append(arts.Aids, id)
// }
// arts.Position = int(viewAt)
// return
// }
func (s *Service) listFromRecommends(c context.Context, aid int64, arts *model.ArticleViewList) (pre int64, next int64) {
recommends := s.genRecommendArtFromPool(s.RecommendsMap[_recommendCategory], _slideCount)
tmpAids, _ := s.dealRecommends(recommends)
var aids []int64
for _, id := range tmpAids {
if id != aid {
aids = append(aids, id)
}
}
if len(aids) == 0 {
return
}
if len(aids) == 1 {
next = aids[0]
arts.Aids = append([]int64{aid}, aids[0])
return
}
half := len(aids) / 2
beforeAids := make([]int64, half)
afterAids := make([]int64, len(aids)-half)
copy(beforeAids, aids[:half])
copy(afterAids, aids[half:])
aids = append([]int64{}, beforeAids...)
aids = append(aids, aid)
aids = append(aids, afterAids...)
arts.Position = half
arts.Aids = aids
pre = arts.Aids[half-1]
next = arts.Aids[half+1]
return
}
func (s *Service) newRecommend(c context.Context, arts *model.ArticleViewList, side int) (res int64) {
var (
m = make(map[int64]bool)
nids []int64
)
recommends := s.genRecommendArtFromPool(s.RecommendsMap[_recommendCategory], _slideCount)
aids, _ := s.dealRecommends(recommends)
if len(aids) == 0 {
return
}
for _, aid := range arts.Aids {
m[aid] = true
}
for _, aid := range aids {
if !m[aid] {
nids = append(nids, aid)
}
}
if len(nids) == 0 {
return
}
if side == _left {
res = nids[len(nids)-1]
arts.Aids = append(nids, arts.Aids...)
}
if side == _right {
res = nids[0]
arts.Aids = append(arts.Aids, nids...)
}
return
}