123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- package service
- import (
- "context"
- "fmt"
- "go-common/app/service/bbq/common"
- "go-common/library/conf/env"
- "go-common/library/ecode"
- "time"
- "go-common/app/interface/bbq/app-bbq/api/http/v1"
- "go-common/app/interface/bbq/app-bbq/model"
- "go-common/app/interface/bbq/app-bbq/model/grpc"
- rec "go-common/app/service/bbq/recsys/api/grpc/v1"
- user "go-common/app/service/bbq/user/api"
- video "go-common/app/service/bbq/video/api/grpc/v1"
- "go-common/library/log"
- "go-common/library/net/trace"
- )
- // SvList 短视屏推荐列表
- func (s *Service) SvList(c context.Context, pageSize int64, mid int64, base *v1.Base, deviceID string) (res []*v1.VideoResponse, err error) {
- var (
- svids []int64
- svRes map[int64]*v1.VideoResponse
- )
- res = make([]*v1.VideoResponse, 0)
- //推荐列表
- svids, err = s.dao.RawRecList(c, pageSize, mid, base.BUVID)
- if err != nil || len(svids) == 0 || env.DeployEnv == env.DeployEnvUat {
- log.Warnv(c, log.KV("log", fmt.Sprintf("s.dao.GetList err[%v]", err)))
- // 降级
- svids, _ = s.dao.GetList(c, pageSize)
- }
- svRes, err = s.svInfos(c, svids, mid, false)
- for _, id := range svids {
- if sv, ok := svRes[id]; ok {
- if common.IsRecommendSvStateAvailable(int64(sv.State)) {
- res = append(res, sv)
- } else {
- log.Warnw(c, "log", "get error svid in recommend list", "svid", id, "mid", mid, "sv", sv)
- }
- }
- }
- return
- }
- // svPlays 批量获取playurl(相对地址方法)
- func (s *Service) svPlays(c context.Context, svids []int64) map[int64]*v1.VideoPlay {
- var (
- relAddr []string
- err error
- bvcUrls map[string]*grpc.VideoKeyItem
- bvcKeys map[int64][]*model.SVBvcKey
- )
- playMap := make(map[int64]*v1.VideoPlay)
- bvcKeys, err = s.dao.RawSVBvcKey(c, svids)
- if err != nil {
- log.Error("s.dao.RawSVBvcKey err[%v]", err)
- }
- for id, keys := range bvcKeys {
- playMap[id] = &v1.VideoPlay{
- SVID: id,
- }
- for k, v := range keys {
- if k == 0 {
- playMap[id].Quality = int64(v.CodeRate)
- }
- fi := &v1.FileInfo{
- TimeLength: v.Duration,
- FileSize: v.FileSize,
- Path: v.Path,
- }
- playMap[id].FileInfo = append(playMap[id].FileInfo, fi)
- playMap[id].SupportQuality = append(playMap[id].SupportQuality, int64(v.CodeRate))
- relAddr = append(relAddr, v.Path)
- }
- }
- bvcUrls, err = s.dao.RelPlayURLs(c, relAddr)
- if err != nil {
- log.Error("s.dao.RelPlayURLs err[%v]", err)
- }
- //拼装playurl
- for _, svid := range svids {
- if play, ok := playMap[svid]; ok {
- for fk, f := range play.FileInfo {
- if urls, ok := bvcUrls[f.Path]; ok {
- playMap[svid].ExpireTime = int64(urls.Etime)
- playMap[svid].CurrentTime = time.Now().Unix()
- for _, u := range urls.URL {
- if playMap[svid].FileInfo[fk].URL == "" {
- playMap[svid].FileInfo[fk].URL = u
- if playMap[svid].URL == "" {
- playMap[svid].URL = u
- }
- continue
- }
- if playMap[svid].FileInfo[fk].URLBc == "" {
- playMap[svid].FileInfo[fk].URLBc = u
- break
- }
- }
- } else {
- delete(playMap, svid)
- break
- }
- }
- playMap[svid] = play
- }
- }
- return playMap
- }
- // SvStatistics 视频统计服务
- func (s *Service) SvStatistics(c context.Context, mid int64, svids []int64) (res []*v1.SvStatRes, err error) {
- var (
- stMap map[int64]*model.SvStInfo
- ulike map[int64]bool
- upIDs []int64
- )
- svInfos, _ := s.dao.RawVideos(c, svids)
- for _, sv := range svInfos {
- upIDs = append(upIDs, sv.MID)
- }
- stMap, err = s.dao.RawVideoStatistic(c, svids)
- if err != nil {
- log.Error("s.dao.RawVideoStatistic err[%v]", err)
- }
- //点赞状态
- ulike, err = s.dao.CheckUserLike(c, mid, svids)
- if err != nil {
- log.Error("s.dao.CheckUserLike err[%v]", err)
- }
- uflw, _ := s.dao.BatchUserInfo(c, mid, upIDs, false, false, true)
- if err != nil {
- log.Error("s.dao.IsFollow err[%v]", err)
- }
- for _, id := range svids {
- rp := &v1.SvStatRes{}
- rp.SVID = id
- if st, ok := stMap[id]; ok {
- rp.Like = st.Like
- rp.Share = st.Share
- rp.Play = st.Play
- rp.Subtitles = st.Subtitles
- rp.Reply = st.Reply
- }
- if l, ok := ulike[id]; ok {
- rp.IsLike = l
- }
- if sv, ok := svInfos[id]; ok {
- if f, ok2 := uflw[sv.MID]; ok2 {
- rp.FollowState = f.FollowState
- }
- }
- res = append(res, rp)
- }
- return
- }
- // SvCPlays 批量拉取playurl
- func (s *Service) SvCPlays(c context.Context, svids []int64, mid int64) (res []*v1.VideoPlay, err error) {
- res = make([]*v1.VideoPlay, 0)
- //视频列表
- svRes, err := s.dao.RawVideos(c, svids)
- if err != nil {
- log.Error("s.dao.RawVideos err[%v]", err)
- return
- }
- avaliableSvids := make([]int64, 0)
- for _, v := range svRes {
- if (mid == 0 || v.MID != mid) && common.IsSvStateGuestAvailable(int64(v.State)) {
- avaliableSvids = append(avaliableSvids, v.SVID)
- } else if v.MID == mid && common.IsSvStateOwnerAvailable(int64(v.State)) {
- avaliableSvids = append(avaliableSvids, v.SVID)
- }
- }
- playMap := s.svPlays(c, avaliableSvids)
- for _, svid := range avaliableSvids {
- var play *v1.VideoPlay
- if p, ok := playMap[svid]; !ok {
- log.Warn("play不存在 svid[%d]", svid)
- continue
- } else {
- play = p
- }
- res = append(res, play)
- }
- return
- }
- // SvDetail 单条sv的视频详情,暂时只用于评论中转页
- func (s *Service) SvDetail(c context.Context, svid int64, mid int64) (res *v1.VideoResponse, err error) {
- _, err = s.dao.VideoBase(c, mid, svid)
- if err != nil {
- return
- }
- svInfos, err := s.svInfos(c, []int64{svid}, mid, true)
- if err != nil {
- return
- }
- if val, exists := svInfos[svid]; exists {
- res = val
- } else {
- err = ecode.VideoUnExists
- log.Infow(c, "log", "not sv info", "svid", svid)
- }
- return
- }
- // svInfos 批量获取视频信息
- // @params allowState 可放出状态,传空为app整体可露出状态
- // @params needStInfo 是否需要视频统计数据
- func (s *Service) svInfos(c context.Context, ids []int64, mid int64, needStInfo bool) (res map[int64]*v1.VideoResponse, err error) {
- var (
- mids []int64
- svRes map[int64]*model.SvInfo
- ulike map[int64]bool
- stMap map[int64]*model.SvStInfo
- )
- res = make(map[int64]*v1.VideoResponse)
- stMap = make(map[int64]*model.SvStInfo)
- //视频列表
- svRes, err = s.dao.RawVideos(c, ids)
- if err != nil {
- log.Error("s.dao.RawVideos err[%v]", err)
- return
- }
- for _, v := range svRes {
- mids = append(mids, v.MID)
- }
- if mid != 0 {
- ulike, err = s.dao.CheckUserLike(c, mid, ids)
- if err != nil {
- log.Error("s.dao.CheckUserLike err[%v]", err)
- }
- }
- // query id
- tracer, _ := trace.FromContext(c)
- queryID := fmt.Sprintf("%s", tracer)
- //账号
- var userMap map[int64]*user.UserBase
- userMap, err = s.dao.JustGetUserBase(c, mids)
- if err != nil {
- log.Error("s.dao.UserBase err[%v]", err)
- }
- // play信息
- playMap := s.svPlays(c, ids)
- if needStInfo {
- stMap, err = s.dao.RawVideoStatistic(c, ids)
- if err != nil {
- log.Error("s.dao.RawVideoStatistic err[%v]", err)
- }
- }
- // extension信息
- extensions, tmpErr := s.getExtension(c, ids)
- if tmpErr != nil {
- log.Warnw(c, "log", "get extension fail")
- }
- for _, v := range svRes {
- if common.IsSvStateAvailable(int64(v.State)) {
- sv := &v1.VideoResponse{}
- if acc, ok := userMap[v.MID]; ok {
- sv.UserInfo = *acc
- }
- if lk, ok := ulike[v.SVID]; ok {
- sv.IsLike = lk
- }
- sv.SVID = v.SVID
- sv.Title = v.Title
- sv.Content = v.Content
- sv.MID = v.MID
- sv.Duration = v.Duration
- sv.Pubtime = v.Pubtime
- sv.Ctime = v.Ctime
- sv.AVID = v.AVID
- sv.CID = v.CID
- sv.From = v.From
- sv.CoverURL = v.CoverURL
- sv.CoverHeight = v.CoverHeight
- sv.CoverWidth = v.CoverWidth
- sv.QueryID = queryID
- sv.State = v.State
- if play, ok := playMap[v.SVID]; ok {
- sv.Play = *play
- res[v.SVID] = sv
- } else {
- log.Warn("play不存在 svid[%d],此条记录直接舍弃", v.SVID)
- }
- if st, ok := stMap[v.SVID]; ok {
- sv.SvStInfo = *st
- }
- if extension, exists := extensions[v.SVID]; exists {
- sv.Extension = extension.Extension
- }
- res[v.SVID] = sv
- }
- }
- return
- }
- // SvRelRec 相关推荐服务
- func (s *Service) SvRelRec(c context.Context, data *v1.SvRelReq) (res map[string]interface{}, err error) {
- res = make(map[string]interface{})
- var svMap map[int64]*v1.VideoResponse
- list := make([]*v1.VideoResponse, 0)
- relReq := &rec.RecsysRequest{
- SVID: data.SVID,
- Offset: data.Offset,
- Limit: data.Limit,
- QueryID: data.QueryID,
- App: data.APP,
- AppVersion: data.APPVersion,
- BUVID: data.BUVID,
- MID: data.MID,
- }
- IDList, err := s.dao.RelRecList(c, relReq)
- if err != nil {
- err = nil
- return
- }
- svMap, err = s.svInfos(c, IDList, data.MID, false)
- if err != nil {
- err = nil
- return
- }
- for _, id := range IDList {
- if sv, ok := svMap[id]; ok {
- list = append(list, sv)
- }
- }
- res["list"] = list
- return
- }
- // SvDel 视频删除
- func (s *Service) SvDel(c context.Context, in *video.VideoDeleteRequest) (interface{}, error) {
- return s.dao.SvDel(c, in)
- }
|