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