import { UploadFiles } from 'express'
+import memoizee from 'memoizee'
import { Transaction } from 'sequelize/types'
+import { CONFIG } from '@server/initializers/config'
import { DEFAULT_AUDIO_RESOLUTION, JOB_PRIORITY, MEMOIZE_LENGTH, MEMOIZE_TTL } from '@server/initializers/constants'
import { TagModel } from '@server/models/video/tag'
import { VideoModel } from '@server/models/video/video'
import { VideoJobInfoModel } from '@server/models/video/video-job-info'
import { FilteredModelAttributes } from '@server/types'
-import { MThumbnail, MUserId, MVideoFile, MVideoTag, MVideoThumbnail, MVideoUUID } from '@server/types/models'
-import { ThumbnailType, VideoCreate, VideoPrivacy, VideoState, VideoTranscodingPayload } from '@shared/models'
-import { CreateJobOptions, JobQueue } from './job-queue/job-queue'
+import { MThumbnail, MUserId, MVideoFile, MVideoFullLight, MVideoTag, MVideoThumbnail, MVideoUUID } from '@server/types/models'
+import { ManageVideoTorrentPayload, ThumbnailType, VideoCreate, VideoPrivacy, VideoState, VideoTranscodingPayload } from '@shared/models'
+import { CreateJobArgument, CreateJobOptions, JobQueue } from './job-queue/job-queue'
import { updateVideoMiniatureFromExisting } from './thumbnail'
-import { CONFIG } from '@server/initializers/config'
-import memoizee from 'memoizee'
+import { moveFilesIfPrivacyChanged } from './video-privacy'
function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): FilteredModelAttributes<VideoModel> {
return {
// ---------------------------------------------------------------------------
-async function addOptimizeOrMergeAudioJob (options: {
+async function buildOptimizeOrMergeAudioJob (options: {
video: MVideoUUID
videoFile: MVideoFile
user: MUserId
}) {
const { video, videoFile, user, isNewVideo } = options
- let dataInput: VideoTranscodingPayload
+ let payload: VideoTranscodingPayload
if (videoFile.isAudio()) {
- dataInput = {
+ payload = {
type: 'merge-audio-to-webtorrent',
resolution: DEFAULT_AUDIO_RESOLUTION,
videoUUID: video.uuid,
isNewVideo
}
} else {
- dataInput = {
+ payload = {
type: 'optimize-to-webtorrent',
videoUUID: video.uuid,
isNewVideo
}
}
- const jobOptions = {
- priority: await getTranscodingJobPriority(user)
- }
+ await VideoJobInfoModel.increaseOrCreate(payload.videoUUID, 'pendingTranscode')
- return addTranscodingJob(dataInput, jobOptions)
+ return {
+ type: 'video-transcoding' as 'video-transcoding',
+ priority: await getTranscodingJobPriority(user),
+ payload
+ }
}
-async function addTranscodingJob (payload: VideoTranscodingPayload, options: CreateJobOptions = {}) {
+async function buildTranscodingJob (payload: VideoTranscodingPayload, options: CreateJobOptions = {}) {
await VideoJobInfoModel.increaseOrCreate(payload.videoUUID, 'pendingTranscode')
- return JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload }, options)
+ return { type: 'video-transcoding' as 'video-transcoding', payload, ...options }
}
async function getTranscodingJobPriority (user: MUserId) {
// ---------------------------------------------------------------------------
-async function addMoveToObjectStorageJob (options: {
+async function buildMoveToObjectStorageJob (options: {
video: MVideoUUID
previousVideoState: VideoState
isNewVideo?: boolean // Default true
await VideoJobInfoModel.increaseOrCreate(video.uuid, 'pendingMove')
- const dataInput = { videoUUID: video.uuid, isNewVideo, previousVideoState }
- return JobQueue.Instance.createJobWithPromise({ type: 'move-to-object-storage', payload: dataInput })
+ return {
+ type: 'move-to-object-storage' as 'move-to-object-storage',
+ payload: {
+ videoUUID: video.uuid,
+ isNewVideo,
+ previousVideoState
+ }
+ }
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
+async function addVideoJobsAfterUpdate (options: {
+ video: MVideoFullLight
+ isNewVideo: boolean
+
+ nameChanged: boolean
+ oldPrivacy: VideoPrivacy
+}) {
+ const { video, nameChanged, oldPrivacy, isNewVideo } = options
+ const jobs: CreateJobArgument[] = []
+
+ const filePathChanged = await moveFilesIfPrivacyChanged(video, oldPrivacy)
+
+ if (!video.isLive && (nameChanged || filePathChanged)) {
+ for (const file of (video.VideoFiles || [])) {
+ const payload: ManageVideoTorrentPayload = { action: 'update-metadata', videoId: video.id, videoFileId: file.id }
+
+ jobs.push({ type: 'manage-video-torrent', payload })
+ }
+
+ const hls = video.getHLSPlaylist()
+
+ for (const file of (hls?.VideoFiles || [])) {
+ const payload: ManageVideoTorrentPayload = { action: 'update-metadata', streamingPlaylistId: hls.id, videoFileId: file.id }
+
+ jobs.push({ type: 'manage-video-torrent', payload })
+ }
+ }
+
+ jobs.push({
+ type: 'federate-video',
+ payload: {
+ videoUUID: video.uuid,
+ isNewVideo
+ }
+ })
+
+ const wasConfidentialVideo = new Set([ VideoPrivacy.PRIVATE, VideoPrivacy.UNLISTED, VideoPrivacy.INTERNAL ]).has(oldPrivacy)
+
+ if (wasConfidentialVideo) {
+ jobs.push({
+ type: 'notify',
+ payload: {
+ action: 'new-video',
+ videoUUID: video.uuid
+ }
+ })
+ }
+
+ return JobQueue.Instance.createSequentialJobFlow(...jobs)
+}
+
+// ---------------------------------------------------------------------------
+
export {
buildLocalVideoFromReq,
buildVideoThumbnailsFromReq,
setVideoTags,
- addOptimizeOrMergeAudioJob,
- addTranscodingJob,
- addMoveToObjectStorageJob,
+ buildOptimizeOrMergeAudioJob,
+ buildTranscodingJob,
+ buildMoveToObjectStorageJob,
getTranscodingJobPriority,
+ addVideoJobsAfterUpdate,
getCachedVideoDuration
}