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.
599 lines
16 KiB
599 lines
16 KiB
package channel |
|
|
|
import ( |
|
"context" |
|
"encoding/json" |
|
"fmt" |
|
"strconv" |
|
"sync" |
|
"time" |
|
|
|
cdm "go-common/app/interface/main/app-card/model" |
|
cardm "go-common/app/interface/main/app-card/model/card" |
|
"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/live" |
|
"go-common/app/interface/main/app-card/model/card/operate" |
|
shopping "go-common/app/interface/main/app-card/model/card/show" |
|
"go-common/app/interface/main/app-channel/model" |
|
"go-common/app/interface/main/app-channel/model/card" |
|
"go-common/app/interface/main/app-channel/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" |
|
relation "go-common/app/service/main/relation/model" |
|
episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1" |
|
seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1" |
|
"go-common/library/log" |
|
"go-common/library/sync/errgroup" |
|
|
|
farm "github.com/dgryski/go-farm" |
|
) |
|
|
|
const ( |
|
_fTypeOperation = "operation" |
|
_fTypeRecommend = "recommend" |
|
) |
|
|
|
// Index channel index |
|
func (s *Service) Index2(c context.Context, mid, channelID, idx int64, plat int8, mobiApp, device, buvid, channelName, ip string, |
|
build, loginEvent, displayID, qn, fnver, fnval int, pull bool, now time.Time) (res *feed.Show2, err error) { |
|
var ( |
|
aiCards []*card.Card |
|
requestCnt = 10 |
|
isIpad = plat == model.PlatIPad |
|
topic cardm.Handler |
|
item []cardm.Handler |
|
channelResource *tag.ChannelResource |
|
topChannel, isRec int |
|
infocs []*feed.Item |
|
) |
|
if isIpad { |
|
requestCnt = 20 |
|
} |
|
if channelID > 0 { |
|
channelName = "" |
|
} |
|
g, ctx := errgroup.WithContext(c) |
|
g.Go(func() (err error) { |
|
if channelResource, err = s.tg.Resources(ctx, plat, channelID, mid, channelName, buvid, build, requestCnt, loginEvent, displayID); err != nil { |
|
log.Error("index s.tg.Resources error(%v)", err) |
|
return |
|
} |
|
if channelResource != nil { |
|
aids := channelResource.Oids |
|
for _, aid := range aids { |
|
t := &card.Card{ |
|
Type: model.GotoAv, |
|
Value: aid, |
|
FromType: _fTypeRecommend, |
|
} |
|
aiCards = append(aiCards, t) |
|
} |
|
if channelResource.Failover { |
|
isRec = 0 |
|
} else { |
|
isRec = 1 |
|
} |
|
if channelResource.IsChannel { |
|
topChannel = 1 |
|
} else { |
|
topChannel = 0 |
|
} |
|
} |
|
return |
|
}) |
|
g.Go(func() (err error) { |
|
var t *tag.ChannelDetail |
|
if t, err = s.tg.ChannelDetail(c, mid, channelID, channelName, s.isOverseas(plat)); err != nil { |
|
log.Error("s.tag.ChannelDetail(%d, %d, %s) error(%v)", mid, channelID, channelName, err) |
|
return |
|
} |
|
channelID = t.Tag.ID |
|
channelName = t.Tag.Name |
|
return |
|
}) |
|
err = g.Wait() |
|
//infoc |
|
infoc := &feedInfoc{ |
|
mobiApp: mobiApp, |
|
device: device, |
|
build: strconv.Itoa(build), |
|
now: now.Format("2006-01-02 15:04:05"), |
|
pull: strconv.FormatBool(pull), |
|
loginEvent: strconv.Itoa(loginEvent), |
|
channelID: strconv.FormatInt(channelID, 10), |
|
channelName: channelName, |
|
mid: strconv.FormatInt(mid, 10), |
|
buvid: buvid, |
|
displayID: strconv.Itoa(displayID), |
|
isRec: strconv.Itoa(isRec), |
|
topChannel: strconv.Itoa(topChannel), |
|
ServerCode: "0", |
|
} |
|
//infoc |
|
if err != nil { |
|
log.Error("RankUser errgroup.WithContext error(%v)", err) |
|
res = &feed.Show2{ |
|
Feed: []cardm.Handler{}, |
|
} |
|
infoc.Items = []*feed.Item{} |
|
infoc.ServerCode = err.Error() |
|
s.infoc(infoc) |
|
return |
|
} |
|
var ( |
|
tmps = []*card.Card{} |
|
) |
|
if loginEvent == 1 || loginEvent == 2 { |
|
if cards, ok := s.cardCache[channelID]; ok { |
|
isShowCard := s.isShowOperationCards(c, buvid, channelID, cards, now) |
|
for _, c := range cards { |
|
if !isShowCard && c.Type != model.GotoTopstick { |
|
continue |
|
} |
|
t := &card.Card{} |
|
*t = *c |
|
t.FromType = _fTypeOperation |
|
tmps = append(tmps, t) |
|
} |
|
tmps = append(tmps, aiCards...) |
|
} else { |
|
tmps = aiCards |
|
} |
|
} else { |
|
tmps = aiCards |
|
} |
|
topic, item, infocs, err = s.dealItem2(c, mid, idx, channelID, plat, build, buvid, ip, mobiApp, pull, qn, fnver, fnval, now, tmps) |
|
res = &feed.Show2{ |
|
Topic: topic, |
|
Feed: item, |
|
} |
|
infoc.Items = infocs |
|
s.infoc(infoc) |
|
return |
|
} |
|
|
|
// dealItem |
|
func (s *Service) dealItem2(c context.Context, mid, idx, channelID int64, plat int8, build int, buvid, ip, mobiApp string, pull bool, |
|
qn, fnver, fnval int, now time.Time, cards []*card.Card) (top cardm.Handler, is []cardm.Handler, infocs []*feed.Item, err error) { |
|
if len(cards) == 0 { |
|
is = []cardm.Handler{} |
|
return |
|
} |
|
var ( |
|
aids, shopIDs, audioIDs, sids, roomIDs, metaIDs []int64 |
|
upIDs, tids, rmUpIDs, mtUpIDs, avUpIDs, avUpCountIDs []int64 |
|
seasonIDs, epIDs []int32 |
|
am map[int64]*archive.ArchiveWithPlayer |
|
tagm map[int64]*tag.Tag |
|
rm map[int64]*live.Room |
|
sm map[int64]*bangumi.Season |
|
metam map[int64]*article.Meta |
|
shopm map[int64]*shopping.Shopping |
|
audiom map[int64]*audio.Audio |
|
cardAids = map[int64]struct{}{} |
|
ac map[int64]*account.Card |
|
statm map[int64]*relation.Stat |
|
isAtten map[int64]int8 |
|
upAvCount = map[int64]int{} |
|
channelCards []*card.Card |
|
seasonm map[int32]*seasongrpc.CardInfoProto |
|
epidsCards map[int32]*episodegrpc.EpisodeCardsProto |
|
// key |
|
_initCardPlatKey = "card_platkey_%d_%d" |
|
) |
|
specialm := map[int64]*operate.Card{} |
|
convergem := map[int64]*operate.Card{} |
|
downloadm := map[int64]*operate.Card{} |
|
followm := map[int64]*operate.Card{} |
|
liveUpm := map[int64][]*live.Card{} |
|
cardSet := map[int64]*operate.Card{} |
|
LOOP: |
|
for _, card := range cards { |
|
key := fmt.Sprintf(_initCardPlatKey, plat, card.ID) |
|
if cardPlat, ok := s.cardPlatCache[key]; ok { |
|
for _, l := range cardPlat { |
|
if model.InvalidBuild(build, l.Build, l.Condition) { |
|
continue LOOP |
|
} |
|
} |
|
} else if card.FromType == _fTypeOperation { |
|
continue LOOP |
|
} |
|
channelCards = append(channelCards, card) |
|
switch card.Type { |
|
case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv: |
|
if card.Value != 0 { |
|
aids = append(aids, card.Value) |
|
cardAids[card.Value] = struct{}{} |
|
} |
|
case model.GotoLive, model.GotoPlayerLive: |
|
if card.Value != 0 { |
|
roomIDs = append(roomIDs, card.Value) |
|
} |
|
case model.GotoBangumi: |
|
if card.Value != 0 { |
|
sids = append(sids, card.Value) |
|
} |
|
case model.GotoPGC: |
|
if card.Value != 0 { |
|
epIDs = append(epIDs, int32(card.Value)) |
|
} |
|
case model.GotoConverge: |
|
if card.Value != 0 { |
|
cardm, aid, roomID, metaID := s.convergeCard2(c, 3, card.Value) |
|
for id, card := range cardm { |
|
convergem[id] = card |
|
} |
|
aids = append(aids, aid...) |
|
roomIDs = append(roomIDs, roomID...) |
|
metaIDs = append(metaIDs, metaID...) |
|
} |
|
case model.GotoGameDownload, model.GotoGameDownloadS: |
|
if card.Value != 0 { |
|
cardm := s.downloadCard(c, card.Value) |
|
for id, card := range cardm { |
|
downloadm[id] = card |
|
} |
|
} |
|
case model.GotoArticle, model.GotoArticleS: |
|
if card.Value != 0 { |
|
metaIDs = append(metaIDs, card.Value) |
|
} |
|
case model.GotoShoppingS: |
|
if card.Value != 0 { |
|
shopIDs = append(shopIDs, card.Value) |
|
} |
|
case model.GotoAudio: |
|
if card.Value != 0 { |
|
audioIDs = append(audioIDs, card.Value) |
|
} |
|
case model.GotoChannelRcmd: |
|
cardm, aid, tid := s.channelRcmdCard(c, card.Value) |
|
for id, card := range cardm { |
|
followm[id] = card |
|
} |
|
aids = append(aids, aid...) |
|
tids = append(tids, tid...) |
|
case model.GotoLiveUpRcmd: |
|
if card.Value != 0 { |
|
cardm, upID := s.liveUpRcmdCard(c, card.Value) |
|
for id, card := range cardm { |
|
liveUpm[id] = card |
|
} |
|
upIDs = append(upIDs, upID...) |
|
} |
|
case model.GotoSubscribe: |
|
if card.Value != 0 { |
|
cardm, upID, tid := s.subscribeCard(c, card.Value) |
|
for id, card := range cardm { |
|
followm[id] = card |
|
} |
|
upIDs = append(upIDs, upID...) |
|
tids = append(tids, tid...) |
|
} |
|
case model.GotoSpecial, model.GotoSpecialS: |
|
cardm := s.specialCard(c, card.Value) |
|
for id, card := range cardm { |
|
specialm[id] = card |
|
} |
|
case model.GotoTopstick: |
|
cardm := s.topstickCard(c, card.Value) |
|
for id, card := range cardm { |
|
specialm[id] = card |
|
} |
|
case model.GotoPgcsRcmd: |
|
cardm, ssid := s.cardSetChange(c, card.Value) |
|
seasonIDs = append(seasonIDs, ssid...) |
|
for id, card := range cardm { |
|
cardSet[id] = card |
|
} |
|
case model.GotoUpRcmdS: |
|
if card.Value != 0 { |
|
avUpCountIDs = append(avUpCountIDs, card.Value) |
|
} |
|
} |
|
} |
|
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, build); err != nil { |
|
return |
|
} |
|
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 len(epIDs) != 0 { |
|
g.Go(func() (err error) { |
|
if epidsCards, err = s.bgm.EpidsCardsInfoReply(ctx, epIDs); 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.sp.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(avUpCountIDs) != 0 { |
|
var mutex sync.Mutex |
|
for _, upid := range avUpCountIDs { |
|
var ( |
|
tmpupid = upid |
|
) |
|
g.Go(func() (err error) { |
|
var cnt int |
|
if cnt, err = s.arc.UpCount2(ctx, tmpupid); err != nil { |
|
log.Error("%+v", err) |
|
err = nil |
|
} |
|
mutex.Lock() |
|
upAvCount[tmpupid] = cnt |
|
mutex.Unlock() |
|
return |
|
}) |
|
} |
|
} |
|
if err = g.Wait(); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
upIDs = append(upIDs, avUpIDs...) |
|
upIDs = append(upIDs, rmUpIDs...) |
|
upIDs = append(upIDs, mtUpIDs...) |
|
upIDs = append(upIDs, avUpCountIDs...) |
|
g, ctx = errgroup.WithContext(c) |
|
if len(upIDs) != 0 { |
|
g.Go(func() (err error) { |
|
if ac, 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 |
|
}) |
|
} |
|
} |
|
if err = g.Wait(); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
for _, card := range channelCards { |
|
var ( |
|
r = card.CardToAiChange() |
|
main interface{} |
|
) |
|
switch r.Goto { |
|
case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer: |
|
r.HideButton = true |
|
} |
|
h := cardm.Handle(plat, cdm.CardGt(r.Goto), "", cdm.ColumnSvrSingle, r, tagm, isAtten, statm, ac) |
|
if h == nil { |
|
continue |
|
} |
|
op := &operate.Card{} |
|
op.From(cdm.CardGt(r.Goto), r.ID, 0, plat, build) |
|
switch r.Goto { |
|
case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer: |
|
op.ShowUGCPay = true |
|
if a, ok := am[r.ID]; ok && (a.AttrVal(archive.AttrBitOverseaLock) == 0 || !model.IsOverseas(plat)) { |
|
main = am |
|
} |
|
op.Switch = cdm.SwitchCooperationHide |
|
case model.GotoLive, model.GotoPlayerLive: |
|
main = rm |
|
case model.GotoBangumi: |
|
main = sm |
|
case model.GotoPGC: |
|
main = epidsCards |
|
case model.GotoSpecial, model.GotoSpecialS, model.GotoTopstick: |
|
op = specialm[r.ID] |
|
case model.GotoGameDownload, model.GotoGameDownloadS: |
|
op = downloadm[r.ID] |
|
case model.GotoArticle, 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: |
|
op = followm[r.ID] |
|
case model.GotoLiveUpRcmd: |
|
main = liveUpm |
|
case model.GotoConverge: |
|
main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoLive: rm, cdm.GotoArticle: metam} |
|
op = convergem[r.ID] |
|
case model.GotoPgcsRcmd: |
|
main = seasonm |
|
op = cardSet[r.ID] |
|
case model.GotoUpRcmdS: |
|
op.Limit = upAvCount[r.ID] |
|
} |
|
h.From(main, op) |
|
if h.Get() == nil { |
|
continue |
|
} |
|
h.Get().FromType = card.FromType |
|
if h.Get().Right { |
|
switch card.FromType { |
|
case _fTypeOperation: |
|
h.Get().ThreePointWatchLater() |
|
case _fTypeRecommend: |
|
h.Get().ThreePointChannel() |
|
} |
|
switch r.Goto { |
|
case model.GotoTopstick: |
|
top = h |
|
default: |
|
is = append(is, h) |
|
} |
|
} |
|
// infoc |
|
tinfo := &feed.Item{ |
|
Goto: card.Type, |
|
Param: strconv.FormatInt(card.Value, 10), |
|
URI: h.Get().URI, |
|
FromType: card.FromType, |
|
} |
|
infocs = append(infocs, tinfo) |
|
} |
|
rl := len(is) |
|
if rl == 0 { |
|
is = []cardm.Handler{} |
|
return |
|
} |
|
if idx == 0 { |
|
idx = now.Unix() |
|
} |
|
for i, h := range is { |
|
if pull { |
|
h.Get().Idx = idx + int64(rl-i) |
|
} else { |
|
h.Get().Idx = idx - int64(i+1) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// ArchivesWithPlayer archives witch player |
|
func (s *Service) ArchivesWithPlayer(c context.Context, aids []int64, qn int, platform string, fnver, fnval, build int) (res map[int64]*archive.ArchiveWithPlayer, err error) { |
|
if res, err = s.arc.ArchivesWithPlayer(c, aids, qn, platform, fnver, fnval, build); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
if len(res) != 0 { |
|
return |
|
} |
|
am, err := s.arc.Archives(c, aids) |
|
if err != nil { |
|
return |
|
} |
|
if len(am) == 0 { |
|
return |
|
} |
|
res = make(map[int64]*archive.ArchiveWithPlayer, len(am)) |
|
for aid, a := range am { |
|
res[aid] = &archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(a)} |
|
} |
|
return |
|
} |
|
|
|
// isShowOperationCards is show operation cards by buvid |
|
func (s *Service) isShowOperationCards(c context.Context, buvid string, channelID int64, cards []*card.Card, now time.Time) (isShow bool) { |
|
var ( |
|
md5, mcmd5 string |
|
) |
|
g, ctx := errgroup.WithContext(c) |
|
g.Go(func() (err error) { |
|
if mcmd5, err = s.cd.ChannelCardCache(ctx, buvid, channelID); err != nil { |
|
isShow = true |
|
return |
|
} |
|
return nil |
|
}) |
|
g.Go(func() (err error) { |
|
md5 = s.hashCards(cards) |
|
return nil |
|
}) |
|
g.Wait() |
|
if md5 != mcmd5 { |
|
isShow = true |
|
s.cd.AddChannelCardCache(c, buvid, md5, channelID, now) |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) hashCards(v []*card.Card) string { |
|
bs, err := json.Marshal(v) |
|
if err != nil { |
|
log.Error("json.Marshal error(%v)", err) |
|
return "" |
|
} |
|
return strconv.FormatUint(farm.Hash64(bs), 10) |
|
}
|
|
|