]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/videos/updater.ts
Bumped to version v5.2.1
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / videos / updater.ts
CommitLineData
08a47c75 1import { Transaction } from 'sequelize/types'
28dfb44b 2import { resetSequelizeInstance, runInReadCommittedTransaction } from '@server/helpers/database-utils'
908e6ead 3import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger'
08a47c75
C
4import { Notifier } from '@server/lib/notifier'
5import { PeerTubeSocket } from '@server/lib/peertube-socket'
c3441b03 6import { Hooks } from '@server/lib/plugins/hooks'
08a47c75 7import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist'
08a47c75 8import { VideoLiveModel } from '@server/models/video/video-live'
c56faf0d 9import { MActor, MChannelAccountLight, MChannelId, MVideoAccountLightBlacklistAllFiles, MVideoFullLight } from '@server/types/models'
08a47c75 10import { VideoObject, VideoPrivacy } from '@shared/models'
57e4e1c1 11import { APVideoAbstractBuilder, getVideoAttributesFromObject, updateVideoRates } from './shared'
08a47c75
C
12
13export class APVideoUpdater extends APVideoAbstractBuilder {
08a47c75
C
14 private readonly wasPrivateVideo: boolean
15 private readonly wasUnlistedVideo: boolean
16
08a47c75
C
17 private readonly oldVideoChannel: MChannelAccountLight
18
908e6ead 19 protected lTags: LoggerTagsFn
46320694 20
c56faf0d
C
21 constructor (
22 protected readonly videoObject: VideoObject,
23 private readonly video: MVideoAccountLightBlacklistAllFiles
24 ) {
08a47c75
C
25 super()
26
08a47c75
C
27 this.wasPrivateVideo = this.video.privacy === VideoPrivacy.PRIVATE
28 this.wasUnlistedVideo = this.video.privacy === VideoPrivacy.UNLISTED
29
30 this.oldVideoChannel = this.video.VideoChannel
31
908e6ead 32 this.lTags = loggerTagsFactory('ap', 'video', 'update', video.uuid, video.url)
08a47c75
C
33 }
34
c56faf0d 35 async update (overrideTo?: string[]) {
46320694
C
36 logger.debug(
37 'Updating remote video "%s".', this.videoObject.uuid,
908e6ead 38 { videoObject: this.videoObject, ...this.lTags() }
46320694 39 )
08a47c75
C
40
41 try {
c56faf0d
C
42 const channelActor = await this.getOrCreateVideoChannelFromVideoObject()
43
08a47c75
C
44 const thumbnailModel = await this.tryToGenerateThumbnail(this.video)
45
28dfb44b 46 this.checkChannelUpdateOrThrow(channelActor)
08a47c75 47
28dfb44b 48 const videoUpdated = await this.updateVideo(channelActor.VideoChannel, undefined, overrideTo)
08a47c75 49
28dfb44b 50 if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel)
08a47c75 51
28dfb44b 52 await runInReadCommittedTransaction(async t => {
08a47c75
C
53 await this.setWebTorrentFiles(videoUpdated, t)
54 await this.setStreamingPlaylists(videoUpdated, t)
08a47c75
C
55 })
56
28dfb44b
C
57 await Promise.all([
58 runInReadCommittedTransaction(t => this.setTags(videoUpdated, t)),
59 runInReadCommittedTransaction(t => this.setTrackers(videoUpdated, t)),
60 this.setOrDeleteLive(videoUpdated),
61 this.setPreview(videoUpdated)
62 ])
63
64 await runInReadCommittedTransaction(t => this.setCaptions(videoUpdated, t))
65
08a47c75
C
66 await autoBlacklistVideoIfNeeded({
67 video: videoUpdated,
68 user: undefined,
69 isRemote: true,
70 isNew: false,
71 transaction: undefined
72 })
73
57e4e1c1
C
74 await updateVideoRates(videoUpdated, this.videoObject)
75
08a47c75
C
76 // Notify our users?
77 if (this.wasPrivateVideo || this.wasUnlistedVideo) {
78 Notifier.Instance.notifyOnNewVideoIfNeeded(videoUpdated)
79 }
80
81 if (videoUpdated.isLive) {
82 PeerTubeSocket.Instance.sendVideoLiveNewState(videoUpdated)
08a47c75
C
83 }
84
c3441b03
C
85 Hooks.runAction('action:activity-pub.remote-video.updated', { video: videoUpdated, videoAPObject: this.videoObject })
86
908e6ead 87 logger.info('Remote video with uuid %s updated', this.videoObject.uuid, this.lTags())
08a47c75
C
88
89 return videoUpdated
90 } catch (err) {
823c34c0 91 await this.catchUpdateError(err)
08a47c75
C
92 }
93 }
94
95 // Check we can update the channel: we trust the remote server
c56faf0d
C
96 private checkChannelUpdateOrThrow (newChannelActor: MActor) {
97 if (!this.oldVideoChannel.Actor.serverId || !newChannelActor.serverId) {
08a47c75
C
98 throw new Error('Cannot check old channel/new channel validity because `serverId` is null')
99 }
100
c56faf0d
C
101 if (this.oldVideoChannel.Actor.serverId !== newChannelActor.serverId) {
102 throw new Error(`New channel ${newChannelActor.url} is not on the same server than new channel ${this.oldVideoChannel.Actor.url}`)
08a47c75
C
103 }
104 }
105
28dfb44b 106 private updateVideo (channel: MChannelId, transaction?: Transaction, overrideTo?: string[]) {
c56faf0d
C
107 const to = overrideTo || this.videoObject.to
108 const videoData = getVideoAttributesFromObject(channel, this.videoObject, to)
08a47c75
C
109 this.video.name = videoData.name
110 this.video.uuid = videoData.uuid
111 this.video.url = videoData.url
112 this.video.category = videoData.category
113 this.video.licence = videoData.licence
114 this.video.language = videoData.language
115 this.video.description = videoData.description
116 this.video.support = videoData.support
117 this.video.nsfw = videoData.nsfw
118 this.video.commentsEnabled = videoData.commentsEnabled
119 this.video.downloadEnabled = videoData.downloadEnabled
120 this.video.waitTranscoding = videoData.waitTranscoding
121 this.video.state = videoData.state
122 this.video.duration = videoData.duration
123 this.video.createdAt = videoData.createdAt
124 this.video.publishedAt = videoData.publishedAt
125 this.video.originallyPublishedAt = videoData.originallyPublishedAt
126 this.video.privacy = videoData.privacy
127 this.video.channelId = videoData.channelId
128 this.video.views = videoData.views
129 this.video.isLive = videoData.isLive
130
136d7efd 131 // Ensures we update the updatedAt attribute, even if main attributes did not change
08a47c75
C
132 this.video.changed('updatedAt', true)
133
134 return this.video.save({ transaction }) as Promise<MVideoFullLight>
135 }
136
137 private async setCaptions (videoUpdated: MVideoFullLight, t: Transaction) {
08a47c75
C
138 await this.insertOrReplaceCaptions(videoUpdated, t)
139 }
140
28dfb44b
C
141 private async setOrDeleteLive (videoUpdated: MVideoFullLight, transaction?: Transaction) {
142 if (!this.video.isLive) return
143
08a47c75
C
144 if (this.video.isLive) return this.insertOrReplaceLive(videoUpdated, transaction)
145
146 // Delete existing live if it exists
147 await VideoLiveModel.destroy({
148 where: {
149 videoId: this.video.id
150 },
151 transaction
152 })
153
154 videoUpdated.VideoLive = null
155 }
156
823c34c0 157 private async catchUpdateError (err: Error) {
45657746 158 if (this.video !== undefined) {
823c34c0 159 await resetSequelizeInstance(this.video)
08a47c75
C
160 }
161
162 // This is just a debug because we will retry the insert
908e6ead 163 logger.debug('Cannot update the remote video.', { err, ...this.lTags() })
08a47c75
C
164 throw err
165 }
166}