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.
 
 
 

1004 lines
28 KiB

package feed
import (
"context"
"encoding/json"
"fmt"
"time"
cdm "go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/bplus"
"go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/ai"
"go-common/app/interface/main/app-card/model/card/audio"
"go-common/app/interface/main/app-card/model/card/bangumi"
"go-common/app/interface/main/app-card/model/card/banner"
"go-common/app/interface/main/app-card/model/card/cm"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-card/model/card/show"
"go-common/app/interface/main/app-feed/model"
"go-common/app/interface/main/app-feed/model/feed"
tag "go-common/app/interface/main/tag/model"
article "go-common/app/interface/openplatform/article/model"
account "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/model/archive"
locmdl "go-common/app/service/main/location/model"
relation "go-common/app/service/main/relation/model"
episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const _qn480 = 32
var (
_cardAdAvm = map[int]struct{}{
1: struct{}{},
}
_cardAdWebm = map[int]struct{}{
2: struct{}{},
7: struct{}{},
20: struct{}{},
}
_cardAdWebSm = map[int]struct{}{
3: struct{}{},
26: struct{}{},
}
_followMode = &feed.FollowMode{
Title: "当前为首页推荐 - 关注模式(内测版)",
Option: []*feed.Option{
{Title: "通用模式", Desc: "开启后,推荐你可能感兴趣的内容", Value: 0},
{Title: "关注模式(内测版)", Desc: "开启后,仅显示关注UP主更新的视频", Value: 1},
},
ToastMessage: "关注UP主的内容已经看完啦,请稍后再试",
}
)
func (s *Service) Index2(c context.Context, buvid string, mid int64, plat int8, param *feed.IndexParam, style int, now time.Time) (is []card.Handler, config *feed.Config, infoc *feed.Infoc, err error) {
var (
rs []*ai.Item
adm map[int]*cm.AdInfo
adAidm map[int64]struct{}
banners []*banner.Banner
version string
blackAidm map[int64]struct{}
adInfom map[int]*cm.AdInfo
follow *operate.Card
info *locmdl.Info
)
ip := metadata.String(c, metadata.RemoteIP)
config = s.indexConfig(c, plat, buvid, mid, param)
if config.FollowMode == nil {
param.RecsysMode = 0
}
noCache := param.RecsysMode == 1
followMode := config.FollowMode != nil
infoc = &feed.Infoc{}
infoc.AutoPlayInfoc = fmt.Sprintf("%d|%d", config.AutoplayCard, param.AutoPlayCard)
if info, err = s.loc.Info(c, ip); err != nil {
log.Warn("s.loc.Info(%v) error(%v)", ip, err)
err = nil
}
group := s.group(mid, buvid)
if !s.c.Feed.Index.Abnormal || followMode {
g, ctx := errgroup.WithContext(c)
g.Go(func() error {
rs, infoc.UserFeature, infoc.IsRcmd, infoc.NewUser, infoc.Code = s.indexRcmd2(ctx, plat, buvid, mid, param, group, info, style, infoc.AutoPlayInfoc, noCache, now)
return nil
})
g.Go(func() (err error) {
if banners, version, err = s.indexBanner2(ctx, plat, buvid, mid, param); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if param.RecsysMode == 0 {
g.Go(func() (err error) {
if adm, adAidm, err = s.indexAd2(ctx, plat, buvid, mid, param, info, style, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if blackAidm, err = s.BlackList(ctx, mid); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if follow, err = s.SearchFollow2(ctx, param.Platform, param.MobiApp, param.Device, buvid, param.Build, mid); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
if param.RecsysMode == 1 {
var tmp []*ai.Item
for _, r := range rs {
if r.Goto == model.GotoBanner {
continue
}
tmp = append(tmp, r)
}
if len(tmp) == 0 {
is = []card.Handler{}
return
}
}
rs, adInfom = s.mergeItem2(c, plat, mid, rs, adm, adAidm, banners, version, blackAidm, follow, followMode)
} else {
count := s.indexCount(plat)
rs = s.recommendCache(count)
log.Warn("feed index show disaster recovery data len(%d)", len(is))
}
if config.AutoplayCard == 1 && cdm.Columnm[param.Column] == cdm.ColumnSvrSingle {
param.Qn = _qn480
}
is, infoc.IsRcmd = s.dealItem2(c, mid, buvid, plat, rs, param, infoc.IsRcmd, noCache, followMode, follow, now)
s.dealAdLoc(is, param, adInfom, now)
return
}
func (s *Service) indexConfig(c context.Context, plat int8, buvid string, mid int64, param *feed.IndexParam) (config *feed.Config) {
config = &feed.Config{}
config.Column = cdm.Columnm[param.Column]
// if mid > 0 && mid%20 == 19 {
// config.FeedCleanAbtest = 1
// } else {
// config.FeedCleanAbtest = 0
// }
config.FeedCleanAbtest = 0
if !model.IsIPad(plat) {
if ab, ok := s.abtestCache[_feedgroups]; ok {
if ab.AbTestIn(buvid + _feedgroups) {
switch param.AutoPlayCard {
case 0, 1, 2, 3:
config.AutoplayCard = 1
default:
config.AutoplayCard = 2
}
} else {
config.AutoplayCard = 2
}
} else {
switch param.AutoPlayCard {
case 1, 3:
config.AutoplayCard = 1
default:
config.AutoplayCard = 2
}
}
} else {
// ipad 不允许自动播放
config.AutoplayCard = 2
}
if mid < 1 {
return
}
if _, ok := s.autoplayMidsCache[mid]; ok && param.AutoPlayCard != 4 {
config.AutoplayCard = 1
}
if _, ok := s.followModeList[mid]; ok {
tmpConfig := &feed.FollowMode{}
if s.c.Feed.Index.FollowMode == nil {
*tmpConfig = *_followMode
} else {
*tmpConfig = *s.c.Feed.Index.FollowMode
}
if param.RecsysMode != 1 {
tmpConfig.ToastMessage = ""
}
config.FollowMode = tmpConfig
}
return
}
func (s *Service) indexRcmd2(c context.Context, plat int8, buvid string, mid int64, param *feed.IndexParam, group int, zone *locmdl.Info, style int, autoPlay string, noCache bool, now time.Time) (is []*ai.Item, userFeature json.RawMessage, isRcmd, newUser bool, code int) {
count := s.indexCount(plat)
if buvid != "" || mid > 0 {
var (
err error
zoneID int64
)
if zone != nil {
zoneID = zone.ZoneID
}
if is, userFeature, code, newUser, err = s.rcmd.Recommend(c, plat, buvid, mid, param.Build, param.LoginEvent, param.ParentMode, param.RecsysMode, zoneID, group, param.Interest, param.Network, style, param.Column, param.Flush, autoPlay, now); err != nil {
log.Error("%+v", err)
}
if noCache {
isRcmd = true
return
}
if len(is) != 0 {
isRcmd = true
}
var fromCache bool
if len(is) == 0 && mid > 0 && !ecode.ServiceUnavailable.Equal(err) {
if is, err = s.indexCache(c, mid, count); err != nil {
log.Error("%+v", err)
}
if len(is) != 0 {
s.pHit.Incr("index_cache")
} else {
s.pMiss.Incr("index_cache")
}
fromCache = true
}
if len(is) == 0 || (fromCache && len(is) < count) {
is = s.recommendCache(count)
}
} else {
is = s.recommendCache(count)
}
return
}
func (s *Service) indexAd2(c context.Context, plat int8, buvid string, mid int64, param *feed.IndexParam, zone *locmdl.Info, style int, now time.Time) (adm map[int]*cm.AdInfo, adAidm map[int64]struct{}, err error) {
var advert *cm.Ad
resource := s.adResource(plat, param.Build)
if resource == 0 {
return
}
// 兼容老的style逻辑,3为新单列,上报给商业产品的参数定义为:1 单列 2双列
if style == 3 {
style = 1
}
var country, province, city string
if zone != nil {
country = zone.Country
province = zone.Province
city = zone.City
}
if advert, err = s.ad.Ad(c, mid, param.Build, buvid, []int64{resource}, country, province, city, param.Network, param.MobiApp, param.Device, param.OpenEvent, param.AdExtra, style, now); err != nil {
return
}
if advert == nil || len(advert.AdsInfo) == 0 {
return
}
if adsInfo, ok := advert.AdsInfo[resource]; ok {
adm = make(map[int]*cm.AdInfo, len(adsInfo))
adAidm = make(map[int64]struct{}, len(adsInfo))
for source, info := range adsInfo {
if info == nil {
continue
}
var adInfo *cm.AdInfo
if info.AdInfo != nil {
adInfo = info.AdInfo
adInfo.RequestID = advert.RequestID
adInfo.Resource = resource
adInfo.Source = source
adInfo.IsAd = info.IsAd
adInfo.IsAdLoc = true
adInfo.CmMark = info.CmMark
adInfo.Index = info.Index
adInfo.CardIndex = info.CardIndex
adInfo.ClientIP = advert.ClientIP
if adInfo.CreativeID != 0 && adInfo.CardType == _cardAdAv {
adAidm[adInfo.CreativeContent.VideoID] = struct{}{}
}
} else {
adInfo = &cm.AdInfo{RequestID: advert.RequestID, Resource: resource, Source: source, IsAdLoc: true, IsAd: info.IsAd, CmMark: info.CmMark, Index: info.Index, CardIndex: info.CardIndex, ClientIP: advert.ClientIP}
}
adm[adInfo.CardIndex-1] = adInfo
}
}
return
}
func (s *Service) indexBanner2(c context.Context, plat int8, buvid string, mid int64, param *feed.IndexParam) (banners []*banner.Banner, version string, err error) {
hash := param.BannerHash
if param.LoginEvent != 0 {
hash = ""
}
banners, version, err = s.banners(c, plat, param.Build, mid, buvid, param.Network, param.MobiApp, param.Device, param.OpenEvent, param.AdExtra, hash)
return
}
func (s *Service) mergeItem2(c context.Context, plat int8, mid int64, rs []*ai.Item, adm map[int]*cm.AdInfo, adAidm map[int64]struct{}, banners []*banner.Banner, version string, blackAids map[int64]struct{}, follow *operate.Card, followMode bool) (is []*ai.Item, adInfom map[int]*cm.AdInfo) {
if len(rs) == 0 {
return
}
const (
cardIndex = 7
cardIndexIPad = 17
cardOffset = 2
)
if len(banners) != 0 {
rs = append([]*ai.Item{&ai.Item{Goto: model.GotoBanner, Banners: banners, Version: version}}, rs...)
for index, ad := range adm {
if _, ok := _cardAdWebm[ad.CardType]; ok && ((model.IsIPad(plat) && index <= cardIndexIPad) || index <= cardIndex) {
ad.CardIndex = ad.CardIndex + cardOffset
}
}
}
if follow != nil {
followPos := s.c.Feed.Index.FollowPosition
if followPos-1 >= 0 && followPos-1 <= len(rs) {
rs = append(rs[:followPos-1], append([]*ai.Item{&ai.Item{ID: follow.ID, Goto: model.GotoSearchSubscribe}}, rs[followPos-1:]...)...)
}
}
is = make([]*ai.Item, 0, len(rs)+len(adm))
adInfom = make(map[int]*cm.AdInfo, len(adm))
var existsAdWeb bool
for _, r := range rs {
for {
if ad, ok := adm[len(is)]; ok {
if ad.CreativeID != 0 {
var item *ai.Item
if _, ok := _cardAdAvm[ad.CardType]; ok {
item = &ai.Item{ID: ad.CreativeContent.VideoID, Goto: model.GotoAdAv, Ad: ad}
} else if _, ok := _cardAdWebm[ad.CardType]; ok {
item = &ai.Item{Goto: model.GotoAdWeb, Ad: ad}
existsAdWeb = true
} else if _, ok := _cardAdWebSm[ad.CardType]; ok {
item = &ai.Item{Goto: model.GotoAdWebS, Ad: ad}
} else {
b, _ := json.Marshal(ad)
log.Error("ad---%s", b)
break
}
is = append(is, item)
continue
} else {
adInfom[ad.CardIndex-1] = ad
}
}
break
}
if r.Goto == model.GotoAv {
if _, ok := blackAids[r.ID]; ok {
continue
} else if _, ok := s.blackCache[r.ID]; ok {
continue
}
if _, ok := adAidm[r.ID]; ok {
continue
}
} else if r.Goto == model.GotoBanner && len(is) != 0 {
// banner 必须在第一位
continue
} else if r.Goto == model.GotoRank && existsAdWeb {
continue
} else if r.Goto == model.GotoLogin && mid > 0 {
continue
} else if r.Goto == model.GotoFollowMode && !followMode {
continue
}
is = append(is, r)
}
return
}
func (*Service) dealAdLoc(is []card.Handler, param *feed.IndexParam, adInfom map[int]*cm.AdInfo, now time.Time) {
il := len(is)
if il == 0 {
return
}
if param.Idx < 1 {
param.Idx = now.Unix()
}
for i, h := range is {
if param.Pull {
h.Get().Idx = param.Idx + int64(il-i)
} else {
h.Get().Idx = param.Idx - int64(i+1)
}
if ad, ok := adInfom[i]; ok {
h.Get().AdInfo = ad
} else if h.Get().AdInfo != nil {
h.Get().AdInfo.CardIndex = i + 1
}
}
}
func (s *Service) dealItem2(c context.Context, mid int64, buvid string, plat int8, rs []*ai.Item, param *feed.IndexParam, isRcmd, noCache, followMode bool, follow *operate.Card, now time.Time) (is []card.Handler, isAI bool) {
if len(rs) == 0 {
is = []card.Handler{}
return
}
var (
aids, tids, roomIDs, sids, metaIDs, shopIDs, audioIDs, picIDs []int64
seasonIDs []int32
upIDs, avUpIDs, rmUpIDs, mtUpIDs []int64
am map[int64]*archive.ArchiveWithPlayer
tagm map[int64]*tag.Tag
rm map[int64]*live.Room
sm map[int64]*bangumi.Season
hasUpdate, getBanner bool
update *bangumi.Update
metam map[int64]*article.Meta
shopm map[int64]*show.Shopping
audiom map[int64]*audio.Audio
cardm map[int64]*account.Card
statm map[int64]*relation.Stat
moe *bangumi.Moe
isAtten map[int64]int8
arcOK bool
rank *operate.Card
seasonm map[int32]*episodegrpc.EpisodeCardsProto
banners []*banner.Banner
version string
picm map[int64]*bplus.Picture
)
convergem := map[int64]*operate.Card{}
followm := map[int64]*operate.Card{}
downloadm := map[int64]*operate.Card{}
specialm := map[int64]*operate.Card{}
liveUpm := map[int64][]*live.Card{}
isAI = isRcmd
for _, r := range rs {
if r == nil {
continue
}
switch r.Goto {
case model.GotoBanner:
if len(r.Banners) != 0 {
banners = r.Banners
version = r.Version
} else {
getBanner = true
}
case model.GotoAv, model.GotoAdAv, model.GotoPlayer, model.GotoUpRcmdAv:
if r.ID != 0 {
aids = append(aids, r.ID)
}
if r.Tid != 0 {
tids = append(tids, r.Tid)
}
case model.GotoLive, model.GotoPlayerLive:
if r.ID != 0 {
roomIDs = append(roomIDs, r.ID)
}
case model.GotoBangumi:
if r.ID != 0 {
sids = append(sids, r.ID)
}
case model.GotoPGC:
if r.ID != 0 {
seasonIDs = append(seasonIDs, int32(r.ID))
}
case model.GotoRank:
os, aid := s.RankCard(plat)
rank = &operate.Card{}
rank.FromRank(os)
aids = append(aids, aid...)
case model.GotoBangumiRcmd:
hasUpdate = true
case model.GotoConverge:
cardm, aid, roomID, metaID := s.convergeCard(c, 3, r.ID)
for id, card := range cardm {
convergem[id] = card
}
aids = append(aids, aid...)
roomIDs = append(roomIDs, roomID...)
metaIDs = append(metaIDs, metaID...)
case model.GotoGameDownloadS:
cardm := s.downloadCard(c, r.ID)
for id, card := range cardm {
downloadm[id] = card
}
case model.GotoArticleS:
if r.ID != 0 {
metaIDs = append(metaIDs, r.ID)
}
case model.GotoShoppingS:
if r.ID != 0 {
shopIDs = append(shopIDs, r.ID)
}
case model.GotoAudio:
if r.ID != 0 {
audioIDs = append(audioIDs, r.ID)
}
case model.GotoLiveUpRcmd:
cardm, upID := s.liveUpRcmdCard(c, r.ID)
for id, card := range cardm {
liveUpm[id] = card
}
upIDs = append(upIDs, upID...)
case model.GotoSubscribe:
cardm, upID, tid := s.subscribeCard(c, r.ID)
for id, card := range cardm {
followm[id] = card
}
upIDs = append(upIDs, upID...)
tids = append(tids, tid...)
case model.GotoSearchSubscribe:
if follow != nil {
followm[follow.ID] = follow
for _, item := range follow.Items {
upIDs = append(upIDs, item.ID)
}
}
case model.GotoChannelRcmd:
cardm, aid, tid := s.channelRcmdCard(c, r.ID)
for id, card := range cardm {
followm[id] = card
}
aids = append(aids, aid...)
tids = append(tids, tid...)
case model.GotoSpecial, model.GotoSpecialS:
cardm := s.specialCard(c, r.ID)
for id, card := range cardm {
specialm[id] = card
}
case model.GotoPicture:
if r.ID != 0 {
picIDs = append(picIDs, r.ID)
}
if r.RcmdReason != nil && r.RcmdReason.Style == 4 {
upIDs = append(upIDs, r.RcmdReason.FollowedMid)
}
}
}
g, ctx := errgroup.WithContext(c)
if getBanner {
g.Go(func() (err error) {
if banners, version, err = s.banners(ctx, plat, param.Build, mid, buvid, param.Network, param.MobiApp, param.Device, param.OpenEvent, param.AdExtra, ""); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(aids) != 0 {
g.Go(func() (err error) {
if am, err = s.ArchivesWithPlayer(ctx, aids, param.Qn, param.MobiApp, param.Fnver, param.Fnval, param.ForceHost, param.Build); err != nil {
return
}
arcOK = true
for _, a := range am {
avUpIDs = append(avUpIDs, a.Author.Mid)
}
return
})
}
if len(tids) != 0 {
g.Go(func() (err error) {
if tagm, err = s.tg.InfoByIDs(ctx, mid, tids); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(roomIDs) != 0 {
g.Go(func() (err error) {
if rm, err = s.lv.AppMRoom(ctx, roomIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, r := range rm {
rmUpIDs = append(rmUpIDs, r.UID)
}
return
})
}
if len(sids) != 0 {
g.Go(func() (err error) {
if sm, err = s.bgm.Seasons(ctx, sids, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(seasonIDs) != 0 {
g.Go(func() (err error) {
if seasonm, err = s.bgm.CardsInfoReply(ctx, seasonIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if hasUpdate && mid > 0 {
g.Go(func() (err error) {
/*
{
"code": 0,
"message": "success",
"result": {
"title": "小埋。。。",
"square_cover": "http://i0.hdslb.com/bfs/bangumi/dd2281c9f1c44e07c835e488ce1e1bae36f533e3.jpg",
"updates": 67
}
}
*/
if update, err = s.bgm.Updates(ctx, mid, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(metaIDs) != 0 {
g.Go(func() (err error) {
if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, meta := range metam {
if meta.Author != nil {
mtUpIDs = append(mtUpIDs, meta.Author.Mid)
}
}
return
})
}
if len(shopIDs) != 0 {
g.Go(func() (err error) {
if shopm, err = s.show.Card(ctx, shopIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(audioIDs) != 0 {
g.Go(func() (err error) {
if audiom, err = s.audio.Audios(ctx, audioIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(picIDs) != 0 {
g.Go(func() (err error) {
if picm, err = s.bplus.DynamicDetail(ctx, picIDs...); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
// 萌战下线
// if mid > 0 {
// g.Go(func() (err error) {
// if moe, err = s.bgm.FollowPull(ctx, mid, mobiApp, device, now); err != nil {
// log.Error("%+v", err)
// err = nil
// }
// return
// })
// }
if err := g.Wait(); err != nil {
log.Error("%+v", err)
if noCache {
is = []card.Handler{}
return
}
if isRcmd {
count := s.indexCount(plat)
rs = s.recommendCache(count)
}
} else {
upIDs = append(upIDs, avUpIDs...)
upIDs = append(upIDs, rmUpIDs...)
upIDs = append(upIDs, mtUpIDs...)
g, ctx = errgroup.WithContext(c)
if len(upIDs) != 0 {
g.Go(func() (err error) {
if cardm, err = s.acc.Cards3(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if statm, err = s.rel.Stats(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if mid > 0 && param.RecsysMode == 0 {
g.Go(func() error {
isAtten = s.acc.IsAttention(ctx, upIDs, mid)
return nil
})
}
}
g.Wait()
}
isAI = isAI && arcOK
if moe != nil {
moePos := s.c.Feed.Index.MoePosition
if moePos-1 >= 0 && moePos-1 <= len(rs) {
rs = append(rs[:moePos-1], append([]*ai.Item{&ai.Item{ID: moe.ID, Goto: model.GotoMoe}}, rs[moePos-1:]...)...)
}
}
var cardTotal int
is = make([]card.Handler, 0, len(rs))
insert := map[int]card.Handler{}
for _, r := range rs {
if r == nil {
continue
}
var (
main interface{}
cardType cdm.CardType
)
op := &operate.Card{}
op.From(cdm.CardGt(r.Goto), r.ID, r.Tid, plat, param.Build)
// 卡片展示点赞数实验
// if mid%20 == 11 && ((plat == model.PlatIPhone && param.Build >= 8290) || (plat == model.PlatAndroid && param.Build >= 5360000)) {
// op.FromSwitch(cdm.SwitchFeedIndexLike)
// }
// 变化卡片类型
switch r.Goto {
case model.GotoSpecialS, model.GotoGameDownloadS, model.GotoShoppingS:
if r.Style == 2 {
cardType = cdm.LargeCoverV1
}
case model.GotoPicture:
if p, ok := picm[r.ID]; ok {
switch cdm.Columnm[param.Column] {
case cdm.ColumnSvrSingle:
if len(p.Imgs) < 3 {
cardType = cdm.OnePicV1
} else {
cardType = cdm.ThreePicV1
}
case cdm.ColumnSvrDouble:
if len(p.Imgs) < 3 {
// 版本过滤5.37为新卡片
if (plat == model.PlatIPhone && param.Build > 8300) || (plat == model.PlatAndroid && param.Build > 5365000) {
cardType = cdm.OnePicV2
} else {
cardType = cdm.SmallCoverV2
}
} else {
cardType = cdm.ThreePicV2
}
default:
continue
}
} else {
continue
}
case model.GotoInterest:
switch cdm.Columnm[param.Column] {
case cdm.ColumnSvrSingle:
cardType = cdm.OptionsV1
case cdm.ColumnSvrDouble:
cardType = cdm.OptionsV2
default:
continue
}
case model.GotoFollowMode:
cardType = cdm.Select
default:
}
h := card.Handle(plat, cdm.CardGt(r.Goto), cardType, param.Column, r, tagm, isAtten, statm, cardm)
if h == nil {
continue
}
switch r.Goto {
case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer:
if !arcOK {
if r.Archive != nil {
am = map[int64]*archive.ArchiveWithPlayer{r.Archive.Aid: &archive.ArchiveWithPlayer{Archive3: r.Archive}}
}
if r.Tag != nil {
tagm = map[int64]*tag.Tag{r.Tag.ID: r.Tag}
op.Tid = r.Tag.ID
}
}
if a, ok := am[r.ID]; ok && (a.AttrVal(archive.AttrBitOverseaLock) == 0 || !model.IsOverseas(plat)) {
main = am
op.TrackID = r.TrackID
}
if plat == model.PlatIPhone && param.Build > 8290 || plat == model.PlatAndroid && param.Build > 5365000 {
op.Switch = cdm.SwitchCooperationShow
} else {
op.Switch = cdm.SwitchCooperationHide
}
case model.GotoLive, model.GotoPlayerLive:
main = rm
case model.GotoBangumi:
main = sm
case model.GotoPGC:
main = seasonm
case model.GotoLogin:
op.FromLogin(r.ID)
case model.GotoSpecial, model.GotoSpecialS:
op = specialm[r.ID]
case model.GotoRank:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am}
op = rank
case model.GotoBangumiRcmd:
main = update
case model.GotoBanner:
op.FromBanner(banners, version)
case model.GotoConverge:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoLive: rm, cdm.GotoArticle: metam}
op = convergem[r.ID]
case model.GotoGameDownloadS:
op = downloadm[r.ID]
case model.GotoArticleS:
main = metam
case model.GotoShoppingS:
main = shopm
case model.GotoAudio:
main = audiom
case model.GotoChannelRcmd:
main = am
op = followm[r.ID]
case model.GotoSubscribe, model.GotoSearchSubscribe:
op = followm[r.ID]
case model.GotoLiveUpRcmd:
main = liveUpm
case model.GotoMoe:
main = moe
case model.GotoPicture:
main = picm
case model.GotoAdAv:
main = am
op.FromAdAv(r.Ad)
case model.GotoAdWebS, model.GotoAdWeb:
main = r.Ad
case model.GotoInterest:
main = s.c.Feed.Index.Interest
case model.GotoFollowMode:
var (
title string
desc string
button []string
)
if s.c.Feed.Index.FollowMode != nil && s.c.Feed.Index.FollowMode.Card != nil {
title = s.c.Feed.Index.FollowMode.Card.Title
desc = s.c.Feed.Index.FollowMode.Card.Desc
button = s.c.Feed.Index.FollowMode.Card.Button
}
op.FromFollowMode(title, desc, button)
default:
log.Warn("unexpected goto(%s) %+v", r.Goto, r)
continue
}
if op != nil {
op.Plat = plat
op.Build = param.Build
}
h.From(main, op)
// 卡片不正常要continue
if !h.Get().Right {
continue
}
switch r.Goto {
case model.GotoAdAv, model.GotoAdWebS, model.GotoAdWeb:
// 判断结果列表长度,如果列表的末尾不是广告位,则放到插入队列里
if len(is) != r.Ad.CardIndex-1 {
insert[r.Ad.CardIndex-1] = h
// 插入队列后一定要continue,否则就直接加到队列末尾了
continue
}
}
is, cardTotal = s.appendItem(plat, is, h, param.Column, cardTotal)
// 从插入队列里获取广告
if h, ok := insert[len(is)]; ok {
is, cardTotal = s.appendItem(plat, is, h, param.Column, cardTotal)
}
}
// 双列末尾卡片去空窗
if !model.IsIPad(plat) {
if cdm.Columnm[param.Column] == cdm.ColumnSvrDouble {
is = is[:len(is)-cardTotal%2]
}
} else {
// 复杂的ipad去空窗逻辑
if cardTotal%4 == 3 {
if is[len(is)-2].Get().CardLen == 2 {
is = is[:len(is)-2]
} else {
is = is[:len(is)-3]
}
} else if cardTotal%4 == 2 {
if is[len(is)-1].Get().CardLen == 2 {
is = is[:len(is)-1]
} else {
is = is[:len(is)-2]
}
} else if cardTotal%4 == 1 {
is = is[:len(is)-1]
}
}
if len(is) == 0 {
is = []card.Handler{}
return
}
return
}
func (s *Service) appendItem(plat int8, rs []card.Handler, h card.Handler, column cdm.ColumnStatus, cardTotal int) (is []card.Handler, total int) {
h.Get().ThreePointFrom()
if !model.IsIPad(plat) {
// 双列大小卡换位去空窗
if cdm.Columnm[column] == cdm.ColumnSvrDouble {
// 通栏卡
if h.Get().CardLen == 0 {
if cardTotal%2 == 1 {
is = card.SwapTwoItem(rs, h)
} else {
is = append(rs, h)
}
} else {
is = append(rs, h)
}
} else {
is = append(rs, h)
}
} else {
// ipad卡片不展示标签
h.Get().DescButton = nil
// ipad大小卡换位去空窗
if h.Get().CardLen == 0 {
// 通栏卡
if cardTotal%4 == 3 {
is = card.SwapFourItem(rs, h)
} else if cardTotal%4 == 2 {
is = card.SwapThreeItem(rs, h)
} else if cardTotal%4 == 1 {
is = card.SwapTwoItem(rs, h)
} else {
is = append(rs, h)
}
} else if h.Get().CardLen == 2 {
// 半栏卡
if cardTotal%4 == 3 {
is = card.SwapTwoItem(rs, h)
} else if cardTotal%4 == 2 {
is = append(rs, h)
} else if cardTotal%4 == 1 {
is = card.SwapTwoItem(rs, h)
} else {
is = append(rs, h)
}
} else {
is = append(rs, h)
}
}
total = cardTotal + h.Get().CardLen
return
}
func (s *Service) Converge(c context.Context, mid int64, plat int8, param *feed.ConvergeParam, now time.Time) (is []card.Handler, converge *operate.Card, err error) {
cardm, _, _, _ := s.convergeCard(c, 0, param.ID)
converge, ok := cardm[param.ID]
if !ok {
is = []card.Handler{}
return
}
rs := make([]*ai.Item, 0, len(converge.Items))
for _, item := range converge.Items {
rs = append(rs, &ai.Item{ID: item.ID, Goto: string(item.CardGoto)})
}
indexParam := &feed.IndexParam{
MobiApp: param.MobiApp,
Device: param.Device,
Build: param.Build,
Qn: param.Qn,
Fnver: param.Fnver,
Fnval: param.Fnval,
ForceHost: param.ForceHost,
}
is, _ = s.dealItem2(c, mid, "", plat, rs, indexParam, false, true, false, nil, now)
for _, item := range is {
// 运营tab页没有不感兴趣
item.Get().ThreePointWatchLater()
}
return
}