go-common/app/interface/bbq/app-bbq/service/sv.go
2019-04-22 18:49:16 +08:00

351 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}