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

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