mirror of https://github.com/Chocobozzz/PeerTube
				
				
				
			
		
			
				
	
	
		
			133 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
import express from 'express'
 | 
						|
import memoizee from 'memoizee'
 | 
						|
import { logger } from '@server/helpers/logger'
 | 
						|
import { Hooks } from '@server/lib/plugins/hooks'
 | 
						|
import { VideoModel } from '@server/models/video/video'
 | 
						|
import { CategoryOverview, ChannelOverview, TagOverview, VideosOverview } from '../../../shared/models/overviews'
 | 
						|
import { buildNSFWFilter } from '../../helpers/express-utils'
 | 
						|
import { MEMOIZE_TTL, OVERVIEWS } from '../../initializers/constants'
 | 
						|
import { asyncMiddleware, optionalAuthenticate, videosOverviewValidator } from '../../middlewares'
 | 
						|
import { TagModel } from '../../models/video/tag'
 | 
						|
 | 
						|
const overviewsRouter = express.Router()
 | 
						|
 | 
						|
overviewsRouter.get('/videos',
 | 
						|
  videosOverviewValidator,
 | 
						|
  optionalAuthenticate,
 | 
						|
  asyncMiddleware(getVideosOverview)
 | 
						|
)
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------
 | 
						|
 | 
						|
export { overviewsRouter }
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------
 | 
						|
 | 
						|
const buildSamples = memoizee(async function () {
 | 
						|
  const [ categories, channels, tags ] = await Promise.all([
 | 
						|
    VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
 | 
						|
    VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
 | 
						|
    TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
 | 
						|
  ])
 | 
						|
 | 
						|
  const result = { categories, channels, tags }
 | 
						|
 | 
						|
  logger.debug('Building samples for overview endpoint.', { result })
 | 
						|
 | 
						|
  return result
 | 
						|
}, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE })
 | 
						|
 | 
						|
// This endpoint could be quite long, but we cache it
 | 
						|
async function getVideosOverview (req: express.Request, res: express.Response) {
 | 
						|
  const attributes = await buildSamples()
 | 
						|
 | 
						|
  const page = req.query.page || 1
 | 
						|
  const index = page - 1
 | 
						|
 | 
						|
  const categories: CategoryOverview[] = []
 | 
						|
  const channels: ChannelOverview[] = []
 | 
						|
  const tags: TagOverview[] = []
 | 
						|
 | 
						|
  await Promise.all([
 | 
						|
    getVideosByCategory(attributes.categories, index, res, categories),
 | 
						|
    getVideosByChannel(attributes.channels, index, res, channels),
 | 
						|
    getVideosByTag(attributes.tags, index, res, tags)
 | 
						|
  ])
 | 
						|
 | 
						|
  const result: VideosOverview = {
 | 
						|
    categories,
 | 
						|
    channels,
 | 
						|
    tags
 | 
						|
  }
 | 
						|
 | 
						|
  return res.json(result)
 | 
						|
}
 | 
						|
 | 
						|
async function getVideosByTag (tagsSample: string[], index: number, res: express.Response, acc: TagOverview[]) {
 | 
						|
  if (tagsSample.length <= index) return
 | 
						|
 | 
						|
  const tag = tagsSample[index]
 | 
						|
  const videos = await getVideos(res, { tagsOneOf: [ tag ] })
 | 
						|
 | 
						|
  if (videos.length === 0) return
 | 
						|
 | 
						|
  acc.push({
 | 
						|
    tag,
 | 
						|
    videos
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
async function getVideosByCategory (categoriesSample: number[], index: number, res: express.Response, acc: CategoryOverview[]) {
 | 
						|
  if (categoriesSample.length <= index) return
 | 
						|
 | 
						|
  const category = categoriesSample[index]
 | 
						|
  const videos = await getVideos(res, { categoryOneOf: [ category ] })
 | 
						|
 | 
						|
  if (videos.length === 0) return
 | 
						|
 | 
						|
  acc.push({
 | 
						|
    category: videos[0].category,
 | 
						|
    videos
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
async function getVideosByChannel (channelsSample: number[], index: number, res: express.Response, acc: ChannelOverview[]) {
 | 
						|
  if (channelsSample.length <= index) return
 | 
						|
 | 
						|
  const channelId = channelsSample[index]
 | 
						|
  const videos = await getVideos(res, { videoChannelId: channelId })
 | 
						|
 | 
						|
  if (videos.length === 0) return
 | 
						|
 | 
						|
  acc.push({
 | 
						|
    channel: videos[0].channel,
 | 
						|
    videos
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
async function getVideos (
 | 
						|
  res: express.Response,
 | 
						|
  where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] }
 | 
						|
) {
 | 
						|
  const query = await Hooks.wrapObject({
 | 
						|
    start: 0,
 | 
						|
    count: 12,
 | 
						|
    sort: '-createdAt',
 | 
						|
    includeLocalVideos: true,
 | 
						|
    nsfw: buildNSFWFilter(res),
 | 
						|
    user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
 | 
						|
    withFiles: false,
 | 
						|
    countVideos: false,
 | 
						|
 | 
						|
    ...where
 | 
						|
  }, 'filter:api.overviews.videos.list.params')
 | 
						|
 | 
						|
  const { data } = await Hooks.wrapPromiseFun(
 | 
						|
    VideoModel.listForApi,
 | 
						|
    query,
 | 
						|
    'filter:api.overviews.videos.list.result'
 | 
						|
  )
 | 
						|
 | 
						|
  return data.map(d => d.toFormattedJSON())
 | 
						|
}
 |