919 lines
23 KiB
Go
919 lines
23 KiB
Go
package show
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/rand"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go-common/app/interface/main/app-show/conf"
|
|
"go-common/app/interface/main/app-show/model"
|
|
"go-common/app/interface/main/app-show/model/show"
|
|
"go-common/app/service/main/archive/api"
|
|
"go-common/app/service/main/archive/model/archive"
|
|
resource "go-common/app/service/main/resource/model"
|
|
seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
|
|
"go-common/library/log"
|
|
"go-common/library/sync/errgroup"
|
|
)
|
|
|
|
const (
|
|
_cnt = 4
|
|
_initShowKey = "show_key_%d_%v"
|
|
_initCardKey = "card_key_%d"
|
|
_initlanguage = "hans"
|
|
_bangumiSeasonID = 1
|
|
_bangumiEpisodeID = 2
|
|
)
|
|
|
|
var (
|
|
_emptyShow = []*show.Show{}
|
|
_emptyItem = &show.Item{}
|
|
_emptyShowItems = []*show.Item{}
|
|
// ad
|
|
_recommend = map[int8]string{
|
|
model.PlatIPhone: "1508",
|
|
model.PlatAndroid: "1515",
|
|
model.PlatIPad: "1522",
|
|
model.PlatIPhoneI: "1529",
|
|
model.PlatAndroidG: "1543",
|
|
model.PlatAndroidI: "1777",
|
|
model.PlatIPadI: "1536",
|
|
}
|
|
_bangumiReids = map[int]struct{}{
|
|
167: struct{}{},
|
|
}
|
|
)
|
|
|
|
// Display display show data.
|
|
func (s *Service) Display(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
|
|
device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
|
|
res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, false, false, now)
|
|
return
|
|
}
|
|
|
|
// RegionDisplay display region show data.
|
|
func (s *Service) RegionDisplay(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
|
|
device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
|
|
res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, true, false, now)
|
|
return
|
|
}
|
|
|
|
func (s *Service) Index(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
|
|
device, language, adExtra string, isTmp bool, now time.Time) (res []*show.Show) {
|
|
res = s.showDisplay(c, mid, plat, build, buvid, channel, ip, ak, network, mobiApp, device, language, adExtra, isTmp, true, true, now)
|
|
if cards := s.showCardDisplay(plat, build); len(cards) > 0 {
|
|
cards = append(cards, res...)
|
|
res = cards
|
|
}
|
|
return
|
|
}
|
|
|
|
// Display display show data.
|
|
func (s *Service) showDisplay(c context.Context, mid int64, plat int8, build int, buvid, channel, ip, ak, network, mobiApp,
|
|
device, language, adExtra string, isTmp, isRegion, isIndex bool, now time.Time) (res []*show.Show) {
|
|
var (
|
|
bnr string
|
|
banners map[int][]*resource.Banner
|
|
showRec []*show.Item
|
|
showLive []*show.Item
|
|
isBangumi = false
|
|
isRegionBanner = false
|
|
ss []*show.Show
|
|
resIDStr = _bannersPlat[plat]
|
|
)
|
|
if language == "" {
|
|
language = _initlanguage
|
|
}
|
|
key := fmt.Sprintf(_initShowKey, plat, language)
|
|
if (plat == model.PlatIPhone && build > 6050) || (plat == model.PlatAndroid && build > 512007) {
|
|
ss = s.cacheBgEp[key]
|
|
} else if ((mobiApp == "iphone" && build > 5600) || (mobiApp == "android" && build > 507000)) && isIndex {
|
|
ss = s.cacheBg[key]
|
|
} else {
|
|
ss = s.cache[key]
|
|
}
|
|
if isTmp {
|
|
ss = s.tempCache[key]
|
|
}
|
|
if len(ss) == 0 {
|
|
res = _emptyShow
|
|
return
|
|
}
|
|
res = make([]*show.Show, 0, len(ss))
|
|
if (mobiApp == "iphone" && build > 4310) || (mobiApp == "android" && build > 502000) || isIndex {
|
|
isBangumi = true
|
|
}
|
|
if (mobiApp == "iphone" && build > 4350) || (mobiApp == "android" && build > 503000) {
|
|
isRegionBanner = true
|
|
}
|
|
g, ctx := errgroup.WithContext(c)
|
|
g.Go(func() error {
|
|
banners = s.resBanners(ctx, plat, build, mid, resIDStr, channel, ip, buvid, network, mobiApp, device, adExtra)
|
|
return nil
|
|
})
|
|
if !isRegion {
|
|
g.Go(func() error {
|
|
showRec = s.getRecommend(ctx, mid, build, plat, buvid, network, mobiApp, device, ip)
|
|
return nil
|
|
})
|
|
g.Go(func() error {
|
|
showLive = s.getLive(ctx, mid, ak, ip, 0, now)
|
|
return nil
|
|
})
|
|
}
|
|
if err := g.Wait(); err != nil {
|
|
log.Error("showDisplay errgroup.WithContext error(%v)", err)
|
|
}
|
|
for i, sw := range ss {
|
|
if mobiApp == "white" && 101220 >= build && sw.Param == "165" { // 165 ad region
|
|
continue
|
|
} else if sw.Param != "165" || ((mobiApp != "iphone" || device != "pad") || build <= 3590) {
|
|
if model.InvalidBuild(build, sw.Build, sw.Condition) {
|
|
continue
|
|
}
|
|
}
|
|
if sw.Type == "recommend" {
|
|
if isRegion {
|
|
continue
|
|
}
|
|
sw = s.dealRecommend(c, sw, plat, mid, build, buvid, network, mobiApp, device, ip, showRec)
|
|
bnr = "0"
|
|
} else if sw.Type == "live" {
|
|
if isRegion {
|
|
continue
|
|
}
|
|
sw = s.dealLive(c, sw, showLive)
|
|
bnr = "65537"
|
|
} else if sw.Type == "bangumi" {
|
|
if ok := s.auditRegion(mobiApp, plat, build, "13"); ok {
|
|
continue
|
|
}
|
|
if isRegion && isBangumi && !isRegionBanner {
|
|
bnr = "-1"
|
|
} else if isRegion && !isBangumi && !isRegionBanner {
|
|
continue
|
|
} else {
|
|
bnr = "13"
|
|
}
|
|
} else {
|
|
bnr = sw.Param
|
|
if isRegion {
|
|
if ok := s.auditRegion(mobiApp, plat, build, sw.Param); ok {
|
|
continue
|
|
}
|
|
if !isRegionBanner {
|
|
if sw.Param == "1" && !isBangumi {
|
|
bnr = "-1"
|
|
}
|
|
if sw.Type == "topic" && i > 0 && (ss[i-1].Type == "bangumi" || ss[i-1].Type == "1") {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sw.Banner = s.getBanners(c, plat, build, bnr, channel, ip, banners, isIndex)
|
|
res = append(res, sw)
|
|
}
|
|
return
|
|
}
|
|
|
|
// showCardDisplay
|
|
func (s *Service) showCardDisplay(plat int8, build int) (res []*show.Show) {
|
|
var ss []*show.Show
|
|
key := fmt.Sprintf(_initCardKey, plat)
|
|
ss = s.cardCache[key]
|
|
if len(ss) == 0 {
|
|
res = _emptyShow
|
|
return
|
|
}
|
|
res = []*show.Show{}
|
|
for _, sw := range ss {
|
|
if model.InvalidBuild(build, sw.Build, sw.Condition) {
|
|
continue
|
|
}
|
|
tmp := &show.Show{}
|
|
*tmp = *sw
|
|
tmp.FillBuildURI(plat, build)
|
|
res = append(res, tmp)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Change change display show data.
|
|
func (s *Service) Change(c context.Context, mid int64, build int, plat int8, rand int, buvid, ip, network, mobiApp, device string) (sis []*show.Item) {
|
|
cnt := s.itemNum(plat)
|
|
// first get recommend data.
|
|
tmp := s.userRecommend(c, mid, build, plat, buvid, network, mobiApp, device, ip, cnt)
|
|
if len(tmp) == cnt {
|
|
sis = append(sis, tmp...)
|
|
}
|
|
if len(sis) < cnt {
|
|
start := cnt * rand
|
|
end := start + cnt
|
|
rcLen := len(s.rcmmndCache)
|
|
if rcLen < end {
|
|
rand = 0
|
|
start = cnt * rand
|
|
end = start + cnt
|
|
}
|
|
if rcLen > end {
|
|
sis = s.rcmmndCache[start:end]
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RegionChange change show region data.
|
|
func (s *Service) RegionChange(c context.Context, rid, rand int, plat int8, build int, mobiApp string) (sis []*show.Item) {
|
|
if rand < 0 {
|
|
rand = 0
|
|
}
|
|
var (
|
|
cnt = 4
|
|
pn = rand + 1
|
|
isOsea = model.IsOverseas(plat)
|
|
bangumiType = 0
|
|
tmp []*show.Item
|
|
)
|
|
if (mobiApp == "iphone" && build > 5600) || (mobiApp == "android" && build > 507000) {
|
|
if _, isBangumi := _bangumiReids[rid]; isBangumi {
|
|
if (plat == model.PlatIPhone && build > 6050) || (plat == model.PlatAndroid && build > 512007) {
|
|
bangumiType = _bangumiEpisodeID
|
|
} else {
|
|
bangumiType = _bangumiSeasonID
|
|
}
|
|
}
|
|
}
|
|
if model.IsIPad(plat) {
|
|
cnt = 8
|
|
}
|
|
as, aids, err := s.dyn.RegionDynamic(c, rid, pn, cnt)
|
|
if err != nil {
|
|
log.Error("s.rcmmnd.RegionDynamic(%d, %d, %d) error(%v)", rid, pn, cnt, err)
|
|
sis = []*show.Item{}
|
|
return
|
|
}
|
|
if bangumiType != 0 {
|
|
tmp = s.fromArchivesBangumiOsea(c, as, aids, isOsea, bangumiType)
|
|
} else {
|
|
tmp = s.fromArchivesOsea(as, isOsea)
|
|
}
|
|
sis = append(sis, tmp...)
|
|
return
|
|
}
|
|
|
|
// BangumiChange change show bangumi data.
|
|
func (s *Service) BangumiChange(c context.Context, rand int, plat int8) (sis []*show.Item) {
|
|
if rand < 0 {
|
|
rand = 0
|
|
}
|
|
rand = rand + 1
|
|
var (
|
|
cnt = 4
|
|
)
|
|
if model.IsIPad(plat) {
|
|
cnt = 8
|
|
}
|
|
start := cnt * rand
|
|
end := start + cnt
|
|
if bgms, ok := s.bgmCache[plat]; ok {
|
|
bcLen := len(bgms)
|
|
if bcLen < end {
|
|
rand = 0
|
|
start = cnt * rand
|
|
end = start + cnt
|
|
}
|
|
if bcLen > end {
|
|
sis = bgms[start:end]
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Dislike dislike show data
|
|
func (s *Service) Dislike(c context.Context, mid int64, plat int8, id int64, buvid, mobiApp, device, gt, ip string) (si *show.Item) {
|
|
var (
|
|
cnt = 1
|
|
changeAid string
|
|
port string
|
|
)
|
|
// first get recommend data.
|
|
tmp := s.userRecommend(c, mid, 0, plat, buvid, "", mobiApp, device, ip, cnt)
|
|
if len(tmp) > 0 {
|
|
si = tmp[0]
|
|
port = "userRecommend"
|
|
} else {
|
|
si = s.rcmmndCache[0]
|
|
port = "loadRcmmndCache"
|
|
}
|
|
if si != nil {
|
|
changeAid = si.Param
|
|
}
|
|
if err := s.dbus.Pub(c, buvid, gt, id, mid); err != nil {
|
|
log.Error("s.dbus.Pub(%s,%s,%d,%d) error(%v)", buvid, gt, id, mid, err)
|
|
log.Error("dbus_Pub_dislike error mid:%v , dislike_aid:%v , change_aid:%v , interface_name:%v", mid, id, changeAid, port)
|
|
return
|
|
}
|
|
log.Info("dbus_Pub_dislike success mid:%v , dislike_aid:%v , change_aid:%v , interface_name:%v", mid, id, changeAid, port)
|
|
return
|
|
}
|
|
|
|
// Widget
|
|
func (s *Service) Widget(c context.Context, plat int8) (res []*show.Item) {
|
|
var (
|
|
isOsea = model.IsOverseas(plat) //is overseas
|
|
resCache []*show.Item
|
|
randID int
|
|
)
|
|
if isOsea {
|
|
resCache = s.rcmmndOseaCache
|
|
} else {
|
|
resCache = s.rcmmndCache
|
|
}
|
|
resCacheLen := len(resCache)
|
|
if resCacheLen >= 3 {
|
|
for {
|
|
if len(res) >= 3 || len(resCache) == 0 {
|
|
log.Info("Widget len 3")
|
|
break
|
|
}
|
|
if randInt := rand.Intn(resCacheLen); randInt != randID && resCache[randInt] != nil {
|
|
randID = randInt
|
|
res = append(res, resCache[randInt])
|
|
}
|
|
}
|
|
} else if resCacheLen > 0 {
|
|
log.Info("Widget resCache")
|
|
res = resCache
|
|
} else {
|
|
log.Info("Widget is null")
|
|
res = _emptyShowItems
|
|
}
|
|
return
|
|
}
|
|
|
|
// LiveChange live change.
|
|
func (s *Service) LiveChange(c context.Context, mid int64, ak, ip string, rand int, now time.Time) (sis []*show.Item) {
|
|
return s.getLive(c, mid, ak, ip, rand, now)
|
|
}
|
|
|
|
// dealRecommend deal recommend.
|
|
func (s *Service) dealRecommend(c context.Context, sw *show.Show, plat int8, mid int64, build int, buvid, network, mobiApp, device, ipaddr string, showRec []*show.Item) (rs *show.Show) {
|
|
cnt := s.itemNum(plat)
|
|
sis := make([]*show.Item, 0, cnt)
|
|
// first get recommend data.
|
|
if len(showRec) == cnt {
|
|
sis = append(sis, showRec...)
|
|
}
|
|
// if recommend data not enough, get from @hetongzi.
|
|
if len(sis) < cnt {
|
|
rcLen := len(s.rcmmndCache)
|
|
if rcLen < cnt {
|
|
sis = s.rcmmndCache[0:rcLen]
|
|
} else {
|
|
sis = s.rcmmndCache[0:cnt]
|
|
}
|
|
if rcLen > 0 {
|
|
sis = s.adVideo(c, mid, build, plat, buvid, network, mobiApp, device, ipaddr, sis)
|
|
}
|
|
}
|
|
if len(sis) == 0 {
|
|
sis = []*show.Item{}
|
|
}
|
|
rs = &show.Show{
|
|
Head: sw.Head,
|
|
Body: sis,
|
|
}
|
|
return
|
|
}
|
|
|
|
// getRecommend user recommend data
|
|
func (s *Service) getRecommend(c context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string) (sis []*show.Item) {
|
|
cnt := s.itemNum(plat)
|
|
// first get recommend data.
|
|
sis = s.userRecommend(c, mid, build, plat, buvid, network, mobiApp, device, ipaddr, cnt)
|
|
return
|
|
}
|
|
|
|
// userRecommend user recommend data.
|
|
func (s *Service) userRecommend(ctx context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string, cnt int) (sis []*show.Item) {
|
|
// get redis seed whether or not hit
|
|
if !s.rcmmndOn {
|
|
return
|
|
}
|
|
var (
|
|
key = buvid
|
|
i int
|
|
aids []int64
|
|
rcs []*rcmmndCfg
|
|
err error
|
|
)
|
|
if mid > 0 {
|
|
key = strconv.FormatInt(mid, 10)
|
|
}
|
|
if key == "" {
|
|
return
|
|
}
|
|
Retry:
|
|
for i = 0; i < 2; i++ {
|
|
if aids, err = s.dao.PopRcmmndCache(ctx, key, cnt); err != nil {
|
|
log.Error("s.dao.PopRcmmndCache(%d) error(%v)", key, err)
|
|
return
|
|
}
|
|
if len(aids) < cnt {
|
|
break
|
|
}
|
|
for _, aid := range aids {
|
|
if _, ok := s.blackCache[aid]; ok {
|
|
continue Retry
|
|
}
|
|
}
|
|
var isOsea = model.IsOverseas(plat)
|
|
if sis = s.fromAidsOsea(ctx, aids, isOsea); len(sis) < cnt {
|
|
log.Warn("recommend aids(%v) get from archive have not normal(%v)", aids, sis)
|
|
continue Retry
|
|
}
|
|
return
|
|
}
|
|
// if i==2, mean retry two counts, else if i<2, means break and recommend not enough.
|
|
if i == 2 {
|
|
return
|
|
}
|
|
if host := s.rcmmndHost(mid); host != "" {
|
|
rcs, aids = s.apiRecommend(ctx, plat, key, host, mid)
|
|
}
|
|
var (
|
|
clen = len(rcs)
|
|
caids = make([]int64, 0, cnt)
|
|
fill = cnt - clen
|
|
)
|
|
if clen+len(aids) < cnt {
|
|
return
|
|
}
|
|
if cnt < clen {
|
|
fill = 0
|
|
}
|
|
for _, rc := range rcs {
|
|
if rc.Goto == "" || rc.Goto == model.GotoAv {
|
|
caids = append(caids, rc.Aid)
|
|
if len(caids) == cnt {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if fill > 0 {
|
|
caids = append(caids, aids[:fill]...)
|
|
}
|
|
if aids = aids[fill:]; len(aids) >= cnt {
|
|
select {
|
|
case s.rcmmndCh <- recommend{key: key, aids: aids[fill:]}:
|
|
default:
|
|
log.Warn("recommendProc chan full")
|
|
}
|
|
}
|
|
var isOsea = model.IsOverseas(plat) //is overseas
|
|
if sis = s.fromAidsOsea(ctx, caids, isOsea); len(sis) < clen { // NOTE: if cnt=1 means dislike change one
|
|
for {
|
|
var (
|
|
over = cnt - len(sis)
|
|
start = 0
|
|
)
|
|
if over == 0 || start+over > len(aids) {
|
|
break
|
|
}
|
|
if tmp := s.fromAidsOsea(ctx, aids[start:over], isOsea); len(tmp) > 0 {
|
|
sis = append(sis, tmp...)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
for i, rc := range rcs {
|
|
if rc.Goto != "" && rc.Goto != model.GotoAv {
|
|
sis[i].Param = strconv.FormatInt(rc.Aid, 10)
|
|
sis[i].Goto = rc.Goto
|
|
sis[i].URI = model.FillURI(rc.Goto, sis[i].Param, nil)
|
|
}
|
|
if rc.Title != "" {
|
|
sis[i].Title = rc.Title
|
|
}
|
|
if rc.Cover != "" {
|
|
sis[i].Cover = rc.Cover
|
|
}
|
|
}
|
|
sis = s.adVideo(ctx, mid, build, plat, buvid, network, mobiApp, device, ipaddr, sis)
|
|
return
|
|
}
|
|
|
|
// rcmmndHost get recommend host
|
|
func (s *Service) rcmmndHost(mid int64) (host string) {
|
|
// if mid=0, let host is 1: base recommend
|
|
yu := mid % 20
|
|
g := s.rcmmndGroup[yu]
|
|
if hosts, ok := s.rcmmndHosts[g]; ok {
|
|
if len(hosts) == 1 {
|
|
host = hosts[0]
|
|
} else {
|
|
host = hosts[rand.Intn(len(hosts))]
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// apiRecommend get recommend fron big data.
|
|
func (s *Service) apiRecommend(ctx context.Context, plat int8, key, host string, mid int64) (rcs []*rcmmndCfg, aids []int64) {
|
|
var (
|
|
uri string
|
|
recURL = conf.Conf.Host.Data + "/mobile/home/%s"
|
|
)
|
|
uri = fmt.Sprintf(recURL, key)
|
|
params := url.Values{}
|
|
params.Set("plat", strconv.Itoa(int(plat)))
|
|
params.Set("v2", "1")
|
|
var res struct {
|
|
Code int `json:"code"`
|
|
Data []int64 `json:"data"`
|
|
Configs []*rcmmndCfg `json:"config"`
|
|
}
|
|
if err := s.client.Post(ctx, uri, "", params, &res); err != nil {
|
|
log.Error("recommend url(%s) error(%v)", uri+"?"+params.Encode(), err)
|
|
return
|
|
}
|
|
if res.Code != 0 {
|
|
log.Error("url(%s) res code(%d) or res.result(%v,%v)", uri, res.Code, res.Data, res.Configs)
|
|
return
|
|
}
|
|
aids = res.Data
|
|
rcs = res.Configs
|
|
return
|
|
}
|
|
|
|
// itemNum get item number by plat.
|
|
func (s *Service) itemNum(plat int8) int {
|
|
// cnt is items number
|
|
cnt := 6
|
|
if plat == model.PlatAndroid || plat == model.PlatAndroidI || plat == model.PlatAndroidG {
|
|
cnt = 4
|
|
} else if plat == model.PlatIPad || plat == model.PlatIPadI {
|
|
cnt = 8
|
|
} else if plat == model.PlatAndroidTV {
|
|
cnt = 16
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
// dealLive dela live data
|
|
func (s *Service) dealLive(c context.Context, sw *show.Show, sis []*show.Item) (rs *show.Show) {
|
|
rs = &show.Show{
|
|
Head: sw.Head,
|
|
Body: sis,
|
|
Ext: sw.Ext,
|
|
}
|
|
return
|
|
}
|
|
|
|
// getLive get lives: feed, moe, hot.
|
|
func (s *Service) getLive(c context.Context, mid int64, ak, ip string, rand int, now time.Time) (sis []*show.Item) {
|
|
const (
|
|
_halfCnt = 2
|
|
)
|
|
sis = make([]*show.Item, _cnt) // _cnt=4 [0,1,2,3]: 0 1 feed and hot, 2 3 moe and hot
|
|
feed, err := s.lv.Feed(c, mid, ak, ip, now)
|
|
if err != nil {
|
|
log.Error("s.live.Feed(%d) error(%d)", mid, err)
|
|
}
|
|
var have int
|
|
// get two feed
|
|
if feed != nil {
|
|
for i := 0; i < _halfCnt && i < len(feed.Lives); i++ {
|
|
si := &show.Item{}
|
|
si.FromLive(feed.Lives[i])
|
|
sis[i] = si
|
|
have++
|
|
}
|
|
}
|
|
// get two moe
|
|
fdCnt := have
|
|
start := _halfCnt * rand
|
|
if len(s.liveMoeCache) < start+_halfCnt {
|
|
start = 0
|
|
}
|
|
index := _halfCnt
|
|
MOENEXT:
|
|
for _, l := range s.liveMoeCache[start:] {
|
|
for i := 0; i < fdCnt; i++ {
|
|
if sis[i].Param == l.Param {
|
|
continue MOENEXT
|
|
}
|
|
}
|
|
sis[index] = l
|
|
index++
|
|
have++
|
|
if index >= _cnt {
|
|
break
|
|
}
|
|
}
|
|
// if feed and moe not enough, get hot
|
|
yu := _cnt - have
|
|
if yu > 0 {
|
|
start := yu * rand
|
|
if len(s.liveHotCache) < start+yu {
|
|
start = 0
|
|
}
|
|
var nilI int
|
|
HOTNEXT:
|
|
for _, l := range s.liveHotCache[start:] {
|
|
nilI = -1
|
|
for i := len(sis) - 1; i >= 0; i-- {
|
|
if sis[i] == nil {
|
|
nilI = i
|
|
} else if sis[i].Param == l.Param {
|
|
continue HOTNEXT
|
|
}
|
|
}
|
|
if nilI != -1 {
|
|
sis[nilI] = l
|
|
have++
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if have < _cnt {
|
|
for k, v := range sis {
|
|
if v == nil {
|
|
sis[k] = _emptyItem
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromArchives return region show items from archive archives.
|
|
func (s *Service) fromArchivesPB(as []*api.Arc) (sis, sisOsea []*show.Item) {
|
|
var asLen = len(as)
|
|
if asLen == 0 {
|
|
sis = []*show.Item{}
|
|
return
|
|
}
|
|
sis = make([]*show.Item, 0, asLen)
|
|
for _, a := range as {
|
|
i := &show.Item{}
|
|
i.FromArchivePB(a)
|
|
if a.AttrVal(archive.AttrBitOverseaLock) == 0 {
|
|
sisOsea = append(sisOsea, i)
|
|
}
|
|
sis = append(sis, i)
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromArchivesBangumi aid to sid
|
|
func (s *Service) fromArchivesBangumi(c context.Context, as []*api.Arc, aids []int64, sids map[int32]*seasongrpc.CardInfoProto, bangumiType int) (sis, sisOsea []*show.Item) {
|
|
var (
|
|
asLen = len(as)
|
|
err error
|
|
// bangumi
|
|
)
|
|
if asLen == 0 {
|
|
sis = []*show.Item{}
|
|
return
|
|
}
|
|
if sids == nil {
|
|
if sids, err = s.fromSeasonID(c, aids); err != nil {
|
|
log.Error("s.fromSeasonID error(%v)", err)
|
|
return
|
|
}
|
|
}
|
|
sis = make([]*show.Item, 0, asLen)
|
|
for _, a := range as {
|
|
i := &show.Item{}
|
|
if sid, ok := sids[int32(a.Aid)]; ok && sid.SeasonId != 0 {
|
|
i.FromArchivePBBangumi(a, sid, bangumiType)
|
|
} else {
|
|
i.FromArchivePB(a)
|
|
}
|
|
sis = append(sis, i)
|
|
if a.AttrVal(archive.AttrBitOverseaLock) == 0 {
|
|
sisOsea = append(sisOsea, i)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromArchivesOsea isOverseas
|
|
func (s *Service) fromArchivesOsea(as []*api.Arc, isOsea bool) (sis []*show.Item) {
|
|
tmp, tmpOsea := s.fromArchivesPB(as)
|
|
if isOsea {
|
|
sis = tmpOsea
|
|
} else {
|
|
sis = tmp
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromArchivesOsea isOverseas
|
|
func (s *Service) fromArchivesBangumiOsea(c context.Context, as []*api.Arc, aids []int64, isOsea bool, bangumiType int) (sis []*show.Item) {
|
|
tmp, tmpOsea := s.fromArchivesBangumi(c, as, aids, nil, bangumiType)
|
|
if isOsea {
|
|
sis = tmpOsea
|
|
} else {
|
|
sis = tmp
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromAids get Aids.
|
|
func (s *Service) fromAids(ctx context.Context, aids []int64) (sis, sisOsea []*show.Item) {
|
|
as, err := s.arc.ArchivesPB(ctx, aids)
|
|
if err != nil {
|
|
log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
if len(as) == 0 {
|
|
log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
|
|
return
|
|
}
|
|
sis = make([]*show.Item, 0, len(aids))
|
|
for _, aid := range aids {
|
|
var isOverseas int32
|
|
si := &show.Item{}
|
|
si.Goto = model.GotoAv
|
|
si.Param = strconv.FormatInt(aid, 10)
|
|
si.URI = model.FillURI(si.Goto, si.Param, nil)
|
|
if v, ok := as[aid]; ok {
|
|
isOverseas = v.AttrVal(archive.AttrBitOverseaLock)
|
|
si.Danmaku = int(v.Stat.Danmaku)
|
|
si.Play = int(v.Stat.View)
|
|
si.Title = v.Title
|
|
si.Duration = v.Duration
|
|
si.Rname = v.TypeName
|
|
si.Name = v.Author.Name
|
|
si.Like = int(v.Stat.Like)
|
|
si.Cover = model.CoverURL(v.Pic)
|
|
}
|
|
if isOverseas == 0 {
|
|
sisOsea = append(sisOsea, si)
|
|
}
|
|
sis = append(sis, si)
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromCardAids get Aids.
|
|
func (s *Service) fromCardAids(ctx context.Context, aids []int64) (sis map[int64]*show.Item) {
|
|
as, err := s.arc.ArchivesPB(ctx, aids)
|
|
if err != nil {
|
|
log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
if len(as) == 0 {
|
|
log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
|
|
return
|
|
}
|
|
sis = map[int64]*show.Item{}
|
|
for _, aid := range aids {
|
|
si := &show.Item{}
|
|
si.Goto = model.GotoAv
|
|
si.Param = strconv.FormatInt(aid, 10)
|
|
si.URI = model.FillURI(si.Goto, si.Param, nil)
|
|
if v, ok := as[aid]; ok {
|
|
if !v.IsNormal() {
|
|
continue
|
|
}
|
|
si.Danmaku = int(v.Stat.Danmaku)
|
|
si.Play = int(v.Stat.View)
|
|
si.Title = v.Title
|
|
si.Duration = v.Duration
|
|
if region, ok := s.reRegionCache[int(v.TypeID)]; ok {
|
|
si.Desc = region.Name
|
|
si.Reid = region.Rid
|
|
}
|
|
si.Rid = int(v.TypeID)
|
|
si.Rname = v.TypeName
|
|
si.Name = v.Author.Name
|
|
si.Like = int(v.Stat.Like)
|
|
si.Cover = model.CoverURL(v.Pic)
|
|
}
|
|
sis[aid] = si
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromRankAids
|
|
func (s *Service) fromRankAids(ctx context.Context, aids []int64, scores map[int64]int64, as map[int64]*api.Arc) (sis, sisOsea []*show.Item) {
|
|
var (
|
|
aid int64
|
|
arc *api.Arc
|
|
ok bool
|
|
)
|
|
for _, aid = range aids {
|
|
if arc, ok = as[aid]; ok {
|
|
i := &show.Item{}
|
|
if region, ok := s.reRegionCache[int(arc.TypeID)]; ok {
|
|
i.Desc = region.Name
|
|
}
|
|
i.FromArchiveRank(arc, scores)
|
|
if arc.AttrVal(archive.AttrBitOverseaLock) == 0 {
|
|
sisOsea = append(sisOsea, i)
|
|
}
|
|
sis = append(sis, i)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromAids get Aids.
|
|
func (s *Service) fromBgAids(ctx context.Context, aids []int64, sids map[int32]*seasongrpc.CardInfoProto, bangumiType int) (sis, sisOsea, sisbg, sisbgOsea, sisbgep, sisbgepOsea []*show.Item) {
|
|
var (
|
|
err error
|
|
)
|
|
as, err := s.arc.ArchivesPB(ctx, aids)
|
|
if err != nil {
|
|
log.Error("s.arc.ArchivesPB aids(%v) error(%v)", aids, err)
|
|
return
|
|
}
|
|
if len(as) == 0 {
|
|
log.Warn("s.arc.ArchivesPB(%v) length is 0", aids)
|
|
return
|
|
}
|
|
sis = make([]*show.Item, 0, len(aids))
|
|
if sids == nil {
|
|
if sids, err = s.fromSeasonID(ctx, aids); err != nil {
|
|
log.Error("s.fromSeasonID error(%v)", err)
|
|
return
|
|
}
|
|
}
|
|
for _, aid := range aids {
|
|
var isOverseas int32
|
|
si := &show.Item{}
|
|
sibg := &show.Item{}
|
|
sibgep := &show.Item{}
|
|
if v, ok := as[aid]; ok {
|
|
isOverseas = v.AttrVal(archive.AttrBitOverseaLock)
|
|
if sid, ok := sids[int32(aid)]; ok && sid.SeasonId != 0 {
|
|
sibg.FromArchivePBBangumi(v, sid, _bangumiSeasonID)
|
|
sibgep.FromArchivePBBangumi(v, sid, _bangumiEpisodeID)
|
|
} else {
|
|
sibg.FromArchivePB(v)
|
|
sibgep.FromArchivePB(v)
|
|
}
|
|
si.FromArchivePB(v)
|
|
if isOverseas == 0 {
|
|
sisOsea = append(sisOsea, si)
|
|
sisbgOsea = append(sisbgOsea, sibg)
|
|
sisbgepOsea = append(sisbgepOsea, sibg)
|
|
}
|
|
sis = append(sis, si)
|
|
sisbg = append(sisbg, sibg)
|
|
sisbgep = append(sisbgep, sibgep)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// fromSeasonID
|
|
func (s *Service) fromSeasonID(c context.Context, arcAids []int64) (seasonID map[int32]*seasongrpc.CardInfoProto, err error) {
|
|
if seasonID, err = s.bgm.CardsByAids(c, arcAids); err != nil {
|
|
log.Error("s.bgm.Seasonid CardsByAids %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// isOverseas
|
|
func (s *Service) fromAidsOsea(ctx context.Context, aids []int64, isOsea bool) (sis []*show.Item) {
|
|
tmp, tmpOsea := s.fromAids(ctx, aids)
|
|
if isOsea {
|
|
sis = tmpOsea
|
|
} else {
|
|
sis = tmp
|
|
}
|
|
return
|
|
}
|
|
|
|
// adVideo
|
|
func (s *Service) adVideo(ctx context.Context, mid int64, build int, plat int8, buvid, network, mobiApp, device, ipaddr string, sis []*show.Item) (res []*show.Item) {
|
|
var cpmsis map[int]*show.Item
|
|
if resID, ok := _recommend[plat]; ok {
|
|
cpmsis = s.cpmRecommend(ctx, mid, build, buvid, resID, network, mobiApp, device, ipaddr)
|
|
}
|
|
for rank, ad := range cpmsis {
|
|
if len(sis) >= rank {
|
|
if ad.IsAdReplace {
|
|
sis[rank-1] = ad
|
|
} else {
|
|
sis[rank-1].IsAdLoc = true
|
|
sis[rank-1].IsAd = ad.IsAd
|
|
sis[rank-1].CmMark = ad.CmMark
|
|
sis[rank-1].SrcId = ad.SrcId
|
|
sis[rank-1].RequestId = ad.RequestId
|
|
sis[rank-1].ClientIp = ad.ClientIp
|
|
}
|
|
}
|
|
}
|
|
res = sis
|
|
return
|
|
}
|