video.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. package service
  2. import (
  3. "context"
  4. "html/template"
  5. "math"
  6. musicmdl "go-common/app/interface/main/favorite/model"
  7. "go-common/app/service/main/archive/api"
  8. pb "go-common/app/service/main/favorite/api"
  9. "go-common/app/service/main/favorite/model"
  10. "go-common/library/ecode"
  11. "go-common/library/log"
  12. "go-common/library/net/metadata"
  13. )
  14. var (
  15. _emptyArchives = []*model.FavArchive{}
  16. _emptyVideoFolders = []*model.VideoFolder{}
  17. )
  18. // newCovers get three cover of each fid
  19. func (s *Service) newCovers(c context.Context, mid int64, recents map[int64][]*model.Resource) (fcvs map[int64][]*model.Cover, err error) {
  20. var (
  21. fids, misFids []int64
  22. )
  23. for fid := range recents {
  24. fids = append(fids, fid)
  25. }
  26. if fcvs, misFids, err = s.videoDao.NewCoversCache(c, mid, fids); err != nil {
  27. log.Error("s.videoDao.NewCoversCache(fids %v) err(%v)", fids, err)
  28. return
  29. }
  30. // get miss cover from db
  31. if len(misFids) > 0 {
  32. var (
  33. allAids []int64
  34. allMids []int64
  35. as map[int64]*api.Arc
  36. ms map[int64]*musicmdl.Music
  37. )
  38. for _, fid := range misFids {
  39. if resources, ok := recents[fid]; ok {
  40. for _, res := range resources {
  41. if int8(res.Typ) == model.TypeVideo {
  42. allAids = append(allAids, res.Oid)
  43. } else {
  44. allMids = append(allMids, res.Oid)
  45. }
  46. }
  47. }
  48. }
  49. if len(allAids) > 0 {
  50. if as, err = s.arcsRPC(c, allAids); err != nil {
  51. log.Error("s.arcsRPC(aids %v),err(%v)", allAids, err)
  52. return
  53. }
  54. }
  55. if len(allMids) > 0 {
  56. if ms, err = s.musicDao.MusicMap(c, allMids); err != nil {
  57. log.Error("s.musicMap(allMids %v),err(%v)", allMids, err)
  58. return
  59. }
  60. }
  61. // set miss fid's cover
  62. for _, misFid := range misFids {
  63. fid := misFid
  64. cvs := make([]*model.Cover, 0)
  65. for _, res := range recents[fid] {
  66. cv := &model.Cover{}
  67. cv.Aid = res.Oid
  68. cv.Type = res.Typ
  69. if int8(res.Typ) == model.TypeVideo {
  70. if arc, ok := as[res.Oid]; ok {
  71. if !arc.IsNormal() {
  72. continue
  73. }
  74. cv.Pic = arc.Pic
  75. cvs = append(cvs, cv)
  76. }
  77. } else {
  78. if music, ok := ms[res.Oid]; ok {
  79. cv.Pic = music.Cover
  80. cvs = append(cvs, cv)
  81. }
  82. }
  83. }
  84. if err := s.videoDao.SetNewCoverCache(c, mid, fid, cvs); err != nil {
  85. log.Error("s.videoDao.SetNewCoverCache(%d,%d,%v) error(%v)", mid, fid, cvs, err)
  86. }
  87. fcvs[fid] = cvs
  88. }
  89. }
  90. return
  91. }
  92. func (s *Service) arcsRPC(c context.Context, aids []int64) (arcsMap map[int64]*api.Arc, err error) {
  93. var (
  94. batch = s.conf.Fav.MaxPagesize
  95. arcs map[int64]*api.Arc
  96. )
  97. arcsMap = make(map[int64]*api.Arc, len(aids))
  98. for len(aids) > 0 {
  99. if len(aids) < batch {
  100. batch = len(aids)
  101. }
  102. arcs, err = s.ArcsRPC(c, aids[:batch])
  103. if err != nil {
  104. log.Error("s.ArcsRPC(%v) error(%v)", aids[:batch], err)
  105. return
  106. }
  107. for k, v := range arcs {
  108. arcsMap[k] = v
  109. }
  110. aids = aids[batch:]
  111. }
  112. return
  113. }
  114. func (s *Service) normalArcs(c context.Context, aids []int64) (as []*api.Arc, err error) {
  115. arcs, err := s.ArcsRPC(c, aids)
  116. if err != nil {
  117. log.Error("s.ArcsRPC(%v) error(%v)", aids, err)
  118. return
  119. }
  120. as = make([]*api.Arc, 0, len(aids))
  121. for _, v := range aids {
  122. if a, ok := arcs[v]; ok {
  123. as = append(as, a)
  124. }
  125. }
  126. return
  127. }
  128. // FavVideo get fav videos from search or db
  129. func (s *Service) FavVideo(c context.Context, mid, vmid, uid, fid int64, keyword, order string, tid, pn, ps int) (sv *model.SearchArchive, err error) {
  130. if order != "click" && order != "pubdate" {
  131. order = model.SortMtime
  132. }
  133. if order == "pubdate" {
  134. order = model.SortPubtime
  135. }
  136. sv = new(model.SearchArchive)
  137. var favs *model.Favorites
  138. if favs, err = s.FavoritesRPC(c, model.TypeVideo, mid, vmid, fid, tid, keyword, order, pn, ps); err != nil || favs == nil {
  139. log.Error("s.FavoritesRPC(%d,%d,%d,%d,%d,%d) error(%v)", model.TypeVideo, mid, vmid, fid, pn, ps, err)
  140. return
  141. }
  142. if len(favs.List) == 0 {
  143. sv.Result = nil
  144. sv.Archives = _emptyArchives
  145. return
  146. }
  147. if err = s.newFillArchives(c, favs.List, sv); err != nil {
  148. log.Error("s.newFillArchives error(%v)", err)
  149. }
  150. sv.Mid = uid
  151. sv.Fid = fid
  152. sv.Tid = tid
  153. sv.Order = order
  154. sv.Keyword = keyword
  155. sv.PageCount = int(math.Ceil(float64(favs.Page.Count) / float64(s.conf.Fav.MaxPagesize)))
  156. sv.PageSize = s.conf.Fav.MaxPagesize
  157. sv.Total = favs.Page.Count
  158. sv.NumPages = 0
  159. sv.NumResults = 0
  160. return
  161. }
  162. // TidList get video folder type names from search.
  163. func (s *Service) TidList(c context.Context, mid, vmid, uid, fid int64) (res []*model.Partition, err error) {
  164. tidCounts, err := s.TlistsRPC(c, model.TypeVideo, mid, vmid, fid)
  165. if err != nil {
  166. log.Error("s.TlistsRPC(%d,%d,%d,%d) error(%v)", model.TypeVideo, mid, vmid, fid, err)
  167. return
  168. }
  169. types, err := s.TypesRPC(c)
  170. if err != nil {
  171. log.Error("s.TypesRPC() error(%v)", err)
  172. return
  173. }
  174. for _, t := range tidCounts {
  175. if t.Tid == 0 {
  176. continue
  177. }
  178. if v, ok := types[int16(t.Tid)]; ok {
  179. t.Name = v.Name
  180. }
  181. res = append(res, t)
  182. }
  183. return
  184. }
  185. func (s *Service) archive(c context.Context, aid int64) (arc *api.Arc, err error) {
  186. arc, err = s.ArcRPC(c, aid)
  187. if err != nil {
  188. log.Error("s.ArcRPC(%d), error(%v)", aid, err)
  189. }
  190. if !arc.IsNormal() {
  191. err = ecode.ArchiveNotExist
  192. }
  193. return
  194. }
  195. // FavFolders get mid user's favorites.
  196. func (s *Service) FavFolders(c context.Context, mid, vmid, uid, aid int64, isSelf bool, mediaList bool, fromWeb bool) (res []*model.VideoFolder, err error) {
  197. var fs []*model.Folder
  198. typ := model.TypeVideo
  199. ip := metadata.String(c, metadata.RemoteIP)
  200. if fs, err = s.AllFoldersRPC(c, typ, mid, vmid, aid, ip); err != nil {
  201. log.Error("s.AllFoldersRPC(%d,%d,%d,%d,%s) error(%v)", typ, mid, vmid, ip, err)
  202. return
  203. }
  204. if len(fs) == 0 {
  205. res = _emptyVideoFolders
  206. return
  207. }
  208. faids := make(map[int64][]*model.Resource, len(fs))
  209. for _, f := range fs {
  210. faids[f.ID] = f.RecentRes
  211. }
  212. var covers map[int64][]*model.Cover
  213. if covers, err = s.newCovers(c, uid, faids); err != nil {
  214. log.Error("s.newCovers(%d,%v) error(%v)", uid, faids, err)
  215. err = nil
  216. }
  217. //兼容老的缓存,后期下掉
  218. for _, cover := range covers {
  219. for _, co := range cover {
  220. if co.Type == 0 {
  221. co.Type = int32(model.TypeVideo)
  222. }
  223. }
  224. }
  225. for _, f := range fs {
  226. maxCount := model.DefaultFolderLimit
  227. if !f.IsDefault() {
  228. maxCount = model.NormalFolderLimit
  229. }
  230. name := f.Name
  231. if fromWeb { // web端html转义
  232. name = template.HTMLEscapeString(name)
  233. }
  234. if mediaList {
  235. if f.IsDefault() && name == "默认收藏夹" {
  236. name = "默认播单"
  237. }
  238. }
  239. cover := []*model.Cover{}
  240. if mediaList {
  241. if f.Cover != "" {
  242. cover = []*model.Cover{{
  243. Type: 0,
  244. Pic: f.Cover,
  245. }}
  246. } else {
  247. cover = covers[f.ID]
  248. }
  249. } else {
  250. for _, co := range covers[f.ID] {
  251. if int8(co.Type) == model.TypeVideo {
  252. cover = append(cover, co)
  253. }
  254. }
  255. }
  256. vf := &model.VideoFolder{
  257. MediaId: f.ID*100 + f.Mid%100,
  258. Fid: f.ID,
  259. Mid: f.Mid,
  260. Name: name,
  261. MaxCount: maxCount,
  262. CurCount: f.Count,
  263. Favoured: f.Favored,
  264. State: int8(f.Attr & 3),
  265. CTime: f.CTime,
  266. MTime: f.MTime,
  267. Cover: cover,
  268. }
  269. res = append(res, vf)
  270. }
  271. return
  272. }
  273. // AddFavFolder add a new favorite folder
  274. func (s *Service) AddFavFolder(c context.Context, mid int64, name, cookie, accessKey string, state int32) (fid int64, err error) {
  275. var reply *pb.AddFolderReply
  276. reply, err = s.favClient.AddFolder(c, &pb.AddFolderReq{
  277. Typ: int32(model.TypeVideo),
  278. Mid: mid,
  279. Name: name,
  280. Cookie: cookie,
  281. AccessKey: accessKey,
  282. Public: state,
  283. })
  284. if err != nil {
  285. return
  286. }
  287. fid = reply.Fid
  288. return
  289. }
  290. // UpFavName update favorite name.
  291. func (s *Service) UpFavName(c context.Context, mid, fid int64, name, cookie, accessKey string) (err error) {
  292. _, err = s.favClient.UpFolderName(c, &pb.UpFolderNameReq{
  293. Typ: int32(model.TypeVideo),
  294. Fid: fid,
  295. Mid: mid,
  296. Name: name,
  297. Cookie: cookie,
  298. AccessKey: accessKey,
  299. })
  300. return
  301. }
  302. // SetVideoFolderSort set folder sort.
  303. func (s *Service) SetVideoFolderSort(c context.Context, mid int64, fids []int64) (err error) {
  304. _, err = s.favClient.SetFolderSort(c, &pb.SetFolderSortReq{
  305. Typ: int32(model.TypeVideo),
  306. Mid: mid,
  307. Fids: fids,
  308. })
  309. return
  310. }
  311. // UpFavState update folder state.
  312. func (s *Service) UpFavState(c context.Context, mid, fid int64, public int32, cookie string, accessKey string) (err error) {
  313. _, err = s.favClient.UpFolderAttr(c, &pb.UpFolderAttrReq{
  314. Typ: int32(model.TypeVideo),
  315. Fid: fid,
  316. Mid: mid,
  317. Public: public,
  318. })
  319. return
  320. }
  321. // DelVideoFolder delete favFolder and push databus msg to del videos in folder.
  322. func (s *Service) DelVideoFolder(c context.Context, mid, fid int64) (err error) {
  323. _, err = s.favClient.DelFolder(c, &pb.DelFolderReq{
  324. Typ: int32(model.TypeVideo),
  325. Mid: mid,
  326. Fid: fid,
  327. })
  328. return
  329. }
  330. // RecentArcs return the newest archives in all folder.
  331. func (s *Service) RecentArcs(c context.Context, mid int64, pageNum, pageSize int) (sv *model.SearchArchive, err error) {
  332. aids, err := s.RecentsRPC(c, model.TypeVideo, mid, pageSize)
  333. if err != nil {
  334. return
  335. }
  336. sv = new(model.SearchArchive)
  337. if len(aids) == 0 {
  338. sv.Result = nil
  339. sv.Archives = _emptyArchives
  340. return
  341. }
  342. archives, err := s.normalArcs(c, aids)
  343. if err != nil {
  344. log.Error("s.NormalArchives(%v) error(%v)", sv, err)
  345. return
  346. }
  347. if err = s.fillArchives(c, sv); err != nil {
  348. log.Error("s.RecentArcs err(%v)", err)
  349. }
  350. farchives := make([]*model.FavArchive, 0, len(archives))
  351. for _, arc := range archives {
  352. farchive := new(model.FavArchive)
  353. farchive.Arc = arc
  354. farchives = append(farchives, farchive)
  355. }
  356. sv.Result = nil
  357. sv.Archives = farchives
  358. sv.Mid = mid
  359. sv.PageCount = sv.NumPages
  360. sv.Total = sv.NumResults
  361. sv.NumPages = 0
  362. sv.NumResults = 0
  363. return
  364. }
  365. func (s *Service) fillArchives(c context.Context, sv *model.SearchArchive) (err error) {
  366. aids := make([]int64, 0, len(sv.Result))
  367. searchArcs := make(map[int64]*model.SearchArchiveResult, len(sv.Result))
  368. for _, v := range sv.Result {
  369. aids = append(aids, v.ID)
  370. searchArcs[v.ID] = &model.SearchArchiveResult{
  371. FavTime: v.FavTime,
  372. Title: v.Title,
  373. Play: v.Play,
  374. }
  375. }
  376. archives, err := s.normalArcs(c, aids)
  377. if err != nil {
  378. log.Error("s.NormalArchives(%v) error(%v)", sv, err)
  379. return
  380. }
  381. farchives := make([]*model.FavArchive, 0, len(archives))
  382. for _, arc := range archives {
  383. var farchive = &model.FavArchive{}
  384. farchive.Arc = arc
  385. farchive.FavAt = searchArcs[arc.Aid].FavTime
  386. farchive.HighlightTitle = searchArcs[arc.Aid].Title
  387. farchive.PlayNum = searchArcs[arc.Aid].Play
  388. farchives = append(farchives, farchive)
  389. }
  390. sv.Result = nil
  391. sv.Archives = farchives
  392. return
  393. }
  394. func (s *Service) newFillArchives(c context.Context, favorites []*model.Favorite, sv *model.SearchArchive) (err error) {
  395. aids := make([]int64, 0, len(sv.Result))
  396. favoriteArcs := make(map[int64]*model.Favorite, len(sv.Result))
  397. for _, v := range favorites {
  398. aids = append(aids, v.Oid)
  399. favoriteArcs[v.Oid] = v
  400. }
  401. archives, err := s.normalArcs(c, aids)
  402. if err != nil {
  403. log.Error("s.normalArcs(%v) error(%v)", aids, err)
  404. return
  405. }
  406. farchives := make([]*model.FavArchive, 0, len(archives))
  407. for _, arc := range archives {
  408. var farchive = &model.FavArchive{}
  409. farchive.Arc = arc
  410. farchive.FavAt = int64(favoriteArcs[arc.Aid].MTime)
  411. farchive.HighlightTitle = arc.Title
  412. farchives = append(farchives, farchive)
  413. }
  414. sv.Result = nil
  415. sv.Archives = farchives
  416. return
  417. }
  418. // AddArc add a archive into folder.
  419. func (s *Service) AddArc(c context.Context, mid, fid, aid int64, ck, ak string) (err error) {
  420. if _, err = s.archive(c, aid); err != nil {
  421. return
  422. }
  423. _, err = s.favClient.AddFav(c, &pb.AddFavReq{
  424. Tp: int32(model.TypeVideo),
  425. Mid: mid,
  426. Fid: fid,
  427. Oid: aid,
  428. })
  429. if err != nil {
  430. return
  431. }
  432. s.cache.Do(c, func(c context.Context) {
  433. if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil {
  434. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err)
  435. }
  436. })
  437. return
  438. }
  439. // AddArcToFolders add a archive into multi folders.
  440. func (s *Service) AddArcToFolders(c context.Context, mid, aid int64, fids []int64, ck, ak string) (err error) {
  441. if len(fids) == 0 {
  442. err = s.AddArc(c, mid, 0, aid, ck, ak)
  443. }
  444. for _, fid := range fids {
  445. err = s.AddArc(c, mid, fid, aid, ck, ak)
  446. }
  447. return
  448. }
  449. // DelArc delete a archive from favorite.
  450. func (s *Service) DelArc(c context.Context, mid, fid, aid int64) (err error) {
  451. _, err = s.favClient.DelFav(c, &pb.DelFavReq{
  452. Tp: int32(model.TypeVideo),
  453. Mid: mid,
  454. Fid: fid,
  455. Oid: aid,
  456. })
  457. if err != nil {
  458. return
  459. }
  460. s.cache.Do(c, func(c context.Context) {
  461. if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil {
  462. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err)
  463. }
  464. })
  465. return
  466. }
  467. // DelArcs delete some archives from favorite.
  468. func (s *Service) DelArcs(c context.Context, mid, fid int64, aids []int64) (err error) {
  469. _, err = s.favClient.MultiDel(c, &pb.MultiDelReq{
  470. Typ: int32(model.TypeVideo),
  471. Mid: mid,
  472. Fid: fid,
  473. Oids: aids,
  474. })
  475. if err != nil {
  476. return
  477. }
  478. s.cache.Do(c, func(c context.Context) {
  479. if err := s.videoDao.DelCoverCache(c, mid, fid); err != nil {
  480. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, fid, err)
  481. }
  482. })
  483. return
  484. }
  485. // MoveArcs move archives from old favorite to new favorite
  486. func (s *Service) MoveArcs(c context.Context, mid, oldfid, newfid int64, aids []int64) (err error) {
  487. if len(aids) == 0 || oldfid == newfid {
  488. return
  489. }
  490. _, err = s.favClient.MoveFavs(c, &pb.MoveFavsReq{
  491. Typ: int32(model.TypeVideo),
  492. Mid: mid,
  493. OldFid: oldfid,
  494. NewFid: newfid,
  495. Oids: aids,
  496. })
  497. if err != nil {
  498. return
  499. }
  500. s.cache.Do(c, func(c context.Context) {
  501. if err := s.videoDao.DelCoverCache(c, mid, newfid); err != nil {
  502. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, newfid, err)
  503. }
  504. if err := s.videoDao.DelCoverCache(c, mid, oldfid); err != nil {
  505. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, oldfid, err)
  506. }
  507. })
  508. return
  509. }
  510. // CopyArcs copy archives to other favorite.
  511. func (s *Service) CopyArcs(c context.Context, mid, oldmid, oldfid, newfid int64, aids []int64) (err error) {
  512. if len(aids) == 0 || oldfid == newfid {
  513. return
  514. }
  515. _, err = s.favClient.CopyFavs(c, &pb.CopyFavsReq{
  516. Typ: int32(model.TypeVideo),
  517. OldMid: oldmid,
  518. Mid: mid,
  519. OldFid: oldfid,
  520. NewFid: newfid,
  521. Oids: aids,
  522. })
  523. if err != nil {
  524. return
  525. }
  526. s.cache.Do(c, func(c context.Context) {
  527. if err := s.videoDao.DelCoverCache(c, mid, newfid); err != nil {
  528. log.Error("s.videoDao.DelCoverCache(%d,%d) error(%v)", mid, newfid, err)
  529. }
  530. })
  531. return
  532. }
  533. // IsFaveds check if aids faved by user
  534. func (s *Service) IsFaveds(c context.Context, mid int64, aids []int64) (m map[int64]bool, err error) {
  535. if m, err = s.IsFavsRPC(c, model.TypeVideo, mid, aids); err != nil {
  536. log.Error("s.IsFavsRPC(%d,%d,%v) error(%v)", model.TypeVideo, mid, aids, err)
  537. }
  538. return
  539. }
  540. // IsFaved check if aid faved by user
  541. func (s *Service) IsFaved(c context.Context, mid, aid int64) (faved bool, count int, err error) {
  542. if faved, err = s.IsFavRPC(c, model.TypeVideo, mid, aid); err != nil {
  543. log.Error("s.IsFavsRPC(%d,%d,%d) error(%v)", model.TypeVideo, mid, aid, err)
  544. }
  545. count = 1
  546. return
  547. }
  548. // InDef detemine aid whether or not archive in default folder.
  549. func (s *Service) InDef(c context.Context, mid, aid int64) (isin bool, err error) {
  550. if isin, err = s.InDefaultRPC(c, model.TypeVideo, mid, aid); err != nil {
  551. log.Error("s.InDefaultRPC(%d,%d,%d) error(%v)", model.TypeVideo, mid, aid, err)
  552. }
  553. return
  554. }
  555. // CleanState return this folder clean state.
  556. func (s *Service) CleanState(c context.Context, mid, fid int64) (cleanState int, err error) {
  557. reply, err := s.favClient.CleanState(c, &pb.CleanStateReq{
  558. Typ: int32(model.TypeVideo),
  559. Mid: mid,
  560. Fid: fid,
  561. })
  562. if err != nil {
  563. return
  564. }
  565. cleanState = int(reply.CleanState)
  566. return
  567. }
  568. // CleanInvalidArcs clean invalid archives.
  569. func (s *Service) CleanInvalidArcs(c context.Context, mid, fid int64) (err error) {
  570. _, err = s.favClient.CleanInvalidFavs(c, &pb.CleanInvalidFavsReq{
  571. Typ: int32(model.TypeVideo),
  572. Mid: mid,
  573. Fid: fid,
  574. })
  575. return
  576. }