X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fcontrollers%2Fapi%2Fvideos%2Findex.ts;h=3a19fe989b303a448145d846e11291cc2e26dafd;hb=e95561cdf195d2926e1856ed285c2b86960bc86f;hp=4ae7ea2edbd90f9e878fa80968703cf2b01dfdb3;hpb=4771e0008dd26eadbb7eaff64255a6ec914fdadb;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 4ae7ea2ed..3a19fe989 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -1,7 +1,7 @@ import * as express from 'express' import * as Promise from 'bluebird' import * as multer from 'multer' -import * as path from 'path' +import { extname, join } from 'path' import { database as db } from '../../../initializers/database' import { @@ -16,7 +16,8 @@ import { addEventToRemoteVideo, quickAndDirtyUpdateVideoToFriends, addVideoToFriends, - updateVideoToFriends + updateVideoToFriends, + JobScheduler } from '../../../lib' import { authenticate, @@ -35,7 +36,7 @@ import { logger, retryTransactionWrapper, generateRandomString, - getFormatedObjects, + getFormattedObjects, renamePromise } from '../../../helpers' import { TagInstance } from '../../../models' @@ -49,19 +50,18 @@ const videosRouter = express.Router() // multer configuration const storage = multer.diskStorage({ - destination: function (req, file, cb) { + destination: (req, file, cb) => { cb(null, CONFIG.STORAGE.VIDEOS_DIR) }, - filename: function (req, file, cb) { + filename: (req, file, cb) => { let extension = '' if (file.mimetype === 'video/webm') extension = 'webm' else if (file.mimetype === 'video/mp4') extension = 'mp4' else if (file.mimetype === 'video/ogg') extension = 'ogv' generateRandomString(16) .then(randomString => { - const filename = randomString - cb(null, filename + '.' + extension) + cb(null, randomString + '.' + extension) }) .catch(err => { logger.error('Cannot generate random string for file name.', err) @@ -92,7 +92,7 @@ videosRouter.put('/:id', videosUpdateValidator, updateVideoRetryWrapper ) -videosRouter.post('/', +videosRouter.post('/upload', authenticate, reqFiles, videosAddValidator, @@ -127,15 +127,15 @@ export { // --------------------------------------------------------------------------- -function listVideoCategories (req: express.Request, res: express.Response, next: express.NextFunction) { +function listVideoCategories (req: express.Request, res: express.Response) { res.json(VIDEO_CATEGORIES) } -function listVideoLicences (req: express.Request, res: express.Response, next: express.NextFunction) { +function listVideoLicences (req: express.Request, res: express.Response) { res.json(VIDEO_LICENCES) } -function listVideoLanguages (req: express.Request, res: express.Response, next: express.NextFunction) { +function listVideoLanguages (req: express.Request, res: express.Response) { res.json(VIDEO_LANGUAGES) } @@ -143,7 +143,7 @@ function listVideoLanguages (req: express.Request, res: express.Response, next: // We need this because we run the transaction in SERIALIZABLE isolation that can fail function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { const options = { - arguments: [ req, res, req.files.videofile[0] ], + arguments: [ req, res, req.files['videofile'][0] ], errorMessage: 'Cannot insert the video with many retries.' } @@ -155,8 +155,8 @@ function addVideoRetryWrapper (req: express.Request, res: express.Response, next .catch(err => next(err)) } -function addVideo (req: express.Request, res: express.Response, videoFile: Express.Multer.File) { - const videoInfos: VideoCreate = req.body +function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) { + const videoInfo: VideoCreate = req.body return db.sequelize.transaction(t => { const user = res.locals.oauth.token.User @@ -168,22 +168,22 @@ function addVideo (req: express.Request, res: express.Response, videoFile: Expre return db.Author.findOrCreateAuthor(name, podId, userId, t) .then(author => { - const tags = videoInfos.tags + const tags = videoInfo.tags if (!tags) return { author, tagInstances: undefined } return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ author, tagInstances })) }) .then(({ author, tagInstances }) => { const videoData = { - name: videoInfos.name, - remoteId: null, - extname: path.extname(videoFile.filename), - category: videoInfos.category, - licence: videoInfos.licence, - language: videoInfos.language, - nsfw: videoInfos.nsfw, - description: videoInfos.description, - duration: videoFile['duration'], // duration was added by a previous middleware + name: videoInfo.name, + remote: false, + extname: extname(videoPhysicalFile.filename), + category: videoInfo.category, + licence: videoInfo.licence, + language: videoInfo.language, + nsfw: videoInfo.nsfw, + description: videoInfo.description, + duration: videoPhysicalFile['duration'], // duration was added by a previous middleware authorId: author.id } @@ -191,28 +191,68 @@ function addVideo (req: express.Request, res: express.Response, videoFile: Expre return { author, tagInstances, video } }) .then(({ author, tagInstances, video }) => { + const videoFileData = { + extname: extname(videoPhysicalFile.filename), + resolution: 0, // TODO: improve readability, + size: videoPhysicalFile.size + } + + const videoFile = db.VideoFile.build(videoFileData) + return { author, tagInstances, video, videoFile } + }) + .then(({ author, tagInstances, video, videoFile }) => { const videoDir = CONFIG.STORAGE.VIDEOS_DIR - const source = path.join(videoDir, videoFile.filename) - const destination = path.join(videoDir, video.getVideoFilename()) + const source = join(videoDir, videoPhysicalFile.filename) + const destination = join(videoDir, video.getVideoFilename(videoFile)) return renamePromise(source, destination) .then(() => { // This is important in case if there is another attempt in the retry process - videoFile.filename = video.getVideoFilename() - return { author, tagInstances, video } + videoPhysicalFile.filename = video.getVideoFilename(videoFile) + return { author, tagInstances, video, videoFile } }) }) - .then(({ author, tagInstances, video }) => { + .then(({ author, tagInstances, video, videoFile }) => { + const tasks = [] + + tasks.push( + video.createTorrentAndSetInfoHash(videoFile), + video.createThumbnail(videoFile), + video.createPreview(videoFile) + ) + + if (CONFIG.TRANSCODING.ENABLED === true) { + // Put uuid because we don't have id auto incremented for now + const dataInput = { + videoUUID: video.uuid + } + + tasks.push( + JobScheduler.Instance.createJob(t, 'videoTranscoder', dataInput) + ) + } + + return Promise.all(tasks).then(() => ({ author, tagInstances, video, videoFile })) + }) + .then(({ author, tagInstances, video, videoFile }) => { const options = { transaction: t } return video.save(options) .then(videoCreated => { - // Do not forget to add Author informations to the created video + // Do not forget to add Author information to the created video videoCreated.Author = author - return { tagInstances, video: videoCreated } + return { tagInstances, video: videoCreated, videoFile } }) }) + .then(({ tagInstances, video, videoFile }) => { + const options = { transaction: t } + videoFile.videoId = video.id + + return videoFile.save(options) + .then(() => video.VideoFiles = [ videoFile ]) + .then(() => ({ tagInstances, video })) + }) .then(({ tagInstances, video }) => { if (!tagInstances) return video @@ -224,7 +264,7 @@ function addVideo (req: express.Request, res: express.Response, videoFile: Expre }) }) .then(video => { - // Let transcoding job send the video to friends because the videofile extension might change + // Let transcoding job send the video to friends because the video file extension might change if (CONFIG.TRANSCODING.ENABLED === true) return undefined return video.toAddRemoteJSON() @@ -234,9 +274,9 @@ function addVideo (req: express.Request, res: express.Response, videoFile: Expre }) }) }) - .then(() => logger.info('Video with name %s created.', videoInfos.name)) + .then(() => logger.info('Video with name %s created.', videoInfo.name)) .catch((err: Error) => { - logger.debug('Cannot insert the video.', { error: err.stack }) + logger.debug('Cannot insert the video.', err) throw err }) } @@ -258,14 +298,14 @@ function updateVideoRetryWrapper (req: express.Request, res: express.Response, n function updateVideo (req: express.Request, res: express.Response) { const videoInstance = res.locals.video const videoFieldsSave = videoInstance.toJSON() - const videoInfosToUpdate: VideoUpdate = req.body + const videoInfoToUpdate: VideoUpdate = req.body return db.sequelize.transaction(t => { let tagsPromise: Promise - if (!videoInfosToUpdate.tags) { + if (!videoInfoToUpdate.tags) { tagsPromise = Promise.resolve(null) } else { - tagsPromise = db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t) + tagsPromise = db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t) } return tagsPromise @@ -274,12 +314,12 @@ function updateVideo (req: express.Request, res: express.Response) { transaction: t } - if (videoInfosToUpdate.name !== undefined) videoInstance.set('name', videoInfosToUpdate.name) - if (videoInfosToUpdate.category !== undefined) videoInstance.set('category', videoInfosToUpdate.category) - if (videoInfosToUpdate.licence !== undefined) videoInstance.set('licence', videoInfosToUpdate.licence) - if (videoInfosToUpdate.language !== undefined) videoInstance.set('language', videoInfosToUpdate.language) - if (videoInfosToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfosToUpdate.nsfw) - if (videoInfosToUpdate.description !== undefined) videoInstance.set('description', videoInfosToUpdate.description) + if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name) + if (videoInfoToUpdate.category !== undefined) videoInstance.set('category', videoInfoToUpdate.category) + if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence) + if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language) + if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw) + if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description) return videoInstance.save(options).then(() => tagInstances) }) @@ -310,7 +350,7 @@ function updateVideo (req: express.Request, res: express.Response) { // Force fields we want to update // If the transaction is retried, sequelize will think the object has not changed // So it will skip the SQL request, even if the last one was ROLLBACKed! - Object.keys(videoFieldsSave).forEach(function (key) { + Object.keys(videoFieldsSave).forEach(key => { const value = videoFieldsSave[key] videoInstance.set(key, value) }) @@ -319,7 +359,7 @@ function updateVideo (req: express.Request, res: express.Response) { }) } -function getVideo (req: express.Request, res: express.Response, next: express.NextFunction) { +function getVideo (req: express.Request, res: express.Response) { const videoInstance = res.locals.video if (videoInstance.isOwned()) { @@ -345,12 +385,12 @@ function getVideo (req: express.Request, res: express.Response, next: express.Ne } // Do not wait the view system - res.json(videoInstance.toFormatedJSON()) + res.json(videoInstance.toFormattedJSON()) } function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { db.Video.listForApi(req.query.start, req.query.count, req.query.sort) - .then(result => res.json(getFormatedObjects(result.data, result.total))) + .then(result => res.json(getFormattedObjects(result.data, result.total))) .catch(err => next(err)) } @@ -367,6 +407,6 @@ function removeVideo (req: express.Request, res: express.Response, next: express function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { db.Video.searchAndPopulateAuthorAndPodAndTags(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort) - .then(result => res.json(getFormatedObjects(result.data, result.total))) + .then(result => res.json(getFormattedObjects(result.data, result.total))) .catch(err => next(err)) }