From d17d743051c5716e1e08cd8870d718cfd6a57f0c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 10 Dec 2021 13:49:19 +0100 Subject: [PATCH] Add upload/import/go live video attributes hooks --- server/controllers/api/videos/import.ts | 17 ++++-- server/controllers/api/videos/live.ts | 4 +- server/controllers/api/videos/upload.ts | 3 +- .../fixtures/peertube-plugin-test/main.js | 15 +++++ server/tests/plugins/filter-hooks.ts | 59 +++++++++++++++++++ .../plugins/server/server-hook.model.ts | 6 ++ 6 files changed, 98 insertions(+), 6 deletions(-) diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index eddb9b32d..52864bdfd 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts @@ -38,6 +38,7 @@ import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoIm import { VideoModel } from '../../../models/video/video' import { VideoCaptionModel } from '../../../models/video/video-caption' import { VideoImportModel } from '../../../models/video/video-import' +import { Hooks } from '@server/lib/plugins/hooks' const auditLogger = auditLoggerFactory('video-imports') const videoImportsRouter = express.Router() @@ -94,7 +95,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to videoName = result.name } - const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) + const video = await buildVideo(res.locals.videoChannel.id, body, { name: videoName }) const thumbnailModel = await processThumbnail(req, video) const previewModel = await processPreview(req, video) @@ -151,7 +152,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) }) } - const video = buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) + const video = await buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) // Process video thumbnail from request.files let thumbnailModel = await processThumbnail(req, video) @@ -210,8 +211,8 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) return res.json(videoImport.toFormattedJSON()).end() } -function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): MVideoThumbnail { - const videoData = { +async function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): Promise { + let videoData = { name: body.name || importData.name || 'Unknown name', remote: false, category: body.category || importData.category, @@ -231,6 +232,14 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You ? new Date(body.originallyPublishedAt) : importData.originallyPublishedAt } + + videoData = await Hooks.wrapObject( + videoData, + body.targetUrl + ? 'filter:api.video.import-url.video-attribute.result' + : 'filter:api.video.import-torrent.video-attribute.result' + ) + const video = new VideoModel(videoData) video.url = getLocalVideoActivityPubUrl(video) diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts index e29615ff5..3e1480cf2 100644 --- a/server/controllers/api/videos/live.ts +++ b/server/controllers/api/videos/live.ts @@ -83,7 +83,9 @@ async function addLiveVideo (req: express.Request, res: express.Response) { const videoInfo: LiveVideoCreate = req.body // Prepare data so we don't block the transaction - const videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) + let videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) + videoData = await Hooks.wrapObject(videoData, 'filter:api.video.live.video-attribute.result') + videoData.isLive = true videoData.state = VideoState.WAITING_FOR_LIVE videoData.duration = 0 diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts index c827f6bf0..1be87f746 100644 --- a/server/controllers/api/videos/upload.ts +++ b/server/controllers/api/videos/upload.ts @@ -153,7 +153,8 @@ async function addVideo (options: { const videoChannel = res.locals.videoChannel const user = res.locals.oauth.token.User - const videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) + let videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) + videoData = await Hooks.wrapObject(videoData, 'filter:api.video.upload.video-attribute.result') videoData.state = buildNextVideoState() videoData.duration = videoPhysicalFile.duration // duration was added by a previous middleware diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index aba415d1e..04e059848 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js @@ -240,6 +240,21 @@ async function register ({ registerHook, registerSetting, settingsManager, stora } }) + // Upload/import/live attributes + for (const target of [ + 'filter:api.video.upload.video-attribute.result', + 'filter:api.video.import-url.video-attribute.result', + 'filter:api.video.import-torrent.video-attribute.result', + 'filter:api.video.live.video-attribute.result' + ]) { + registerHook({ + target, + handler: (result) => { + return { ...result, description: result.description + ' - ' + target } + } + }) + } + { const filterHooks = [ 'filter:api.search.videos.local.list.params', diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 80014566b..ff2afc56b 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts @@ -537,6 +537,65 @@ describe('Test plugin filter hooks', function () { }) }) + describe('Upload/import/live attributes filters', function () { + + before(async function () { + await servers[0].config.enableLive({ transcoding: false, allowReplay: false }) + await servers[0].config.enableImports() + await servers[0].config.disableTranscoding() + }) + + it('Should run filter:api.video.upload.video-attribute.result', async function () { + for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) { + const { id } = await servers[0].videos.upload({ attributes: { name: 'video', description: 'upload' }, mode }) + + const video = await servers[0].videos.get({ id }) + expect(video.description).to.equal('upload - filter:api.video.upload.video-attribute.result') + } + }) + + it('Should run filter:api.video.import-url.video-attribute.result', async function () { + const attributes = { + name: 'video', + description: 'import url', + channelId: servers[0].store.channel.id, + targetUrl: FIXTURE_URLS.goodVideo, + privacy: VideoPrivacy.PUBLIC + } + const { video: { id } } = await servers[0].imports.importVideo({ attributes }) + + const video = await servers[0].videos.get({ id }) + expect(video.description).to.equal('import url - filter:api.video.import-url.video-attribute.result') + }) + + it('Should run filter:api.video.import-torrent.video-attribute.result', async function () { + const attributes = { + name: 'video', + description: 'import torrent', + channelId: servers[0].store.channel.id, + magnetUri: FIXTURE_URLS.magnet, + privacy: VideoPrivacy.PUBLIC + } + const { video: { id } } = await servers[0].imports.importVideo({ attributes }) + + const video = await servers[0].videos.get({ id }) + expect(video.description).to.equal('import torrent - filter:api.video.import-torrent.video-attribute.result') + }) + + it('Should run filter:api.video.live.video-attribute.result', async function () { + const fields = { + name: 'live', + description: 'live', + channelId: servers[0].store.channel.id, + privacy: VideoPrivacy.PUBLIC + } + const { id } = await servers[0].live.create({ fields }) + + const video = await servers[0].videos.get({ id }) + expect(video.description).to.equal('live - filter:api.video.live.video-attribute.result') + }) + }) + describe('Stats filters', function () { it('Should run filter:api.server.stats.get.result', async function () { diff --git a/shared/models/plugins/server/server-hook.model.ts b/shared/models/plugins/server/server-hook.model.ts index 7e344e003..056c41a7f 100644 --- a/shared/models/plugins/server/server-hook.model.ts +++ b/shared/models/plugins/server/server-hook.model.ts @@ -53,6 +53,12 @@ export const serverFilterHookObject = { 'filter:api.video-thread.create.accept.result': true, 'filter:api.video-comment-reply.create.accept.result': true, + // Filter attributes when creating video object + 'filter:api.video.upload.video-attribute.result': true, + 'filter:api.video.import-url.video-attribute.result': true, + 'filter:api.video.import-torrent.video-attribute.result': true, + 'filter:api.video.live.video-attribute.result': true, + // Filter params/result used to list threads of a specific video // (used by the video watch page) 'filter:api.video-threads.list.params': true,