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

711 lines
18 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 view
import (
"context"
"crypto/md5"
"encoding/hex"
"net/url"
"strconv"
"strings"
"time"
cdm "go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-view/model"
"go-common/app/interface/main/app-view/model/creative"
"go-common/app/interface/main/app-view/model/view"
account "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
location "go-common/app/service/main/location/model"
relation "go-common/app/service/main/relation/model"
resource "go-common/app/service/main/resource/model"
sharerpc "go-common/app/service/main/share/api"
thumbuppb "go-common/app/service/main/thumbup/api"
thumbup "go-common/app/service/main/thumbup/model"
"go-common/library/conf/env"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
egV2 "go-common/library/sync/errgroup.v2"
"github.com/pkg/errors"
)
const (
_descLen = 250
_promptCoin = 1
_promptFav = 2
_avTypeAv = 1
_businessLike = "archive"
_coinAv = 1
)
// View all view data.
func (s *Service) View(c context.Context, mid, aid, movieID int64, plat int8, build, qn, fnver, fnval, forceHost, parentMode int, ak, mobiApp, device, buvid, cdnIP, network, adExtra, from string, now time.Time) (v *view.View, err error) {
if v, err = s.ViewPage(c, mid, aid, movieID, plat, build, ak, mobiApp, device, cdnIP, true, now); err != nil {
ip := metadata.String(c, metadata.RemoteIP)
if err == ecode.AccessDenied || err == ecode.NothingFound {
log.Warn("s.ViewPage() mid(%d) aid(%d) movieID(%d) plat(%d) ak(%s) ip(%s) cdn_ip(%s) error(%v)", mid, aid, movieID, plat, ak, ip, cdnIP, err)
} else {
log.Error("s.ViewPage() mid(%d) aid(%d) movieID(%d) plat(%d) ak(%s) ip(%s) cdn_ip(%s) error(%v)", mid, aid, movieID, plat, ak, ip, cdnIP, err)
}
return
}
g, ctx := errgroup.WithContext(c)
g.Go(func() (err error) {
v.VIPActive = s.vipActiveCache[view.VIPActiveView]
return
})
g.Go(func() (err error) {
s.initReqUser(ctx, v, mid, plat, build)
if v.AttrVal(archive.AttrBitIsPGC) != archive.AttrYes {
s.initContributions(ctx, v)
}
return
})
g.Go(func() (err error) {
s.initRelateCMTag(ctx, v, plat, build, qn, fnver, fnval, forceHost, parentMode, mid, buvid, mobiApp, device, network, adExtra, from, now)
return
})
if v.AttrVal(archive.AttrBitIsPGC) != archive.AttrYes {
g.Go(func() (err error) {
s.initDM(ctx, v)
return
})
g.Go(func() (err error) {
s.initAudios(ctx, v)
return
})
g.Go(func() (err error) {
if model.IsIPhoneB(plat) || (model.IsIPhone(plat) && (build >= 7000 && build <= 8000)) {
return
}
s.initElec(ctx, v, mid)
return
})
if len([]rune(v.Desc)) > _descLen {
g.Go(func() (err error) {
if desc, _ := s.arcDao.Description(ctx, v.Aid); desc != "" {
v.Desc = desc
}
return
})
}
}
if v.AttrVal(archive.AttrBitHasBGM) == archive.AttrYes {
g.Go(func() (err error) {
if v.Bgm, err = s.creativeDao.Bgm(ctx, v.Aid, v.FirstCid); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
}
return
}
// ViewPage view page data.
func (s *Service) ViewPage(c context.Context, mid, aid, movieID int64, plat int8, build int, ak, mobiApp, device, cdnIP string, nMovie bool, now time.Time) (v *view.View, err error) {
if aid == 0 && movieID == 0 {
err = ecode.NothingFound
return
}
const (
_androidMovie = 5220000
_iPhoneMovie = 6500
_iPadMovie = 6720
_iPadHDMovie = 12020
)
var (
vs *view.ViewStatic
vp *archive.View3
seasoninfo map[int64]int64
ok bool
)
if movieID != 0 {
if seasoninfo, err = s.banDao.SeasonidAid(c, movieID, now); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
if aid, ok = seasoninfo[movieID]; !ok || aid == 0 {
err = ecode.NothingFound
return
}
var a *api.Arc
if a, err = s.arcDao.Archive3(c, aid); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
if a == nil {
err = ecode.NothingFound
return
}
vs = &view.ViewStatic{Archive3: archive.BuildArchive3(a)}
s.prom.Incr("from_movieID")
} else {
if vp, err = s.arcDao.ViewCache(c, aid); err != nil {
log.Error("%+v", err)
}
if vp == nil || vp.Archive3 == nil || len(vp.Pages) == 0 || vp.AttrVal(archive.AttrBitIsMovie) == archive.AttrYes {
if vp, err = s.arcDao.View3(c, aid); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
}
if vp == nil || vp.Archive3 == nil || len(vp.Pages) == 0 {
err = ecode.NothingFound
return
}
vs = &view.ViewStatic{Archive3: vp.Archive3}
s.initPages(c, vs, vp.Pages)
s.prom.Incr("from_aid")
}
if _, ok := s.specialMids[vs.Author.Mid]; ok && env.DeployEnv == env.DeployEnvProd {
err = ecode.NothingFound
log.Error("aid(%d) mid(%d) can not view on prod", vs.Aid, vs.Author.Mid)
return
}
// TODO 产品最帅了!
vs.Stat.DisLike = 0
if s.overseaCheck(vs.Archive3, plat) {
err = ecode.AreaLimit
return
}
// check region area limit
if err = s.areaLimit(c, plat, int(vs.TypeID)); err != nil {
return
}
v = &view.View{ViewStatic: vs, DMSeg: 1, PlayerIcon: s.playerIcon}
if v.AttrVal(archive.AttrBitIsPGC) != archive.AttrYes {
// check access
if err = s.checkAceess(c, mid, v.Aid, int(v.State), int(v.Access), ak); err != nil {
// archive is ForbitFixed and Transcoding and StateForbitDistributing need analysis history body .
if v.State != archive.StateForbidFixed {
return
}
err = nil
}
if v.Access > 0 {
v.Stat.View = 0
}
}
g, ctx := errgroup.WithContext(c)
if mid != 0 {
g.Go(func() (err error) {
v.History, _ = s.arcDao.Progress(ctx, v.Aid, mid)
return
})
}
if v.AttrVal(archive.AttrBitIsPGC) == archive.AttrYes {
if (v.AttrVal(archive.AttrBitIsMovie) != archive.AttrYes) || (plat == model.PlatAndroid && build >= _androidMovie) || (plat == model.PlatIPhone && build >= _iPhoneMovie) || (plat == model.PlatIPad && build >= _iPadMovie) ||
(plat == model.PlatIpadHD && build > _iPadHDMovie) || plat == model.PlatAndroidTVYST || plat == model.PlatAndroidTV || plat == model.PlatAndroidI || plat == model.PlatIPhoneB {
g.Go(func() error {
return s.initPGC(ctx, v, mid, build, mobiApp, device)
})
} else {
g.Go(func() error {
return s.initMovie(ctx, v, mid, build, mobiApp, device, nMovie)
})
}
} else {
g.Go(func() (err error) {
if err = s.initDownload(ctx, v, mid, cdnIP); err != nil {
ip := metadata.String(ctx, metadata.RemoteIP)
log.Error("aid(%d) mid(%d) ip(%s) cdn_ip(%s) error(%+v)", v.Aid, mid, ip, cdnIP, err)
}
return
})
if v.Rights.UGCPay == 1 && mid != v.Author.Mid {
g.Go(func() (err error) {
if err = s.initUGCPay(ctx, v, plat, mid); err != nil {
log.Error("%+v", err)
err = nil
return
}
return nil
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
}
if v.Rights.UGCPay == 1 {
if (v.Asset == nil || v.Asset.Paid == 0) && mid != v.Author.Mid {
v.Rights.Download = int32(location.ForbiddenDown)
}
}
return
}
// AddShare add a share
func (s *Service) AddShare(c context.Context, aid, mid int64, ip string) (share int, isReport bool, upID int64, err error) {
var a *api.Arc
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
upID = a.Author.Mid
shareReply, err := s.shareClient.AddShare(context.Background(), &sharerpc.AddShareRequest{
Oid: aid,
Mid: mid,
Type: 3,
Ip: ip,
})
if err != nil {
if ecode.Cause(err).Equal(ecode.ShareAlreadyAdd) {
err = nil
return
}
log.Error("s.shareClient.AddShare(%d, %d, 3) error(%v)", aid, mid, err)
return
}
if shareReply != nil && shareReply.Shares > int64(a.Stat.Share) {
isReport = true
}
return
}
// Shot shot service
func (s *Service) Shot(c context.Context, aid, cid int64) (shot *view.Videoshot, err error) {
var (
arcShot *archive.Videoshot
points []*creative.Points
)
shot = new(view.Videoshot)
if arcShot, err = s.arcDao.Shot(c, aid, cid); err != nil {
log.Error("%+v", err)
return
}
if arcShot == nil {
return
}
shot.Videoshot = arcShot
a := &api.Arc{Attribute: arcShot.Attr}
if a.AttrVal(archive.AttrBitHasViewpoint) == archive.AttrYes {
if points, err = s.creativeDao.Points(c, aid, cid); err != nil {
log.Error("%+v", err)
err = nil
}
shot.Points = points
}
return
}
// Like add a like.
func (s *Service) Like(c context.Context, aid, mid int64, status int8) (upperID int64, toast string, err error) {
var (
a *api.Arc
typ int8
stat *thumbuppb.LikeReply
)
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
upperID = a.Author.Mid
if status == 0 {
typ = thumbup.TypeLike
} else if status == 1 {
typ = thumbup.TypeCancelLike
}
if stat, err = s.thumbupDao.Like(c, mid, upperID, _businessLike, a.Aid, typ); err != nil {
if ecode.EqualError(ecode.ThumbupDupLikeErr, err) {
log.Error("%+v", err)
err = nil
toast = "点赞收到!视频可能推荐哦"
}
return
}
if typ == thumbup.TypeLike {
if stat.LikeNumber < 100 {
toast = "点赞收到!视频可能推荐哦"
} else if stat.LikeNumber >= 100 && stat.LikeNumber < 1000 {
toast = "感谢点赞,推荐已收到啦"
} else if stat.LikeNumber >= 1000 && stat.LikeNumber < 10000 {
toast = "get视频也许更多人能看见"
} else {
toast = "点赞爆棚,感谢推荐!"
}
}
return
}
// Dislike add a dislike.
func (s *Service) Dislike(c context.Context, aid, mid int64, status int8) (upperID int64, err error) {
var (
a *api.Arc
typ int8
)
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
upperID = a.Author.Mid
if status == 0 {
typ = thumbup.TypeDislike
} else if status == 1 {
typ = thumbup.TypeCancelDislike
}
_, err = s.thumbupDao.Like(c, mid, upperID, _businessLike, a.Aid, typ)
return
}
// AddCoin add a coin
func (s *Service) AddCoin(c context.Context, aid, mid, upID, avtype, multiply int64, ak string, selectLike int) (prompt, like bool, err error) {
var maxCoin int64 = 2
var typeID int16
var pubTime int64
if avtype == _avTypeAv {
var a *api.Arc
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
if a.Copyright == int32(archive.CopyrightCopy) {
maxCoin = 1
}
upID = a.Author.Mid
typeID = int16(a.TypeID)
pubTime = int64(a.PubDate)
}
if err = s.coinDao.AddCoins(c, aid, mid, upID, maxCoin, avtype, multiply, typeID, pubTime); err != nil {
return
}
eg, ctx := errgroup.WithContext(c)
eg.Go(func() (err error) {
if avtype == _avTypeAv && selectLike == 1 {
if _, err = s.thumbupDao.Like(ctx, mid, upID, _businessLike, aid, thumbup.TypeLike); err != nil {
log.Error("%+v", err)
err = nil
} else {
like = true
}
}
return
})
eg.Go(func() (err error) {
if prompt, err = s.relDao.Prompt(ctx, mid, upID, _promptCoin); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
eg.Wait()
return
}
// AddFav add a favorite
func (s *Service) AddFav(c context.Context, mid, vmid int64, fids []int64, aid int64, ak string) (prompt bool, err error) {
var a *api.Arc
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
if err = s.favDao.AddVideo(c, mid, fids, aid, ak); err != nil {
return
}
if prompt, err = s.relDao.Prompt(c, mid, vmid, _promptFav); err != nil {
log.Error("%+v", err)
err = nil
}
return
}
// Paster get paster if nologin.
func (s *Service) Paster(c context.Context, plat, adType int8, aid, typeID, buvid string) (p *resource.Paster, err error) {
if p, err = s.rscDao.Paster(c, plat, adType, aid, typeID, buvid); err != nil {
log.Error("%+v", err)
}
return
}
// VipPlayURL get playurl token.
func (s *Service) VipPlayURL(c context.Context, aid, cid, mid int64) (res *view.VipPlayURL, err error) {
var (
a *api.Arc
card *account.Card
)
res = &view.VipPlayURL{
From: "app",
Ts: time.Now().Unix(),
Aid: aid,
Cid: cid,
Mid: mid,
}
if card, err = s.accDao.Card3(c, mid); err != nil {
log.Error("%+v", err)
err = ecode.AccessDenied
return
}
if res.VIP = int(card.Level); res.VIP > 6 {
res.VIP = 6
}
if card.Vip.Type != 0 && card.Vip.Status == 1 {
res.SVIP = 1
}
if a, err = s.arcDao.Archive(c, aid); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
if mid == a.Author.Mid {
res.Owner = 1
}
params := url.Values{}
params.Set("from", res.From)
params.Set("ts", strconv.FormatInt(res.Ts, 10))
params.Set("aid", strconv.FormatInt(res.Aid, 10))
params.Set("cid", strconv.FormatInt(res.Cid, 10))
params.Set("mid", strconv.FormatInt(res.Mid, 10))
params.Set("vip", strconv.Itoa(res.VIP))
params.Set("svip", strconv.Itoa(res.SVIP))
params.Set("owner", strconv.Itoa(res.Owner))
tmp := params.Encode()
if strings.IndexByte(tmp, '+') > -1 {
tmp = strings.Replace(tmp, "+", "%20", -1)
}
mh := md5.Sum([]byte(strings.ToLower(tmp) + s.c.PlayURL.Secret))
res.Fcs = hex.EncodeToString(mh[:])
return
}
// Follow get auto follow switch from creative and acc.
func (s *Service) Follow(c context.Context, vmid, mid int64) (res *creative.PlayerFollow, err error) {
var (
fl bool
profile *relation.Stat
fs *creative.FollowSwitch
)
g, ctx := errgroup.WithContext(c)
g.Go(func() (err error) {
profile, err = s.relDao.Stat(ctx, vmid)
if err != nil {
log.Error("%+v", err)
}
return
})
if mid > 0 {
g.Go(func() (err error) {
fl, err = s.accDao.Following3(ctx, mid, vmid)
if err != nil {
log.Error("%+v", err)
}
return
})
}
g.Go(func() (err error) {
fs, err = s.creativeDao.FollowSwitch(ctx, vmid)
if err != nil {
log.Error("%+v", err)
}
return
})
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
res = &creative.PlayerFollow{}
if profile.Follower >= s.c.AutoLimit && fs.State == 1 && !fl {
res.Show = true
}
return
}
// UpperRecmd is
func (s *Service) UpperRecmd(c context.Context, plat int8, platform, mobiApp, device, buvid string, build int, mid, vimd int64) (res card.Handler, err error) {
var (
upIDs []int64
follow *operate.Card
cardm map[int64]*account.Card
statm map[int64]*relation.Stat
isAtten map[int64]int8
)
if follow, err = s.searchFollow(c, platform, mobiApp, device, buvid, build, mid, vimd); err != nil {
log.Error("%+v", err)
return
}
if follow == nil {
err = ecode.AppNotData
log.Error("follow is nil")
return
}
for _, item := range follow.Items {
upIDs = append(upIDs, item.ID)
}
g, ctx := errgroup.WithContext(c)
if len(upIDs) != 0 {
g.Go(func() (err error) {
if cardm, err = s.accDao.Cards3(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if statm, err = s.relDao.Stats(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if mid != 0 {
g.Go(func() error {
isAtten = s.accDao.IsAttention(ctx, upIDs, mid)
return nil
})
}
}
g.Wait()
op := &operate.Card{}
op.From(cdm.CardGt(model.GotoSearchUpper), 0, 0, plat, build)
h := card.Handle(plat, cdm.CardGt(model.GotoSearchUpper), "", cdm.ColumnSvrSingle, nil, nil, isAtten, statm, cardm)
if h == nil {
err = ecode.AppNotData
return
}
op = follow
h.From(nil, op)
if h.Get().Right {
res = h
} else {
err = ecode.AppNotData
}
return
}
// LikeTriple like & coin & fav
func (s *Service) LikeTriple(c context.Context, aid, mid int64, ak string) (res *view.TripleRes, err error) {
res = new(view.TripleRes)
maxCoin := int64(1)
multiply := int64(1)
var a *api.Arc
if a, err = s.arcDao.Archive(c, aid); err != nil {
if errors.Cause(err) == ecode.NothingFound {
err = ecode.ArchiveNotExist
}
return
}
if !a.IsNormal() {
err = ecode.ArchiveNotExist
return
}
if a.Copyright == int32(archive.CopyrightOriginal) {
maxCoin = 2
multiply = 2
}
res.UpID = a.Author.Mid
eg := egV2.WithContext(c)
eg.Go(func(ctx context.Context) (err error) {
if multiply == 2 {
userCoins, _ := s.coinDao.UserCoins(ctx, mid)
if userCoins < 1 {
return
}
if userCoins < 2 {
multiply = 1
}
}
err = s.coinDao.AddCoins(ctx, aid, mid, a.Author.Mid, maxCoin, _coinAv, multiply, int16(a.TypeID), int64(a.PubDate))
if err == nil || ecode.EqualError(ecode.CoinOverMax, err) {
res.Multiply = multiply
res.Anticheat = true
res.Coin = true
err = nil
} else {
log.Error("s.coinDao.AddCoins err(%+v) aid(%d) mid(%d)", err, aid, mid)
err = nil
arcUserCoins, _ := s.coinDao.ArchiveUserCoins(ctx, aid, mid, _coinAv)
if arcUserCoins != nil && arcUserCoins.Multiply > 0 {
res.Coin = true
}
}
return
})
eg.Go(func(ctx context.Context) (err error) {
var isFav bool
if isFav, err = s.favDao.IsFavVideo(ctx, mid, aid); err != nil {
log.Error("s.favDao.IsFavVideo err(%+v) aid(%d) mid(%d)", err, aid, mid)
err = nil
} else if isFav {
res.Fav = true
return
}
if err = s.favDao.AddFav(ctx, mid, aid); err != nil {
log.Error("s.favDao.AddFav err(%+v) aid(%d) mid(%d)", err, aid, mid)
if ecode.EqualError(ecode.FavVideoExist, err) || ecode.EqualError(ecode.FavResourceExist, err) {
res.Fav = true
}
err = nil
} else {
res.Fav = true
res.Anticheat = true
}
return
})
eg.Go(func(ctx context.Context) (err error) {
if _, err = s.thumbupDao.Like(ctx, mid, res.UpID, _businessLike, aid, thumbup.TypeLike); err != nil {
log.Error("s.thumbupDao.Like err(%+v) aid(%d) mid(%d)", err, aid, mid)
if ecode.EqualError(ecode.ThumbupDupLikeErr, err) {
res.Like = true
}
err = nil
} else {
res.Like = true
res.Anticheat = true
}
return
})
eg.Go(func(ctx context.Context) (err error) {
if res.Prompt, err = s.relDao.Prompt(ctx, mid, a.Author.Mid, _promptFav); err != nil {
log.Error("s.relDao.Prompt err(%+v)", err)
err = nil
}
return
})
eg.Wait()
if !res.Coin && !res.Fav {
res.Prompt = false
}
return
}