diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-05-14 11:10:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-14 11:10:26 +0200 |
commit | 2158ac90341dc3fcae958540de65032da25c8d6e (patch) | |
tree | a780923d701f3daa130996768e38c1e1b6a0646c /server/lib | |
parent | 7405b6ba897dbce1b4fd50c92174f1df5ac15adc (diff) | |
download | PeerTube-2158ac90341dc3fcae958540de65032da25c8d6e.tar.gz PeerTube-2158ac90341dc3fcae958540de65032da25c8d6e.tar.zst PeerTube-2158ac90341dc3fcae958540de65032da25c8d6e.zip |
Add server plugin filter hooks for import with torrent and url (#2621)
* Add server plugin filter hooks for import with torrent and url
* WIP: pre and post-import filter hooks
* Rebased
* Cleanup filters to accept imports
Co-authored-by: Chocobozzz <me@florianbigard.com>
Diffstat (limited to 'server/lib')
-rw-r--r-- | server/lib/job-queue/handlers/video-import.ts | 76 | ||||
-rw-r--r-- | server/lib/moderation.ts | 24 |
2 files changed, 79 insertions, 21 deletions
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index ad549c6fc..a197ef629 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -1,27 +1,36 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { logger } from '../../../helpers/logger' | 2 | import { move, remove, stat } from 'fs-extra' |
3 | import { downloadYoutubeDLVideo } from '../../../helpers/youtube-dl' | 3 | import { extname } from 'path' |
4 | import { VideoImportModel } from '../../../models/video/video-import' | 4 | import { addOptimizeOrMergeAudioJob } from '@server/helpers/video' |
5 | import { isPostImportVideoAccepted } from '@server/lib/moderation' | ||
6 | import { Hooks } from '@server/lib/plugins/hooks' | ||
7 | import { getVideoFilePath } from '@server/lib/video-paths' | ||
8 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/typings/models/video/video-import' | ||
9 | import { | ||
10 | VideoImportPayload, | ||
11 | VideoImportTorrentPayload, | ||
12 | VideoImportTorrentPayloadType, | ||
13 | VideoImportYoutubeDLPayload, | ||
14 | VideoImportYoutubeDLPayloadType, | ||
15 | VideoState | ||
16 | } from '../../../../shared' | ||
5 | import { VideoImportState } from '../../../../shared/models/videos' | 17 | import { VideoImportState } from '../../../../shared/models/videos' |
18 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | ||
6 | import { getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 19 | import { getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
7 | import { extname } from 'path' | 20 | import { logger } from '../../../helpers/logger' |
8 | import { VideoFileModel } from '../../../models/video/video-file' | ||
9 | import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants' | ||
10 | import { VideoImportPayload, VideoImportTorrentPayload, VideoImportYoutubeDLPayload, VideoState } from '../../../../shared' | ||
11 | import { federateVideoIfNeeded } from '../../activitypub/videos' | ||
12 | import { VideoModel } from '../../../models/video/video' | ||
13 | import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' | ||
14 | import { getSecureTorrentName } from '../../../helpers/utils' | 21 | import { getSecureTorrentName } from '../../../helpers/utils' |
15 | import { move, remove, stat } from 'fs-extra' | 22 | import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' |
16 | import { Notifier } from '../../notifier' | 23 | import { downloadYoutubeDLVideo } from '../../../helpers/youtube-dl' |
17 | import { CONFIG } from '../../../initializers/config' | 24 | import { CONFIG } from '../../../initializers/config' |
25 | import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants' | ||
18 | import { sequelizeTypescript } from '../../../initializers/database' | 26 | import { sequelizeTypescript } from '../../../initializers/database' |
19 | import { generateVideoMiniature } from '../../thumbnail' | 27 | import { VideoModel } from '../../../models/video/video' |
20 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | 28 | import { VideoFileModel } from '../../../models/video/video-file' |
29 | import { VideoImportModel } from '../../../models/video/video-import' | ||
21 | import { MThumbnail } from '../../../typings/models/video/thumbnail' | 30 | import { MThumbnail } from '../../../typings/models/video/thumbnail' |
22 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/typings/models/video/video-import' | 31 | import { federateVideoIfNeeded } from '../../activitypub/videos' |
23 | import { getVideoFilePath } from '@server/lib/video-paths' | 32 | import { Notifier } from '../../notifier' |
24 | import { addOptimizeOrMergeAudioJob } from '@server/helpers/video' | 33 | import { generateVideoMiniature } from '../../thumbnail' |
25 | 34 | ||
26 | async function processVideoImport (job: Bull.Job) { | 35 | async function processVideoImport (job: Bull.Job) { |
27 | const payload = job.data as VideoImportPayload | 36 | const payload = job.data as VideoImportPayload |
@@ -44,6 +53,7 @@ async function processTorrentImport (job: Bull.Job, payload: VideoImportTorrentP | |||
44 | const videoImport = await getVideoImportOrDie(payload.videoImportId) | 53 | const videoImport = await getVideoImportOrDie(payload.videoImportId) |
45 | 54 | ||
46 | const options = { | 55 | const options = { |
56 | type: payload.type, | ||
47 | videoImportId: payload.videoImportId, | 57 | videoImportId: payload.videoImportId, |
48 | 58 | ||
49 | generateThumbnail: true, | 59 | generateThumbnail: true, |
@@ -61,6 +71,7 @@ async function processYoutubeDLImport (job: Bull.Job, payload: VideoImportYoutub | |||
61 | 71 | ||
62 | const videoImport = await getVideoImportOrDie(payload.videoImportId) | 72 | const videoImport = await getVideoImportOrDie(payload.videoImportId) |
63 | const options = { | 73 | const options = { |
74 | type: payload.type, | ||
64 | videoImportId: videoImport.id, | 75 | videoImportId: videoImport.id, |
65 | 76 | ||
66 | generateThumbnail: payload.generateThumbnail, | 77 | generateThumbnail: payload.generateThumbnail, |
@@ -80,6 +91,7 @@ async function getVideoImportOrDie (videoImportId: number) { | |||
80 | } | 91 | } |
81 | 92 | ||
82 | type ProcessFileOptions = { | 93 | type ProcessFileOptions = { |
94 | type: VideoImportYoutubeDLPayloadType | VideoImportTorrentPayloadType | ||
83 | videoImportId: number | 95 | videoImportId: number |
84 | 96 | ||
85 | generateThumbnail: boolean | 97 | generateThumbnail: boolean |
@@ -105,7 +117,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
105 | const fps = await getVideoFileFPS(tempVideoPath) | 117 | const fps = await getVideoFileFPS(tempVideoPath) |
106 | const duration = await getDurationFromVideoFile(tempVideoPath) | 118 | const duration = await getDurationFromVideoFile(tempVideoPath) |
107 | 119 | ||
108 | // Create video file object in database | 120 | // Prepare video file object for creation in database |
109 | const videoFileData = { | 121 | const videoFileData = { |
110 | extname: extname(tempVideoPath), | 122 | extname: extname(tempVideoPath), |
111 | resolution: videoFileResolution, | 123 | resolution: videoFileResolution, |
@@ -115,6 +127,30 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
115 | } | 127 | } |
116 | videoFile = new VideoFileModel(videoFileData) | 128 | videoFile = new VideoFileModel(videoFileData) |
117 | 129 | ||
130 | const hookName = options.type === 'youtube-dl' | ||
131 | ? 'filter:api.video.post-import-url.accept.result' | ||
132 | : 'filter:api.video.post-import-torrent.accept.result' | ||
133 | |||
134 | // Check we accept this video | ||
135 | const acceptParameters = { | ||
136 | videoImport, | ||
137 | video: videoImport.Video, | ||
138 | videoFilePath: tempVideoPath, | ||
139 | videoFile, | ||
140 | user: videoImport.User | ||
141 | } | ||
142 | const acceptedResult = await Hooks.wrapFun(isPostImportVideoAccepted, acceptParameters, hookName) | ||
143 | |||
144 | if (acceptedResult.accepted !== true) { | ||
145 | logger.info('Refused imported video.', { acceptedResult, acceptParameters }) | ||
146 | |||
147 | videoImport.state = VideoImportState.REJECTED | ||
148 | await videoImport.save() | ||
149 | |||
150 | throw new Error(acceptedResult.errorMessage) | ||
151 | } | ||
152 | |||
153 | // Video is accepted, resuming preparation | ||
118 | const videoWithFiles = Object.assign(videoImport.Video, { VideoFiles: [ videoFile ], VideoStreamingPlaylists: [] }) | 154 | const videoWithFiles = Object.assign(videoImport.Video, { VideoFiles: [ videoFile ], VideoStreamingPlaylists: [] }) |
119 | // To clean files if the import fails | 155 | // To clean files if the import fails |
120 | const videoImportWithFiles: MVideoImportDefaultFiles = Object.assign(videoImport, { Video: videoWithFiles }) | 156 | const videoImportWithFiles: MVideoImportDefaultFiles = Object.assign(videoImport, { Video: videoWithFiles }) |
@@ -194,7 +230,9 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
194 | } | 230 | } |
195 | 231 | ||
196 | videoImport.error = err.message | 232 | videoImport.error = err.message |
197 | videoImport.state = VideoImportState.FAILED | 233 | if (videoImport.state !== VideoImportState.REJECTED) { |
234 | videoImport.state = VideoImportState.FAILED | ||
235 | } | ||
198 | await videoImport.save() | 236 | await videoImport.save() |
199 | 237 | ||
200 | Notifier.Instance.notifyOnFinishedVideoImport(videoImport, false) | 238 | Notifier.Instance.notifyOnFinishedVideoImport(videoImport, false) |
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index 55f7a985d..4afebb32a 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts | |||
@@ -1,12 +1,15 @@ | |||
1 | import { VideoModel } from '../models/video/video' | 1 | import { VideoModel } from '../models/video/video' |
2 | import { VideoCommentModel } from '../models/video/video-comment' | 2 | import { VideoCommentModel } from '../models/video/video-comment' |
3 | import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model' | 3 | import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model' |
4 | import { VideoCreate } from '../../shared/models/videos' | 4 | import { VideoCreate, VideoImportCreate } from '../../shared/models/videos' |
5 | import { UserModel } from '../models/account/user' | 5 | import { UserModel } from '../models/account/user' |
6 | import { VideoTorrentObject } from '../../shared/models/activitypub/objects' | 6 | import { VideoTorrentObject } from '../../shared/models/activitypub/objects' |
7 | import { ActivityCreate } from '../../shared/models/activitypub' | 7 | import { ActivityCreate } from '../../shared/models/activitypub' |
8 | import { ActorModel } from '../models/activitypub/actor' | 8 | import { ActorModel } from '../models/activitypub/actor' |
9 | import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object' | 9 | import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object' |
10 | import { VideoFileModel } from '@server/models/video/video-file' | ||
11 | import { PathLike } from 'fs-extra' | ||
12 | import { MUser } from '@server/typings/models' | ||
10 | 13 | ||
11 | export type AcceptResult = { | 14 | export type AcceptResult = { |
12 | accepted: boolean | 15 | accepted: boolean |
@@ -55,10 +58,27 @@ function isRemoteVideoCommentAccepted (_object: { | |||
55 | return { accepted: true } | 58 | return { accepted: true } |
56 | } | 59 | } |
57 | 60 | ||
61 | function isPreImportVideoAccepted (object: { | ||
62 | videoImportBody: VideoImportCreate | ||
63 | user: MUser | ||
64 | }): AcceptResult { | ||
65 | return { accepted: true } | ||
66 | } | ||
67 | |||
68 | function isPostImportVideoAccepted (object: { | ||
69 | videoFilePath: PathLike | ||
70 | videoFile: VideoFileModel | ||
71 | user: MUser | ||
72 | }): AcceptResult { | ||
73 | return { accepted: true } | ||
74 | } | ||
75 | |||
58 | export { | 76 | export { |
59 | isLocalVideoAccepted, | 77 | isLocalVideoAccepted, |
60 | isLocalVideoThreadAccepted, | 78 | isLocalVideoThreadAccepted, |
61 | isRemoteVideoAccepted, | 79 | isRemoteVideoAccepted, |
62 | isRemoteVideoCommentAccepted, | 80 | isRemoteVideoCommentAccepted, |
63 | isLocalVideoCommentReplyAccepted | 81 | isLocalVideoCommentReplyAccepted, |
82 | isPreImportVideoAccepted, | ||
83 | isPostImportVideoAccepted | ||
64 | } | 84 | } |