Add live server hooks

This commit is contained in:
Chocobozzz 2020-11-06 13:59:50 +01:00 committed by Chocobozzz
parent c8f3cfeba7
commit 3cabf3532b
9 changed files with 133 additions and 32 deletions

View File

@ -262,7 +262,7 @@ live:
# PeerTube will transcode segments in a video file
# If the user daily/total quota is reached, PeerTube will stop the live
# /!\ transcoding.enabled (and not live.transcoding.enabled) has to be true to create a replay
allow_replay: true
allow_replay: false
rtmp:
port: 1935

View File

@ -5,6 +5,7 @@ import { CONFIG } from '@server/initializers/config'
import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants'
import { getVideoActivityPubUrl } from '@server/lib/activitypub/url'
import { federateVideoIfNeeded } from '@server/lib/activitypub/videos'
import { Hooks } from '@server/lib/plugins/hooks'
import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator } from '@server/middlewares/validators/videos/video-live'
import { VideoLiveModel } from '@server/models/video/video-live'
@ -128,6 +129,8 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
return { videoCreated }
})
Hooks.runAction('action:api.live-video.created', { video: videoCreated })
return res.json({
video: {
id: videoCreated.id,

View File

@ -118,7 +118,7 @@ class LiveManager {
}
run () {
logger.info('Running RTMP server.')
logger.info('Running RTMP server on port %d', config.rtmp.port)
this.rtmpServer = new NodeRtmpServer(config)
this.rtmpServer.run()

View File

@ -20,7 +20,7 @@ import {
import { ActivityCreate } from '../../shared/models/activitypub'
import { VideoObject } from '../../shared/models/activitypub/objects'
import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object'
import { VideoCreate, VideoImportCreate } from '../../shared/models/videos'
import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos'
import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model'
import { UserModel } from '../models/account/user'
import { ActorModel } from '../models/activitypub/actor'
@ -43,6 +43,13 @@ function isLocalVideoAccepted (object: {
return { accepted: true }
}
function isLocalLiveVideoAccepted (object: {
liveVideoBody: LiveVideoCreate
user: UserModel
}): AcceptResult {
return { accepted: true }
}
function isLocalVideoThreadAccepted (_object: {
commentBody: VideoCommentCreate
video: VideoModel
@ -175,6 +182,8 @@ function createAccountAbuse (options: {
}
export {
isLocalLiveVideoAccepted,
isLocalVideoAccepted,
isLocalVideoThreadAccepted,
isRemoteVideoAccepted,

View File

@ -11,6 +11,8 @@ import { CONFIG } from '../../../initializers/config'
import { areValidationErrors } from '../utils'
import { getCommonVideoEditAttributes } from './videos'
import { VideoModel } from '@server/models/video/video'
import { Hooks } from '@server/lib/plugins/hooks'
import { isLocalLiveVideoAccepted } from '@server/lib/moderation'
const videoLiveGetValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
@ -97,6 +99,8 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([
}
}
if (!await isLiveVideoAccepted(req, res)) return cleanUpReqFiles(req)
return next()
}
])
@ -137,3 +141,29 @@ export {
videoLiveUpdateValidator,
videoLiveGetValidator
}
// ---------------------------------------------------------------------------
async function isLiveVideoAccepted (req: express.Request, res: express.Response) {
// Check we accept this video
const acceptParameters = {
liveVideoBody: req.body,
user: res.locals.oauth.token.User
}
const acceptedResult = await Hooks.wrapFun(
isLocalLiveVideoAccepted,
acceptParameters,
'filter:api.live-video.create.accept.result'
)
if (!acceptedResult || acceptedResult.accepted !== true) {
logger.info('Refused local live video.', { acceptedResult, acceptParameters })
res.status(403)
.json({ error: acceptedResult.errorMessage || 'Refused local live video' })
return false
}
return true
}

View File

@ -7,6 +7,8 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
'action:api.video.uploaded',
'action:api.video.viewed',
'action:api.live-video.created',
'action:api.video-thread.created',
'action:api.video-comment-reply.created',
'action:api.video-comment.deleted',
@ -46,15 +48,22 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
}
})
for (const hook of [ 'filter:api.video.upload.accept.result', 'filter:api.live-video.create.accept.result' ]) {
registerHook({
target: 'filter:api.video.upload.accept.result',
handler: ({ accepted }, { videoBody }) => {
target: hook,
handler: ({ accepted }, { videoBody, liveVideoBody }) => {
if (!accepted) return { accepted: false }
if (videoBody.name.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word' }
const name = videoBody
? videoBody.name
: liveVideoBody.name
if (name.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word' }
return { accepted: true }
}
})
}
registerHook({
target: 'filter:api.video.pre-import-url.accept.result',

View File

@ -1,6 +1,27 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { ServerHookName, VideoPrivacy } from '@shared/models'
import {
addVideoCommentReply,
addVideoCommentThread,
blockUser,
createLive,
createUser,
deleteVideoComment,
getPluginTestPath,
installPlugin,
registerUser,
removeUser,
setAccessTokensToServers,
setDefaultVideoChannel,
unblockUser,
updateUser,
updateVideo,
uploadVideo,
userLogin,
viewVideo
} from '../../../shared/extra-utils'
import {
cleanupTests,
flushAndRunMultipleServers,
@ -9,31 +30,13 @@ import {
ServerInfo,
waitUntilLog
} from '../../../shared/extra-utils/server/servers'
import {
addVideoCommentReply,
addVideoCommentThread,
blockUser,
createUser,
deleteVideoComment,
getPluginTestPath,
installPlugin,
registerUser,
removeUser,
setAccessTokensToServers,
unblockUser,
updateUser,
updateVideo,
uploadVideo,
userLogin,
viewVideo
} from '../../../shared/extra-utils'
describe('Test plugin action hooks', function () {
let servers: ServerInfo[]
let videoUUID: string
let threadId: number
function checkHook (hook: string) {
function checkHook (hook: ServerHookName) {
return waitUntilLog(servers[0], 'Run hook ' + hook)
}
@ -42,6 +45,7 @@ describe('Test plugin action hooks', function () {
servers = await flushAndRunMultipleServers(2)
await setAccessTokensToServers(servers)
await setDefaultVideoChannel(servers)
await installPlugin({
url: servers[0].url,
@ -51,7 +55,11 @@ describe('Test plugin action hooks', function () {
killallServers([ servers[0] ])
await reRunServer(servers[0])
await reRunServer(servers[0], {
live: {
enabled: true
}
})
})
describe('Application hooks', function () {
@ -81,6 +89,21 @@ describe('Test plugin action hooks', function () {
})
})
describe('Live hooks', function () {
it('Should run action:api.live-video.created', async function () {
const attributes = {
name: 'live',
privacy: VideoPrivacy.PUBLIC,
channelId: servers[0].videoChannel.id
}
await createLive(servers[0].url, servers[0].accessToken, attributes)
await checkHook('action:api.live-video.created')
})
})
describe('Comments hooks', function () {
it('Should run action:api.video-thread.created', async function () {
const res = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'thread')

View File

@ -6,6 +6,7 @@ import { ServerConfig } from '@shared/models'
import {
addVideoCommentReply,
addVideoCommentThread,
createLive,
doubleFollow,
getConfig,
getPluginTestPath,
@ -19,6 +20,7 @@ import {
registerUser,
setAccessTokensToServers,
setDefaultVideoChannel,
updateCustomSubConfig,
updateVideo,
uploadVideo,
waitJobs
@ -61,6 +63,17 @@ describe('Test plugin filter hooks', function () {
const res = await getVideosList(servers[0].url)
videoUUID = res.body.data[0].uuid
await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
live: { enabled: true },
signup: { enabled: true },
import: {
videos: {
http: { enabled: true },
torrent: { enabled: true }
}
}
})
})
it('Should run filter:api.videos.list.params', async function () {
@ -87,6 +100,16 @@ describe('Test plugin filter hooks', function () {
await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video with bad word' }, 403)
})
it('Should run filter:api.live-video.create.accept.result', async function () {
const attributes = {
name: 'video with bad word',
privacy: VideoPrivacy.PUBLIC,
channelId: servers[0].videoChannel.id
}
await createLive(servers[0].url, servers[0].accessToken, attributes, 403)
})
it('Should run filter:api.video.pre-import-url.accept.result', async function () {
const baseAttributes = {
name: 'normal title',

View File

@ -9,9 +9,10 @@ export const serverFilterHookObject = {
// Used to get detailed video information (video watch page for example)
'filter:api.video.get.result': true,
// Filter the result of the accept upload, import via torrent or url functions
// Filter the result of the accept upload/live, import via torrent/url functions
// If this function returns false then the upload is aborted with an error
'filter:api.video.upload.accept.result': true,
'filter:api.live-video.create.accept.result': true,
'filter:api.video.pre-import-url.accept.result': true,
'filter:api.video.pre-import-torrent.accept.result': true,
'filter:api.video.post-import-url.accept.result': true,
@ -54,6 +55,9 @@ export const serverActionHookObject = {
// Fired when a local video is viewed
'action:api.video.viewed': true,
// Fired when a live video is created
'action:api.live-video.created': true,
// Fired when a thread is created
'action:api.video-thread.created': true,
// Fired when a reply to a thread is created