123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- package feed
- import (
- "context"
- "encoding/json"
- "time"
- cdm "go-common/app/interface/main/app-card/model"
- "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/banner"
- "go-common/app/interface/main/app-card/model/card/cm"
- "go-common/app/interface/main/app-card/model/card/operate"
- "go-common/app/interface/main/app-intl/model"
- "go-common/app/interface/main/app-intl/model/feed"
- tag "go-common/app/interface/main/tag/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"
- "go-common/library/ecode"
- "go-common/library/log"
- "go-common/library/net/metadata"
- "go-common/library/sync/errgroup"
- "go-common/library/text/translate/chinese"
- )
- // Index is.
- func (s *Service) Index(c context.Context, buvid string, mid int64, plat int8, param *feed.IndexParam, now time.Time, style int) (is []card.Handler, userFeature json.RawMessage, isRcmd, newUser bool, code int, autoPlay, clean int8, autoPlayInfoc string, 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
- ip = metadata.String(c, metadata.RemoteIP)
- info *locmdl.Info
- isTW = model.TWLocale(param.Locale)
- )
- // 国际版不做abtest
- clean = 0
- autoPlay = 2
- group := s.group(mid, buvid)
- if info, err = s.loc.Info(c, ip); err != nil {
- log.Warn("s.loc.Info(%v) error(%v)", ip, err)
- err = nil
- }
- if !s.c.Feed.Index.Abnormal {
- g, ctx := errgroup.WithContext(c)
- g.Go(func() error {
- rs, userFeature, isRcmd, newUser, code = s.indexRcmd(ctx, plat, param.Build, buvid, mid, group, param.LoginEvent, info, param.Interest, param.Network, style, param.Column, param.Flush, autoPlayInfoc, now)
- if isTW {
- for _, r := range rs {
- if r.RcmdReason != nil {
- r.RcmdReason.Content = chinese.Convert(ctx, r.RcmdReason.Content)
- }
- }
- }
- return nil
- })
- g.Go(func() (err error) {
- if blackAidm, err = s.BlackList(ctx, mid); err != nil {
- log.Error("%+v", err)
- err = nil
- }
- return
- })
- if err = g.Wait(); err != nil {
- return
- }
- rs, adInfom = s.mergeItem(c, mid, rs, adm, adAidm, banners, version, blackAidm, plat, follow)
- } else {
- count := s.indexCount(plat)
- rs = s.recommendCache(count)
- log.Warn("feed index show disaster recovery data len(%d)", len(is))
- }
- is, isRcmd, err = s.dealItem(c, param.Column, mid, buvid, plat, param.Build, rs, isRcmd, param.MobiApp, param.Device, param.Network, param.OpenEvent, param.AdExtra, param.Qn, param.Fnver, param.Fnval, follow, isTW, now)
- s.dealAdLoc(is, param, adInfom, now)
- return
- }
- // indexRcmd is.
- func (s *Service) indexRcmd(c context.Context, plat int8, build int, buvid string, mid int64, group int, loginEvent int, info *locmdl.Info, interest, network string, style int, column cdm.ColumnStatus, flush int, autoPlay string, 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 info != nil {
- zoneID = info.ZoneID
- }
- if is, userFeature, code, newUser, err = s.rcmd.Recommend(c, plat, buvid, mid, build, loginEvent, zoneID, group, interest, network, style, column, flush, autoPlay, now); err != nil {
- log.Error("%+v", err)
- } else 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
- }
- // mergeItem is.
- func (s *Service) mergeItem(c context.Context, mid int64, rs []*ai.Item, adm map[int]*cm.AdInfo, adAidm map[int64]struct{}, banners []*banner.Banner, version string, blackAids map[int64]struct{}, plat int8, follow *operate.Card) (is []*ai.Item, adInfom map[int]*cm.AdInfo) {
- if len(rs) == 0 {
- return
- }
- if len(banners) != 0 {
- rs = append([]*ai.Item{{Goto: model.GotoBanner, Banners: banners, Version: version}}, rs...)
- }
- is = make([]*ai.Item, 0, len(rs)+len(adm))
- adInfom = make(map[int]*cm.AdInfo, len(adm))
- for _, r := range rs {
- 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.GotoLogin && mid != 0 {
- continue
- }
- is = append(is, r)
- }
- return
- }
- // dealAdLoc is.
- 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
- }
- }
- }
- // dealItem is.
- func (s *Service) dealItem(c context.Context, column cdm.ColumnStatus, mid int64, buvid string, plat int8, build int, rs []*ai.Item, isRcmd bool, mobiApp, device, network, openEvent, adExtra string, qn, fnver, fnval int, follow *operate.Card, isTW bool, now time.Time) (is []card.Handler, isAI bool, err error) {
- if len(rs) == 0 {
- is = []card.Handler{}
- return
- }
- var (
- aids, tids []int64
- upIDs, avUpIDs, rmUpIDs, mtUpIDs []int64
- am map[int64]*archive.ArchiveWithPlayer
- tagm map[int64]*tag.Tag
- rank *operate.Card
- cardm map[int64]*account.Card
- statm map[int64]*relation.Stat
- isAtten map[int64]int8
- arcOK bool
- )
- followm := map[int64]*operate.Card{}
- isAI = isRcmd
- for _, r := range rs {
- if r == nil {
- continue
- }
- if isTW && r.RcmdReason != nil {
- r.RcmdReason.Content = chinese.Convert(c, r.RcmdReason.Content)
- }
- switch r.Goto {
- case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv:
- if r.ID != 0 {
- aids = append(aids, r.ID)
- }
- if r.Tid != 0 {
- tids = append(tids, r.Tid)
- }
- case model.GotoRank:
- os, aid := s.RankCard(plat)
- rank = &operate.Card{}
- rank.FromRank(os)
- aids = append(aids, aid...)
- 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...)
- }
- }
- g, ctx := errgroup.WithContext(c)
- if len(aids) != 0 {
- g.Go(func() (err error) {
- if am, err = s.ArchivesWithPlayer(ctx, aids, qn, mobiApp, fnver, fnval); err != nil {
- return
- }
- arcOK = true
- for _, a := range am {
- avUpIDs = append(avUpIDs, a.Author.Mid)
- if isTW {
- out := chinese.Converts(ctx, a.Title, a.Desc, a.TypeName)
- a.Title = out[a.Title]
- a.Desc = out[a.Desc]
- a.TypeName = out[a.TypeName]
- }
- }
- 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 err = g.Wait(); err != nil {
- log.Error("%+v", err)
- 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 {
- g.Go(func() error {
- isAtten = s.acc.IsAttention(ctx, upIDs, mid)
- return nil
- })
- }
- }
- g.Wait()
- }
- isAI = isAI && arcOK
- var cardTotal int
- is = make([]card.Handler, 0, len(rs))
- 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, build)
- h := card.Handle(plat, cdm.CardGt(r.Goto), cardType, column, r, tagm, isAtten, statm, cardm)
- if h == nil {
- continue
- }
- switch r.Goto {
- case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv:
- if !arcOK {
- if r.Archive != nil {
- if isTW {
- out := chinese.Converts(c, r.Archive.Title, r.Archive.Desc, r.Archive.TypeName, r.Archive.Author.Name)
- r.Archive.Title = out[r.Archive.Title]
- r.Archive.Desc = out[r.Archive.Desc]
- r.Archive.TypeName = out[r.Archive.TypeName]
- }
- am = map[int64]*archive.ArchiveWithPlayer{r.Archive.Aid: {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
- }
- case model.GotoRank:
- main = map[cdm.Gt]interface{}{cdm.GotoAv: am}
- op = rank
- case model.GotoChannelRcmd:
- main = am
- case model.GotoLogin:
- op.FromLogin(r.ID)
- default:
- log.Warn("unexpected goto(%s) %+v", r.Goto, r)
- continue
- }
- h.From(main, op)
- // 卡片不正常要continue
- if !h.Get().Right {
- continue
- }
- is, cardTotal = s.appendItem(plat, is, h, column, cardTotal)
- }
- // 双列末尾卡片去空窗
- if !model.IsIPad(plat) {
- if cdm.Columnm[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
- }
- // appendItem is.
- 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 h.Get().ThreePoint != nil {
- h.Get().ThreePoint.Feedbacks = nil
- }
- 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
- }
- // indexCount is.
- func (s *Service) indexCount(plat int8) (count int) {
- if plat == model.PlatIPad {
- count = s.c.Feed.Index.IPadCount
- } else {
- count = s.c.Feed.Index.Count
- }
- return
- }
|