resetSequelizeInstance,
retryTransactionWrapper
} from '../../../helpers'
-import { getServerAccount } from '../../../helpers/utils'
-import { CONFIG, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, VIDEO_PRIVACIES } from '../../../initializers'
-import { database as db } from '../../../initializers/database'
-import { sendAddVideo } from '../../../lib/activitypub/send/send-add'
-import { sendCreateViewToOrigin } from '../../../lib/activitypub/send/send-create'
-import { sendUpdateVideo } from '../../../lib/activitypub/send/send-update'
-import { shareVideoByServer } from '../../../lib/activitypub/share'
-import { getVideoActivityPubUrl } from '../../../lib/activitypub/url'
-import { fetchRemoteVideoDescription } from '../../../lib/activitypub/videos'
-import { sendCreateViewToVideoFollowers } from '../../../lib/index'
-import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler/transcoding-job-scheduler'
+import { getServerActor } from '../../../helpers/utils'
+import {
+ CONFIG,
+ sequelizeTypescript,
+ VIDEO_CATEGORIES,
+ VIDEO_LANGUAGES,
+ VIDEO_LICENCES,
+ VIDEO_MIMETYPE_EXT,
+ VIDEO_PRIVACIES
+} from '../../../initializers'
+import {
+ fetchRemoteVideoDescription,
+ getVideoActivityPubUrl,
+ shareVideoByServerAndChannel
+} from '../../../lib/activitypub'
+import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send'
+import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler'
import {
asyncMiddleware,
authenticate,
videosSortValidator,
videosUpdateValidator
} from '../../../middlewares'
-import { VideoInstance } from '../../../models'
+import { TagModel } from '../../../models/video/tag'
+import { VideoModel } from '../../../models/video/video'
+import { VideoFileModel } from '../../../models/video/video-file'
import { abuseVideoRouter } from './abuse'
import { blacklistRouter } from './blacklist'
import { videoChannelRouter } from './channel'
videosRouter.post('/upload',
authenticate,
reqFiles,
- videosAddValidator,
+ asyncMiddleware(videosAddValidator),
asyncMiddleware(addVideoRetryWrapper)
)
}).end()
}
-function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
+async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
const videoInfo: VideoCreate = req.body
- return db.sequelize.transaction(async t => {
- const sequelizeOptions = { transaction: t }
+ // Prepare data so we don't block the transaction
+ const videoData = {
+ name: videoInfo.name,
+ remote: false,
+ extname: extname(videoPhysicalFile.filename),
+ category: videoInfo.category,
+ licence: videoInfo.licence,
+ language: videoInfo.language,
+ nsfw: videoInfo.nsfw,
+ description: videoInfo.description,
+ privacy: videoInfo.privacy,
+ duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
+ channelId: res.locals.videoChannel.id
+ }
+ const video = new VideoModel(videoData)
+ video.url = getVideoActivityPubUrl(video)
- const videoData = {
- name: videoInfo.name,
- remote: false,
- extname: extname(videoPhysicalFile.filename),
- category: videoInfo.category,
- licence: videoInfo.licence,
- language: videoInfo.language,
- nsfw: videoInfo.nsfw,
- description: videoInfo.description,
- privacy: videoInfo.privacy,
- duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
- channelId: res.locals.videoChannel.id
- }
- const video = db.Video.build(videoData)
- video.url = getVideoActivityPubUrl(video)
+ const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
+ const videoFileHeight = await getVideoFileHeight(videoFilePath)
- const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
- const videoFileHeight = await getVideoFileHeight(videoFilePath)
+ const videoFileData = {
+ extname: extname(videoPhysicalFile.filename),
+ resolution: videoFileHeight,
+ size: videoPhysicalFile.size
+ }
+ const videoFile = new VideoFileModel(videoFileData)
+ const videoDir = CONFIG.STORAGE.VIDEOS_DIR
+ const source = join(videoDir, videoPhysicalFile.filename)
+ const destination = join(videoDir, video.getVideoFilename(videoFile))
- const videoFileData = {
- extname: extname(videoPhysicalFile.filename),
- resolution: videoFileHeight,
- size: videoPhysicalFile.size
- }
- const videoFile = db.VideoFile.build(videoFileData)
- const videoDir = CONFIG.STORAGE.VIDEOS_DIR
- const source = join(videoDir, videoPhysicalFile.filename)
- const destination = join(videoDir, video.getVideoFilename(videoFile))
+ await renamePromise(source, destination)
+ // This is important in case if there is another attempt in the retry process
+ videoPhysicalFile.filename = video.getVideoFilename(videoFile)
- await renamePromise(source, destination)
- // This is important in case if there is another attempt in the retry process
- videoPhysicalFile.filename = video.getVideoFilename(videoFile)
+ const tasks = []
- const tasks = []
+ tasks.push(
+ video.createTorrentAndSetInfoHash(videoFile),
+ video.createThumbnail(videoFile),
+ video.createPreview(videoFile)
+ )
+ await Promise.all(tasks)
- tasks.push(
- video.createTorrentAndSetInfoHash(videoFile),
- video.createThumbnail(videoFile),
- video.createPreview(videoFile)
- )
+ return sequelizeTypescript.transaction(async t => {
+ const sequelizeOptions = { transaction: t }
if (CONFIG.TRANSCODING.ENABLED === true) {
// Put uuid because we don't have id auto incremented for now
videoUUID: video.uuid
}
- tasks.push(
- transcodingJobScheduler.createJob(t, 'videoFileOptimizer', dataInput)
- )
+ await transcodingJobScheduler.createJob(t, 'videoFileOptimizer', dataInput)
}
- await Promise.all(tasks)
const videoCreated = await video.save(sequelizeOptions)
// Do not forget to add video channel information to the created video
videoCreated.VideoChannel = res.locals.videoChannel
videoFile.videoId = video.id
-
await videoFile.save(sequelizeOptions)
- video.VideoFiles = [videoFile]
+
+ video.VideoFiles = [ videoFile ]
if (videoInfo.tags) {
- const tagInstances = await db.Tag.findOrCreateTags(videoInfo.tags, t)
+ const tagInstances = await TagModel.findOrCreateTags(videoInfo.tags, t)
- await video.setTags(tagInstances, sequelizeOptions)
+ await video.$set('Tags', tagInstances, sequelizeOptions)
video.Tags = tagInstances
}
// Don't send video to remote servers, it is private
if (video.privacy === VideoPrivacy.PRIVATE) return videoCreated
- await sendAddVideo(video, t)
- await shareVideoByServer(video, t)
+ await sendCreateVideo(video, t)
+ // TODO: share by video channel
+ await shareVideoByServerAndChannel(video, t)
logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid)
}
async function updateVideo (req: express.Request, res: express.Response) {
- const videoInstance: VideoInstance = res.locals.video
+ const videoInstance: VideoModel = res.locals.video
const videoFieldsSave = videoInstance.toJSON()
const videoInfoToUpdate: VideoUpdate = req.body
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
try {
- await db.sequelize.transaction(async t => {
+ await sequelizeTypescript.transaction(async t => {
const sequelizeOptions = {
transaction: t
}
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.privacy !== undefined) videoInstance.set('privacy', videoInfoToUpdate.privacy)
+ if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10))
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
if (videoInfoToUpdate.tags) {
- const tagInstances = await db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t)
+ const tagInstances = await TagModel.findOrCreateTags(videoInfoToUpdate.tags, t)
- await videoInstance.setTags(tagInstances, sequelizeOptions)
+ await videoInstance.$set('Tags', tagInstances, sequelizeOptions)
videoInstance.Tags = tagInstances
}
}
// Video is not private anymore, send a create action to remote servers
- if (wasPrivateVideo === true && videoInstance.privacy !== VideoPrivacy.PRIVATE) {
- await sendAddVideo(videoInstance, t)
- await shareVideoByServer(videoInstance, t)
+ if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) {
+ await sendCreateVideo(videoInstanceUpdated, t)
+ // TODO: Send by video channel
+ await shareVideoByServerAndChannel(videoInstanceUpdated, t)
}
})
const videoInstance = res.locals.video
await videoInstance.increment('views')
- const serverAccount = await getServerAccount()
+ const serverAccount = await getServerActor()
if (videoInstance.isOwned()) {
await sendCreateViewToVideoFollowers(serverAccount, videoInstance, undefined)
}
async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
- const resultList = await db.Video.listForApi(req.query.start, req.query.count, req.query.sort)
+ const resultList = await VideoModel.listForApi(req.query.start, req.query.count, req.query.sort)
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
}
async function removeVideo (req: express.Request, res: express.Response) {
- const videoInstance: VideoInstance = res.locals.video
+ const videoInstance: VideoModel = res.locals.video
- await db.sequelize.transaction(async t => {
+ await sequelizeTypescript.transaction(async t => {
await videoInstance.destroy({ transaction: t })
})
}
async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
- const resultList = await db.Video.searchAndPopulateAccountAndServerAndTags(
+ const resultList = await VideoModel.searchAndPopulateAccountAndServerAndTags(
req.query.search,
req.query.start,
req.query.count,