465 lines
10 KiB
Go
465 lines
10 KiB
Go
|
package service
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sort"
|
||
|
"time"
|
||
|
|
||
|
"go-common/app/interface/main/history/model"
|
||
|
arcmdl "go-common/app/service/main/archive/model/archive"
|
||
|
"go-common/library/ecode"
|
||
|
"go-common/library/log"
|
||
|
)
|
||
|
|
||
|
const maxToView = 100
|
||
|
|
||
|
var (
|
||
|
_empToView = []*model.ToView{}
|
||
|
_empArcToView = []*model.ArcToView{}
|
||
|
_empWebArcToView = []*model.WebArcToView{}
|
||
|
)
|
||
|
|
||
|
// AddToView add the user a toview item.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) AddToView(c context.Context, mid, aid int64, ip string) (err error) {
|
||
|
var (
|
||
|
ok bool
|
||
|
count int
|
||
|
arc *arcmdl.View3
|
||
|
now = time.Now().Unix()
|
||
|
)
|
||
|
arcAid := &arcmdl.ArgAid2{Aid: aid}
|
||
|
if arc, err = s.arcRPC.View3(c, arcAid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if arc == nil {
|
||
|
return
|
||
|
}
|
||
|
if arc.Rights.UGCPay == 1 {
|
||
|
return ecode.ToViewPayUGC
|
||
|
}
|
||
|
if ok, err = s.toviewDao.Expire(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if ok {
|
||
|
if count, err = s.toviewDao.CntCache(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
if _, count, err = s.toView(c, mid, 1, maxToView, ip); err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
if count >= maxToView {
|
||
|
err = ecode.ToViewOverMax
|
||
|
return
|
||
|
}
|
||
|
if err = s.toviewDao.Add(c, mid, aid, now); err != nil {
|
||
|
return
|
||
|
}
|
||
|
s.toviewCache.Do(c, func(ctx context.Context) {
|
||
|
if errCache := s.toviewDao.AddCache(ctx, mid, aid, now); errCache != nil {
|
||
|
log.Warn("s.toviewDao.AddCache(%d,%d,%d) err:%v", mid, aid, now, errCache)
|
||
|
}
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// AddMultiToView add toview items to user.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) AddMultiToView(c context.Context, mid int64, aids []int64, ip string) (err error) {
|
||
|
var (
|
||
|
ok bool
|
||
|
count int
|
||
|
expectedAids []int64
|
||
|
arcs map[int64]*arcmdl.View3
|
||
|
viewMap map[int64]*model.ToView
|
||
|
views []*model.ToView
|
||
|
now = time.Now().Unix()
|
||
|
)
|
||
|
arcAids := &arcmdl.ArgAids2{Aids: aids}
|
||
|
if arcs, err = s.arcRPC.Views3(c, arcAids); err != nil {
|
||
|
return
|
||
|
} else if len(arcs) == 0 {
|
||
|
return
|
||
|
}
|
||
|
for _, v := range arcs {
|
||
|
if v.Rights.UGCPay == 1 {
|
||
|
return ecode.ToViewPayUGC
|
||
|
}
|
||
|
}
|
||
|
if ok, err = s.toviewDao.Expire(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if ok {
|
||
|
if viewMap, err = s.toviewDao.CacheMap(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
var list []*model.ToView
|
||
|
list, _, err = s.toView(c, mid, 1, maxToView, ip)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
viewMap = make(map[int64]*model.ToView)
|
||
|
for _, v := range list {
|
||
|
if v == nil {
|
||
|
continue
|
||
|
}
|
||
|
viewMap[v.Aid] = v
|
||
|
}
|
||
|
}
|
||
|
count = len(viewMap)
|
||
|
if count >= maxToView {
|
||
|
err = ecode.ToViewOverMax
|
||
|
return
|
||
|
}
|
||
|
expectedLen := maxToView - count
|
||
|
for _, aid := range aids {
|
||
|
if _, exist := viewMap[aid]; !exist {
|
||
|
expectedAids = append(expectedAids, aid)
|
||
|
expectedLen--
|
||
|
if expectedLen == 0 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if err = s.toviewDao.Adds(c, mid, expectedAids, now); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if ok {
|
||
|
s.toviewCache.Do(c, func(ctx context.Context) {
|
||
|
for _, aid := range expectedAids {
|
||
|
views = append(views, &model.ToView{Aid: aid, Unix: now})
|
||
|
}
|
||
|
if errCache := s.toviewDao.AddCacheList(ctx, mid, views); errCache != nil {
|
||
|
log.Warn("s.toviewDao.AddCacheList(%d,%v) err:%v", mid, views, errCache)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// RemainingToView add toview items to user.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) RemainingToView(c context.Context, mid int64, ip string) (remaining int, err error) {
|
||
|
var (
|
||
|
count int
|
||
|
)
|
||
|
if _, count, err = s.toView(c, mid, 1, maxToView, ip); err != nil {
|
||
|
return
|
||
|
}
|
||
|
remaining = maxToView - count
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ClearToView clear the user toview items.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) ClearToView(c context.Context, mid int64) (err error) {
|
||
|
if err = s.toviewDao.ClearCache(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
s.userActionLog(mid, model.ToviewClear)
|
||
|
return s.toviewDao.Clear(c, mid)
|
||
|
}
|
||
|
|
||
|
// DelToView delete the user to videos.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) DelToView(c context.Context, mid int64, aids []int64, viewed bool, ip string) (err error) {
|
||
|
var (
|
||
|
delAids []int64
|
||
|
list []*model.ToView
|
||
|
rhs, hs map[int64]*model.History
|
||
|
rs *model.History
|
||
|
)
|
||
|
// viewed del all viewed
|
||
|
if viewed {
|
||
|
if list, _, err = s.toView(c, mid, 1, maxToView, ip); err != nil {
|
||
|
return
|
||
|
}
|
||
|
for _, l := range list {
|
||
|
aids = append(aids, l.Aid)
|
||
|
}
|
||
|
if len(aids) == 0 {
|
||
|
return
|
||
|
}
|
||
|
if hs, err = s.historyDao.AidsMap(c, mid, aids); err != nil {
|
||
|
return
|
||
|
}
|
||
|
rhs, _ = s.historyDao.CacheMap(c, mid)
|
||
|
for _, rs = range rhs {
|
||
|
hs[rs.Aid] = rs
|
||
|
}
|
||
|
for k, v := range hs {
|
||
|
if v.Pro >= 30 || v.Pro == -1 {
|
||
|
delAids = append(delAids, k)
|
||
|
}
|
||
|
}
|
||
|
if len(delAids) == 0 {
|
||
|
return
|
||
|
}
|
||
|
if err = s.toviewDao.Del(c, mid, delAids); err != nil {
|
||
|
return
|
||
|
}
|
||
|
s.toviewCache.Do(c, func(ctx context.Context) {
|
||
|
s.toviewDao.DelCaches(ctx, mid, delAids)
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
if err = s.toviewDao.Del(c, mid, aids); err != nil {
|
||
|
return
|
||
|
}
|
||
|
s.toviewCache.Do(c, func(ctx context.Context) {
|
||
|
s.toviewDao.DelCaches(ctx, mid, aids)
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// WebToView get videos of user view history.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) WebToView(c context.Context, mid int64, pn, ps int, ip string) (res []*model.WebArcToView, count int, err error) {
|
||
|
var (
|
||
|
ok bool
|
||
|
aids, epids []int64
|
||
|
avs map[int64]*arcmdl.View3
|
||
|
views []*model.ToView
|
||
|
v *model.ToView
|
||
|
hm map[int64]*model.History
|
||
|
av *arcmdl.View3
|
||
|
epban = make(map[int64]*model.Bangumi)
|
||
|
seasonMap = make(map[int64]*model.BangumiSeason)
|
||
|
)
|
||
|
if views, count, err = s.toView(c, mid, pn, ps, ip); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(views) == 0 {
|
||
|
return
|
||
|
}
|
||
|
for _, v = range views {
|
||
|
if v != nil {
|
||
|
aids = append(aids, v.Aid)
|
||
|
}
|
||
|
}
|
||
|
argAids := &arcmdl.ArgAids2{Aids: aids}
|
||
|
if avs, err = s.arcRPC.Views3(c, argAids); err != nil {
|
||
|
log.Error("s.arcRPC.Views3(arcAids:(%v), arcs) error(%v)", aids, err)
|
||
|
return
|
||
|
}
|
||
|
if len(avs) == 0 {
|
||
|
return
|
||
|
}
|
||
|
seasonMap, epids = s.season(c, mid, aids, ip)
|
||
|
// bangumi info
|
||
|
if len(epids) > 0 {
|
||
|
epban = s.bangumi(c, mid, epids)
|
||
|
}
|
||
|
if hm, err = s.toViewPro(c, mid, aids); err != nil {
|
||
|
err = nil
|
||
|
}
|
||
|
res = make([]*model.WebArcToView, 0, len(aids))
|
||
|
for _, v = range views {
|
||
|
if v == nil {
|
||
|
count--
|
||
|
continue
|
||
|
}
|
||
|
// NOTE compat android
|
||
|
if av, ok = avs[v.Aid]; !ok || av == nil {
|
||
|
count--
|
||
|
continue
|
||
|
}
|
||
|
// NOTE all no pay
|
||
|
av.Rights.Movie = 0
|
||
|
at := &model.WebArcToView{View3: av}
|
||
|
at.AddTime = v.Unix
|
||
|
if hm[v.Aid] != nil {
|
||
|
at.Cid = hm[v.Aid].Cid
|
||
|
at.Progress = hm[v.Aid].Pro
|
||
|
}
|
||
|
if season, ok := seasonMap[v.Aid]; ok && season != nil {
|
||
|
if bangumi, ok := epban[season.Epid]; ok && bangumi != nil {
|
||
|
at.BangumiInfo = bangumi
|
||
|
}
|
||
|
}
|
||
|
res = append(res, at)
|
||
|
}
|
||
|
if len(res) == 0 {
|
||
|
res = _empWebArcToView
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ToView get videos of user view history.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) ToView(c context.Context, mid int64, pn, ps int, ip string) (res []*model.ArcToView, count int, err error) {
|
||
|
var (
|
||
|
ok bool
|
||
|
aids []int64
|
||
|
avs map[int64]*arcmdl.View3
|
||
|
views []*model.ToView
|
||
|
v *model.ToView
|
||
|
hm map[int64]*model.History
|
||
|
av *arcmdl.View3
|
||
|
)
|
||
|
res = _empArcToView
|
||
|
if views, count, err = s.toView(c, mid, pn, ps, ip); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(views) == 0 {
|
||
|
return
|
||
|
}
|
||
|
for _, v = range views {
|
||
|
if v != nil {
|
||
|
aids = append(aids, v.Aid)
|
||
|
}
|
||
|
}
|
||
|
argAids := &arcmdl.ArgAids2{Aids: aids}
|
||
|
if avs, err = s.arcRPC.Views3(c, argAids); err != nil {
|
||
|
log.Error("s.arcRPC.Views3(%v) error(%v)", aids, err)
|
||
|
return
|
||
|
}
|
||
|
if len(avs) == 0 {
|
||
|
return
|
||
|
}
|
||
|
if hm, err = s.toViewPro(c, mid, aids); err != nil {
|
||
|
err = nil
|
||
|
}
|
||
|
res = make([]*model.ArcToView, 0, len(aids))
|
||
|
for _, v = range views {
|
||
|
if v == nil {
|
||
|
count--
|
||
|
continue
|
||
|
}
|
||
|
// NOTE compat android
|
||
|
if av, ok = avs[v.Aid]; !ok || av.Archive3 == nil {
|
||
|
count--
|
||
|
continue
|
||
|
}
|
||
|
// NOTE all no pay
|
||
|
av.Rights.Movie = 0
|
||
|
at := &model.ArcToView{
|
||
|
Archive3: av.Archive3,
|
||
|
Count: len(av.Pages),
|
||
|
}
|
||
|
at.AddTime = v.Unix
|
||
|
// get cid and progress
|
||
|
if hm[v.Aid] != nil {
|
||
|
at.Cid = hm[v.Aid].Cid
|
||
|
at.Progress = hm[v.Aid].Pro
|
||
|
}
|
||
|
for n, p := range av.Pages {
|
||
|
if p.Cid == at.Cid {
|
||
|
p.Page = int32(n + 1)
|
||
|
at.Page = p
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
res = append(res, at)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// toView return ToSee of After the paging data.
|
||
|
func (s *Service) toView(c context.Context, mid int64, pn, ps int, ip string) (res []*model.ToView, count int, err error) {
|
||
|
var (
|
||
|
ok bool
|
||
|
start = (pn - 1) * ps
|
||
|
end = start + ps - 1
|
||
|
)
|
||
|
if ok, err = s.toviewDao.Expire(c, mid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if ok {
|
||
|
if end > maxToView {
|
||
|
end = maxToView
|
||
|
}
|
||
|
if res, err = s.toviewDao.Cache(c, mid, start, end); err != nil {
|
||
|
return
|
||
|
}
|
||
|
count, err = s.toviewDao.CntCache(c, mid)
|
||
|
if count > maxToView {
|
||
|
count = maxToView
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
var views []*model.ToView
|
||
|
var viewMap = make(map[int64]*model.ToView)
|
||
|
if viewMap, err = s.toviewDao.MapInfo(c, mid, nil); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(viewMap) == 0 {
|
||
|
res = _empToView
|
||
|
return
|
||
|
}
|
||
|
for _, v := range viewMap {
|
||
|
views = append(views, v)
|
||
|
}
|
||
|
sort.Sort(model.ToViews(views))
|
||
|
if count = len(views); count > maxToView {
|
||
|
count = maxToView
|
||
|
views = views[:count]
|
||
|
}
|
||
|
switch {
|
||
|
case count > start && count > end:
|
||
|
res = views[start : end+1]
|
||
|
case count > start && count <= end:
|
||
|
res = views[start:]
|
||
|
default:
|
||
|
res = _empToView
|
||
|
}
|
||
|
s.toviewCache.Do(c, func(ctx context.Context) {
|
||
|
if errCache := s.toviewDao.AddCacheList(ctx, mid, views); errCache != nil {
|
||
|
log.Warn("s.toviewDao.AddCacheList(%d,%v) err:%v", mid, views, errCache)
|
||
|
}
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (s *Service) toViewPro(c context.Context, mid int64, aids []int64) (res map[int64]*model.History, err error) {
|
||
|
var (
|
||
|
miss []int64
|
||
|
hm map[int64]*model.History
|
||
|
)
|
||
|
if res, miss, err = s.historyDao.Cache(c, mid, aids); err != nil {
|
||
|
err = nil
|
||
|
} else if len(res) == len(aids) {
|
||
|
return
|
||
|
}
|
||
|
if len(res) == 0 {
|
||
|
res = make(map[int64]*model.History)
|
||
|
miss = aids
|
||
|
}
|
||
|
if hm, err = s.historyDao.AidsMap(c, mid, miss); err != nil {
|
||
|
err = nil
|
||
|
}
|
||
|
for k, v := range hm {
|
||
|
res[k] = v
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (s *Service) season(c context.Context, mid int64, aids []int64, ip string) (seasonMap map[int64]*model.BangumiSeason, epids []int64) {
|
||
|
var (
|
||
|
n = 50
|
||
|
seasonM = make(map[int64]*model.BangumiSeason, n)
|
||
|
)
|
||
|
seasonMap = make(map[int64]*model.BangumiSeason, n)
|
||
|
for len(aids) > 0 {
|
||
|
if n > len(aids) {
|
||
|
n = len(aids)
|
||
|
}
|
||
|
seasonM, _ = s.historyDao.BangumisByAids(c, mid, aids[:n], ip)
|
||
|
aids = aids[n:]
|
||
|
for k, v := range seasonM {
|
||
|
epids = append(epids, v.Epid)
|
||
|
seasonMap[k] = v
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ManagerToView manager get mid toview list.
|
||
|
// +wd:ignore
|
||
|
func (s *Service) ManagerToView(c context.Context, mid int64, ip string) ([]*model.ToView, error) {
|
||
|
return s.toviewDao.ListInfo(c, mid, nil)
|
||
|
}
|