aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub/videos.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/activitypub/videos.ts')
-rw-r--r--server/lib/activitypub/videos.ts143
1 files changed, 85 insertions, 58 deletions
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 3a8451a32..5c10f9764 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -24,7 +24,6 @@ import {
24 REMOTE_SCHEME, 24 REMOTE_SCHEME,
25 STATIC_PATHS 25 STATIC_PATHS
26} from '../../initializers/constants' 26} from '../../initializers/constants'
27import { ActorModel } from '../../models/activitypub/actor'
28import { TagModel } from '../../models/video/tag' 27import { TagModel } from '../../models/video/tag'
29import { VideoModel } from '../../models/video/video' 28import { VideoModel } from '../../models/video/video'
30import { VideoFileModel } from '../../models/video/video-file' 29import { VideoFileModel } from '../../models/video/video-file'
@@ -38,7 +37,6 @@ import { JobQueue } from '../job-queue'
38import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub-http-fetcher' 37import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub-http-fetcher'
39import { createRates } from './video-rates' 38import { createRates } from './video-rates'
40import { addVideoShares, shareVideoByServerAndChannel } from './share' 39import { addVideoShares, shareVideoByServerAndChannel } from './share'
41import { AccountModel } from '../../models/account/account'
42import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' 40import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video'
43import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 41import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
44import { Notifier } from '../notifier' 42import { Notifier } from '../notifier'
@@ -49,15 +47,33 @@ import { VideoShareModel } from '../../models/video/video-share'
49import { VideoCommentModel } from '../../models/video/video-comment' 47import { VideoCommentModel } from '../../models/video/video-comment'
50import { sequelizeTypescript } from '../../initializers/database' 48import { sequelizeTypescript } from '../../initializers/database'
51import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail' 49import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail'
52import { ThumbnailModel } from '../../models/video/thumbnail'
53import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 50import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
54import { join } from 'path' 51import { join } from 'path'
55import { FilteredModelAttributes } from '../../typings/sequelize' 52import { FilteredModelAttributes } from '../../typings/sequelize'
56import { autoBlacklistVideoIfNeeded } from '../video-blacklist' 53import { autoBlacklistVideoIfNeeded } from '../video-blacklist'
57import { ActorFollowScoreCache } from '../files-cache' 54import { ActorFollowScoreCache } from '../files-cache'
58import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models' 55import {
56 MAccountActor,
57 MChannelAccountLight,
58 MChannelDefault,
59 MChannelId,
60 MVideo,
61 MVideoAccountAllFiles,
62 MVideoAccountLight,
63 MVideoAP,
64 MVideoAPWithoutCaption,
65 MVideoFile,
66 MVideoFullLight,
67 MVideoId,
68 MVideoTag,
69 MVideoThumbnail,
70 MVideoWithAllFiles
71} from '../../typings/models'
72import { MThumbnail } from '../../typings/models/video/thumbnail'
73
74async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) {
75 const video = videoArg as MVideoAP
59 76
60async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) {
61 if ( 77 if (
62 // Check this is not a blacklisted video, or unfederated blacklisted video 78 // Check this is not a blacklisted video, or unfederated blacklisted video
63 (video.isBlacklisted() === false || (isNewVideo === false && video.VideoBlacklist.unfederated === false)) && 79 (video.isBlacklisted() === false || (isNewVideo === false && video.VideoBlacklist.unfederated === false)) &&
@@ -102,7 +118,7 @@ async function fetchRemoteVideo (videoUrl: string): Promise<{ response: request.
102 return { response, videoObject: body } 118 return { response, videoObject: body }
103} 119}
104 120
105async function fetchRemoteVideoDescription (video: VideoModel) { 121async function fetchRemoteVideoDescription (video: MVideoAccountLight) {
106 const host = video.VideoChannel.Account.Actor.Server.host 122 const host = video.VideoChannel.Account.Actor.Server.host
107 const path = video.getDescriptionAPIPath() 123 const path = video.getDescriptionAPIPath()
108 const options = { 124 const options = {
@@ -114,14 +130,14 @@ async function fetchRemoteVideoDescription (video: VideoModel) {
114 return body.description ? body.description : '' 130 return body.description ? body.description : ''
115} 131}
116 132
117function fetchRemoteVideoStaticFile (video: VideoModel, path: string, destPath: string) { 133function fetchRemoteVideoStaticFile (video: MVideoAccountLight, path: string, destPath: string) {
118 const url = buildRemoteBaseUrl(video, path) 134 const url = buildRemoteBaseUrl(video, path)
119 135
120 // We need to provide a callback, if no we could have an uncaught exception 136 // We need to provide a callback, if no we could have an uncaught exception
121 return doRequestAndSaveToFile({ uri: url }, destPath) 137 return doRequestAndSaveToFile({ uri: url }, destPath)
122} 138}
123 139
124function buildRemoteBaseUrl (video: VideoModel, path: string) { 140function buildRemoteBaseUrl (video: MVideoAccountLight, path: string) {
125 const host = video.VideoChannel.Account.Actor.Server.host 141 const host = video.VideoChannel.Account.Actor.Server.host
126 142
127 return REMOTE_SCHEME.HTTP + '://' + host + path 143 return REMOTE_SCHEME.HTTP + '://' + host + path
@@ -146,7 +162,7 @@ type SyncParam = {
146 thumbnail: boolean 162 thumbnail: boolean
147 refreshVideo?: boolean 163 refreshVideo?: boolean
148} 164}
149async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) { 165async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) {
150 logger.info('Adding likes/dislikes/shares/comments of video %s.', video.uuid) 166 logger.info('Adding likes/dislikes/shares/comments of video %s.', video.uuid)
151 167
152 const jobPayloads: ActivitypubHttpFetcherPayload[] = [] 168 const jobPayloads: ActivitypubHttpFetcherPayload[] = []
@@ -194,12 +210,24 @@ async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: Vid
194 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) 210 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }))
195} 211}
196 212
213function getOrCreateVideoAndAccountAndChannel (options: {
214 videoObject: { id: string } | string,
215 syncParam?: SyncParam,
216 fetchType?: 'all',
217 allowRefresh?: boolean
218}): Promise<{ video: MVideoAccountAllFiles, created: boolean, autoBlacklisted?: boolean }>
219function getOrCreateVideoAndAccountAndChannel (options: {
220 videoObject: { id: string } | string,
221 syncParam?: SyncParam,
222 fetchType?: VideoFetchByUrlType,
223 allowRefresh?: boolean
224}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }>
197async function getOrCreateVideoAndAccountAndChannel (options: { 225async function getOrCreateVideoAndAccountAndChannel (options: {
198 videoObject: { id: string } | string, 226 videoObject: { id: string } | string,
199 syncParam?: SyncParam, 227 syncParam?: SyncParam,
200 fetchType?: VideoFetchByUrlType, 228 fetchType?: VideoFetchByUrlType,
201 allowRefresh?: boolean // true by default 229 allowRefresh?: boolean // true by default
202}) { 230}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> {
203 // Default params 231 // Default params
204 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } 232 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false }
205 const fetchType = options.fetchType || 'all' 233 const fetchType = options.fetchType || 'all'
@@ -227,8 +255,9 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
227 const { videoObject: fetchedVideo } = await fetchRemoteVideo(videoUrl) 255 const { videoObject: fetchedVideo } = await fetchRemoteVideo(videoUrl)
228 if (!fetchedVideo) throw new Error('Cannot fetch remote video with url: ' + videoUrl) 256 if (!fetchedVideo) throw new Error('Cannot fetch remote video with url: ' + videoUrl)
229 257
230 const channelActor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo) 258 const actor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo)
231 const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, channelActor, syncParam.thumbnail) 259 const videoChannel = actor.VideoChannel
260 const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, videoChannel, syncParam.thumbnail)
232 261
233 await syncVideoExternalAttributes(videoCreated, fetchedVideo, syncParam) 262 await syncVideoExternalAttributes(videoCreated, fetchedVideo, syncParam)
234 263
@@ -236,22 +265,22 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
236} 265}
237 266
238async function updateVideoFromAP (options: { 267async function updateVideoFromAP (options: {
239 video: VideoModel, 268 video: MVideoAccountAllFiles,
240 videoObject: VideoTorrentObject, 269 videoObject: VideoTorrentObject,
241 account: AccountModelIdActor, 270 account: MAccountActor,
242 channel: VideoChannelModelIdActor, 271 channel: MChannelDefault,
243 overrideTo?: string[] 272 overrideTo?: string[]
244}) { 273}) {
245 const { video, videoObject, account, channel, overrideTo } = options 274 const { video, videoObject, account, channel, overrideTo } = options
246 275
247 logger.debug('Updating remote video "%s".', options.videoObject.uuid) 276 logger.debug('Updating remote video "%s".', options.videoObject.uuid, { account, channel })
248 277
249 let videoFieldsSave: any 278 let videoFieldsSave: any
250 const wasPrivateVideo = video.privacy === VideoPrivacy.PRIVATE 279 const wasPrivateVideo = video.privacy === VideoPrivacy.PRIVATE
251 const wasUnlistedVideo = video.privacy === VideoPrivacy.UNLISTED 280 const wasUnlistedVideo = video.privacy === VideoPrivacy.UNLISTED
252 281
253 try { 282 try {
254 let thumbnailModel: ThumbnailModel 283 let thumbnailModel: MThumbnail
255 284
256 try { 285 try {
257 thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) 286 thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE)
@@ -259,7 +288,7 @@ async function updateVideoFromAP (options: {
259 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) 288 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err })
260 } 289 }
261 290
262 await sequelizeTypescript.transaction(async t => { 291 const videoUpdated = await sequelizeTypescript.transaction(async t => {
263 const sequelizeOptions = { transaction: t } 292 const sequelizeOptions = { transaction: t }
264 293
265 videoFieldsSave = video.toJSON() 294 videoFieldsSave = video.toJSON()
@@ -293,21 +322,21 @@ async function updateVideoFromAP (options: {
293 video.channelId = videoData.channelId 322 video.channelId = videoData.channelId
294 video.views = videoData.views 323 video.views = videoData.views
295 324
296 await video.save(sequelizeOptions) 325 const videoUpdated = await video.save(sequelizeOptions) as MVideoFullLight
297 326
298 if (thumbnailModel) await video.addAndSaveThumbnail(thumbnailModel, t) 327 if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t)
299 328
300 // FIXME: use icon URL instead 329 // FIXME: use icon URL instead
301 const previewUrl = buildRemoteBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.getPreview().filename)) 330 const previewUrl = buildRemoteBaseUrl(videoUpdated, join(STATIC_PATHS.PREVIEWS, videoUpdated.getPreview().filename))
302 const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) 331 const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
303 await video.addAndSaveThumbnail(previewModel, t) 332 await videoUpdated.addAndSaveThumbnail(previewModel, t)
304 333
305 { 334 {
306 const videoFileAttributes = videoFileActivityUrlToDBAttributes(video, videoObject) 335 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject)
307 const newVideoFiles = videoFileAttributes.map(a => new VideoFileModel(a)) 336 const newVideoFiles = videoFileAttributes.map(a => new VideoFileModel(a))
308 337
309 // Remove video files that do not exist anymore 338 // Remove video files that do not exist anymore
310 const destroyTasks = video.VideoFiles 339 const destroyTasks = videoUpdated.VideoFiles
311 .filter(f => !newVideoFiles.find(newFile => newFile.hasSameUniqueKeysThan(f))) 340 .filter(f => !newVideoFiles.find(newFile => newFile.hasSameUniqueKeysThan(f)))
312 .map(f => f.destroy(sequelizeOptions)) 341 .map(f => f.destroy(sequelizeOptions))
313 await Promise.all(destroyTasks) 342 await Promise.all(destroyTasks)
@@ -318,15 +347,15 @@ async function updateVideoFromAP (options: {
318 .then(([ file ]) => file) 347 .then(([ file ]) => file)
319 }) 348 })
320 349
321 video.VideoFiles = await Promise.all(upsertTasks) 350 videoUpdated.VideoFiles = await Promise.all(upsertTasks)
322 } 351 }
323 352
324 { 353 {
325 const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(video, videoObject, video.VideoFiles) 354 const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(videoUpdated, videoObject, videoUpdated.VideoFiles)
326 const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a)) 355 const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a))
327 356
328 // Remove video files that do not exist anymore 357 // Remove video files that do not exist anymore
329 const destroyTasks = video.VideoStreamingPlaylists 358 const destroyTasks = videoUpdated.VideoStreamingPlaylists
330 .filter(f => !newStreamingPlaylists.find(newPlaylist => newPlaylist.hasSameUniqueKeysThan(f))) 359 .filter(f => !newStreamingPlaylists.find(newPlaylist => newPlaylist.hasSameUniqueKeysThan(f)))
331 .map(f => f.destroy(sequelizeOptions)) 360 .map(f => f.destroy(sequelizeOptions))
332 await Promise.all(destroyTasks) 361 await Promise.all(destroyTasks)
@@ -337,38 +366,42 @@ async function updateVideoFromAP (options: {
337 .then(([ streamingPlaylist ]) => streamingPlaylist) 366 .then(([ streamingPlaylist ]) => streamingPlaylist)
338 }) 367 })
339 368
340 video.VideoStreamingPlaylists = await Promise.all(upsertTasks) 369 videoUpdated.VideoStreamingPlaylists = await Promise.all(upsertTasks)
341 } 370 }
342 371
343 { 372 {
344 // Update Tags 373 // Update Tags
345 const tags = videoObject.tag.map(tag => tag.name) 374 const tags = videoObject.tag.map(tag => tag.name)
346 const tagInstances = await TagModel.findOrCreateTags(tags, t) 375 const tagInstances = await TagModel.findOrCreateTags(tags, t)
347 await video.$set('Tags', tagInstances, sequelizeOptions) 376 await videoUpdated.$set('Tags', tagInstances, sequelizeOptions)
348 } 377 }
349 378
350 { 379 {
351 // Update captions 380 // Update captions
352 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(video.id, t) 381 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t)
353 382
354 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 383 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => {
355 return VideoCaptionModel.insertOrReplaceLanguage(video.id, c.identifier, t) 384 return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, t)
356 }) 385 })
357 video.VideoCaptions = await Promise.all(videoCaptionsPromises) 386 await Promise.all(videoCaptionsPromises)
358 } 387 }
388
389 return videoUpdated
359 }) 390 })
360 391
361 await autoBlacklistVideoIfNeeded({ 392 await autoBlacklistVideoIfNeeded({
362 video, 393 video: videoUpdated,
363 user: undefined, 394 user: undefined,
364 isRemote: true, 395 isRemote: true,
365 isNew: false, 396 isNew: false,
366 transaction: undefined 397 transaction: undefined
367 }) 398 })
368 399
369 if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(video) // Notify our users? 400 if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoUpdated) // Notify our users?
370 401
371 logger.info('Remote video with uuid %s updated', videoObject.uuid) 402 logger.info('Remote video with uuid %s updated', videoObject.uuid)
403
404 return videoUpdated
372 } catch (err) { 405 } catch (err) {
373 if (video !== undefined && videoFieldsSave !== undefined) { 406 if (video !== undefined && videoFieldsSave !== undefined) {
374 resetSequelizeInstance(video, videoFieldsSave) 407 resetSequelizeInstance(video, videoFieldsSave)
@@ -381,15 +414,15 @@ async function updateVideoFromAP (options: {
381} 414}
382 415
383async function refreshVideoIfNeeded (options: { 416async function refreshVideoIfNeeded (options: {
384 video: VideoModel, 417 video: MVideoThumbnail,
385 fetchedType: VideoFetchByUrlType, 418 fetchedType: VideoFetchByUrlType,
386 syncParam: SyncParam 419 syncParam: SyncParam
387}): Promise<VideoModel> { 420}): Promise<MVideoThumbnail> {
388 if (!options.video.isOutdated()) return options.video 421 if (!options.video.isOutdated()) return options.video
389 422
390 // We need more attributes if the argument video was fetched with not enough joints 423 // We need more attributes if the argument video was fetched with not enough joints
391 const video = options.fetchedType === 'all' 424 const video = options.fetchedType === 'all'
392 ? options.video 425 ? options.video as MVideoAccountAllFiles
393 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url) 426 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url)
394 427
395 try { 428 try {
@@ -410,12 +443,11 @@ async function refreshVideoIfNeeded (options: {
410 } 443 }
411 444
412 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) 445 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
413 const account = await AccountModel.load(channelActor.VideoChannel.accountId)
414 446
415 const updateOptions = { 447 const updateOptions = {
416 video, 448 video,
417 videoObject, 449 videoObject,
418 account, 450 account: channelActor.VideoChannel.Account,
419 channel: channelActor.VideoChannel 451 channel: channelActor.VideoChannel
420 } 452 }
421 await retryTransactionWrapper(updateVideoFromAP, updateOptions) 453 await retryTransactionWrapper(updateVideoFromAP, updateOptions)
@@ -467,15 +499,15 @@ function isAPPlaylistSegmentHashesUrlObject (tag: any): tag is ActivityPlaylistS
467 return tag.name === 'sha256' && tag.type === 'Link' && urlMediaType === 'application/json' 499 return tag.name === 'sha256' && tag.type === 'Link' && urlMediaType === 'application/json'
468} 500}
469 501
470async function createVideo (videoObject: VideoTorrentObject, channelActor: ActorModel, waitThumbnail = false) { 502async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAccountLight, waitThumbnail = false) {
471 logger.debug('Adding remote video %s.', videoObject.id) 503 logger.debug('Adding remote video %s.', videoObject.id)
472 504
473 const videoData = await videoActivityObjectToDBAttributes(channelActor.VideoChannel, videoObject, videoObject.to) 505 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to)
474 const video = VideoModel.build(videoData) 506 const video = VideoModel.build(videoData) as MVideoThumbnail
475 507
476 const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) 508 const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE)
477 509
478 let thumbnailModel: ThumbnailModel 510 let thumbnailModel: MThumbnail
479 if (waitThumbnail === true) { 511 if (waitThumbnail === true) {
480 thumbnailModel = await promiseThumbnail 512 thumbnailModel = await promiseThumbnail
481 } 513 }
@@ -483,8 +515,8 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
483 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { 515 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => {
484 const sequelizeOptions = { transaction: t } 516 const sequelizeOptions = { transaction: t }
485 517
486 const videoCreated = await video.save(sequelizeOptions) 518 const videoCreated = await video.save(sequelizeOptions) as MVideoFullLight
487 videoCreated.VideoChannel = channelActor.VideoChannel 519 videoCreated.VideoChannel = channel
488 520
489 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) 521 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
490 522
@@ -517,15 +549,14 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
517 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 549 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => {
518 return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t) 550 return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t)
519 }) 551 })
520 const captions = await Promise.all(videoCaptionsPromises) 552 await Promise.all(videoCaptionsPromises)
521 553
522 video.VideoFiles = videoFiles 554 videoCreated.VideoFiles = videoFiles
523 video.VideoStreamingPlaylists = streamingPlaylists 555 videoCreated.VideoStreamingPlaylists = streamingPlaylists
524 video.Tags = tagInstances 556 videoCreated.Tags = tagInstances
525 video.VideoCaptions = captions
526 557
527 const autoBlacklisted = await autoBlacklistVideoIfNeeded({ 558 const autoBlacklisted = await autoBlacklistVideoIfNeeded({
528 video, 559 video: videoCreated,
529 user: undefined, 560 user: undefined,
530 isRemote: true, 561 isRemote: true,
531 isNew: true, 562 isNew: true,
@@ -548,11 +579,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
548 return { autoBlacklisted, videoCreated } 579 return { autoBlacklisted, videoCreated }
549} 580}
550 581
551async function videoActivityObjectToDBAttributes ( 582async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) {
552 videoChannel: VideoChannelModelId,
553 videoObject: VideoTorrentObject,
554 to: string[] = []
555) {
556 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED 583 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
557 const duration = videoObject.duration.replace(/[^\d]+/, '') 584 const duration = videoObject.duration.replace(/[^\d]+/, '')
558 585
@@ -603,7 +630,7 @@ async function videoActivityObjectToDBAttributes (
603 } 630 }
604} 631}
605 632
606function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject) { 633function videoFileActivityUrlToDBAttributes (video: MVideo, videoObject: VideoTorrentObject) {
607 const fileUrls = videoObject.url.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[] 634 const fileUrls = videoObject.url.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[]
608 635
609 if (fileUrls.length === 0) { 636 if (fileUrls.length === 0) {
@@ -641,7 +668,7 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid
641 return attributes 668 return attributes
642} 669}
643 670
644function streamingPlaylistActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject, videoFiles: VideoFileModel[]) { 671function streamingPlaylistActivityUrlToDBAttributes (video: MVideoId, videoObject: VideoTorrentObject, videoFiles: MVideoFile[]) {
645 const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[] 672 const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[]
646 if (playlistUrls.length === 0) return [] 673 if (playlistUrls.length === 0) return []
647 674