X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=server%2Flib%2Fjob-queue%2Fhandlers%2Fvideo-import.ts;h=1650916a67b7f2a5bd0efb3ecfd834eafb88b04d;hb=3acc50844047a37698f0618fa235c138e386a053;hp=2d19b82a4dc200e5ddf4886d0c25f3ea1586eb50;hpb=3e17515e2996b79e23f569c296051a91af3fcbe4;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 2d19b82a4..1650916a6 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts @@ -6,15 +6,20 @@ import { VideoImportState } from '../../../../shared/models/videos' import { getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' import { extname, join } from 'path' import { VideoFileModel } from '../../../models/video/video-file' -import { renamePromise, statPromise, unlinkPromise } from '../../../helpers/core-utils' -import { CONFIG, sequelizeTypescript } from '../../../initializers' -import { doRequestAndSaveToFile } from '../../../helpers/requests' +import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants' import { VideoState } from '../../../../shared' import { JobQueue } from '../index' import { federateVideoIfNeeded } from '../../activitypub' import { VideoModel } from '../../../models/video/video' import { downloadWebTorrentVideo } from '../../../helpers/webtorrent' import { getSecureTorrentName } from '../../../helpers/utils' +import { move, remove, stat } from 'fs-extra' +import { Notifier } from '../../notifier' +import { CONFIG } from '../../../initializers/config' +import { sequelizeTypescript } from '../../../initializers/database' +import { ThumbnailModel } from '../../../models/video/thumbnail' +import { createVideoMiniatureFromUrl, generateVideoMiniature } from '../../thumbnail' +import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' type VideoImportYoutubeDLPayload = { type: 'youtube-dl' @@ -65,7 +70,7 @@ async function processTorrentImport (job: Bull.Job, payload: VideoImportTorrentP torrentName: videoImport.torrentName ? getSecureTorrentName(videoImport.torrentName) : undefined, magnetUri: videoImport.magnetUri } - return processFile(() => downloadWebTorrentVideo(target), videoImport, options) + return processFile(() => downloadWebTorrentVideo(target, VIDEO_IMPORT_TIMEOUT), videoImport, options) } async function processYoutubeDLImport (job: Bull.Job, payload: VideoImportYoutubeDLPayload) { @@ -83,7 +88,7 @@ async function processYoutubeDLImport (job: Bull.Job, payload: VideoImportYoutub generatePreview: false } - return processFile(() => downloadYoutubeDLVideo(videoImport.targetUrl), videoImport, options) + return processFile(() => downloadYoutubeDLVideo(videoImport.targetUrl, VIDEO_IMPORT_TIMEOUT), videoImport, options) } async function getVideoImportOrDie (videoImportId: number) { @@ -109,12 +114,13 @@ async function processFile (downloader: () => Promise, videoImport: Vide let tempVideoPath: string let videoDestFile: string let videoFile: VideoFileModel + try { // Download video from youtubeDL tempVideoPath = await downloader() // Get information about this video - const stats = await statPromise(tempVideoPath) + const stats = await stat(tempVideoPath) const isAble = await videoImport.User.isAbleToUploadVideo({ size: stats.size }) if (isAble === false) { throw new Error('The user video quota is exceeded with this video to import.') @@ -133,36 +139,28 @@ async function processFile (downloader: () => Promise, videoImport: Vide videoId: videoImport.videoId } videoFile = new VideoFileModel(videoFileData) - // Import if the import fails, to clean files + // To clean files if the import fails videoImport.Video.VideoFiles = [ videoFile ] // Move file videoDestFile = join(CONFIG.STORAGE.VIDEOS_DIR, videoImport.Video.getVideoFilename(videoFile)) - await renamePromise(tempVideoPath, videoDestFile) + await move(tempVideoPath, videoDestFile) tempVideoPath = null // This path is not used anymore // Process thumbnail - if (options.downloadThumbnail) { - if (options.thumbnailUrl) { - const destThumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, videoImport.Video.getThumbnailName()) - await doRequestAndSaveToFile({ method: 'GET', uri: options.thumbnailUrl }, destThumbnailPath) - } else { - await videoImport.Video.createThumbnail(videoFile) - } - } else if (options.generateThumbnail) { - await videoImport.Video.createThumbnail(videoFile) + let thumbnailModel: ThumbnailModel + if (options.downloadThumbnail && options.thumbnailUrl) { + thumbnailModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.MINIATURE) + } else if (options.generateThumbnail || options.downloadThumbnail) { + thumbnailModel = await generateVideoMiniature(videoImport.Video, videoFile, ThumbnailType.MINIATURE) } // Process preview - if (options.downloadPreview) { - if (options.thumbnailUrl) { - const destPreviewPath = join(CONFIG.STORAGE.PREVIEWS_DIR, videoImport.Video.getPreviewName()) - await doRequestAndSaveToFile({ method: 'GET', uri: options.thumbnailUrl }, destPreviewPath) - } else { - await videoImport.Video.createPreview(videoFile) - } - } else if (options.generatePreview) { - await videoImport.Video.createPreview(videoFile) + let previewModel: ThumbnailModel + if (options.downloadPreview && options.thumbnailUrl) { + previewModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.PREVIEW) + } else if (options.generatePreview || options.downloadPreview) { + previewModel = await generateVideoMiniature(videoImport.Video, videoFile, ThumbnailType.PREVIEW) } // Create torrent @@ -180,22 +178,33 @@ async function processFile (downloader: () => Promise, videoImport: Vide // Update video DB object video.duration = duration video.state = CONFIG.TRANSCODING.ENABLED ? VideoState.TO_TRANSCODE : VideoState.PUBLISHED - const videoUpdated = await video.save({ transaction: t }) + await video.save({ transaction: t }) + + if (thumbnailModel) await video.addAndSaveThumbnail(thumbnailModel, t) + if (previewModel) await video.addAndSaveThumbnail(previewModel, t) // Now we can federate the video (reload from database, we need more attributes) - const videoForFederation = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(video.uuid, t) + const videoForFederation = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) await federateVideoIfNeeded(videoForFederation, true, t) // Update video import object videoImport.state = VideoImportState.SUCCESS const videoImportUpdated = await videoImport.save({ transaction: t }) - logger.info('Video %s imported.', videoImport.targetUrl) + logger.info('Video %s imported.', video.uuid) - videoImportUpdated.Video = videoUpdated + videoImportUpdated.Video = videoForFederation return videoImportUpdated }) + Notifier.Instance.notifyOnFinishedVideoImport(videoImportUpdated, true) + + if (videoImportUpdated.Video.VideoBlacklist) { + Notifier.Instance.notifyOnVideoAutoBlacklist(videoImportUpdated.Video) + } else { + Notifier.Instance.notifyOnNewVideo(videoImportUpdated.Video) + } + // Create transcoding jobs? if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { // Put uuid because we don't have id auto incremented for now @@ -204,12 +213,12 @@ async function processFile (downloader: () => Promise, videoImport: Vide isNewVideo: true } - await JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput }) + await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) } } catch (err) { try { - // if (tempVideoPath) await unlinkPromise(tempVideoPath) + if (tempVideoPath) await remove(tempVideoPath) } catch (errUnlink) { logger.warn('Cannot cleanup files after a video import error.', { err: errUnlink }) } @@ -218,6 +227,8 @@ async function processFile (downloader: () => Promise, videoImport: Vide videoImport.state = VideoImportState.FAILED await videoImport.save() + Notifier.Instance.notifyOnFinishedVideoImport(videoImport, false) + throw err } }