1 import * as Bluebird from 'bluebird'
2 import { ActivityUpdate } from '../../../../shared/models/activitypub'
3 import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor'
4 import { VideoTorrentObject } from '../../../../shared/models/activitypub/objects'
5 import { retryTransactionWrapper } from '../../../helpers/database-utils'
6 import { logger } from '../../../helpers/logger'
7 import { resetSequelizeInstance } from '../../../helpers/utils'
8 import { sequelizeTypescript } from '../../../initializers'
9 import { AccountModel } from '../../../models/account/account'
10 import { ActorModel } from '../../../models/activitypub/actor'
11 import { TagModel } from '../../../models/video/tag'
12 import { VideoFileModel } from '../../../models/video/video-file'
13 import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
15 generateThumbnailFromUrl, getOrCreateAccountAndVideoAndChannel, videoActivityObjectToDBAttributes,
16 videoFileActivityUrlToDBAttributes
19 async function processUpdateActivity (activity: ActivityUpdate) {
20 const actor = await getOrCreateActorAndServerAndModel(activity.actor)
22 if (activity.object.type === 'Video') {
23 return processUpdateVideo(actor, activity)
24 } else if (activity.object.type === 'Person') {
25 return processUpdateAccount(actor, activity)
31 // ---------------------------------------------------------------------------
37 // ---------------------------------------------------------------------------
39 function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
41 arguments: [ actor, activity ],
42 errorMessage: 'Cannot update the remote video with many retries'
45 return retryTransactionWrapper(updateRemoteVideo, options)
48 async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
49 const videoAttributesToUpdate = activity.object as VideoTorrentObject
51 const res = await getOrCreateAccountAndVideoAndChannel(videoAttributesToUpdate.id)
53 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
54 let videoInstance = res.video
55 let videoFieldsSave: any
58 await sequelizeTypescript.transaction(async t => {
59 const sequelizeOptions = {
63 videoFieldsSave = videoInstance.toJSON()
65 const videoChannel = videoInstance.VideoChannel
66 if (videoChannel.Account.Actor.id !== actor.id) {
67 throw new Error('Account ' + actor.url + ' does not own video channel ' + videoChannel.Actor.url)
70 const videoData = await videoActivityObjectToDBAttributes(videoChannel, videoAttributesToUpdate, activity.to, activity.cc)
71 videoInstance.set('name', videoData.name)
72 videoInstance.set('uuid', videoData.uuid)
73 videoInstance.set('url', videoData.url)
74 videoInstance.set('category', videoData.category)
75 videoInstance.set('licence', videoData.licence)
76 videoInstance.set('language', videoData.language)
77 videoInstance.set('description', videoData.description)
78 videoInstance.set('nsfw', videoData.nsfw)
79 videoInstance.set('commentsEnabled', videoData.commentsEnabled)
80 videoInstance.set('duration', videoData.duration)
81 videoInstance.set('createdAt', videoData.createdAt)
82 videoInstance.set('updatedAt', videoData.updatedAt)
83 videoInstance.set('views', videoData.views)
84 videoInstance.set('privacy', videoData.privacy)
86 await videoInstance.save(sequelizeOptions)
88 // Don't block on request
89 generateThumbnailFromUrl(videoInstance, videoAttributesToUpdate.icon)
90 .catch(err => logger.warn('Cannot generate thumbnail of %s.', videoAttributesToUpdate.id, err))
92 // Remove old video files
93 const videoFileDestroyTasks: Bluebird<void>[] = []
94 for (const videoFile of videoInstance.VideoFiles) {
95 videoFileDestroyTasks.push(videoFile.destroy(sequelizeOptions))
97 await Promise.all(videoFileDestroyTasks)
99 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoInstance, videoAttributesToUpdate)
100 const tasks = videoFileAttributes.map(f => VideoFileModel.create(f))
101 await Promise.all(tasks)
103 const tags = videoAttributesToUpdate.tag.map(t => t.name)
104 const tagInstances = await TagModel.findOrCreateTags(tags, t)
105 await videoInstance.$set('Tags', tagInstances, sequelizeOptions)
108 logger.info('Remote video with uuid %s updated', videoAttributesToUpdate.uuid)
110 if (videoInstance !== undefined && videoFieldsSave !== undefined) {
111 resetSequelizeInstance(videoInstance, videoFieldsSave)
114 // This is just a debug because we will retry the insert
115 logger.debug('Cannot update the remote video.', err)
120 function processUpdateAccount (actor: ActorModel, activity: ActivityUpdate) {
122 arguments: [ actor, activity ],
123 errorMessage: 'Cannot update the remote account with many retries'
126 return retryTransactionWrapper(updateRemoteAccount, options)
129 async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) {
130 const accountAttributesToUpdate = activity.object as ActivityPubActor
132 logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid)
133 let accountInstance: AccountModel
134 let actorFieldsSave: object
135 let accountFieldsSave: object
138 const avatarName = await fetchAvatarIfExists(accountAttributesToUpdate)
141 await sequelizeTypescript.transaction(async t => {
142 actorFieldsSave = actor.toJSON()
143 accountInstance = actor.Account
144 accountFieldsSave = actor.Account.toJSON()
146 await updateActorInstance(actor, accountAttributesToUpdate)
148 if (avatarName !== undefined) {
149 await updateActorAvatarInstance(actor, avatarName, t)
152 await actor.save({ transaction: t })
154 actor.Account.set('name', accountAttributesToUpdate.name || accountAttributesToUpdate.preferredUsername)
155 await actor.Account.save({ transaction: t })
158 logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid)
160 if (actor !== undefined && actorFieldsSave !== undefined) {
161 resetSequelizeInstance(actor, actorFieldsSave)
164 if (accountInstance !== undefined && accountFieldsSave !== undefined) {
165 resetSequelizeInstance(accountInstance, accountFieldsSave)
168 // This is just a debug because we will retry the insert
169 logger.debug('Cannot update the remote account.', err)