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.
606 lines
16 KiB
606 lines
16 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"html/template" |
|
"math" |
|
|
|
musicmdl "go-common/app/interface/main/favorite/model" |
|
"go-common/app/service/main/archive/api" |
|
pb "go-common/app/service/main/favorite/api" |
|
"go-common/app/service/main/favorite/model" |
|
"go-common/library/ecode" |
|
"go-common/library/log" |
|
"go-common/library/net/metadata" |
|
) |
|
|
|
var ( |
|
_emptyArchives = []*model.FavArchive{} |
|
_emptyVideoFolders = []*model.VideoFolder{} |
|
) |
|
|
|
// newCovers get three cover of each fid |
|
func (s *Service) newCovers(c context.Context, mid int64, recents map[int64][]*model.Resource) (fcvs map[int64][]*model.Cover, err error) { |
|
var ( |
|
fids, misFids []int64 |
|
) |
|
for fid := range recents { |
|
fids = append(fids, fid) |
|
} |
|
if fcvs, misFids, err = s.videoDao.NewCoversCache(c, mid, fids); err != nil { |
|
log.Error("s.videoDao.NewCoversCache(fids %v) err(%v)", fids, err) |
|
return |
|
} |
|
// get miss cover from db |
|
if len(misFids) > 0 { |
|
var ( |
|
allAids []int64 |
|
allMids []int64 |
|
as map[int64]*api.Arc |
|
ms map[int64]*musicmdl.Music |
|
) |
|
for _, fid := range misFids { |
|
if resources, ok := recents[fid]; ok { |
|
for _, res := range resources { |
|
if int8(res.Typ) == model.TypeVideo { |
|
allAids = append(allAids, res.Oid) |
|
} else { |
|
allMids = append(allMids, res.Oid) |
|
} |
|
} |
|
} |
|
} |
|
if len(allAids) > 0 { |
|
if as, err = s.arcsRPC(c, allAids); err != nil { |
|
log.Error("s.arcsRPC(aids %v),err(%v)", allAids, err) |
|
return |
|
} |
|
} |
|
if len(allMids) > 0 { |
|
if ms, err = s.musicDao.MusicMap(c, allMids); err != nil { |
|
log.Error("s.musicMap(allMids %v),err(%v)", allMids, err) |
|
return |
|
} |
|
} |
|
// set miss fid's cover |
|
for _, misFid := range misFids { |
|
fid := misFid |
|
cvs := make([]*model.Cover, 0) |
|
for _, res := range recents[fid] { |
|
cv := &model.Cover{} |
|
cv.Aid = res.Oid |
|
cv.Type = res.Typ |
|
if int8(res.Typ) == model.TypeVideo { |
|
if arc, ok := as[res.Oid]; ok { |
|
if !arc.IsNormal() { |
|
continue |
|
} |
|
cv.Pic = arc.Pic |
|
cvs = append(cvs, cv) |
|
} |
|
} else { |
|
if music, ok := ms[res.Oid]; ok { |
|
cv.Pic = music.Cover |
|
cvs = append(cvs, cv) |
|
} |
|
} |
|
} |
|
if err := s.videoDao.SetNewCoverCache(c, mid, fid, cvs); err != nil { |
|
log.Error("s.videoDao.SetNewCoverCache(%d,%d,%v) error(%v)", mid, fid, cvs, err) |
|
} |
|
fcvs[fid] = cvs |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) arcsRPC(c context.Context, aids []int64) (arcsMap map[int64]*api.Arc, err error) { |
|
var ( |
|
batch = s.conf.Fav.MaxPagesize |
|
arcs map[int64]*api.Arc |
|
) |
|
arcsMap = make(map[int64]*api.Arc, len(aids)) |
|
for len(aids) > 0 { |
|
if len(aids) < batch { |
|
batch = len(aids) |
|
} |
|
arcs, err = s.ArcsRPC(c, aids[:batch]) |
|
if err != nil { |
|
log.Error("s.ArcsRPC(%v) error(%v)", aids[:batch], err) |
|
return |
|
} |
|
for k, v := range arcs { |
|
arcsMap[k] = v |
|
} |
|
aids = aids[batch:] |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) normalArcs(c context.Context, aids []int64) (as []*api.Arc, err error) { |
|
arcs, err := s.ArcsRPC(c, aids) |
|
if err != nil { |
|
log.Error("s.ArcsRPC(%v) error(%v)", aids, err) |
|
return |
|
} |
|
as = make([]*api.Arc, 0, len(aids)) |
|
for _, v := range aids { |
|
if a, ok := arcs[v]; ok { |
|
as = append(as, a) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// FavVideo get fav videos from search or db |
|
func (s *Service) FavVideo(c context.Context, mid, vmid, uid, fid int64, keyword, order string, tid, pn, ps int) (sv *model.SearchArchive, err error) { |
|
if order != "click" && order != "pubdate" { |
|
order = model.SortMtime |
|
} |
|
if order == "pubdate" { |
|
order = model.SortPubtime |
|
} |
|
sv = new(model.SearchArchive) |
|
var favs *model.Favorites |
|
if favs, err = s.FavoritesRPC(c, model.TypeVideo, mid, vmid, fid, tid, keyword, order, pn, ps); err != nil || favs == nil { |
|
log.Error("s.FavoritesRPC(%d,%d,%d,%d,%d,%d) error(%v)", model.TypeVideo, mid, vmid, fid, pn, ps, err) |
|
return |
|
} |
|
if len(favs.List) == 0 { |
|
sv.Result = nil |
|
sv.Archives = _emptyArchives |
|
return |
|
} |
|
if err = s.newFillArchives(c, favs.List, sv); err != nil { |
|
log.Error("s.newFillArchives error(%v)", err) |
|
} |
|
sv.Mid = uid |
|
sv.Fid = fid |
|
sv.Tid = tid |
|
sv.Order = order |
|
sv.Keyword = keyword |
|
sv.PageCount = int(math.Ceil(float64(favs.Page.Count) / float64(s.conf.Fav.MaxPagesize))) |
|
sv.PageSize = s.conf.Fav.MaxPagesize |
|
sv.Total = favs.Page.Count |
|
sv.NumPages = 0 |
|
sv.NumResults = 0 |
|
return |
|
} |
|
|
|
// TidList get video folder type names from search. |
|
func (s *Service) TidList(c context.Context, mid, vmid, uid, fid int64) (res []*model.Partition, err error) { |
|
tidCounts, err := s.TlistsRPC(c, model.TypeVideo, mid, vmid, fid) |
|
if err != nil { |
|
log.Error("s.TlistsRPC(%d,%d,%d,%d) error(%v)", model.TypeVideo, mid, vmid, fid, err) |
|
return |
|
} |
|
types, err := s.TypesRPC(c) |
|
if err != nil { |
|
log.Error("s.TypesRPC() error(%v)", err) |
|
return |
|
} |
|
for _, t := range tidCounts { |
|
if t.Tid == 0 { |
|
continue |
|
} |
|
if v, ok := types[int16(t.Tid)]; ok { |
|
t.Name = v.Name |
|
} |
|
res = append(res, t) |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) archive(c context.Context, aid int64) (arc *api.Arc, err error) { |
|
arc, err = s.ArcRPC(c, aid) |
|
if err != nil { |
|
log.Error("s.ArcRPC(%d), error(%v)", aid, err) |
|
} |
|
if !arc.IsNormal() { |
|
err = ecode.ArchiveNotExist |
|
} |
|
return |
|
} |
|
|
|
// FavFolders get mid user's favorites. |
|
func (s *Service) FavFolders(c context.Context, mid, vmid, uid, aid int64, isSelf bool, mediaList bool, fromWeb bool) (res []*model.VideoFolder, err error) { |
|
var fs []*model.Folder |
|
typ := model.TypeVideo |
|
ip := metadata.String(c, metadata.RemoteIP) |
|
if fs, err = s.AllFoldersRPC(c, typ, mid, vmid, aid, ip); err != nil { |
|
log.Error("s.AllFoldersRPC(%d,%d,%d,%d,%s) error(%v)", typ, mid, vmid, ip, err) |
|
return |
|
} |
|
if len(fs) == 0 { |
|
res = _emptyVideoFolders |
|
return |
|
} |
|
faids := make(map[int64][]*model.Resource, len(fs)) |
|
for _, f := range fs { |
|
faids[f.ID] = f.RecentRes |
|
} |
|
var covers map[int64][]*model.Cover |
|
if covers, err = s.newCovers(c, uid, faids); err != nil { |
|
log.Error("s.newCovers(%d,%v) error(%v)", uid, faids, err) |
|
err = nil |
|
} |
|
//兼容老的缓存,后期下掉 |
|
for _, cover := range covers { |
|
for _, co := range cover { |
|
if co.Type == 0 { |
|
co.Type = int32(model.TypeVideo) |
|
} |
|
} |
|
} |
|
for _, f := range fs { |
|
maxCount := model.DefaultFolderLimit |
|
if !f.IsDefault() { |
|
maxCount = model.NormalFolderLimit |
|
} |
|
name := f.Name |
|
if fromWeb { // web端html转义 |
|
name = template.HTMLEscapeString(name) |
|
} |
|
if mediaList { |
|
if f.IsDefault() && name == "默认收藏夹" { |
|
name = "默认播单" |
|
} |
|
} |
|
cover := []*model.Cover{} |
|
if mediaList { |
|
if f.Cover != "" { |
|
cover = []*model.Cover{{ |
|
Type: 0, |
|
Pic: f.Cover, |
|
}} |
|
} else { |
|
cover = covers[f.ID] |
|
} |
|
} else { |
|
for _, co := range covers[f.ID] { |
|
if int8(co.Type) == model.TypeVideo { |
|
cover = append(cover, co) |
|
} |
|
} |
|
} |
|
vf := &model.VideoFolder{ |
|
MediaId: f.ID*100 + f.Mid%100, |
|
Fid: f.ID, |
|
Mid: f.Mid, |
|
Name: name, |
|
MaxCount: maxCount, |
|
CurCount: f.Count, |
|
Favoured: f.Favored, |
|
State: int8(f.Attr & 3), |
|
CTime: f.CTime, |
|
MTime: f.MTime, |
|
Cover: cover, |
|
} |
|
res = append(res, vf) |
|
} |
|
|
|
return |
|
} |
|
|
|
// AddFavFolder add a new favorite folder |
|
func (s *Service) AddFavFolder(c context.Context, mid int64, name, cookie, accessKey string, state int32) (fid int64, err error) { |
|
var reply *pb.AddFolderReply |
|
reply, err = s.favClient.AddFolder(c, &pb.AddFolderReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Name: name, |
|
Cookie: cookie, |
|
AccessKey: accessKey, |
|
Public: state, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
fid = reply.Fid |
|
return |
|
} |
|
|
|
// UpFavName update favorite name. |
|
func (s *Service) UpFavName(c context.Context, mid, fid int64, name, cookie, accessKey string) (err error) { |
|
_, err = s.favClient.UpFolderName(c, &pb.UpFolderNameReq{ |
|
Typ: int32(model.TypeVideo), |
|
Fid: fid, |
|
Mid: mid, |
|
Name: name, |
|
Cookie: cookie, |
|
AccessKey: accessKey, |
|
}) |
|
return |
|
} |
|
|
|
// SetVideoFolderSort set folder sort. |
|
func (s *Service) SetVideoFolderSort(c context.Context, mid int64, fids []int64) (err error) { |
|
_, err = s.favClient.SetFolderSort(c, &pb.SetFolderSortReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fids: fids, |
|
}) |
|
return |
|
} |
|
|
|
// UpFavState update folder state. |
|
func (s *Service) UpFavState(c context.Context, mid, fid int64, public int32, cookie string, accessKey string) (err error) { |
|
_, err = s.favClient.UpFolderAttr(c, &pb.UpFolderAttrReq{ |
|
Typ: int32(model.TypeVideo), |
|
Fid: fid, |
|
Mid: mid, |
|
Public: public, |
|
}) |
|
return |
|
} |
|
|
|
// DelVideoFolder delete favFolder and push databus msg to del videos in folder. |
|
func (s *Service) DelVideoFolder(c context.Context, mid, fid int64) (err error) { |
|
_, err = s.favClient.DelFolder(c, &pb.DelFolderReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
}) |
|
return |
|
} |
|
|
|
// RecentArcs return the newest archives in all folder. |
|
func (s *Service) RecentArcs(c context.Context, mid int64, pageNum, pageSize int) (sv *model.SearchArchive, err error) { |
|
aids, err := s.RecentsRPC(c, model.TypeVideo, mid, pageSize) |
|
if err != nil { |
|
return |
|
} |
|
sv = new(model.SearchArchive) |
|
if len(aids) == 0 { |
|
sv.Result = nil |
|
sv.Archives = _emptyArchives |
|
return |
|
} |
|
archives, err := s.normalArcs(c, aids) |
|
if err != nil { |
|
log.Error("s.NormalArchives(%v) error(%v)", sv, err) |
|
return |
|
} |
|
if err = s.fillArchives(c, sv); err != nil { |
|
log.Error("s.RecentArcs err(%v)", err) |
|
} |
|
farchives := make([]*model.FavArchive, 0, len(archives)) |
|
for _, arc := range archives { |
|
farchive := new(model.FavArchive) |
|
farchive.Arc = arc |
|
farchives = append(farchives, farchive) |
|
} |
|
sv.Result = nil |
|
sv.Archives = farchives |
|
sv.Mid = mid |
|
sv.PageCount = sv.NumPages |
|
sv.Total = sv.NumResults |
|
sv.NumPages = 0 |
|
sv.NumResults = 0 |
|
return |
|
} |
|
|
|
func (s *Service) fillArchives(c context.Context, sv *model.SearchArchive) (err error) { |
|
aids := make([]int64, 0, len(sv.Result)) |
|
searchArcs := make(map[int64]*model.SearchArchiveResult, len(sv.Result)) |
|
for _, v := range sv.Result { |
|
aids = append(aids, v.ID) |
|
searchArcs[v.ID] = &model.SearchArchiveResult{ |
|
FavTime: v.FavTime, |
|
Title: v.Title, |
|
Play: v.Play, |
|
} |
|
} |
|
archives, err := s.normalArcs(c, aids) |
|
if err != nil { |
|
log.Error("s.NormalArchives(%v) error(%v)", sv, err) |
|
return |
|
} |
|
farchives := make([]*model.FavArchive, 0, len(archives)) |
|
for _, arc := range archives { |
|
var farchive = &model.FavArchive{} |
|
farchive.Arc = arc |
|
farchive.FavAt = searchArcs[arc.Aid].FavTime |
|
farchive.HighlightTitle = searchArcs[arc.Aid].Title |
|
farchive.PlayNum = searchArcs[arc.Aid].Play |
|
farchives = append(farchives, farchive) |
|
} |
|
sv.Result = nil |
|
sv.Archives = farchives |
|
return |
|
} |
|
|
|
func (s *Service) newFillArchives(c context.Context, favorites []*model.Favorite, sv *model.SearchArchive) (err error) { |
|
aids := make([]int64, 0, len(sv.Result)) |
|
favoriteArcs := make(map[int64]*model.Favorite, len(sv.Result)) |
|
for _, v := range favorites { |
|
aids = append(aids, v.Oid) |
|
favoriteArcs[v.Oid] = v |
|
} |
|
archives, err := s.normalArcs(c, aids) |
|
if err != nil { |
|
log.Error("s.normalArcs(%v) error(%v)", aids, err) |
|
return |
|
} |
|
farchives := make([]*model.FavArchive, 0, len(archives)) |
|
for _, arc := range archives { |
|
var farchive = &model.FavArchive{} |
|
farchive.Arc = arc |
|
farchive.FavAt = int64(favoriteArcs[arc.Aid].MTime) |
|
farchive.HighlightTitle = arc.Title |
|
farchives = append(farchives, farchive) |
|
} |
|
sv.Result = nil |
|
sv.Archives = farchives |
|
return |
|
} |
|
|
|
// AddArc add a archive into folder. |
|
func (s *Service) AddArc(c context.Context, mid, fid, aid int64, ck, ak string) (err error) { |
|
if _, err = s.archive(c, aid); err != nil { |
|
return |
|
} |
|
_, err = s.favClient.AddFav(c, &pb.AddFavReq{ |
|
Tp: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
Oid: aid, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
s.cache.Do(c, func(c context.Context) { |
|
if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err) |
|
} |
|
}) |
|
return |
|
} |
|
|
|
// AddArcToFolders add a archive into multi folders. |
|
func (s *Service) AddArcToFolders(c context.Context, mid, aid int64, fids []int64, ck, ak string) (err error) { |
|
if len(fids) == 0 { |
|
err = s.AddArc(c, mid, 0, aid, ck, ak) |
|
} |
|
for _, fid := range fids { |
|
err = s.AddArc(c, mid, fid, aid, ck, ak) |
|
} |
|
return |
|
} |
|
|
|
// DelArc delete a archive from favorite. |
|
func (s *Service) DelArc(c context.Context, mid, fid, aid int64) (err error) { |
|
_, err = s.favClient.DelFav(c, &pb.DelFavReq{ |
|
Tp: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
Oid: aid, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
s.cache.Do(c, func(c context.Context) { |
|
if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err) |
|
} |
|
}) |
|
return |
|
} |
|
|
|
// DelArcs delete some archives from favorite. |
|
func (s *Service) DelArcs(c context.Context, mid, fid int64, aids []int64) (err error) { |
|
_, err = s.favClient.MultiDel(c, &pb.MultiDelReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
Oids: aids, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
s.cache.Do(c, func(c context.Context) { |
|
if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err) |
|
} |
|
}) |
|
return |
|
} |
|
|
|
// MoveArcs move archives from old favorite to new favorite |
|
func (s *Service) MoveArcs(c context.Context, mid, oldfid, newfid int64, aids []int64) (err error) { |
|
if len(aids) == 0 || oldfid == newfid { |
|
return |
|
} |
|
_, err = s.favClient.MoveFavs(c, &pb.MoveFavsReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
OldFid: oldfid, |
|
NewFid: newfid, |
|
Oids: aids, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
s.cache.Do(c, func(c context.Context) { |
|
if err := s.videoDao.DelCoverCache(c, mid, newfid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, newfid, err) |
|
} |
|
if err := s.videoDao.DelCoverCache(c, mid, oldfid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, oldfid, err) |
|
} |
|
}) |
|
return |
|
} |
|
|
|
// CopyArcs copy archives to other favorite. |
|
func (s *Service) CopyArcs(c context.Context, mid, oldmid, oldfid, newfid int64, aids []int64) (err error) { |
|
if len(aids) == 0 || oldfid == newfid { |
|
return |
|
} |
|
_, err = s.favClient.CopyFavs(c, &pb.CopyFavsReq{ |
|
Typ: int32(model.TypeVideo), |
|
OldMid: oldmid, |
|
Mid: mid, |
|
OldFid: oldfid, |
|
NewFid: newfid, |
|
Oids: aids, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
s.cache.Do(c, func(c context.Context) { |
|
if err := s.videoDao.DelCoverCache(c, mid, newfid); err != nil { |
|
log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, newfid, err) |
|
} |
|
}) |
|
return |
|
} |
|
|
|
// IsFaveds check if aids faved by user |
|
func (s *Service) IsFaveds(c context.Context, mid int64, aids []int64) (m map[int64]bool, err error) { |
|
if m, err = s.IsFavsRPC(c, model.TypeVideo, mid, aids); err != nil { |
|
log.Error("s.IsFavsRPC(%d,%d,%v) error(%v)", model.TypeVideo, mid, aids, err) |
|
} |
|
return |
|
} |
|
|
|
// IsFaved check if aid faved by user |
|
func (s *Service) IsFaved(c context.Context, mid, aid int64) (faved bool, count int, err error) { |
|
if faved, err = s.IsFavRPC(c, model.TypeVideo, mid, aid); err != nil { |
|
log.Error("s.IsFavsRPC(%d,%d,%d) error(%v)", model.TypeVideo, mid, aid, err) |
|
} |
|
count = 1 |
|
return |
|
} |
|
|
|
// InDef detemine aid whether or not archive in default folder. |
|
func (s *Service) InDef(c context.Context, mid, aid int64) (isin bool, err error) { |
|
if isin, err = s.InDefaultRPC(c, model.TypeVideo, mid, aid); err != nil { |
|
log.Error("s.InDefaultRPC(%d,%d,%d) error(%v)", model.TypeVideo, mid, aid, err) |
|
} |
|
return |
|
} |
|
|
|
// CleanState return this folder clean state. |
|
func (s *Service) CleanState(c context.Context, mid, fid int64) (cleanState int, err error) { |
|
reply, err := s.favClient.CleanState(c, &pb.CleanStateReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
}) |
|
if err != nil { |
|
return |
|
} |
|
cleanState = int(reply.CleanState) |
|
return |
|
} |
|
|
|
// CleanInvalidArcs clean invalid archives. |
|
func (s *Service) CleanInvalidArcs(c context.Context, mid, fid int64) (err error) { |
|
_, err = s.favClient.CleanInvalidFavs(c, &pb.CleanInvalidFavsReq{ |
|
Typ: int32(model.TypeVideo), |
|
Mid: mid, |
|
Fid: fid, |
|
}) |
|
return |
|
}
|
|
|