]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/controllers/api/videos/index.ts
Add videos list filters
[github/Chocobozzz/PeerTube.git] / server / controllers / api / videos / index.ts
index 9d9b2b0e19d2acb7083835205aa3698e98d1630b..101183eabd9ac65e2a85f944beb4639ac85d4f0d 100644 (file)
@@ -2,8 +2,7 @@ import * as express from 'express'
 import { extname, join } from 'path'
 import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../shared'
 import { renamePromise } from '../../../helpers/core-utils'
-import { retryTransactionWrapper } from '../../../helpers/database-utils'
-import { getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
+import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
 import { processImage } from '../../../helpers/image-utils'
 import { logger } from '../../../helpers/logger'
 import { getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
@@ -30,7 +29,9 @@ import { JobQueue } from '../../../lib/job-queue'
 import { Redis } from '../../../lib/redis'
 import {
   asyncMiddleware,
+  asyncRetryTransactionMiddleware,
   authenticate,
+  commonVideosFiltersValidator,
   optionalAuthenticate,
   paginationValidator,
   setDefaultPagination,
@@ -38,7 +39,6 @@ import {
   videosAddValidator,
   videosGetValidator,
   videosRemoveValidator,
-  videosSearchValidator,
   videosSortValidator,
   videosUpdateValidator
 } from '../../../middlewares'
@@ -50,8 +50,9 @@ import { blacklistRouter } from './blacklist'
 import { videoCommentRouter } from './comment'
 import { rateVideoRouter } from './rate'
 import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
-import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type'
-import { createReqFiles, isNSFWHidden } from '../../../helpers/express-utils'
+import { createReqFiles, buildNSFWFilter } from '../../../helpers/express-utils'
+import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
+import { videoCaptionsRouter } from './captions'
 
 const videosRouter = express.Router()
 
@@ -77,6 +78,7 @@ videosRouter.use('/', abuseVideoRouter)
 videosRouter.use('/', blacklistRouter)
 videosRouter.use('/', rateVideoRouter)
 videosRouter.use('/', videoCommentRouter)
+videosRouter.use('/', videoCaptionsRouter)
 
 videosRouter.get('/categories', listVideoCategories)
 videosRouter.get('/licences', listVideoLicences)
@@ -89,28 +91,20 @@ videosRouter.get('/',
   setDefaultSort,
   setDefaultPagination,
   optionalAuthenticate,
+  commonVideosFiltersValidator,
   asyncMiddleware(listVideos)
 )
-videosRouter.get('/search',
-  videosSearchValidator,
-  paginationValidator,
-  videosSortValidator,
-  setDefaultSort,
-  setDefaultPagination,
-  optionalAuthenticate,
-  asyncMiddleware(searchVideos)
-)
 videosRouter.put('/:id',
   authenticate,
   reqVideoFileUpdate,
   asyncMiddleware(videosUpdateValidator),
-  asyncMiddleware(updateVideoRetryWrapper)
+  asyncRetryTransactionMiddleware(updateVideo)
 )
 videosRouter.post('/upload',
   authenticate,
   reqVideoFileAdd,
   asyncMiddleware(videosAddValidator),
-  asyncMiddleware(addVideoRetryWrapper)
+  asyncRetryTransactionMiddleware(addVideo)
 )
 
 videosRouter.get('/:id/description',
@@ -129,7 +123,7 @@ videosRouter.post('/:id/views',
 videosRouter.delete('/:id',
   authenticate,
   asyncMiddleware(videosRemoveValidator),
-  asyncMiddleware(removeVideoRetryWrapper)
+  asyncRetryTransactionMiddleware(removeVideo)
 )
 
 // ---------------------------------------------------------------------------
@@ -156,25 +150,8 @@ function listVideoPrivacies (req: express.Request, res: express.Response) {
   res.json(VIDEO_PRIVACIES)
 }
 
-// Wrapper to video add that retry the function if there is a database error
-// We need this because we run the transaction in SERIALIZABLE isolation that can fail
-async function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const options = {
-    arguments: [ req, res, req.files['videofile'][0] ],
-    errorMessage: 'Cannot insert the video with many retries.'
-  }
-
-  const video = await retryTransactionWrapper(addVideo, options)
-
-  res.json({
-    video: {
-      id: video.id,
-      uuid: video.uuid
-    }
-  }).end()
-}
-
-async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
+async function addVideo (req: express.Request, res: express.Response) {
+  const videoPhysicalFile = req.files['videofile'][0]
   const videoInfo: VideoCreate = req.body
 
   // Prepare data so we don't block the transaction
@@ -200,10 +177,13 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
 
   // Build the file object
   const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path)
+  const fps = await getVideoFileFPS(videoPhysicalFile.path)
+
   const videoFileData = {
     extname: extname(videoPhysicalFile.filename),
     resolution: videoFileResolution,
-    size: videoPhysicalFile.size
+    size: videoPhysicalFile.size,
+    fps
   }
   const videoFile = new VideoFileModel(videoFileData)
 
@@ -248,6 +228,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
 
     video.VideoFiles = [ videoFile ]
 
+    // Create tags
     if (videoInfo.tags !== undefined) {
       const tagInstances = await TagModel.findOrCreateTags(videoInfo.tags, t)
 
@@ -255,6 +236,15 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
       video.Tags = tagInstances
     }
 
+    // Schedule an update in the future?
+    if (videoInfo.scheduleUpdate) {
+      await ScheduleVideoUpdateModel.create({
+        videoId: video.id,
+        updateAt: videoInfo.scheduleUpdate.updateAt,
+        privacy: videoInfo.scheduleUpdate.privacy || null
+      }, { transaction: t })
+    }
+
     await federateVideoIfNeeded(video, true, t)
 
     logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid)
@@ -272,18 +262,12 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
     await JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput })
   }
 
