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 }