diff options
author | Chocobozzz <me@florianbigard.com> | 2020-03-11 14:39:28 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2020-03-11 15:02:20 +0100 |
commit | 764a965778ac89e027fd05dd35697c6763e0dc18 (patch) | |
tree | ecc18834566b940c729a57b5bf0d088e894f03d3 /server/controllers | |
parent | fab6746354f9d9cb65c35d8bd9352c4b773b4c69 (diff) | |
download | PeerTube-764a965778ac89e027fd05dd35697c6763e0dc18.tar.gz PeerTube-764a965778ac89e027fd05dd35697c6763e0dc18.tar.zst PeerTube-764a965778ac89e027fd05dd35697c6763e0dc18.zip |
Implement pagination for overviews endpoint
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/api/overviews.ts | 70 |
1 files changed, 43 insertions, 27 deletions
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts index 75f3baedb..fb31932aa 100644 --- a/server/controllers/api/overviews.ts +++ b/server/controllers/api/overviews.ts | |||
@@ -1,17 +1,18 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { buildNSFWFilter } from '../../helpers/express-utils' | 2 | import { buildNSFWFilter } from '../../helpers/express-utils' |
3 | import { VideoModel } from '../../models/video/video' | 3 | import { VideoModel } from '../../models/video/video' |
4 | import { asyncMiddleware } from '../../middlewares' | 4 | import { asyncMiddleware, optionalAuthenticate, videosOverviewValidator } from '../../middlewares' |
5 | import { TagModel } from '../../models/video/tag' | 5 | import { TagModel } from '../../models/video/tag' |
6 | import { VideosOverview } from '../../../shared/models/overviews' | 6 | import { CategoryOverview, ChannelOverview, TagOverview, VideosOverview } from '../../../shared/models/overviews' |
7 | import { MEMOIZE_TTL, OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers/constants' | 7 | import { MEMOIZE_TTL, OVERVIEWS } from '../../initializers/constants' |
8 | import { cacheRoute } from '../../middlewares/cache' | ||
9 | import * as memoizee from 'memoizee' | 8 | import * as memoizee from 'memoizee' |
9 | import { logger } from '@server/helpers/logger' | ||
10 | 10 | ||
11 | const overviewsRouter = express.Router() | 11 | const overviewsRouter = express.Router() |
12 | 12 | ||
13 | overviewsRouter.get('/videos', | 13 | overviewsRouter.get('/videos', |
14 | asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS)), | 14 | videosOverviewValidator, |
15 | optionalAuthenticate, | ||
15 | asyncMiddleware(getVideosOverview) | 16 | asyncMiddleware(getVideosOverview) |
16 | ) | 17 | ) |
17 | 18 | ||
@@ -28,17 +29,28 @@ const buildSamples = memoizee(async function () { | |||
28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | 29 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) |
29 | ]) | 30 | ]) |
30 | 31 | ||
31 | return { categories, channels, tags } | 32 | const result = { categories, channels, tags } |
33 | |||
34 | logger.debug('Building samples for overview endpoint.', { result }) | ||
35 | |||
36 | return result | ||
32 | }, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE }) | 37 | }, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE }) |
33 | 38 | ||
34 | // This endpoint could be quite long, but we cache it | 39 | // This endpoint could be quite long, but we cache it |
35 | async function getVideosOverview (req: express.Request, res: express.Response) { | 40 | async function getVideosOverview (req: express.Request, res: express.Response) { |
36 | const attributes = await buildSamples() | 41 | const attributes = await buildSamples() |
37 | 42 | ||
38 | const [ categories, channels, tags ] = await Promise.all([ | 43 | const page = req.query.page || 1 |
39 | Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | 44 | const index = page - 1 |
40 | Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | 45 | |
41 | Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | 46 | const categories: CategoryOverview[] = [] |
47 | const channels: ChannelOverview[] = [] | ||
48 | const tags: TagOverview[] = [] | ||
49 | |||
50 | await Promise.all([ | ||
51 | getVideosByCategory(attributes.categories, index, res, categories), | ||
52 | getVideosByChannel(attributes.channels, index, res, channels), | ||
53 | getVideosByTag(attributes.tags, index, res, tags) | ||
42 | ]) | 54 | ]) |
43 | 55 | ||
44 | const result: VideosOverview = { | 56 | const result: VideosOverview = { |
@@ -47,45 +59,49 @@ async function getVideosOverview (req: express.Request, res: express.Response) { | |||
47 | tags | 59 | tags |
48 | } | 60 | } |
49 | 61 | ||
50 | // Cleanup our object | ||
51 | for (const key of Object.keys(result)) { | ||
52 | result[key] = result[key].filter(v => v !== undefined) | ||
53 | } | ||
54 | |||
55 | return res.json(result) | 62 | return res.json(result) |
56 | } | 63 | } |
57 | 64 | ||
58 | async function getVideosByTag (tag: string, res: express.Response) { | 65 | async function getVideosByTag (tagsSample: string[], index: number, res: express.Response, acc: TagOverview[]) { |
66 | if (tagsSample.length <= index) return | ||
67 | |||
68 | const tag = tagsSample[index] | ||
59 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) | 69 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) |
60 | 70 | ||
61 | if (videos.length === 0) return undefined | 71 | if (videos.length === 0) return |
62 | 72 | ||
63 | return { | 73 | acc.push({ |
64 | tag, | 74 | tag, |
65 | videos | 75 | videos |
66 | } | 76 | }) |
67 | } | 77 | } |
68 | 78 | ||
69 | async function getVideosByCategory (category: number, res: express.Response) { | 79 | async function getVideosByCategory (categoriesSample: number[], index: number, res: express.Response, acc: CategoryOverview[]) { |
80 | if (categoriesSample.length <= index) return | ||
81 | |||
82 | const category = categoriesSample[index] | ||
70 | const videos = await getVideos(res, { categoryOneOf: [ category ] }) | 83 | const videos = await getVideos(res, { categoryOneOf: [ category ] }) |
71 | 84 | ||
72 | if (videos.length === 0) return undefined | 85 | if (videos.length === 0) return |
73 | 86 | ||
74 | return { | 87 | acc.push({ |
75 | category: videos[0].category, | 88 | category: videos[0].category, |
76 | videos | 89 | videos |
77 | } | 90 | }) |
78 | } | 91 | } |
79 | 92 | ||
80 | async function getVideosByChannel (channelId: number, res: express.Response) { | 93 | async function getVideosByChannel (channelsSample: number[], index: number, res: express.Response, acc: ChannelOverview[]) { |
94 | if (channelsSample.length <= index) return | ||
95 | |||
96 | const channelId = channelsSample[index] | ||
81 | const videos = await getVideos(res, { videoChannelId: channelId }) | 97 | const videos = await getVideos(res, { videoChannelId: channelId }) |
82 | 98 | ||
83 | if (videos.length === 0) return undefined | 99 | if (videos.length === 0) return |
84 | 100 | ||
85 | return { | 101 | acc.push({ |
86 | channel: videos[0].channel, | 102 | channel: videos[0].channel, |
87 | videos | 103 | videos |
88 | } | 104 | }) |
89 | } | 105 | } |
90 | 106 | ||
91 | async function getVideos ( | 107 | async function getVideos ( |