-  return videoCreated
-}
-
-async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const options = {
-    arguments: [ req, res ],
-    errorMessage: 'Cannot update the video with many retries.'
-  }
-
-  await retryTransactionWrapper(updateVideo, options)
-
-  return res.type('json').status(204).end()
+  return res.json({
+    video: {
+      id: videoCreated.id,
+      uuid: videoCreated.uuid
+    }
+  }).end()
 }
 
 async function updateVideo (req: express.Request, res: express.Response) {
@@ -347,8 +331,19 @@ async function updateVideo (req: express.Request, res: express.Response) {
         if (wasPrivateVideo === false) await changeVideoChannelShare(videoInstanceUpdated, oldVideoChannel, t)
       }
 
+      // Schedule an update in the future?
+      if (videoInfoToUpdate.scheduleUpdate) {
+        await ScheduleVideoUpdateModel.upsert({
+          videoId: videoInstanceUpdated.id,
+          updateAt: videoInfoToUpdate.scheduleUpdate.updateAt,
+          privacy: videoInfoToUpdate.scheduleUpdate.privacy || null
+        }, { transaction: t })
+      } else if (videoInfoToUpdate.scheduleUpdate === null) {
+        await ScheduleVideoUpdateModel.deleteByVideoId(videoInstanceUpdated.id, t)
+      }
+
       const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE
-      await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo)
+      await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)
     })
 
     logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
@@ -360,6 +355,8 @@ async function updateVideo (req: express.Request, res: express.Response) {
 
     throw err
   }
+
+  return res.type('json').status(204).end()
 }
 
 function getVideo (req: express.Request, res: express.Response) {
@@ -406,7 +403,12 @@ async function listVideos (req: express.Request, res: express.Response, next: ex
     start: req.query.start,
     count: req.query.count,
     sort: req.query.sort,
-    hideNSFW: isNSFWHidden(res),
+    categoryOneOf: req.query.categoryOneOf,
+    licenceOneOf: req.query.licenceOneOf,
+    languageOneOf: req.query.languageOneOf,
+    tagsOneOf: req.query.tagsOneOf,
+    tagsAllOf: req.query.tagsAllOf,
+    nsfw: buildNSFWFilter(res, req.query.nsfw),
     filter: req.query.filter as VideoFilter,
     withFiles: false
   })
@@ -414,17 +416,6 @@ async function listVideos (req: express.Request, res: express.Response, next: ex
   return res.json(getFormattedObjects(resultList.data, resultList.total))
 }
 
-async function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const options = {
-    arguments: [ req, res ],
-    errorMessage: 'Cannot remove the video with many retries.'
-  }
-
-  await retryTransactionWrapper(removeVideo, options)
-
-  return res.type('json').status(204).end()
-}
-
 async function removeVideo (req: express.Request, res: express.Response) {
   const videoInstance: VideoModel = res.locals.video
 
@@ -433,16 +424,6 @@ async function removeVideo (req: express.Request, res: express.Response) {
   })
 
   logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
-}
-
-async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const resultList = await VideoModel.searchAndPopulateAccountAndServer(
-    req.query.search as string,
-    req.query.start as number,
-    req.query.count as number,
-    req.query.sort as VideoSortField,
-    isNSFWHidden(res)
-  )
 
-  return res.json(getFormattedObjects(resultList.data, resultList.total))
+  return res.type('json').status(204).end()
 }