Browse Source

Add video AP hooks

tags/v5.1.0
Chocobozzz 2 weeks ago
parent
commit
c3441b0320
No known key found for this signature in database GPG Key ID: 583A612D890159BE
6 changed files with 121 additions and 32 deletions
  1. +3
    -0
      server/lib/activitypub/videos/shared/creator.ts
  2. +3
    -0
      server/lib/activitypub/videos/updater.ts
  3. +41
    -30
      server/tests/fixtures/peertube-plugin-test/main.js
  4. +24
    -0
      server/tests/plugins/action-hooks.ts
  5. +6
    -2
      shared/models/plugins/server/server-hook.model.ts
  6. +44
    -0
      support/doc/plugins/guide.md

+ 3
- 0
server/lib/activitypub/videos/shared/creator.ts View File

@@ -1,6 +1,7 @@

import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger'
import { sequelizeTypescript } from '@server/initializers/database'
import { Hooks } from '@server/lib/plugins/hooks'
import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist'
import { VideoModel } from '@server/models/video/video'
import { MThumbnail, MVideoFullLight, MVideoThumbnail } from '@server/types/models'
@@ -61,6 +62,8 @@ export class APVideoCreator extends APVideoAbstractBuilder {

logger.info('Remote video with uuid %s inserted.', this.videoObject.uuid, this.lTags())

Hooks.runAction('action:activity-pub.remote-video.created', { video: videoCreated, videoAPObject: this.videoObject })

return { autoBlacklisted, videoCreated }
} catch (err) {
// FIXME: Use rollback hook when https://github.com/sequelize/sequelize/pull/13038 is released


+ 3
- 0
server/lib/activitypub/videos/updater.ts View File

@@ -3,6 +3,7 @@ import { resetSequelizeInstance, runInReadCommittedTransaction } from '@server/h
import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger'
import { Notifier } from '@server/lib/notifier'
import { PeerTubeSocket } from '@server/lib/peertube-socket'
import { Hooks } from '@server/lib/plugins/hooks'
import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist'
import { VideoLiveModel } from '@server/models/video/video-live'
import { MActor, MChannelAccountLight, MChannelId, MVideoAccountLightBlacklistAllFiles, MVideoFullLight } from '@server/types/models'
@@ -81,6 +82,8 @@ export class APVideoUpdater extends APVideoAbstractBuilder {
PeerTubeSocket.Instance.sendVideoLiveNewState(videoUpdated)
}

Hooks.runAction('action:activity-pub.remote-video.updated', { video: videoUpdated, videoAPObject: this.videoObject })

logger.info('Remote video with uuid %s updated', this.videoObject.uuid, this.lTags())

return videoUpdated


+ 41
- 30
server/tests/fixtures/peertube-plugin-test/main.js View File

@@ -1,42 +1,53 @@
async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) {
const actionHooks = [
'action:application.listening',
'action:notifier.notification.created',
{
const actionHooks = [
'action:application.listening',
'action:notifier.notification.created',

'action:api.video.updated',
'action:api.video.deleted',
'action:api.video.uploaded',
'action:api.video.viewed',
'action:api.video.updated',
'action:api.video.deleted',
'action:api.video.uploaded',
'action:api.video.viewed',

'action:api.video-channel.created',
'action:api.video-channel.updated',
'action:api.video-channel.deleted',
'action:api.video-channel.created',
'action:api.video-channel.updated',
'action:api.video-channel.deleted',

'action:api.live-video.created',
'action:api.live-video.created',

'action:api.video-thread.created',
'action:api.video-comment-reply.created',
'action:api.video-comment.deleted',
'action:api.video-thread.created',
'action:api.video-comment-reply.created',
'action:api.video-comment.deleted',

'action:api.video-caption.created',
'action:api.video-caption.deleted',
'action:api.video-caption.created',
'action:api.video-caption.deleted',

'action:api.user.blocked',
'action:api.user.unblocked',
'action:api.user.registered',
'action:api.user.created',
'action:api.user.deleted',
'action:api.user.updated',
'action:api.user.oauth2-got-token',
'action:api.user.blocked',
'action:api.user.unblocked',
'action:api.user.registered',
'action:api.user.created',
'action:api.user.deleted',
'action:api.user.updated',
'action:api.user.oauth2-got-token',

'action:api.video-playlist-element.created'
]
'action:api.video-playlist-element.created'
]

for (const h of actionHooks) {
registerHook({
target: h,
handler: () => peertubeHelpers.logger.debug('Run hook %s.', h)
})
for (const h of actionHooks) {
registerHook({
target: h,
handler: () => peertubeHelpers.logger.debug('Run hook %s.', h)
})
}

for (const h of [ 'action:activity-pub.remote-video.created', 'action:activity-pub.remote-video.updated' ]) {
registerHook({
target: h,
handler: ({ video, videoAPObject }) => {
peertubeHelpers.logger.debug('Run hook %s - AP %s - video %s.', h, video.name, videoAPObject.name )
}
})
}
}

registerHook({


+ 24
- 0
server/tests/plugins/action-hooks.ts View File

@@ -4,6 +4,7 @@ import { ServerHookName, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/mode
import {
cleanupTests,
createMultipleServers,
doubleFollow,
killallServers,
PeerTubeServer,
PluginsCommand,
@@ -36,6 +37,8 @@ describe('Test plugin action hooks', function () {
enabled: true
}
})

await doubleFollow(servers[0], servers[1])
})

describe('Application hooks', function () {
@@ -231,6 +234,27 @@ describe('Test plugin action hooks', function () {
})
})

describe('Activity Pub hooks', function () {
let videoUUID: string

it('Should run action:activity-pub.remote-video.created', async function () {
this.timeout(30000)

const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
videoUUID = uuid

await servers[0].servers.waitUntilLog('action:activity-pub.remote-video.created - AP remote video - video remote video')
})

it('Should run action:activity-pub.remote-video.updated', async function () {
this.timeout(30000)

await servers[1].videos.update({ id: videoUUID, attributes: { name: 'remote video updated' } })

await servers[0].servers.waitUntilLog('action:activity-pub.remote-video.updated - AP remote video - video remote video')
})
})

after(async function () {
await cleanupTests(servers)
})


+ 6
- 2
shared/models/plugins/server/server-hook.model.ts View File

@@ -1,4 +1,4 @@
// {hookType}:{api?}.{location}.{subLocation?}.{actionType}.{target}
// {hookType}:{root}.{location}.{subLocation?}.{actionType}.{target}

export const serverFilterHookObject = {
// Filter params/result used to list videos for the REST API
@@ -184,7 +184,11 @@ export const serverActionHookObject = {
'action:api.user.oauth2-got-token': true,

// Fired when a video is added to a playlist
'action:api.video-playlist-element.created': true
'action:api.video-playlist-element.created': true,

// Fired when a remote video has been created/updated
'action:activity-pub.remote-video.created': true,
'action:activity-pub.remote-video.updated': true
}

export type ServerActionHookName = keyof typeof serverActionHookObject


+ 44
- 0
support/doc/plugins/guide.md View File

@@ -16,6 +16,7 @@
- [Add external auth methods](#add-external-auth-methods)
- [Add new transcoding profiles](#add-new-transcoding-profiles)
- [Server helpers](#server-helpers)
- [Federation](#federation)
- [Client API (themes & plugins)](#client-api-themes--plugins)
- [Get plugin static and router routes](#get-plugin-static-and-router-routes)
- [Notifier](#notifier)
@@ -587,6 +588,49 @@ async function register ({

See the [plugin API reference](https://docs.joinpeertube.org/api/plugins) to see the complete helpers list.

#### Federation

You can use some server hooks to federate plugin data to other PeerTube instances that may have installed your plugin.

For example to federate additional video metadata:

```js
async function register ({ registerHook }) {

// Send plugin metadata to remote instances
// We also update the JSON LD context because we added a new field
{
registerHook({
target: 'filter:activity-pub.video.json-ld.build.result',
handler: async (jsonld, { video }) => {
return Object.assign(jsonld, { recordedAt: 'https://example.com/event' })
}
})

registerHook({
target: 'filter:activity-pub.activity.context.build.result',
handler: jsonld => {
return jsonld.concat([ { recordedAt: 'https://schema.org/recordedAt' } ])
}
})
}

// Save remote video metadata
{
for (const h of [ 'action:activity-pub.remote-video.created', 'action:activity-pub.remote-video.updated' ]) {
registerHook({
target: h,
handler: ({ video, videoAPObject }) => {
if (videoAPObject.recordedAt) {
// Save information about the video
}
}
})
}
}
```


### Client API (themes & plugins)

#### Get plugin static and router routes


Loading…
Cancel
Save