]>
Commit | Line | Data |
---|---|---|
1 | import * as express from 'express' | |
2 | import { buildNSFWFilter } from '../../helpers/express-utils' | |
3 | import { VideoModel } from '../../models/video/video' | |
4 | import { asyncMiddleware } from '../../middlewares' | |
5 | import { TagModel } from '../../models/video/tag' | |
6 | import { VideosOverview } from '../../../shared/models/overviews' | |
7 | import { MEMOIZE_TTL, OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers/constants' | |
8 | import { cacheRoute } from '../../middlewares/cache' | |
9 | import * as memoizee from 'memoizee' | |
10 | ||
11 | const overviewsRouter = express.Router() | |
12 | ||
13 | overviewsRouter.get('/videos', | |
14 | asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS)), | |
15 | asyncMiddleware(getVideosOverview) | |
16 | ) | |
17 | ||
18 | // --------------------------------------------------------------------------- | |
19 | ||
20 | export { overviewsRouter } | |
21 | ||
22 | // --------------------------------------------------------------------------- | |
23 | ||
24 | const buildSamples = memoizee(async function () { | |
25 | const [ categories, channels, tags ] = await Promise.all([ | |
26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | |
27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | |
28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | |
29 | ]) | |
30 | ||
31 | return { categories, channels, tags } | |
32 | }, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE }) | |
33 | ||
34 | // This endpoint could be quite long, but we cache it | |
35 | async function getVideosOverview (req: express.Request, res: express.Response) { | |
36 | const attributes = await buildSamples() | |
37 | ||
38 | const [ categories, channels, tags ] = await Promise.all([ | |
39 | Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | |
40 | Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | |
41 | Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | |
42 | ]) | |
43 | ||
44 | const result: VideosOverview = { | |
45 | categories, | |
46 | channels, | |
47 | tags | |
48 | } | |
49 | ||
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) | |
56 | } | |
57 | ||
58 | async function getVideosByTag (tag: string, res: express.Response) { | |
59 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) | |
60 | ||
61 | if (videos.length === 0) return undefined | |
62 | ||
63 | return { | |
64 | tag, | |
65 | videos | |
66 | } | |
67 | } | |
68 | ||
69 | async function getVideosByCategory (category: number, res: express.Response) { | |
70 | const videos = await getVideos(res, { categoryOneOf: [ category ] }) | |
71 | ||
72 | if (videos.length === 0) return undefined | |
73 | ||
74 | return { | |
75 | category: videos[0].category, | |
76 | videos | |
77 | } | |
78 | } | |
79 | ||
80 | async function getVideosByChannel (channelId: number, res: express.Response) { | |
81 | const videos = await getVideos(res, { videoChannelId: channelId }) | |
82 | ||
83 | if (videos.length === 0) return undefined | |
84 | ||
85 | return { | |
86 | channel: videos[0].channel, | |
87 | videos | |
88 | } | |
89 | } | |
90 | ||
91 | async function getVideos ( | |
92 | res: express.Response, | |
93 | where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] } | |
94 | ) { | |
95 | const query = Object.assign({ | |
96 | start: 0, | |
97 | count: 12, | |
98 | sort: '-createdAt', | |
99 | includeLocalVideos: true, | |
100 | nsfw: buildNSFWFilter(res), | |
101 | withFiles: false, | |
102 | countVideos: false | |
103 | }, where) | |
104 | ||
105 | const { data } = await VideoModel.listForApi(query) | |
106 | ||
107 | return data.map(d => d.toFormattedJSON()) | |
108 | } |