go-common/app/interface/bbq/app-bbq/service/sv.go

351 lines
8.7 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
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)
}