diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-02 11:54:29 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-02 16:57:53 +0200 |
commit | c56faf0d9453490737f283b29a203bb1ca632b95 (patch) | |
tree | 6f6f92ae762921112e49cf5a440381053bb5a492 /server/lib/activitypub/videos | |
parent | 08a47c75f992e7138dca5121f227909a8347d365 (diff) | |
download | PeerTube-c56faf0d9453490737f283b29a203bb1ca632b95.tar.gz PeerTube-c56faf0d9453490737f283b29a203bb1ca632b95.tar.zst PeerTube-c56faf0d9453490737f283b29a203bb1ca632b95.zip |
Move AP video channel creation
Diffstat (limited to 'server/lib/activitypub/videos')
-rw-r--r-- | server/lib/activitypub/videos/fetch.ts | 26 | ||||
-rw-r--r-- | server/lib/activitypub/videos/shared/abstract-builder.ts | 13 | ||||
-rw-r--r-- | server/lib/activitypub/videos/shared/creator.ts | 21 | ||||
-rw-r--r-- | server/lib/activitypub/videos/updater.ts | 47 |
4 files changed, 41 insertions, 66 deletions
diff --git a/server/lib/activitypub/videos/fetch.ts b/server/lib/activitypub/videos/fetch.ts index 5e7f8552b..5113c9d7e 100644 --- a/server/lib/activitypub/videos/fetch.ts +++ b/server/lib/activitypub/videos/fetch.ts | |||
@@ -11,7 +11,6 @@ import { VideoModel } from '@server/models/video/video' | |||
11 | import { MVideoAccountLight, MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' | 11 | import { MVideoAccountLight, MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' |
12 | import { HttpStatusCode } from '@shared/core-utils' | 12 | import { HttpStatusCode } from '@shared/core-utils' |
13 | import { VideoObject } from '@shared/models' | 13 | import { VideoObject } from '@shared/models' |
14 | import { getOrCreateActorAndServerAndModel } from '../actor' | ||
15 | import { APVideoCreator, SyncParam, syncVideoExternalAttributes } from './shared' | 14 | import { APVideoCreator, SyncParam, syncVideoExternalAttributes } from './shared' |
16 | import { APVideoUpdater } from './updater' | 15 | import { APVideoUpdater } from './updater' |
17 | 16 | ||
@@ -37,17 +36,6 @@ async function fetchRemoteVideoDescription (video: MVideoAccountLight) { | |||
37 | return body.description || '' | 36 | return body.description || '' |
38 | } | 37 | } |
39 | 38 | ||
40 | function getOrCreateVideoChannelFromVideoObject (videoObject: VideoObject) { | ||
41 | const channel = videoObject.attributedTo.find(a => a.type === 'Group') | ||
42 | if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) | ||
43 | |||
44 | if (checkUrlsSameHost(channel.id, videoObject.id) !== true) { | ||
45 | throw new Error(`Video channel url ${channel.id} does not have the same host than video object id ${videoObject.id}`) | ||
46 | } | ||
47 | |||
48 | return getOrCreateActorAndServerAndModel(channel.id, 'all') | ||
49 | } | ||
50 | |||
51 | type GetVideoResult <T> = Promise<{ | 39 | type GetVideoResult <T> = Promise<{ |
52 | video: T | 40 | video: T |
53 | created: boolean | 41 | created: boolean |
@@ -117,11 +105,8 @@ async function getOrCreateVideoAndAccountAndChannel ( | |||
117 | const { videoObject } = await fetchRemoteVideo(videoUrl) | 105 | const { videoObject } = await fetchRemoteVideo(videoUrl) |
118 | if (!videoObject) throw new Error('Cannot fetch remote video with url: ' + videoUrl) | 106 | if (!videoObject) throw new Error('Cannot fetch remote video with url: ' + videoUrl) |
119 | 107 | ||
120 | const actor = await getOrCreateVideoChannelFromVideoObject(videoObject) | ||
121 | const videoChannel = actor.VideoChannel | ||
122 | |||
123 | try { | 108 | try { |
124 | const creator = new APVideoCreator({ videoObject, channel: videoChannel }) | 109 | const creator = new APVideoCreator(videoObject) |
125 | const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(creator.create.bind(creator), syncParam.thumbnail) | 110 | const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(creator.create.bind(creator), syncParam.thumbnail) |
126 | 111 | ||
127 | await syncVideoExternalAttributes(videoCreated, videoObject, syncParam) | 112 | await syncVideoExternalAttributes(videoCreated, videoObject, syncParam) |
@@ -160,13 +145,7 @@ async function refreshVideoIfNeeded (options: { | |||
160 | return video | 145 | return video |
161 | } | 146 | } |
162 | 147 | ||
163 | const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) | 148 | const videoUpdater = new APVideoUpdater(videoObject, video) |
164 | |||
165 | const videoUpdater = new APVideoUpdater({ | ||
166 | video, | ||
167 | videoObject, | ||
168 | channel: channelActor.VideoChannel | ||
169 | }) | ||
170 | await videoUpdater.update() | 149 | await videoUpdater.update() |
171 | 150 | ||
172 | await syncVideoExternalAttributes(video, videoObject, options.syncParam) | 151 | await syncVideoExternalAttributes(video, videoObject, options.syncParam) |
@@ -197,6 +176,5 @@ export { | |||
197 | fetchRemoteVideo, | 176 | fetchRemoteVideo, |
198 | fetchRemoteVideoDescription, | 177 | fetchRemoteVideoDescription, |
199 | refreshVideoIfNeeded, | 178 | refreshVideoIfNeeded, |
200 | getOrCreateVideoChannelFromVideoObject, | ||
201 | getOrCreateVideoAndAccountAndChannel | 179 | getOrCreateVideoAndAccountAndChannel |
202 | } | 180 | } |
diff --git a/server/lib/activitypub/videos/shared/abstract-builder.ts b/server/lib/activitypub/videos/shared/abstract-builder.ts index 9d5f37e5f..c7631cd45 100644 --- a/server/lib/activitypub/videos/shared/abstract-builder.ts +++ b/server/lib/activitypub/videos/shared/abstract-builder.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { Transaction } from 'sequelize/types' | 1 | import { Transaction } from 'sequelize/types' |
2 | import { checkUrlsSameHost } from '@server/helpers/activitypub' | ||
2 | import { deleteNonExistingModels } from '@server/helpers/database-utils' | 3 | import { deleteNonExistingModels } from '@server/helpers/database-utils' |
3 | import { logger } from '@server/helpers/logger' | 4 | import { logger } from '@server/helpers/logger' |
4 | import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '@server/lib/thumbnail' | 5 | import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '@server/lib/thumbnail' |
@@ -9,6 +10,7 @@ import { VideoLiveModel } from '@server/models/video/video-live' | |||
9 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | 10 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' |
10 | import { MStreamingPlaylistFilesVideo, MThumbnail, MVideoCaption, MVideoFile, MVideoFullLight, MVideoThumbnail } from '@server/types/models' | 11 | import { MStreamingPlaylistFilesVideo, MThumbnail, MVideoCaption, MVideoFile, MVideoFullLight, MVideoThumbnail } from '@server/types/models' |
11 | import { ActivityTagObject, ThumbnailType, VideoObject, VideoStreamingPlaylistType } from '@shared/models' | 12 | import { ActivityTagObject, ThumbnailType, VideoObject, VideoStreamingPlaylistType } from '@shared/models' |
13 | import { getOrCreateActorAndServerAndModel } from '../../actor' | ||
12 | import { | 14 | import { |
13 | getCaptionAttributesFromObject, | 15 | getCaptionAttributesFromObject, |
14 | getFileAttributesFromUrl, | 16 | getFileAttributesFromUrl, |
@@ -23,6 +25,17 @@ import { getTrackerUrls, setVideoTrackers } from './trackers' | |||
23 | export abstract class APVideoAbstractBuilder { | 25 | export abstract class APVideoAbstractBuilder { |
24 | protected abstract videoObject: VideoObject | 26 | protected abstract videoObject: VideoObject |
25 | 27 | ||
28 | protected async getOrCreateVideoChannelFromVideoObject () { | ||
29 | const channel = this.videoObject.attributedTo.find(a => a.type === 'Group') | ||
30 | if (!channel) throw new Error('Cannot find associated video channel to video ' + this.videoObject.url) | ||
31 | |||
32 | if (checkUrlsSameHost(channel.id, this.videoObject.id) !== true) { | ||
33 | throw new Error(`Video channel url ${channel.id} does not have the same host than video object id ${this.videoObject.id}`) | ||
34 | } | ||
35 | |||
36 | return getOrCreateActorAndServerAndModel(channel.id, 'all') | ||
37 | } | ||
38 | |||
26 | protected tryToGenerateThumbnail (video: MVideoThumbnail): Promise<MThumbnail> { | 39 | protected tryToGenerateThumbnail (video: MVideoThumbnail): Promise<MThumbnail> { |
27 | return createVideoMiniatureFromUrl({ | 40 | return createVideoMiniatureFromUrl({ |
28 | downloadUrl: getThumbnailFromIcons(this.videoObject).url, | 41 | downloadUrl: getThumbnailFromIcons(this.videoObject).url, |
diff --git a/server/lib/activitypub/videos/shared/creator.ts b/server/lib/activitypub/videos/shared/creator.ts index 4f2d79374..dd9bfb508 100644 --- a/server/lib/activitypub/videos/shared/creator.ts +++ b/server/lib/activitypub/videos/shared/creator.ts | |||
@@ -3,29 +3,24 @@ import { logger } from '@server/helpers/logger' | |||
3 | import { sequelizeTypescript } from '@server/initializers/database' | 3 | import { sequelizeTypescript } from '@server/initializers/database' |
4 | import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist' | 4 | import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist' |
5 | import { VideoModel } from '@server/models/video/video' | 5 | import { VideoModel } from '@server/models/video/video' |
6 | import { MChannelAccountLight, MThumbnail, MVideoFullLight, MVideoThumbnail } from '@server/types/models' | 6 | import { MThumbnail, MVideoFullLight, MVideoThumbnail } from '@server/types/models' |
7 | import { VideoObject } from '@shared/models' | 7 | import { VideoObject } from '@shared/models' |
8 | import { APVideoAbstractBuilder } from './abstract-builder' | 8 | import { APVideoAbstractBuilder } from './abstract-builder' |
9 | import { getVideoAttributesFromObject } from './object-to-model-attributes' | 9 | import { getVideoAttributesFromObject } from './object-to-model-attributes' |
10 | 10 | ||
11 | export class APVideoCreator extends APVideoAbstractBuilder { | 11 | export class APVideoCreator extends APVideoAbstractBuilder { |
12 | protected readonly videoObject: VideoObject | ||
13 | private readonly channel: MChannelAccountLight | ||
14 | 12 | ||
15 | constructor (options: { | 13 | constructor (protected readonly videoObject: VideoObject) { |
16 | videoObject: VideoObject | ||
17 | channel: MChannelAccountLight | ||
18 | }) { | ||
19 | super() | 14 | super() |
20 | |||
21 | this.videoObject = options.videoObject | ||
22 | this.channel = options.channel | ||
23 | } | 15 | } |
24 | 16 | ||
25 | async create (waitThumbnail = false) { | 17 | async create (waitThumbnail = false) { |
26 | logger.debug('Adding remote video %s.', this.videoObject.id) | 18 | logger.debug('Adding remote video %s.', this.videoObject.id) |
27 | 19 | ||
28 | const videoData = await getVideoAttributesFromObject(this.channel, this.videoObject, this.videoObject.to) | 20 | const channelActor = await this.getOrCreateVideoChannelFromVideoObject() |
21 | const channel = channelActor.VideoChannel | ||
22 | |||
23 | const videoData = await getVideoAttributesFromObject(channel, this.videoObject, this.videoObject.to) | ||
29 | const video = VideoModel.build(videoData) as MVideoThumbnail | 24 | const video = VideoModel.build(videoData) as MVideoThumbnail |
30 | 25 | ||
31 | const promiseThumbnail = this.tryToGenerateThumbnail(video) | 26 | const promiseThumbnail = this.tryToGenerateThumbnail(video) |
@@ -38,7 +33,7 @@ export class APVideoCreator extends APVideoAbstractBuilder { | |||
38 | const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { | 33 | const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { |
39 | try { | 34 | try { |
40 | const videoCreated = await video.save({ transaction: t }) as MVideoFullLight | 35 | const videoCreated = await video.save({ transaction: t }) as MVideoFullLight |
41 | videoCreated.VideoChannel = this.channel | 36 | videoCreated.VideoChannel = channel |
42 | 37 | ||
43 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) | 38 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) |
44 | 39 | ||
@@ -51,7 +46,7 @@ export class APVideoCreator extends APVideoAbstractBuilder { | |||
51 | await this.insertOrReplaceLive(videoCreated, t) | 46 | await this.insertOrReplaceLive(videoCreated, t) |
52 | 47 | ||
53 | // We added a video in this channel, set it as updated | 48 | // We added a video in this channel, set it as updated |
54 | await this.channel.setAsUpdated(t) | 49 | await channel.setAsUpdated(t) |
55 | 50 | ||
56 | const autoBlacklisted = await autoBlacklistVideoIfNeeded({ | 51 | const autoBlacklisted = await autoBlacklistVideoIfNeeded({ |
57 | video: videoCreated, | 52 | video: videoCreated, |
diff --git a/server/lib/activitypub/videos/updater.ts b/server/lib/activitypub/videos/updater.ts index 4338d1e22..11c177a68 100644 --- a/server/lib/activitypub/videos/updater.ts +++ b/server/lib/activitypub/videos/updater.ts | |||
@@ -7,17 +7,11 @@ import { PeerTubeSocket } from '@server/lib/peertube-socket' | |||
7 | import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist' | 7 | import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist' |
8 | import { VideoCaptionModel } from '@server/models/video/video-caption' | 8 | import { VideoCaptionModel } from '@server/models/video/video-caption' |
9 | import { VideoLiveModel } from '@server/models/video/video-live' | 9 | import { VideoLiveModel } from '@server/models/video/video-live' |
10 | import { MChannelAccountLight, MChannelDefault, MVideoAccountLightBlacklistAllFiles, MVideoFullLight } from '@server/types/models' | 10 | import { MActor, MChannelAccountLight, MChannelId, MVideoAccountLightBlacklistAllFiles, MVideoFullLight } from '@server/types/models' |
11 | import { VideoObject, VideoPrivacy } from '@shared/models' | 11 | import { VideoObject, VideoPrivacy } from '@shared/models' |
12 | import { APVideoAbstractBuilder, getVideoAttributesFromObject } from './shared' | 12 | import { APVideoAbstractBuilder, getVideoAttributesFromObject } from './shared' |
13 | 13 | ||
14 | export class APVideoUpdater extends APVideoAbstractBuilder { | 14 | export class APVideoUpdater extends APVideoAbstractBuilder { |
15 | protected readonly videoObject: VideoObject | ||
16 | |||
17 | private readonly video: MVideoAccountLightBlacklistAllFiles | ||
18 | private readonly channel: MChannelDefault | ||
19 | private readonly overrideTo: string[] | ||
20 | |||
21 | private readonly wasPrivateVideo: boolean | 15 | private readonly wasPrivateVideo: boolean |
22 | private readonly wasUnlistedVideo: boolean | 16 | private readonly wasUnlistedVideo: boolean |
23 | 17 | ||
@@ -25,19 +19,12 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
25 | 19 | ||
26 | private readonly oldVideoChannel: MChannelAccountLight | 20 | private readonly oldVideoChannel: MChannelAccountLight |
27 | 21 | ||
28 | constructor (options: { | 22 | constructor ( |
29 | video: MVideoAccountLightBlacklistAllFiles | 23 | protected readonly videoObject: VideoObject, |
30 | videoObject: VideoObject | 24 | private readonly video: MVideoAccountLightBlacklistAllFiles |
31 | channel: MChannelDefault | 25 | ) { |
32 | overrideTo?: string[] | ||
33 | }) { | ||
34 | super() | 26 | super() |
35 | 27 | ||
36 | this.video = options.video | ||
37 | this.videoObject = options.videoObject | ||
38 | this.channel = options.channel | ||
39 | this.overrideTo = options.overrideTo | ||
40 | |||
41 | this.wasPrivateVideo = this.video.privacy === VideoPrivacy.PRIVATE | 28 | this.wasPrivateVideo = this.video.privacy === VideoPrivacy.PRIVATE |
42 | this.wasUnlistedVideo = this.video.privacy === VideoPrivacy.UNLISTED | 29 | this.wasUnlistedVideo = this.video.privacy === VideoPrivacy.UNLISTED |
43 | 30 | ||
@@ -46,16 +33,18 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
46 | this.videoFieldsSave = this.video.toJSON() | 33 | this.videoFieldsSave = this.video.toJSON() |
47 | } | 34 | } |
48 | 35 | ||
49 | async update () { | 36 | async update (overrideTo?: string[]) { |
50 | logger.debug('Updating remote video "%s".', this.videoObject.uuid, { videoObject: this.videoObject, channel: this.channel }) | 37 | logger.debug('Updating remote video "%s".', this.videoObject.uuid, { videoObject: this.videoObject }) |
51 | 38 | ||
52 | try { | 39 | try { |
40 | const channelActor = await this.getOrCreateVideoChannelFromVideoObject() | ||
41 | |||
53 | const thumbnailModel = await this.tryToGenerateThumbnail(this.video) | 42 | const thumbnailModel = await this.tryToGenerateThumbnail(this.video) |
54 | 43 | ||
55 | const videoUpdated = await sequelizeTypescript.transaction(async t => { | 44 | const videoUpdated = await sequelizeTypescript.transaction(async t => { |
56 | this.checkChannelUpdateOrThrow() | 45 | this.checkChannelUpdateOrThrow(channelActor) |
57 | 46 | ||
58 | const videoUpdated = await this.updateVideo(t) | 47 | const videoUpdated = await this.updateVideo(channelActor.VideoChannel, t, overrideTo) |
59 | 48 | ||
60 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) | 49 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) |
61 | 50 | ||
@@ -97,19 +86,19 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
97 | } | 86 | } |
98 | 87 | ||
99 | // Check we can update the channel: we trust the remote server | 88 | // Check we can update the channel: we trust the remote server |
100 | private checkChannelUpdateOrThrow () { | 89 | private checkChannelUpdateOrThrow (newChannelActor: MActor) { |
101 | if (!this.oldVideoChannel.Actor.serverId || !this.channel.Actor.serverId) { | 90 | if (!this.oldVideoChannel.Actor.serverId || !newChannelActor.serverId) { |
102 | throw new Error('Cannot check old channel/new channel validity because `serverId` is null') | 91 | throw new Error('Cannot check old channel/new channel validity because `serverId` is null') |
103 | } | 92 | } |
104 | 93 | ||
105 | if (this.oldVideoChannel.Actor.serverId !== this.channel.Actor.serverId) { | 94 | if (this.oldVideoChannel.Actor.serverId !== newChannelActor.serverId) { |
106 | throw new Error(`New channel ${this.channel.Actor.url} is not on the same server than new channel ${this.oldVideoChannel.Actor.url}`) | 95 | throw new Error(`New channel ${newChannelActor.url} is not on the same server than new channel ${this.oldVideoChannel.Actor.url}`) |
107 | } | 96 | } |
108 | } | 97 | } |
109 | 98 | ||
110 | private updateVideo (transaction: Transaction) { | 99 | private updateVideo (channel: MChannelId, transaction: Transaction, overrideTo?: string[]) { |
111 | const to = this.overrideTo || this.videoObject.to | 100 | const to = overrideTo || this.videoObject.to |
112 | const videoData = getVideoAttributesFromObject(this.channel, this.videoObject, to) | 101 | const videoData = getVideoAttributesFromObject(channel, this.videoObject, to) |
113 | this.video.name = videoData.name | 102 | this.video.name = videoData.name |
114 | this.video.uuid = videoData.uuid | 103 | this.video.uuid = videoData.uuid |
115 | this.video.url = videoData.url | 104 | this.video.url = videoData.url |