You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
624 lines
15 KiB
624 lines
15 KiB
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 |
|
}
|
|
|