]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add filter:html.client.json-ld.result hook
authorChocobozzz <me@florianbigard.com>
Fri, 24 Mar 2023 17:37:55 +0000 (18:37 +0100)
committerChocobozzz <me@florianbigard.com>
Fri, 24 Mar 2023 17:37:55 +0000 (18:37 +0100)
server/lib/client-html.ts
server/tests/fixtures/peertube-plugin-test/main.js
server/tests/plugins/filter-hooks.ts
shared/models/plugins/server/server-hook.model.ts

index 4fd9a4263d665fcf1d58b398dad6cfa05022a581..81b3fff027d6ec28bbc83eebe4dd299c8187fcb3 100644 (file)
@@ -27,9 +27,10 @@ import { AccountModel } from '../models/account/account'
 import { VideoModel } from '../models/video/video'
 import { VideoChannelModel } from '../models/video/video-channel'
 import { VideoPlaylistModel } from '../models/video/video-playlist'
-import { MAccountActor, MChannelActor } from '../types/models'
+import { MAccountActor, MChannelActor, MVideo, MVideoPlaylist } from '../types/models'
 import { getActivityStreamDuration } from './activitypub/activity'
 import { getBiggestActorImage } from './actor-image'
+import { Hooks } from './plugins/hooks'
 import { ServerConfigManager } from './server-config-manager'
 
 type Tags = {
@@ -64,6 +65,11 @@ type Tags = {
   }
 }
 
+type HookContext = {
+  video?: MVideo
+  playlist?: MVideoPlaylist
+}
+
 class ClientHtml {
 
   private static htmlCache: { [path: string]: string } = {}
@@ -129,7 +135,7 @@ class ClientHtml {
     const twitterCard = CONFIG.SERVICES.TWITTER.WHITELISTED ? 'player' : 'summary_large_image'
     const schemaType = 'VideoObject'
 
-    customHtml = ClientHtml.addTags(customHtml, {
+    customHtml = await ClientHtml.addTags(customHtml, {
       url,
       originUrl,
       escapedSiteName: escapeHTML(siteName),
@@ -141,7 +147,7 @@ class ClientHtml {
       ogType,
       twitterCard,
       schemaType
-    })
+    }, { video })
 
     return customHtml
   }
@@ -193,7 +199,7 @@ class ClientHtml {
     const twitterCard = CONFIG.SERVICES.TWITTER.WHITELISTED ? 'player' : 'summary'
     const schemaType = 'ItemList'
 
-    customHtml = ClientHtml.addTags(customHtml, {
+    customHtml = await ClientHtml.addTags(customHtml, {
       url,
       originUrl,
       escapedSiteName: escapeHTML(siteName),
@@ -206,7 +212,7 @@ class ClientHtml {
       ogType,
       twitterCard,
       schemaType
-    })
+    }, { playlist: videoPlaylist })
 
     return customHtml
   }
@@ -290,7 +296,7 @@ class ClientHtml {
     const twitterCard = 'summary'
     const schemaType = 'ProfilePage'
 
-    customHtml = ClientHtml.addTags(customHtml, {
+    customHtml = await ClientHtml.addTags(customHtml, {
       url,
       originUrl,
       escapedTitle: escapeHTML(title),
@@ -301,7 +307,7 @@ class ClientHtml {
       twitterCard,
       schemaType,
       disallowIndexation: !entity.Actor.isOwned()
-    })
+    }, {})
 
     return customHtml
   }
@@ -469,7 +475,7 @@ class ClientHtml {
     return metaTags
   }
 
-  private static generateSchemaTags (tags: Tags) {
+  private static async generateSchemaTags (tags: Tags, context: HookContext) {
     const schema = {
       '@context': 'http://schema.org',
       '@type': tags.schemaType,
@@ -495,14 +501,14 @@ class ClientHtml {
       schema['contentUrl'] = tags.url
     }
 
-    return schema
+    return Hooks.wrapObject(schema, 'filter:html.client.json-ld.result', context)
   }
 
-  private static addTags (htmlStringPage: string, tagsValues: Tags) {
+  private static async addTags (htmlStringPage: string, tagsValues: Tags, context: HookContext) {
     const openGraphMetaTags = this.generateOpenGraphMetaTags(tagsValues)
     const standardMetaTags = this.generateStandardMetaTags(tagsValues)
     const twitterCardMetaTags = this.generateTwitterCardMetaTags(tagsValues)
-    const schemaTags = this.generateSchemaTags(tagsValues)
+    const schemaTags = await this.generateSchemaTags(tagsValues, context)
 
     const { url, escapedTitle, embed, originUrl, disallowIndexation } = tagsValues
 
index 84b47954832d1ec2cf0d82a634ba2d9ae76d3640..36dd08d2751dcf4d5e22b4848087497576191d84 100644 (file)
@@ -312,6 +312,8 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
     }
   })
 
+  // ---------------------------------------------------------------------------
+
   registerHook({
     target: 'filter:html.embed.video.allowed.result',
     handler: (result, params) => {
@@ -332,6 +334,19 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
     }
   })
 
+  // ---------------------------------------------------------------------------
+
+  registerHook({
+    target: 'filter:html.client.json-ld.result',
+    handler: (jsonld, context) => {
+      if (!context || !context.video) return jsonld
+
+      return Object.assign(jsonld, { recordedAt: 'http://example.com/recordedAt' })
+    }
+  })
+
+  // ---------------------------------------------------------------------------
+
   registerHook({
     target: 'filter:api.server.stats.get.result',
     handler: (result) => {
index 4d26ff8b739785d925a962e668576f3b3fa69b26..43749b0b557110f0e80394dd04d87973c8fc5f34 100644 (file)
@@ -605,6 +605,27 @@ describe('Test plugin filter hooks', function () {
     })
   })
 
+  describe('Client HTML filters', function () {
+    let videoUUID: string
+
+    before(async function () {
+      this.timeout(60000)
+
+      const { uuid } = await servers[0].videos.quickUpload({ name: 'html video' })
+      videoUUID = uuid
+    })
+
+    it('Should run filter:html.client.json-ld.result', async function () {
+      const res = await makeGetRequest({ url: servers[0].url, path: '/w/' + videoUUID, expectedStatus: HttpStatusCode.OK_200 })
+      expect(res.text).to.contain('"recordedAt":"http://example.com/recordedAt"')
+    })
+
+    it('Should not run filter:html.client.json-ld.result with an account', async function () {
+      const res = await makeGetRequest({ url: servers[0].url, path: '/a/root', expectedStatus: HttpStatusCode.OK_200 })
+      expect(res.text).not.to.contain('"recordedAt":"http://example.com/recordedAt"')
+    })
+  })
+
   describe('Search filters', function () {
 
     before(async function () {
index d2ebe936e332356e7d458ac9922b755c5924bb8e..91509f2b917b4586aa852402a52a45fa486445e2 100644 (file)
@@ -107,6 +107,8 @@ export const serverFilterHookObject = {
   'filter:html.embed.video.allowed.result': true,
   'filter:html.embed.video-playlist.allowed.result': true,
 
+  'filter:html.client.json-ld.result': true,
+
   'filter:job-queue.process.params': true,
   'filter:job-queue.process.result': true,