diff options
author | Chocobozzz <me@florianbigard.com> | 2018-01-26 12:02:18 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-01-26 13:43:34 +0100 |
commit | 7acee6f18aac99e359360fc4f2362d5405135a79 (patch) | |
tree | a8eceaba9a01b913fcfca32f17f26b4f588a633e /server | |
parent | d6e99e5322209a692cc3d870ddb5dcedbda69f2a (diff) | |
download | PeerTube-7acee6f18aac99e359360fc4f2362d5405135a79.tar.gz PeerTube-7acee6f18aac99e359360fc4f2362d5405135a79.tar.zst PeerTube-7acee6f18aac99e359360fc4f2362d5405135a79.zip |
Fix announce activities
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/activitypub/outbox.ts | 7 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/announce.ts | 5 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-announce.ts | 26 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 55 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-announce.ts | 12 | ||||
-rw-r--r-- | server/lib/activitypub/videos.ts | 53 |
6 files changed, 66 insertions, 92 deletions
diff --git a/server/controllers/activitypub/outbox.ts b/server/controllers/activitypub/outbox.ts index ab12a7c4b..41c6ffaeb 100644 --- a/server/controllers/activitypub/outbox.ts +++ b/server/controllers/activitypub/outbox.ts | |||
@@ -43,21 +43,18 @@ async function outboxController (req: express.Request, res: express.Response, ne | |||
43 | const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined) | 43 | const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined) |
44 | 44 | ||
45 | for (const video of data.data) { | 45 | for (const video of data.data) { |
46 | const videoObject = video.toActivityPubObject() | ||
47 | |||
48 | const byActor = video.VideoChannel.Account.Actor | 46 | const byActor = video.VideoChannel.Account.Actor |
49 | const createActivityAudience = buildAudience(followersMatrix[byActor.id]) | 47 | const createActivityAudience = buildAudience(followersMatrix[byActor.id]) |
50 | 48 | ||
51 | // This is a shared video | 49 | // This is a shared video |
52 | if (video.VideoShares !== undefined && video.VideoShares.length !== 0) { | 50 | if (video.VideoShares !== undefined && video.VideoShares.length !== 0) { |
53 | const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience) | ||
54 | |||
55 | const announceAudience = buildAudience(followersMatrix[actor.id]) | 51 | const announceAudience = buildAudience(followersMatrix[actor.id]) |
56 | const url = getAnnounceActivityPubUrl(video.url, actor) | 52 | const url = getAnnounceActivityPubUrl(video.url, actor) |
57 | const announceActivity = await announceActivityData(url, actor, createActivity, undefined, announceAudience) | 53 | const announceActivity = await announceActivityData(url, actor, video.url, undefined, announceAudience) |
58 | 54 | ||
59 | activities.push(announceActivity) | 55 | activities.push(announceActivity) |
60 | } else { | 56 | } else { |
57 | const videoObject = video.toActivityPubObject() | ||
61 | const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience) | 58 | const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience) |
62 | 59 | ||
63 | activities.push(createActivity) | 60 | activities.push(createActivity) |
diff --git a/server/helpers/custom-validators/activitypub/announce.ts b/server/helpers/custom-validators/activitypub/announce.ts index 7dd1d6988..0519c6026 100644 --- a/server/helpers/custom-validators/activitypub/announce.ts +++ b/server/helpers/custom-validators/activitypub/announce.ts | |||
@@ -1,11 +1,10 @@ | |||
1 | import { isActivityPubUrlValid, isBaseActivityValid } from './misc' | 1 | import { isActivityPubUrlValid, isBaseActivityValid } from './misc' |
2 | import { isVideoTorrentCreateActivityValid } from './videos' | ||
3 | 2 | ||
4 | function isAnnounceActivityValid (activity: any) { | 3 | function isAnnounceActivityValid (activity: any) { |
5 | return isBaseActivityValid(activity, 'Announce') && | 4 | return isBaseActivityValid(activity, 'Announce') && |
6 | ( | 5 | ( |
7 | isVideoTorrentCreateActivityValid(activity.object) || | 6 | isActivityPubUrlValid(activity.object) || |
8 | isActivityPubUrlValid(activity.object) | 7 | (activity.object && isActivityPubUrlValid(activity.object.id)) |
9 | ) | 8 | ) |
10 | } | 9 | } |
11 | 10 | ||
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index bf7d7879d..7dafc0593 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { ActivityAnnounce } from '../../../../shared/models/activitypub' | 1 | import { ActivityAnnounce } from '../../../../shared/models/activitypub' |
2 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 2 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
3 | import { logger } from '../../../helpers/logger' | ||
4 | import { sequelizeTypescript } from '../../../initializers' | 3 | import { sequelizeTypescript } from '../../../initializers' |
5 | import { ActorModel } from '../../../models/activitypub/actor' | 4 | import { ActorModel } from '../../../models/activitypub/actor' |
6 | import { VideoModel } from '../../../models/video/video' | 5 | import { VideoModel } from '../../../models/video/video' |
@@ -8,24 +7,11 @@ import { VideoShareModel } from '../../../models/video/video-share' | |||
8 | import { getOrCreateActorAndServerAndModel } from '../actor' | 7 | import { getOrCreateActorAndServerAndModel } from '../actor' |
9 | import { forwardActivity } from '../send/misc' | 8 | import { forwardActivity } from '../send/misc' |
10 | import { getOrCreateAccountAndVideoAndChannel } from '../videos' | 9 | import { getOrCreateAccountAndVideoAndChannel } from '../videos' |
11 | import { processCreateActivity } from './process-create' | ||
12 | 10 | ||
13 | async function processAnnounceActivity (activity: ActivityAnnounce) { | 11 | async function processAnnounceActivity (activity: ActivityAnnounce) { |
14 | const announcedActivity = activity.object | ||
15 | const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor) | 12 | const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor) |
16 | 13 | ||
17 | if (typeof announcedActivity === 'string') { | 14 | return processVideoShare(actorAnnouncer, activity) |
18 | return processVideoShare(actorAnnouncer, activity) | ||
19 | } else if (announcedActivity.type === 'Create' && announcedActivity.object.type === 'Video') { | ||
20 | return processVideoShare(actorAnnouncer, activity) | ||
21 | } | ||
22 | |||
23 | logger.warn( | ||
24 | 'Unknown activity object type %s -> %s when announcing activity.', announcedActivity.type, announcedActivity.object.type, | ||
25 | { activity: activity.id } | ||
26 | ) | ||
27 | |||
28 | return undefined | ||
29 | } | 15 | } |
30 | 16 | ||
31 | // --------------------------------------------------------------------------- | 17 | // --------------------------------------------------------------------------- |
@@ -46,15 +32,11 @@ function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnoun | |||
46 | } | 32 | } |
47 | 33 | ||
48 | async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { | 34 | async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { |
49 | const announced = activity.object | 35 | const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id |
50 | let video: VideoModel | 36 | let video: VideoModel |
51 | 37 | ||
52 | if (typeof announced === 'string') { | 38 | const res = await getOrCreateAccountAndVideoAndChannel(objectUri) |
53 | const res = await getOrCreateAccountAndVideoAndChannel(announced) | 39 | video = res.video |
54 | video = res.video | ||
55 | } else { | ||
56 | video = await processCreateActivity(announced) | ||
57 | } | ||
58 | 40 | ||
59 | return sequelizeTypescript.transaction(async t => { | 41 | return sequelizeTypescript.transaction(async t => { |
60 | // Add share entry | 42 | // Add share entry |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index eff796c1d..ee180b765 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -1,20 +1,17 @@ | |||
1 | import * as Bluebird from 'bluebird' | ||
2 | import { ActivityCreate, VideoTorrentObject } from '../../../../shared' | 1 | import { ActivityCreate, VideoTorrentObject } from '../../../../shared' |
3 | import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects' | 2 | import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects' |
4 | import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object' | 3 | import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object' |
5 | import { VideoRateType } from '../../../../shared/models/videos' | ||
6 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 4 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
7 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
8 | import { sequelizeTypescript } from '../../../initializers' | 6 | import { sequelizeTypescript } from '../../../initializers' |
9 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 7 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
10 | import { ActorModel } from '../../../models/activitypub/actor' | 8 | import { ActorModel } from '../../../models/activitypub/actor' |
11 | import { VideoModel } from '../../../models/video/video' | ||
12 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 9 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
13 | import { VideoCommentModel } from '../../../models/video/video-comment' | 10 | import { VideoCommentModel } from '../../../models/video/video-comment' |
14 | import { getOrCreateActorAndServerAndModel } from '../actor' | 11 | import { getOrCreateActorAndServerAndModel } from '../actor' |
15 | import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc' | 12 | import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc' |
16 | import { addVideoComments, resolveThread } from '../video-comments' | 13 | import { resolveThread } from '../video-comments' |
17 | import { addVideoShares, getOrCreateAccountAndVideoAndChannel } from '../videos' | 14 | import { getOrCreateAccountAndVideoAndChannel } from '../videos' |
18 | 15 | ||
19 | async function processCreateActivity (activity: ActivityCreate) { | 16 | async function processCreateActivity (activity: ActivityCreate) { |
20 | const activityObject = activity.object | 17 | const activityObject = activity.object |
@@ -53,57 +50,9 @@ async function processCreateVideo ( | |||
53 | 50 | ||
54 | const { video } = await getOrCreateAccountAndVideoAndChannel(videoToCreateData, actor) | 51 | const { video } = await getOrCreateAccountAndVideoAndChannel(videoToCreateData, actor) |
55 | 52 | ||
56 | // Process outside the transaction because we could fetch remote data | ||
57 | if (videoToCreateData.likes && Array.isArray(videoToCreateData.likes.orderedItems)) { | ||
58 | logger.info('Adding likes of video %s.', video.uuid) | ||
59 | await createRates(videoToCreateData.likes.orderedItems, video, 'like') | ||
60 | } | ||
61 | |||
62 | if (videoToCreateData.dislikes && Array.isArray(videoToCreateData.dislikes.orderedItems)) { | ||
63 | logger.info('Adding dislikes of video %s.', video.uuid) | ||
64 | await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike') | ||
65 | } | ||
66 | |||
67 | if (videoToCreateData.shares && Array.isArray(videoToCreateData.shares.orderedItems)) { | ||
68 | logger.info('Adding shares of video %s.', video.uuid) | ||
69 | await addVideoShares(video, videoToCreateData.shares.orderedItems) | ||
70 | } | ||
71 | |||
72 | if (videoToCreateData.comments && Array.isArray(videoToCreateData.comments.orderedItems)) { | ||
73 | logger.info('Adding comments of video %s.', video.uuid) | ||
74 | await addVideoComments(video, videoToCreateData.comments.orderedItems) | ||
75 | } | ||
76 | |||
77 | return video | 53 | return video |
78 | } | 54 | } |
79 | 55 | ||
80 | async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) { | ||
81 | let rateCounts = 0 | ||
82 | const tasks: Bluebird<number>[] = [] | ||
83 | |||
84 | for (const actorUrl of actorUrls) { | ||
85 | const actor = await getOrCreateActorAndServerAndModel(actorUrl) | ||
86 | const p = AccountVideoRateModel | ||
87 | .create({ | ||
88 | videoId: video.id, | ||
89 | accountId: actor.Account.id, | ||
90 | type: rate | ||
91 | }) | ||
92 | .then(() => rateCounts += 1) | ||
93 | |||
94 | tasks.push(p) | ||
95 | } | ||
96 | |||
97 | await Promise.all(tasks) | ||
98 | |||
99 | logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) | ||
100 | |||
101 | // This is "likes" and "dislikes" | ||
102 | await video.increment(rate + 's', { by: rateCounts }) | ||
103 | |||
104 | return | ||
105 | } | ||
106 | |||
107 | async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) { | 56 | async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) { |
108 | const options = { | 57 | const options = { |
109 | arguments: [ byActor, activity ], | 58 | arguments: [ byActor, activity ], |
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index 93b5668d2..76cb3f80c 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { ActivityAnnounce, ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub' | 2 | import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub' |
3 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
4 | import { ActorModel } from '../../../models/activitypub/actor' | 3 | import { ActorModel } from '../../../models/activitypub/actor' |
5 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
6 | import { getAnnounceActivityPubUrl } from '../url' | 5 | import { getAnnounceActivityPubUrl } from '../url' |
@@ -16,14 +15,11 @@ import { createActivityData } from './send-create' | |||
16 | 15 | ||
17 | async function buildVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { | 16 | async function buildVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { |
18 | const url = getAnnounceActivityPubUrl(video.url, byActor) | 17 | const url = getAnnounceActivityPubUrl(video.url, byActor) |
19 | const videoObject = video.toActivityPubObject() | 18 | const announcedObject = video.url |
20 | |||
21 | const announcedAudience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC) | ||
22 | const announcedActivity = await createActivityData(url, video.VideoChannel.Account.Actor, videoObject, t, announcedAudience) | ||
23 | 19 | ||
24 | const accountsToForwardView = await getActorsInvolvedInVideo(video, t) | 20 | const accountsToForwardView = await getActorsInvolvedInVideo(video, t) |
25 | const audience = getObjectFollowersAudience(accountsToForwardView) | 21 | const audience = getObjectFollowersAudience(accountsToForwardView) |
26 | return announceActivityData(url, byActor, announcedActivity, t, audience) | 22 | return announceActivityData(url, byActor, announcedObject, t, audience) |
27 | } | 23 | } |
28 | 24 | ||
29 | async function sendVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { | 25 | async function sendVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { |
@@ -48,7 +44,7 @@ async function sendVideoAnnounceToOrigin (byActor: ActorModel, video: VideoModel | |||
48 | async function announceActivityData ( | 44 | async function announceActivityData ( |
49 | url: string, | 45 | url: string, |
50 | byActor: ActorModel, | 46 | byActor: ActorModel, |
51 | object: ActivityCreate, | 47 | object: string, |
52 | t: Transaction, | 48 | t: Transaction, |
53 | audience?: ActivityAudience | 49 | audience?: ActivityAudience |
54 | ): Promise<ActivityAnnounce> { | 50 | ): Promise<ActivityAnnounce> { |
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 50e7e5cde..7d535bb0a 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -1,15 +1,17 @@ | |||
1 | import * as Bluebird from 'bluebird' | ||
1 | import * as magnetUtil from 'magnet-uri' | 2 | import * as magnetUtil from 'magnet-uri' |
2 | import { join } from 'path' | 3 | import { join } from 'path' |
3 | import * as request from 'request' | 4 | import * as request from 'request' |
4 | import { ActivityIconObject } from '../../../shared/index' | 5 | import { ActivityIconObject } from '../../../shared/index' |
5 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' | 6 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' |
6 | import { VideoPrivacy } from '../../../shared/models/videos' | 7 | import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' |
7 | import { isVideoTorrentObjectValid } from '../../helpers/custom-validators/activitypub/videos' | 8 | import { isVideoTorrentObjectValid } from '../../helpers/custom-validators/activitypub/videos' |
8 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 9 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
9 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
10 | import { logger } from '../../helpers/logger' | 11 | import { logger } from '../../helpers/logger' |
11 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 12 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
12 | import { ACTIVITY_PUB, CONFIG, REMOTE_SCHEME, sequelizeTypescript, STATIC_PATHS, VIDEO_MIMETYPE_EXT } from '../../initializers' | 13 | import { ACTIVITY_PUB, CONFIG, REMOTE_SCHEME, sequelizeTypescript, STATIC_PATHS, VIDEO_MIMETYPE_EXT } from '../../initializers' |
14 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | ||
13 | import { ActorModel } from '../../models/activitypub/actor' | 15 | import { ActorModel } from '../../models/activitypub/actor' |
14 | import { TagModel } from '../../models/video/tag' | 16 | import { TagModel } from '../../models/video/tag' |
15 | import { VideoModel } from '../../models/video/video' | 17 | import { VideoModel } from '../../models/video/video' |
@@ -17,6 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel' | |||
17 | import { VideoFileModel } from '../../models/video/video-file' | 19 | import { VideoFileModel } from '../../models/video/video-file' |
18 | import { VideoShareModel } from '../../models/video/video-share' | 20 | import { VideoShareModel } from '../../models/video/video-share' |
19 | import { getOrCreateActorAndServerAndModel } from './actor' | 21 | import { getOrCreateActorAndServerAndModel } from './actor' |
22 | import { addVideoComments } from './video-comments' | ||
20 | 23 | ||
21 | function fetchRemoteVideoPreview (video: VideoModel, reject: Function) { | 24 | function fetchRemoteVideoPreview (video: VideoModel, reject: Function) { |
22 | const host = video.VideoChannel.Account.Actor.Server.host | 25 | const host = video.VideoChannel.Account.Actor.Server.host |
@@ -210,9 +213,57 @@ async function getOrCreateAccountAndVideoAndChannel (videoObject: VideoTorrentOb | |||
210 | 213 | ||
211 | const video = await retryTransactionWrapper(getOrCreateVideo, options) | 214 | const video = await retryTransactionWrapper(getOrCreateVideo, options) |
212 | 215 | ||
216 | // Process outside the transaction because we could fetch remote data | ||
217 | if (videoObject.likes && Array.isArray(videoObject.likes.orderedItems)) { | ||
218 | logger.info('Adding likes of video %s.', video.uuid) | ||
219 | await createRates(videoObject.likes.orderedItems, video, 'like') | ||
220 | } | ||
221 | |||
222 | if (videoObject.dislikes && Array.isArray(videoObject.dislikes.orderedItems)) { | ||
223 | logger.info('Adding dislikes of video %s.', video.uuid) | ||
224 | await createRates(videoObject.dislikes.orderedItems, video, 'dislike') | ||
225 | } | ||
226 | |||
227 | if (videoObject.shares && Array.isArray(videoObject.shares.orderedItems)) { | ||
228 | logger.info('Adding shares of video %s.', video.uuid) | ||
229 | await addVideoShares(video, videoObject.shares.orderedItems) | ||
230 | } | ||
231 | |||
232 | if (videoObject.comments && Array.isArray(videoObject.comments.orderedItems)) { | ||
233 | logger.info('Adding comments of video %s.', video.uuid) | ||
234 | await addVideoComments(video, videoObject.comments.orderedItems) | ||
235 | } | ||
236 | |||
213 | return { actor, channelActor, video } | 237 | return { actor, channelActor, video } |
214 | } | 238 | } |
215 | 239 | ||
240 | async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) { | ||
241 | let rateCounts = 0 | ||
242 | const tasks: Bluebird<number>[] = [] | ||
243 | |||
244 | for (const actorUrl of actorUrls) { | ||
245 | const actor = await getOrCreateActorAndServerAndModel(actorUrl) | ||
246 | const p = AccountVideoRateModel | ||
247 | .create({ | ||
248 | videoId: video.id, | ||
249 | accountId: actor.Account.id, | ||
250 | type: rate | ||
251 | }) | ||
252 | .then(() => rateCounts += 1) | ||
253 | |||
254 | tasks.push(p) | ||
255 | } | ||
256 | |||
257 | await Promise.all(tasks) | ||
258 | |||
259 | logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) | ||
260 | |||
261 | // This is "likes" and "dislikes" | ||
262 | await video.increment(rate + 's', { by: rateCounts }) | ||
263 | |||
264 | return | ||
265 | } | ||
266 | |||
216 | async function addVideoShares (instance: VideoModel, shareUrls: string[]) { | 267 | async function addVideoShares (instance: VideoModel, shareUrls: string[]) { |
217 | for (const shareUrl of shareUrls) { | 268 | for (const shareUrl of shareUrls) { |
218 | // Fetch url | 269 | // Fetch url |