aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub/videos
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-06-01 14:51:16 +0200
committerChocobozzz <me@florianbigard.com>2023-06-29 10:16:55 +0200
commitd8f39b126d9fe4bec1c12fb213548cc6edc87867 (patch)
tree7f0f1cb23165cf4dd789b2d78b1fef7ee116f647 /server/lib/activitypub/videos
parent1fb7d094229acdc190c3f7551b43ac5445814dee (diff)
downloadPeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.tar.gz
PeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.tar.zst
PeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.zip
Add storyboard support
Diffstat (limited to 'server/lib/activitypub/videos')
-rw-r--r--server/lib/activitypub/videos/federate.ts13
-rw-r--r--server/lib/activitypub/videos/shared/abstract-builder.ts12
-rw-r--r--server/lib/activitypub/videos/shared/creator.ts1
-rw-r--r--server/lib/activitypub/videos/shared/object-to-model-attributes.ts26
-rw-r--r--server/lib/activitypub/videos/updater.ts5
5 files changed, 46 insertions, 11 deletions
diff --git a/server/lib/activitypub/videos/federate.ts b/server/lib/activitypub/videos/federate.ts
index bd0c54b0c..d7e251153 100644
--- a/server/lib/activitypub/videos/federate.ts
+++ b/server/lib/activitypub/videos/federate.ts
@@ -1,10 +1,9 @@
1import { Transaction } from 'sequelize/types' 1import { Transaction } from 'sequelize/types'
2import { isArray } from '@server/helpers/custom-validators/misc' 2import { MVideoAP, MVideoAPLight } from '@server/types/models'
3import { MVideoAP, MVideoAPWithoutCaption } from '@server/types/models'
4import { sendCreateVideo, sendUpdateVideo } from '../send' 3import { sendCreateVideo, sendUpdateVideo } from '../send'
5import { shareVideoByServerAndChannel } from '../share' 4import { shareVideoByServerAndChannel } from '../share'
6 5
7async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: Transaction) { 6async function federateVideoIfNeeded (videoArg: MVideoAPLight, isNewVideo: boolean, transaction?: Transaction) {
8 const video = videoArg as MVideoAP 7 const video = videoArg as MVideoAP
9 8
10 if ( 9 if (
@@ -13,13 +12,7 @@ async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVid
13 // Check the video is public/unlisted and published 12 // Check the video is public/unlisted and published
14 video.hasPrivacyForFederation() && video.hasStateForFederation() 13 video.hasPrivacyForFederation() && video.hasStateForFederation()
15 ) { 14 ) {
16 // Fetch more attributes that we will need to serialize in AP object 15 const video = await videoArg.lightAPToFullAP(transaction)
17 if (isArray(video.VideoCaptions) === false) {
18 video.VideoCaptions = await video.$get('VideoCaptions', {
19 attributes: [ 'filename', 'language' ],
20 transaction
21 })
22 }
23 16
24 if (isNewVideo) { 17 if (isNewVideo) {
25 // Now we'll add the video's meta data to our followers 18 // Now we'll add the video's meta data to our followers
diff --git a/server/lib/activitypub/videos/shared/abstract-builder.ts b/server/lib/activitypub/videos/shared/abstract-builder.ts
index c0b92c93d..7c5c73139 100644
--- a/server/lib/activitypub/videos/shared/abstract-builder.ts
+++ b/server/lib/activitypub/videos/shared/abstract-builder.ts
@@ -3,6 +3,7 @@ import { deleteAllModels, filterNonExistingModels } from '@server/helpers/databa
3import { logger, LoggerTagsFn } from '@server/helpers/logger' 3import { logger, LoggerTagsFn } from '@server/helpers/logger'
4import { updatePlaceholderThumbnail, updateVideoMiniatureFromUrl } from '@server/lib/thumbnail' 4import { updatePlaceholderThumbnail, updateVideoMiniatureFromUrl } from '@server/lib/thumbnail'
5import { setVideoTags } from '@server/lib/video' 5import { setVideoTags } from '@server/lib/video'
6import { StoryboardModel } from '@server/models/video/storyboard'
6import { VideoCaptionModel } from '@server/models/video/video-caption' 7import { VideoCaptionModel } from '@server/models/video/video-caption'
7import { VideoFileModel } from '@server/models/video/video-file' 8import { VideoFileModel } from '@server/models/video/video-file'
8import { VideoLiveModel } from '@server/models/video/video-live' 9import { VideoLiveModel } from '@server/models/video/video-live'
@@ -24,6 +25,7 @@ import {
24 getFileAttributesFromUrl, 25 getFileAttributesFromUrl,
25 getLiveAttributesFromObject, 26 getLiveAttributesFromObject,
26 getPreviewFromIcons, 27 getPreviewFromIcons,
28 getStoryboardAttributeFromObject,
27 getStreamingPlaylistAttributesFromObject, 29 getStreamingPlaylistAttributesFromObject,
28 getTagsFromObject, 30 getTagsFromObject,
29 getThumbnailFromIcons 31 getThumbnailFromIcons
@@ -107,6 +109,16 @@ export abstract class APVideoAbstractBuilder {
107 } 109 }
108 } 110 }
109 111
112 protected async insertOrReplaceStoryboard (video: MVideoFullLight, t: Transaction) {
113 const existingStoryboard = await StoryboardModel.loadByVideo(video.id, t)
114 if (existingStoryboard) await existingStoryboard.destroy({ transaction: t })
115
116 const storyboardAttributes = getStoryboardAttributeFromObject(video, this.videoObject)
117 if (!storyboardAttributes) return
118
119 return StoryboardModel.create(storyboardAttributes, { transaction: t })
120 }
121
110 protected async insertOrReplaceLive (video: MVideoFullLight, transaction: Transaction) { 122 protected async insertOrReplaceLive (video: MVideoFullLight, transaction: Transaction) {
111 const attributes = getLiveAttributesFromObject(video, this.videoObject) 123 const attributes = getLiveAttributesFromObject(video, this.videoObject)
112 const [ videoLive ] = await VideoLiveModel.upsert(attributes, { transaction, returning: true }) 124 const [ videoLive ] = await VideoLiveModel.upsert(attributes, { transaction, returning: true })
diff --git a/server/lib/activitypub/videos/shared/creator.ts b/server/lib/activitypub/videos/shared/creator.ts
index 77321d8a5..e6d7bc23c 100644
--- a/server/lib/activitypub/videos/shared/creator.ts
+++ b/server/lib/activitypub/videos/shared/creator.ts
@@ -48,6 +48,7 @@ export class APVideoCreator extends APVideoAbstractBuilder {
48 await this.setTrackers(videoCreated, t) 48 await this.setTrackers(videoCreated, t)
49 await this.insertOrReplaceCaptions(videoCreated, t) 49 await this.insertOrReplaceCaptions(videoCreated, t)
50 await this.insertOrReplaceLive(videoCreated, t) 50 await this.insertOrReplaceLive(videoCreated, t)
51 await this.insertOrReplaceStoryboard(videoCreated, t)
51 52
52 // We added a video in this channel, set it as updated 53 // We added a video in this channel, set it as updated
53 await channel.setAsUpdated(t) 54 await channel.setAsUpdated(t)
diff --git a/server/lib/activitypub/videos/shared/object-to-model-attributes.ts b/server/lib/activitypub/videos/shared/object-to-model-attributes.ts
index 8fd0a816c..a9e0bed97 100644
--- a/server/lib/activitypub/videos/shared/object-to-model-attributes.ts
+++ b/server/lib/activitypub/videos/shared/object-to-model-attributes.ts
@@ -1,6 +1,6 @@
1import { maxBy, minBy } from 'lodash' 1import { maxBy, minBy } from 'lodash'
2import { decode as magnetUriDecode } from 'magnet-uri' 2import { decode as magnetUriDecode } from 'magnet-uri'
3import { basename } from 'path' 3import { basename, extname } from 'path'
4import { isAPVideoFileUrlMetadataObject } from '@server/helpers/custom-validators/activitypub/videos' 4import { isAPVideoFileUrlMetadataObject } from '@server/helpers/custom-validators/activitypub/videos'
5import { isVideoFileInfoHashValid } from '@server/helpers/custom-validators/videos' 5import { isVideoFileInfoHashValid } from '@server/helpers/custom-validators/videos'
6import { logger } from '@server/helpers/logger' 6import { logger } from '@server/helpers/logger'
@@ -25,6 +25,9 @@ import {
25 VideoStreamingPlaylistType 25 VideoStreamingPlaylistType
26} from '@shared/models' 26} from '@shared/models'
27import { getDurationFromActivityStream } from '../../activity' 27import { getDurationFromActivityStream } from '../../activity'
28import { isArray } from '@server/helpers/custom-validators/misc'
29import { generateImageFilename } from '@server/helpers/image-utils'
30import { arrayify } from '@shared/core-utils'
28 31
29function getThumbnailFromIcons (videoObject: VideoObject) { 32function getThumbnailFromIcons (videoObject: VideoObject) {
30 let validIcons = videoObject.icon.filter(i => i.width > THUMBNAILS_SIZE.minWidth) 33 let validIcons = videoObject.icon.filter(i => i.width > THUMBNAILS_SIZE.minWidth)
@@ -166,6 +169,26 @@ function getCaptionAttributesFromObject (video: MVideoId, videoObject: VideoObje
166 })) 169 }))
167} 170}
168 171
172function getStoryboardAttributeFromObject (video: MVideoId, videoObject: VideoObject) {
173 if (!isArray(videoObject.preview)) return undefined
174
175 const storyboard = videoObject.preview.find(p => p.rel.includes('storyboard'))
176 if (!storyboard) return undefined
177
178 const url = arrayify(storyboard.url).find(u => u.mediaType === 'image/jpeg')
179
180 return {
181 filename: generateImageFilename(extname(url.href)),
182 totalHeight: url.height,
183 totalWidth: url.width,
184 spriteHeight: url.tileHeight,
185 spriteWidth: url.tileWidth,
186 spriteDuration: getDurationFromActivityStream(url.tileDuration),
187 fileUrl: url.href,
188 videoId: video.id
189 }
190}
191
169function getVideoAttributesFromObject (videoChannel: MChannelId, videoObject: VideoObject, to: string[] = []) { 192function getVideoAttributesFromObject (videoChannel: MChannelId, videoObject: VideoObject, to: string[] = []) {
170 const privacy = to.includes(ACTIVITY_PUB.PUBLIC) 193 const privacy = to.includes(ACTIVITY_PUB.PUBLIC)
171 ? VideoPrivacy.PUBLIC 194 ? VideoPrivacy.PUBLIC
@@ -228,6 +251,7 @@ export {
228 251
229 getLiveAttributesFromObject, 252 getLiveAttributesFromObject,
230 getCaptionAttributesFromObject, 253 getCaptionAttributesFromObject,
254 getStoryboardAttributeFromObject,
231 255
232 getVideoAttributesFromObject 256 getVideoAttributesFromObject
233} 257}
diff --git a/server/lib/activitypub/videos/updater.ts b/server/lib/activitypub/videos/updater.ts
index 6ddd2301b..3a0886523 100644
--- a/server/lib/activitypub/videos/updater.ts
+++ b/server/lib/activitypub/videos/updater.ts
@@ -57,6 +57,7 @@ export class APVideoUpdater extends APVideoAbstractBuilder {
57 await Promise.all([ 57 await Promise.all([
58 runInReadCommittedTransaction(t => this.setTags(videoUpdated, t)), 58 runInReadCommittedTransaction(t => this.setTags(videoUpdated, t)),
59 runInReadCommittedTransaction(t => this.setTrackers(videoUpdated, t)), 59 runInReadCommittedTransaction(t => this.setTrackers(videoUpdated, t)),
60 runInReadCommittedTransaction(t => this.setStoryboard(videoUpdated, t)),
60 this.setOrDeleteLive(videoUpdated), 61 this.setOrDeleteLive(videoUpdated),
61 this.setPreview(videoUpdated) 62 this.setPreview(videoUpdated)
62 ]) 63 ])
@@ -138,6 +139,10 @@ export class APVideoUpdater extends APVideoAbstractBuilder {
138 await this.insertOrReplaceCaptions(videoUpdated, t) 139 await this.insertOrReplaceCaptions(videoUpdated, t)
139 } 140 }
140 141
142 private async setStoryboard (videoUpdated: MVideoFullLight, t: Transaction) {
143 await this.insertOrReplaceStoryboard(videoUpdated, t)
144 }
145
141 private async setOrDeleteLive (videoUpdated: MVideoFullLight, transaction?: Transaction) { 146 private async setOrDeleteLive (videoUpdated: MVideoFullLight, transaction?: Transaction) {
142 if (!this.video.isLive) return 147 if (!this.video.isLive) return
143 148