aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/process/process-create.ts10
-rw-r--r--server/lib/activitypub/process/process-update.ts10
-rw-r--r--server/lib/activitypub/videos.ts115
3 files changed, 84 insertions, 51 deletions
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts
index 99841da14..559a0c23c 100644
--- a/server/lib/activitypub/process/process-create.ts
+++ b/server/lib/activitypub/process/process-create.ts
@@ -86,10 +86,14 @@ async function processCreateDislike (byActor: ActorModel, activity: ActivityCrea
86async function processCreateView (byActor: ActorModel, activity: ActivityCreate) { 86async function processCreateView (byActor: ActorModel, activity: ActivityCreate) {
87 const view = activity.object as ViewObject 87 const view = activity.object as ViewObject
88 88
89 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: view.object }) 89 const options = {
90 videoObject: view.object,
91 fetchType: 'only-video' as 'only-video'
92 }
93 const { video } = await getOrCreateVideoAndAccountAndChannel(options)
90 94
91 const actor = await ActorModel.loadByUrl(view.actor) 95 const actorExists = await ActorModel.isActorUrlExist(view.actor)
92 if (!actor) throw new Error('Unknown actor ' + view.actor) 96 if (actorExists === false) throw new Error('Unknown actor ' + view.actor)
93 97
94 await Redis.Instance.addVideoView(video.id) 98 await Redis.Instance.addVideoView(video.id)
95 99
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts
index 935da5a54..0bceb370e 100644
--- a/server/lib/activitypub/process/process-update.ts
+++ b/server/lib/activitypub/process/process-update.ts
@@ -51,7 +51,15 @@ async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate)
51 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id }) 51 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id })
52 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) 52 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
53 53
54 return updateVideoFromAP(video, videoObject, actor.Account, channelActor.VideoChannel, activity.to) 54 const updateOptions = {
55 video,
56 videoObject,
57 account: actor.Account,
58 channel: channelActor.VideoChannel,
59 updateViews: true,
60 overrideTo: activity.to
61 }
62 return updateVideoFromAP(updateOptions)
55} 63}
56 64
57async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUpdate) { 65async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUpdate) {
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 5aabd3e0d..de22e3584 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -157,18 +157,26 @@ async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: Vid
157async function getOrCreateVideoAndAccountAndChannel (options: { 157async function getOrCreateVideoAndAccountAndChannel (options: {
158 videoObject: VideoTorrentObject | string, 158 videoObject: VideoTorrentObject | string,
159 syncParam?: SyncParam, 159 syncParam?: SyncParam,
160 fetchType?: VideoFetchByUrlType 160 fetchType?: VideoFetchByUrlType,
161 refreshViews?: boolean
161}) { 162}) {
162 // Default params 163 // Default params
163 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } 164 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false }
164 const fetchType = options.fetchType || 'all' 165 const fetchType = options.fetchType || 'all'
166 const refreshViews = options.refreshViews || false
165 167
166 // Get video url 168 // Get video url
167 const videoUrl = typeof options.videoObject === 'string' ? options.videoObject : options.videoObject.id 169 const videoUrl = typeof options.videoObject === 'string' ? options.videoObject : options.videoObject.id
168 170
169 let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType) 171 let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType)
170 if (videoFromDatabase) { 172 if (videoFromDatabase) {
171 const p = retryTransactionWrapper(refreshVideoIfNeeded, videoFromDatabase, fetchType, syncParam) 173 const refreshOptions = {
174 video: videoFromDatabase,
175 fetchedType: fetchType,
176 syncParam,
177 refreshViews
178 }
179 const p = retryTransactionWrapper(refreshVideoIfNeeded, refreshOptions)
172 if (syncParam.refreshVideo === true) videoFromDatabase = await p 180 if (syncParam.refreshVideo === true) videoFromDatabase = await p
173 181
174 return { video: videoFromDatabase } 182 return { video: videoFromDatabase }
@@ -185,14 +193,15 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
185 return { video } 193 return { video }
186} 194}
187 195
188async function updateVideoFromAP ( 196async function updateVideoFromAP (options: {
189 video: VideoModel, 197 video: VideoModel,
190 videoObject: VideoTorrentObject, 198 videoObject: VideoTorrentObject,
191 account: AccountModel, 199 account: AccountModel,
192 channel: VideoChannelModel, 200 channel: VideoChannelModel,
201 updateViews: boolean,
193 overrideTo?: string[] 202 overrideTo?: string[]
194) { 203}) {
195 logger.debug('Updating remote video "%s".', videoObject.uuid) 204 logger.debug('Updating remote video "%s".', options.videoObject.uuid)
196 let videoFieldsSave: any 205 let videoFieldsSave: any
197 206
198 try { 207 try {
@@ -201,72 +210,72 @@ async function updateVideoFromAP (
201 transaction: t 210 transaction: t
202 } 211 }
203 212
204 videoFieldsSave = video.toJSON() 213 videoFieldsSave = options.video.toJSON()
205 214
206 // Check actor has the right to update the video 215 // Check actor has the right to update the video
207 const videoChannel = video.VideoChannel 216 const videoChannel = options.video.VideoChannel
208 if (videoChannel.Account.id !== account.id) { 217 if (videoChannel.Account.id !== options.account.id) {
209 throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) 218 throw new Error('Account ' + options.account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url)
210 } 219 }
211 220
212 const to = overrideTo ? overrideTo : videoObject.to 221 const to = options.overrideTo ? options.overrideTo : options.videoObject.to
213 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) 222 const videoData = await videoActivityObjectToDBAttributes(options.channel, options.videoObject, to)
214 video.set('name', videoData.name) 223 options.video.set('name', videoData.name)
215 video.set('uuid', videoData.uuid) 224 options.video.set('uuid', videoData.uuid)
216 video.set('url', videoData.url) 225 options.video.set('url', videoData.url)
217 video.set('category', videoData.category) 226 options.video.set('category', videoData.category)
218 video.set('licence', videoData.licence) 227 options.video.set('licence', videoData.licence)
219 video.set('language', videoData.language) 228 options.video.set('language', videoData.language)
220 video.set('description', videoData.description) 229 options.video.set('description', videoData.description)
221 video.set('support', videoData.support) 230 options.video.set('support', videoData.support)
222 video.set('nsfw', videoData.nsfw) 231 options.video.set('nsfw', videoData.nsfw)
223 video.set('commentsEnabled', videoData.commentsEnabled) 232 options.video.set('commentsEnabled', videoData.commentsEnabled)
224 video.set('waitTranscoding', videoData.waitTranscoding) 233 options.video.set('waitTranscoding', videoData.waitTranscoding)
225 video.set('state', videoData.state) 234 options.video.set('state', videoData.state)
226 video.set('duration', videoData.duration) 235 options.video.set('duration', videoData.duration)
227 video.set('createdAt', videoData.createdAt) 236 options.video.set('createdAt', videoData.createdAt)
228 video.set('publishedAt', videoData.publishedAt) 237 options.video.set('publishedAt', videoData.publishedAt)
229 video.set('views', videoData.views) 238 options.video.set('privacy', videoData.privacy)
230 video.set('privacy', videoData.privacy) 239 options.video.set('channelId', videoData.channelId)
231 video.set('channelId', videoData.channelId) 240
232 241 if (options.updateViews === true) options.video.set('views', videoData.views)
233 await video.save(sequelizeOptions) 242 await options.video.save(sequelizeOptions)
234 243
235 // Don't block on request 244 // Don't block on request
236 generateThumbnailFromUrl(video, videoObject.icon) 245 generateThumbnailFromUrl(options.video, options.videoObject.icon)
237 .catch(err => logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err })) 246 .catch(err => logger.warn('Cannot generate thumbnail of %s.', options.videoObject.id, { err }))
238 247
239 // Remove old video files 248 // Remove old video files
240 const videoFileDestroyTasks: Bluebird<void>[] = [] 249 const videoFileDestroyTasks: Bluebird<void>[] = []
241 for (const videoFile of video.VideoFiles) { 250 for (const videoFile of options.video.VideoFiles) {
242 videoFileDestroyTasks.push(videoFile.destroy(sequelizeOptions)) 251 videoFileDestroyTasks.push(videoFile.destroy(sequelizeOptions))
243 } 252 }
244 await Promise.all(videoFileDestroyTasks) 253 await Promise.all(videoFileDestroyTasks)
245 254
246 const videoFileAttributes = videoFileActivityUrlToDBAttributes(video, videoObject) 255 const videoFileAttributes = videoFileActivityUrlToDBAttributes(options.video, options.videoObject)
247 const tasks = videoFileAttributes.map(f => VideoFileModel.create(f, sequelizeOptions)) 256 const tasks = videoFileAttributes.map(f => VideoFileModel.create(f, sequelizeOptions))
248 await Promise.all(tasks) 257 await Promise.all(tasks)
249 258
250 // Update Tags 259 // Update Tags
251 const tags = videoObject.tag.map(tag => tag.name) 260 const tags = options.videoObject.tag.map(tag => tag.name)
252 const tagInstances = await TagModel.findOrCreateTags(tags, t) 261 const tagInstances = await TagModel.findOrCreateTags(tags, t)
253 await video.$set('Tags', tagInstances, sequelizeOptions) 262 await options.video.$set('Tags', tagInstances, sequelizeOptions)
254 263
255 // Update captions 264 // Update captions
256 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(video.id, t) 265 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(options.video.id, t)
257 266
258 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 267 const videoCaptionsPromises = options.videoObject.subtitleLanguage.map(c => {
259 return VideoCaptionModel.insertOrReplaceLanguage(video.id, c.identifier, t) 268 return VideoCaptionModel.insertOrReplaceLanguage(options.video.id, c.identifier, t)
260 }) 269 })
261 await Promise.all(videoCaptionsPromises) 270 await Promise.all(videoCaptionsPromises)
262 }) 271 })
263 272
264 logger.info('Remote video with uuid %s updated', videoObject.uuid) 273 logger.info('Remote video with uuid %s updated', options.videoObject.uuid)
265 274
266 return updatedVideo 275 return updatedVideo
267 } catch (err) { 276 } catch (err) {
268 if (video !== undefined && videoFieldsSave !== undefined) { 277 if (options.video !== undefined && videoFieldsSave !== undefined) {
269 resetSequelizeInstance(video, videoFieldsSave) 278 resetSequelizeInstance(options.video, videoFieldsSave)
270 } 279 }
271 280
272 // This is just a debug because we will retry the insert 281 // This is just a debug because we will retry the insert
@@ -339,9 +348,14 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
339 return videoCreated 348 return videoCreated
340} 349}
341 350
342async function refreshVideoIfNeeded (videoArg: VideoModel, fetchedType: VideoFetchByUrlType, syncParam: SyncParam): Promise<VideoModel> { 351async function refreshVideoIfNeeded (options: {
352 video: VideoModel,
353 fetchedType: VideoFetchByUrlType,
354 syncParam: SyncParam,
355 refreshViews: boolean
356}): Promise<VideoModel> {
343 // We need more attributes if the argument video was fetched with not enough joints 357 // We need more attributes if the argument video was fetched with not enough joints
344 const video = fetchedType === 'all' ? videoArg : await VideoModel.loadByUrlAndPopulateAccount(videoArg.url) 358 const video = options.fetchedType === 'all' ? options.video : await VideoModel.loadByUrlAndPopulateAccount(options.video.url)
345 359
346 if (!video.isOutdated()) return video 360 if (!video.isOutdated()) return video
347 361
@@ -361,8 +375,15 @@ async function refreshVideoIfNeeded (videoArg: VideoModel, fetchedType: VideoFet
361 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) 375 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
362 const account = await AccountModel.load(channelActor.VideoChannel.accountId) 376 const account = await AccountModel.load(channelActor.VideoChannel.accountId)
363 377
364 await updateVideoFromAP(video, videoObject, account, channelActor.VideoChannel) 378 const updateOptions = {
365 await syncVideoExternalAttributes(video, videoObject, syncParam) 379 video,
380 videoObject,
381 account,
382 channel: channelActor.VideoChannel,
383 updateViews: options.refreshViews
384 }
385 await updateVideoFromAP(updateOptions)
386 await syncVideoExternalAttributes(video, videoObject, options.syncParam)
366 } catch (err) { 387 } catch (err) {
367 logger.warn('Cannot refresh video.', { err }) 388 logger.warn('Cannot refresh video.', { err })
368 return video 389 return video