You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
464 lines
10 KiB
464 lines
10 KiB
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) |
|
}
|
|
|