diff options
Diffstat (limited to 'server/lib/activitypub/videos/get.ts')
-rw-r--r-- | server/lib/activitypub/videos/get.ts | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/server/lib/activitypub/videos/get.ts b/server/lib/activitypub/videos/get.ts new file mode 100644 index 000000000..a8c41e178 --- /dev/null +++ b/server/lib/activitypub/videos/get.ts | |||
@@ -0,0 +1,109 @@ | |||
1 | import { getAPId } from '@server/helpers/activitypub' | ||
2 | import { retryTransactionWrapper } from '@server/helpers/database-utils' | ||
3 | import { fetchVideoByUrl, VideoFetchByUrlType } from '@server/helpers/video' | ||
4 | import { JobQueue } from '@server/lib/job-queue' | ||
5 | import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' | ||
6 | import { refreshVideoIfNeeded } from './refresh' | ||
7 | import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' | ||
8 | |||
9 | type GetVideoResult <T> = Promise<{ | ||
10 | video: T | ||
11 | created: boolean | ||
12 | autoBlacklisted?: boolean | ||
13 | }> | ||
14 | |||
15 | type GetVideoParamAll = { | ||
16 | videoObject: { id: string } | string | ||
17 | syncParam?: SyncParam | ||
18 | fetchType?: 'all' | ||
19 | allowRefresh?: boolean | ||
20 | } | ||
21 | |||
22 | type GetVideoParamImmutable = { | ||
23 | videoObject: { id: string } | string | ||
24 | syncParam?: SyncParam | ||
25 | fetchType: 'only-immutable-attributes' | ||
26 | allowRefresh: false | ||
27 | } | ||
28 | |||
29 | type GetVideoParamOther = { | ||
30 | videoObject: { id: string } | string | ||
31 | syncParam?: SyncParam | ||
32 | fetchType?: 'all' | 'only-video' | ||
33 | allowRefresh?: boolean | ||
34 | } | ||
35 | |||
36 | function getOrCreateAPVideo (options: GetVideoParamAll): GetVideoResult<MVideoAccountLightBlacklistAllFiles> | ||
37 | function getOrCreateAPVideo (options: GetVideoParamImmutable): GetVideoResult<MVideoImmutable> | ||
38 | function getOrCreateAPVideo (options: GetVideoParamOther): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail> | ||
39 | |||
40 | async function getOrCreateAPVideo ( | ||
41 | options: GetVideoParamAll | GetVideoParamImmutable | GetVideoParamOther | ||
42 | ): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> { | ||
43 | // Default params | ||
44 | const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } | ||
45 | const fetchType = options.fetchType || 'all' | ||
46 | const allowRefresh = options.allowRefresh !== false | ||
47 | |||
48 | // Get video url | ||
49 | const videoUrl = getAPId(options.videoObject) | ||
50 | let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType) | ||
51 | |||
52 | if (videoFromDatabase) { | ||
53 | if (allowRefresh === true) { | ||
54 | // Typings ensure allowRefresh === false in only-immutable-attributes fetch type | ||
55 | videoFromDatabase = await scheduleRefresh(videoFromDatabase as MVideoThumbnail, fetchType, syncParam) | ||
56 | } | ||
57 | |||
58 | return { video: videoFromDatabase, created: false } | ||
59 | } | ||
60 | |||
61 | const { videoObject } = await fetchRemoteVideo(videoUrl) | ||
62 | if (!videoObject) throw new Error('Cannot fetch remote video with url: ' + videoUrl) | ||
63 | |||
64 | try { | ||
65 | const creator = new APVideoCreator(videoObject) | ||
66 | const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(creator.create.bind(creator), syncParam.thumbnail) | ||
67 | |||
68 | await syncVideoExternalAttributes(videoCreated, videoObject, syncParam) | ||
69 | |||
70 | return { video: videoCreated, created: true, autoBlacklisted } | ||
71 | } catch (err) { | ||
72 | // Maybe a concurrent getOrCreateAPVideo call created this video | ||
73 | if (err.name === 'SequelizeUniqueConstraintError') { | ||
74 | const alreadyCreatedVideo = await fetchVideoByUrl(videoUrl, fetchType) | ||
75 | if (alreadyCreatedVideo) return { video: alreadyCreatedVideo, created: false } | ||
76 | } | ||
77 | |||
78 | throw err | ||
79 | } | ||
80 | } | ||
81 | |||
82 | // --------------------------------------------------------------------------- | ||
83 | |||
84 | export { | ||
85 | getOrCreateAPVideo | ||
86 | } | ||
87 | |||
88 | // --------------------------------------------------------------------------- | ||
89 | |||
90 | async function scheduleRefresh (video: MVideoThumbnail, fetchType: VideoFetchByUrlType, syncParam: SyncParam) { | ||
91 | if (!video.isOutdated()) return video | ||
92 | |||
93 | const refreshOptions = { | ||
94 | video, | ||
95 | fetchedType: fetchType, | ||
96 | syncParam | ||
97 | } | ||
98 | |||
99 | if (syncParam.refreshVideo === true) { | ||
100 | return refreshVideoIfNeeded(refreshOptions) | ||
101 | } | ||
102 | |||
103 | await JobQueue.Instance.createJobWithPromise({ | ||
104 | type: 'activitypub-refresher', | ||
105 | payload: { type: 'video', url: video.url } | ||
106 | }) | ||
107 | |||
108 | return video | ||
109 | } | ||