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'
import { Redis } from '../../../lib/redis'
import {
asyncMiddleware,
+ asyncRetryTransactionMiddleware,
authenticate,
+ commonVideosFiltersValidator,
optionalAuthenticate,
paginationValidator,
setDefaultPagination,
videosAddValidator,
videosGetValidator,
videosRemoveValidator,
- videosSearchValidator,
videosSortValidator,
videosUpdateValidator
} from '../../../middlewares'
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()
videosRouter.use('/', blacklistRouter)
videosRouter.use('/', rateVideoRouter)
videosRouter.use('/', videoCommentRouter)
+videosRouter.use('/', videoCaptionsRouter)
videosRouter.get('/categories', listVideoCategories)
videosRouter.get('/licences', listVideoLicences)
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',
videosRouter.delete('/:id',
authenticate,
asyncMiddleware(videosRemoveValidator),
- asyncMiddleware(removeVideoRetryWrapper)
+ asyncRetryTransactionMiddleware(removeVideo)
)
// ---------------------------------------------------------------------------
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
// 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)
video.VideoFiles = [ videoFile ]
+ // Create tags
if (videoInfo.tags !== undefined) {
const tagInstances = await TagModel.findOrCreateTags(videoInfo.tags, t)
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)
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) {
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)
throw err
}
+
+ return res.type('json').status(204).end()
}
function getVideo (req: express.Request, res: express.Response) {
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
})
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
})
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()
}