]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/overviews.ts
Add channel filters for my videos/followers
[github/Chocobozzz/PeerTube.git] / server / controllers / api / overviews.ts
CommitLineData
41fb13c3
C
1import express from 'express'
2import memoizee from 'memoizee'
4c7e60bc 3import { logger } from '@server/helpers/logger'
64f9b91d
MW
4import { Hooks } from '@server/lib/plugins/hooks'
5import { VideoModel } from '@server/models/video/video'
4c7e60bc 6import { CategoryOverview, ChannelOverview, TagOverview, VideosOverview } from '../../../shared/models/overviews'
2d3741d6 7import { buildNSFWFilter } from '../../helpers/express-utils'
4c7e60bc 8import { MEMOIZE_TTL, OVERVIEWS } from '../../initializers/constants'
764a9657 9import { asyncMiddleware, optionalAuthenticate, videosOverviewValidator } from '../../middlewares'
2d3741d6 10import { TagModel } from '../../models/video/tag'
2d3741d6
C
11
12const overviewsRouter = express.Router()
13
14overviewsRouter.get('/videos',
764a9657
C
15 videosOverviewValidator,
16 optionalAuthenticate,
2d3741d6
C
17 asyncMiddleware(getVideosOverview)
18)
19
20// ---------------------------------------------------------------------------
21
22export { overviewsRouter }
23
24// ---------------------------------------------------------------------------
25
4b5384f6
C
26const buildSamples = memoizee(async function () {
27 const [ categories, channels, tags ] = await Promise.all([
28 VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
a1587156 29 VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
4b5384f6
C
30 TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
31 ])
32
764a9657
C
33 const result = { categories, channels, tags }
34
35 logger.debug('Building samples for overview endpoint.', { result })
36
37 return result
4b5384f6
C
38}, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE })
39
2d3741d6
C
40// This endpoint could be quite long, but we cache it
41async function getVideosOverview (req: express.Request, res: express.Response) {
42 const attributes = await buildSamples()
7348b1fd 43
764a9657
C
44 const page = req.query.page || 1
45 const index = page - 1
46
47 const categories: CategoryOverview[] = []
48 const channels: ChannelOverview[] = []
49 const tags: TagOverview[] = []
50
51 await Promise.all([
52 getVideosByCategory(attributes.categories, index, res, categories),
53 getVideosByChannel(attributes.channels, index, res, channels),
54 getVideosByTag(attributes.tags, index, res, tags)
7348b1fd
C
55 ])
56
2d3741d6 57 const result: VideosOverview = {
7348b1fd
C
58 categories,
59 channels,
60 tags
2d3741d6
C
61 }
62
2d3741d6
C
63 return res.json(result)
64}
65
764a9657
C
66async function getVideosByTag (tagsSample: string[], index: number, res: express.Response, acc: TagOverview[]) {
67 if (tagsSample.length <= index) return
68
69 const tag = tagsSample[index]
2d3741d6
C
70 const videos = await getVideos(res, { tagsOneOf: [ tag ] })
71
764a9657 72 if (videos.length === 0) return
2d3741d6 73
764a9657 74 acc.push({
2d3741d6
C
75 tag,
76 videos
764a9657 77 })
2d3741d6
C
78}
79
764a9657
C
80async function getVideosByCategory (categoriesSample: number[], index: number, res: express.Response, acc: CategoryOverview[]) {
81 if (categoriesSample.length <= index) return
82
83 const category = categoriesSample[index]
2d3741d6
C
84 const videos = await getVideos(res, { categoryOneOf: [ category ] })
85
764a9657 86 if (videos.length === 0) return
2d3741d6 87
764a9657 88 acc.push({
2d3741d6
C
89 category: videos[0].category,
90 videos
764a9657 91 })
2d3741d6
C
92}
93
764a9657
C
94async function getVideosByChannel (channelsSample: number[], index: number, res: express.Response, acc: ChannelOverview[]) {
95 if (channelsSample.length <= index) return
96
97 const channelId = channelsSample[index]
2d3741d6
C
98 const videos = await getVideos(res, { videoChannelId: channelId })
99
764a9657 100 if (videos.length === 0) return
2d3741d6 101
764a9657 102 acc.push({
2d3741d6
C
103 channel: videos[0].channel,
104 videos
764a9657 105 })
2d3741d6
C
106}
107
108async function getVideos (
109 res: express.Response,
110 where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] }
111) {
d1aed103 112 const query = await Hooks.wrapObject({
2d3741d6 113 start: 0,
0f4905e1 114 count: 12,
2d3741d6
C
115 sort: '-createdAt',
116 includeLocalVideos: true,
117 nsfw: buildNSFWFilter(res),
52a350a1 118 user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
fe987656 119 withFiles: false,
d1aed103 120 countVideos: false,
7348b1fd 121
d1aed103
C
122 ...where
123 }, 'filter:api.overviews.videos.list.params')
64f9b91d
MW
124
125 const { data } = await Hooks.wrapPromiseFun(
126 VideoModel.listForApi,
127 query,
128 'filter:api.overviews.videos.list.result'
129 )
2d3741d6
C
130
131 return data.map(d => d.toFormattedJSON())
132}