diff options
Diffstat (limited to 'server')
103 files changed, 3578 insertions, 914 deletions
diff --git a/server/assets/default-audio-background.jpg b/server/assets/default-audio-background.jpg new file mode 100644 index 000000000..a19173eac --- /dev/null +++ b/server/assets/default-audio-background.jpg | |||
Binary files differ | |||
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index 8d4db1e75..5a1d652f2 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts | |||
@@ -16,7 +16,8 @@ import { | |||
16 | accountNameWithHostGetValidator, | 16 | accountNameWithHostGetValidator, |
17 | accountsSortValidator, | 17 | accountsSortValidator, |
18 | ensureAuthUserOwnsAccountValidator, | 18 | ensureAuthUserOwnsAccountValidator, |
19 | videosSortValidator | 19 | videosSortValidator, |
20 | videoChannelsSortValidator | ||
20 | } from '../../middlewares/validators' | 21 | } from '../../middlewares/validators' |
21 | import { AccountModel } from '../../models/account/account' | 22 | import { AccountModel } from '../../models/account/account' |
22 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | 23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
@@ -56,6 +57,10 @@ accountsRouter.get('/:accountName/videos', | |||
56 | 57 | ||
57 | accountsRouter.get('/:accountName/video-channels', | 58 | accountsRouter.get('/:accountName/video-channels', |
58 | asyncMiddleware(accountNameWithHostGetValidator), | 59 | asyncMiddleware(accountNameWithHostGetValidator), |
60 | paginationValidator, | ||
61 | videoChannelsSortValidator, | ||
62 | setDefaultSort, | ||
63 | setDefaultPagination, | ||
59 | asyncMiddleware(listAccountChannels) | 64 | asyncMiddleware(listAccountChannels) |
60 | ) | 65 | ) |
61 | 66 | ||
@@ -108,7 +113,14 @@ async function listAccounts (req: express.Request, res: express.Response) { | |||
108 | } | 113 | } |
109 | 114 | ||
110 | async function listAccountChannels (req: express.Request, res: express.Response) { | 115 | async function listAccountChannels (req: express.Request, res: express.Response) { |
111 | const resultList = await VideoChannelModel.listByAccount(res.locals.account.id) | 116 | const options = { |
117 | accountId: res.locals.account.id, | ||
118 | start: req.query.start, | ||
119 | count: req.query.count, | ||
120 | sort: req.query.sort | ||
121 | } | ||
122 | |||
123 | const resultList = await VideoChannelModel.listByAccount(options) | ||
112 | 124 | ||
113 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 125 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
114 | } | 126 | } |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 40012c03b..27c416a12 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -51,7 +51,7 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
51 | if (serverCommit === undefined) serverCommit = await getServerCommit() | 51 | if (serverCommit === undefined) serverCommit = await getServerCommit() |
52 | 52 | ||
53 | const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) | 53 | const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) |
54 | .filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true) | 54 | .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true) |
55 | .map(r => parseInt(r, 10)) | 55 | .map(r => parseInt(r, 10)) |
56 | 56 | ||
57 | const json: ServerConfig = { | 57 | const json: ServerConfig = { |
@@ -255,6 +255,7 @@ function customConfig (): CustomConfig { | |||
255 | transcoding: { | 255 | transcoding: { |
256 | enabled: CONFIG.TRANSCODING.ENABLED, | 256 | enabled: CONFIG.TRANSCODING.ENABLED, |
257 | allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, | 257 | allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, |
258 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, | ||
258 | threads: CONFIG.TRANSCODING.THREADS, | 259 | threads: CONFIG.TRANSCODING.THREADS, |
259 | resolutions: { | 260 | resolutions: { |
260 | '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], | 261 | '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 0aafba66e..48a6c63b8 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -46,14 +46,18 @@ import { mySubscriptionsRouter } from './my-subscriptions' | |||
46 | import { CONFIG } from '../../../initializers/config' | 46 | import { CONFIG } from '../../../initializers/config' |
47 | import { sequelizeTypescript } from '../../../initializers/database' | 47 | import { sequelizeTypescript } from '../../../initializers/database' |
48 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 48 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
49 | import { UserRegister } from '../../../../shared/models/users/user-register.model' | ||
49 | 50 | ||
50 | const auditLogger = auditLoggerFactory('users') | 51 | const auditLogger = auditLoggerFactory('users') |
51 | 52 | ||
52 | const loginRateLimiter = new RateLimit({ | 53 | // FIXME: https://github.com/nfriedly/express-rate-limit/issues/138 |
54 | // @ts-ignore | ||
55 | const loginRateLimiter = RateLimit({ | ||
53 | windowMs: RATES_LIMIT.LOGIN.WINDOW_MS, | 56 | windowMs: RATES_LIMIT.LOGIN.WINDOW_MS, |
54 | max: RATES_LIMIT.LOGIN.MAX | 57 | max: RATES_LIMIT.LOGIN.MAX |
55 | }) | 58 | }) |
56 | 59 | ||
60 | // @ts-ignore | ||
57 | const askSendEmailLimiter = new RateLimit({ | 61 | const askSendEmailLimiter = new RateLimit({ |
58 | windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS, | 62 | windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS, |
59 | max: RATES_LIMIT.ASK_SEND_EMAIL.MAX | 63 | max: RATES_LIMIT.ASK_SEND_EMAIL.MAX |
@@ -189,15 +193,14 @@ async function createUser (req: express.Request, res: express.Response) { | |||
189 | user: { | 193 | user: { |
190 | id: user.id, | 194 | id: user.id, |
191 | account: { | 195 | account: { |
192 | id: account.id, | 196 | id: account.id |
193 | uuid: account.Actor.uuid | ||
194 | } | 197 | } |
195 | } | 198 | } |
196 | }).end() | 199 | }).end() |
197 | } | 200 | } |
198 | 201 | ||
199 | async function registerUser (req: express.Request, res: express.Response) { | 202 | async function registerUser (req: express.Request, res: express.Response) { |
200 | const body: UserCreate = req.body | 203 | const body: UserRegister = req.body |
201 | 204 | ||
202 | const userToCreate = new UserModel({ | 205 | const userToCreate = new UserModel({ |
203 | username: body.username, | 206 | username: body.username, |
@@ -211,7 +214,7 @@ async function registerUser (req: express.Request, res: express.Response) { | |||
211 | emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null | 214 | emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null |
212 | }) | 215 | }) |
213 | 216 | ||
214 | const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate) | 217 | const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate, body.channel) |
215 | 218 | ||
216 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) | 219 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) |
217 | logger.info('User %s with its channel and account registered.', body.username) | 220 | logger.info('User %s with its channel and account registered.', body.username) |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 3d6dbfe70..81a03a62b 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -19,7 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel' | |||
19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' | 19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' |
20 | import { sendUpdateActor } from '../../lib/activitypub/send' | 20 | import { sendUpdateActor } from '../../lib/activitypub/send' |
21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' | 21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' |
22 | import { createVideoChannel } from '../../lib/video-channel' | 22 | import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel' |
23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' | 23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
24 | import { setAsyncActorKeys } from '../../lib/activitypub' | 24 | import { setAsyncActorKeys } from '../../lib/activitypub' |
25 | import { AccountModel } from '../../models/account/account' | 25 | import { AccountModel } from '../../models/account/account' |
@@ -143,15 +143,14 @@ async function addVideoChannel (req: express.Request, res: express.Response) { | |||
143 | }) | 143 | }) |
144 | 144 | ||
145 | setAsyncActorKeys(videoChannelCreated.Actor) | 145 | setAsyncActorKeys(videoChannelCreated.Actor) |
146 | .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err })) | 146 | .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.url, { err })) |
147 | 147 | ||
148 | auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())) | 148 | auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())) |
149 | logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) | 149 | logger.info('Video channel %s created.', videoChannelCreated.Actor.url) |
150 | 150 | ||
151 | return res.json({ | 151 | return res.json({ |
152 | videoChannel: { | 152 | videoChannel: { |
153 | id: videoChannelCreated.id, | 153 | id: videoChannelCreated.id |
154 | uuid: videoChannelCreated.Actor.uuid | ||
155 | } | 154 | } |
156 | }).end() | 155 | }).end() |
157 | } | 156 | } |
@@ -161,6 +160,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
161 | const videoChannelFieldsSave = videoChannelInstance.toJSON() | 160 | const videoChannelFieldsSave = videoChannelInstance.toJSON() |
162 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) | 161 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) |
163 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate | 162 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate |
163 | let doBulkVideoUpdate = false | ||
164 | 164 | ||
165 | try { | 165 | try { |
166 | await sequelizeTypescript.transaction(async t => { | 166 | await sequelizeTypescript.transaction(async t => { |
@@ -168,9 +168,18 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
168 | transaction: t | 168 | transaction: t |
169 | } | 169 | } |
170 | 170 | ||
171 | if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.displayName) | 171 | if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.name = videoChannelInfoToUpdate.displayName |
172 | if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) | 172 | if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.description = videoChannelInfoToUpdate.description |
173 | if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support) | 173 | |
174 | if (videoChannelInfoToUpdate.support !== undefined) { | ||
175 | const oldSupportField = videoChannelInstance.support | ||
176 | videoChannelInstance.support = videoChannelInfoToUpdate.support | ||
177 | |||
178 | if (videoChannelInfoToUpdate.bulkVideosSupportUpdate === true && oldSupportField !== videoChannelInfoToUpdate.support) { | ||
179 | doBulkVideoUpdate = true | ||
180 | await VideoModel.bulkUpdateSupportField(videoChannelInstance, t) | ||
181 | } | ||
182 | } | ||
174 | 183 | ||
175 | const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) | 184 | const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) |
176 | await sendUpdateActor(videoChannelInstanceUpdated, t) | 185 | await sendUpdateActor(videoChannelInstanceUpdated, t) |
@@ -180,7 +189,8 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
180 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), | 189 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), |
181 | oldVideoChannelAuditKeys | 190 | oldVideoChannelAuditKeys |
182 | ) | 191 | ) |
183 | logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) | 192 | |
193 | logger.info('Video channel %s updated.', videoChannelInstance.Actor.url) | ||
184 | }) | 194 | }) |
185 | } catch (err) { | 195 | } catch (err) { |
186 | logger.debug('Cannot update the video channel.', { err }) | 196 | logger.debug('Cannot update the video channel.', { err }) |
@@ -193,7 +203,12 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
193 | throw err | 203 | throw err |
194 | } | 204 | } |
195 | 205 | ||
196 | return res.type('json').status(204).end() | 206 | res.type('json').status(204).end() |
207 | |||
208 | // Don't process in a transaction, and after the response because it could be long | ||
209 | if (doBulkVideoUpdate) { | ||
210 | await federateAllVideosOfChannel(videoChannelInstance) | ||
211 | } | ||
197 | } | 212 | } |
198 | 213 | ||
199 | async function removeVideoChannel (req: express.Request, res: express.Response) { | 214 | async function removeVideoChannel (req: express.Request, res: express.Response) { |
@@ -205,7 +220,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response) | |||
205 | await videoChannelInstance.destroy({ transaction: t }) | 220 | await videoChannelInstance.destroy({ transaction: t }) |
206 | 221 | ||
207 | auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())) | 222 | auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())) |
208 | logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) | 223 | logger.info('Video channel %s deleted.', videoChannelInstance.Actor.url) |
209 | }) | 224 | }) |
210 | 225 | ||
211 | return res.type('json').status(204).end() | 226 | return res.type('json').status(204).end() |
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index a17136401..62490e63b 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts | |||
@@ -203,7 +203,9 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response) | |||
203 | const videoPlaylistInstance = res.locals.videoPlaylist | 203 | const videoPlaylistInstance = res.locals.videoPlaylist |
204 | const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON() | 204 | const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON() |
205 | const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate | 205 | const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate |
206 | |||
206 | const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE | 207 | const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE |
208 | const wasNotPrivatePlaylist = videoPlaylistInstance.privacy !== VideoPlaylistPrivacy.PRIVATE | ||
207 | 209 | ||
208 | const thumbnailField = req.files['thumbnailfile'] | 210 | const thumbnailField = req.files['thumbnailfile'] |
209 | const thumbnailModel = thumbnailField | 211 | const thumbnailModel = thumbnailField |
@@ -232,6 +234,10 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response) | |||
232 | 234 | ||
233 | if (videoPlaylistInfoToUpdate.privacy !== undefined) { | 235 | if (videoPlaylistInfoToUpdate.privacy !== undefined) { |
234 | videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10) | 236 | videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10) |
237 | |||
238 | if (wasNotPrivatePlaylist === true && videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE) { | ||
239 | await sendDeleteVideoPlaylist(videoPlaylistInstance, t) | ||
240 | } | ||
235 | } | 241 | } |
236 | 242 | ||
237 | const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions) | 243 | const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions) |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 1a18a8ae8..5ebd8fbc4 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -6,7 +6,14 @@ import { logger } from '../../../helpers/logger' | |||
6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
7 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 7 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' |
8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' | 8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' |
9 | import { MIMETYPES, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers/constants' | 9 | import { |
10 | DEFAULT_AUDIO_RESOLUTION, | ||
11 | MIMETYPES, | ||
12 | VIDEO_CATEGORIES, | ||
13 | VIDEO_LANGUAGES, | ||
14 | VIDEO_LICENCES, | ||
15 | VIDEO_PRIVACIES | ||
16 | } from '../../../initializers/constants' | ||
10 | import { | 17 | import { |
11 | changeVideoChannelShare, | 18 | changeVideoChannelShare, |
12 | federateVideoIfNeeded, | 19 | federateVideoIfNeeded, |
@@ -54,6 +61,7 @@ import { CONFIG } from '../../../initializers/config' | |||
54 | import { sequelizeTypescript } from '../../../initializers/database' | 61 | import { sequelizeTypescript } from '../../../initializers/database' |
55 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' | 62 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' |
56 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | 63 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' |
64 | import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding' | ||
57 | 65 | ||
58 | const auditLogger = auditLoggerFactory('videos') | 66 | const auditLogger = auditLoggerFactory('videos') |
59 | const videosRouter = express.Router() | 67 | const videosRouter = express.Router() |
@@ -191,17 +199,17 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
191 | const video = new VideoModel(videoData) | 199 | const video = new VideoModel(videoData) |
192 | video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object | 200 | video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object |
193 | 201 | ||
194 | // Build the file object | 202 | const videoFile = new VideoFileModel({ |
195 | const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path) | ||
196 | const fps = await getVideoFileFPS(videoPhysicalFile.path) | ||
197 | |||
198 | const videoFileData = { | ||
199 | extname: extname(videoPhysicalFile.filename), | 203 | extname: extname(videoPhysicalFile.filename), |
200 | resolution: videoFileResolution, | 204 | size: videoPhysicalFile.size |
201 | size: videoPhysicalFile.size, | 205 | }) |
202 | fps | 206 | |
207 | if (videoFile.isAudio()) { | ||
208 | videoFile.resolution = DEFAULT_AUDIO_RESOLUTION | ||
209 | } else { | ||
210 | videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path) | ||
211 | videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).videoFileResolution | ||
203 | } | 212 | } |
204 | const videoFile = new VideoFileModel(videoFileData) | ||
205 | 213 | ||
206 | // Move physical file | 214 | // Move physical file |
207 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR | 215 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR |
@@ -279,9 +287,21 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
279 | 287 | ||
280 | if (video.state === VideoState.TO_TRANSCODE) { | 288 | if (video.state === VideoState.TO_TRANSCODE) { |
281 | // Put uuid because we don't have id auto incremented for now | 289 | // Put uuid because we don't have id auto incremented for now |
282 | const dataInput = { | 290 | let dataInput: VideoTranscodingPayload |
283 | videoUUID: videoCreated.uuid, | 291 | |
284 | isNewVideo: true | 292 | if (videoFile.isAudio()) { |
293 | dataInput = { | ||
294 | type: 'merge-audio' as 'merge-audio', | ||
295 | resolution: DEFAULT_AUDIO_RESOLUTION, | ||
296 | videoUUID: videoCreated.uuid, | ||
297 | isNewVideo: true | ||
298 | } | ||
299 | } else { | ||
300 | dataInput = { | ||
301 | type: 'optimize' as 'optimize', | ||
302 | videoUUID: videoCreated.uuid, | ||
303 | isNewVideo: true | ||
304 | } | ||
285 | } | 305 | } |
286 | 306 | ||
287 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 307 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) |
@@ -300,7 +320,9 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
300 | const videoFieldsSave = videoInstance.toJSON() | 320 | const videoFieldsSave = videoInstance.toJSON() |
301 | const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) | 321 | const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) |
302 | const videoInfoToUpdate: VideoUpdate = req.body | 322 | const videoInfoToUpdate: VideoUpdate = req.body |
323 | |||
303 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE | 324 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE |
325 | const wasNotPrivateVideo = videoInstance.privacy !== VideoPrivacy.PRIVATE | ||
304 | const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED | 326 | const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED |
305 | 327 | ||
306 | // Process thumbnail or create it from the video | 328 | // Process thumbnail or create it from the video |
@@ -336,9 +358,15 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
336 | const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) | 358 | const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) |
337 | videoInstance.privacy = newPrivacy | 359 | videoInstance.privacy = newPrivacy |
338 | 360 | ||
361 | // The video was private, and is not anymore -> publish it | ||
339 | if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) { | 362 | if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) { |
340 | videoInstance.publishedAt = new Date() | 363 | videoInstance.publishedAt = new Date() |
341 | } | 364 | } |
365 | |||
366 | // The video was not private, but now it is -> we need to unfederate it | ||
367 | if (wasNotPrivateVideo === true && newPrivacy === VideoPrivacy.PRIVATE) { | ||
368 | await VideoModel.sendDelete(videoInstance, { transaction: t }) | ||
369 | } | ||
342 | } | 370 | } |
343 | 371 | ||
344 | const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) | 372 | const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) |
diff --git a/server/controllers/static.ts b/server/controllers/static.ts index fb2e7742a..a6b462443 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts | |||
@@ -194,7 +194,7 @@ async function getVideoCaption (req: express.Request, res: express.Response) { | |||
194 | return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE }) | 194 | return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE }) |
195 | } | 195 | } |
196 | 196 | ||
197 | async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) { | 197 | async function generateNodeinfo (req: express.Request, res: express.Response) { |
198 | const { totalVideos } = await VideoModel.getStats() | 198 | const { totalVideos } = await VideoModel.getStats() |
199 | const { totalLocalVideoComments } = await VideoCommentModel.getStats() | 199 | const { totalLocalVideoComments } = await VideoCommentModel.getStats() |
200 | const { totalUsers } = await UserModel.getStats() | 200 | const { totalUsers } = await UserModel.getStats() |
diff --git a/server/helpers/custom-validators/accounts.ts b/server/helpers/custom-validators/accounts.ts index 146c7708e..31a2de5ca 100644 --- a/server/helpers/custom-validators/accounts.ts +++ b/server/helpers/custom-validators/accounts.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { Response } from 'express' | 2 | import { Response } from 'express' |
3 | import 'express-validator' | 3 | import 'express-validator' |
4 | import * as validator from 'validator' | ||
5 | import { AccountModel } from '../../models/account/account' | 4 | import { AccountModel } from '../../models/account/account' |
6 | import { isUserDescriptionValid, isUserUsernameValid } from './users' | 5 | import { isUserDescriptionValid, isUserUsernameValid } from './users' |
7 | import { exists } from './misc' | 6 | import { exists } from './misc' |
@@ -18,14 +17,8 @@ function isAccountDescriptionValid (value: string) { | |||
18 | return isUserDescriptionValid(value) | 17 | return isUserDescriptionValid(value) |
19 | } | 18 | } |
20 | 19 | ||
21 | function doesAccountIdExist (id: number | string, res: Response, sendNotFound = true) { | 20 | function doesAccountIdExist (id: number, res: Response, sendNotFound = true) { |
22 | let promise: Bluebird<AccountModel> | 21 | const promise = AccountModel.load(id) |
23 | |||
24 | if (validator.isInt('' + id)) { | ||
25 | promise = AccountModel.load(+id) | ||
26 | } else { // UUID | ||
27 | promise = AccountModel.loadByUUID('' + id) | ||
28 | } | ||
29 | 22 | ||
30 | return doesAccountExist(promise, res, sendNotFound) | 23 | return doesAccountExist(promise, res, sendNotFound) |
31 | } | 24 | } |
diff --git a/server/helpers/custom-validators/activitypub/video-comments.ts b/server/helpers/custom-validators/activitypub/video-comments.ts index 26c8c4cc6..e04c5388f 100644 --- a/server/helpers/custom-validators/activitypub/video-comments.ts +++ b/server/helpers/custom-validators/activitypub/video-comments.ts | |||
@@ -36,7 +36,8 @@ function normalizeComment (comment: any) { | |||
36 | if (!comment) return | 36 | if (!comment) return |
37 | 37 | ||
38 | if (typeof comment.url !== 'string') { | 38 | if (typeof comment.url !== 'string') { |
39 | comment.url = comment.url.href || comment.url.url | 39 | if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url |
40 | else comment.url = comment.id | ||
40 | } | 41 | } |
41 | 42 | ||
42 | return | 43 | return |
diff --git a/server/helpers/custom-validators/video-channels.ts b/server/helpers/custom-validators/video-channels.ts index fd56b9a70..f818ce8f1 100644 --- a/server/helpers/custom-validators/video-channels.ts +++ b/server/helpers/custom-validators/video-channels.ts | |||
@@ -26,13 +26,8 @@ async function doesLocalVideoChannelNameExist (name: string, res: express.Respon | |||
26 | return processVideoChannelExist(videoChannel, res) | 26 | return processVideoChannelExist(videoChannel, res) |
27 | } | 27 | } |
28 | 28 | ||
29 | async function doesVideoChannelIdExist (id: number | string, res: express.Response) { | 29 | async function doesVideoChannelIdExist (id: number, res: express.Response) { |
30 | let videoChannel: VideoChannelModel | 30 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) |
31 | if (validator.isInt('' + id)) { | ||
32 | videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) | ||
33 | } else { // UUID | ||
34 | videoChannel = await VideoChannelModel.loadByUUIDAndPopulateAccount('' + id) | ||
35 | } | ||
36 | 31 | ||
37 | return processVideoChannelExist(videoChannel, res) | 32 | return processVideoChannelExist(videoChannel, res) |
38 | } | 33 | } |
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index e0a1d56a5..00f3f198b 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -74,7 +74,18 @@ function createReqFiles ( | |||
74 | }, | 74 | }, |
75 | 75 | ||
76 | filename: async (req, file, cb) => { | 76 | filename: async (req, file, cb) => { |
77 | const extension = mimeTypes[ file.mimetype ] || extname(file.originalname) | 77 | let extension: string |
78 | const fileExtension = extname(file.originalname) | ||
79 | const extensionFromMimetype = mimeTypes[ file.mimetype ] | ||
80 | |||
81 | // Take the file extension if we don't understand the mime type | ||
82 | // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file | ||
83 | if (fileExtension === '.ogg' || fileExtension === '.ogv' || !extensionFromMimetype) { | ||
84 | extension = fileExtension | ||
85 | } else { | ||
86 | extension = extensionFromMimetype | ||
87 | } | ||
88 | |||
78 | let randomString = '' | 89 | let randomString = '' |
79 | 90 | ||
80 | try { | 91 | try { |
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 76b744de8..8041e7b3b 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as ffmpeg from 'fluent-ffmpeg' | 1 | import * as ffmpeg from 'fluent-ffmpeg' |
2 | import { dirname, join } from 'path' | 2 | import { dirname, join } from 'path' |
3 | import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' | 3 | import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos' |
4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' | 4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' |
5 | import { processImage } from './image-utils' | 5 | import { processImage } from './image-utils' |
6 | import { logger } from './logger' | 6 | import { logger } from './logger' |
@@ -18,7 +18,8 @@ function computeResolutionsToTranscode (videoFileHeight: number) { | |||
18 | VideoResolution.H_360P, | 18 | VideoResolution.H_360P, |
19 | VideoResolution.H_720P, | 19 | VideoResolution.H_720P, |
20 | VideoResolution.H_240P, | 20 | VideoResolution.H_240P, |
21 | VideoResolution.H_1080P | 21 | VideoResolution.H_1080P, |
22 | VideoResolution.H_4K | ||
22 | ] | 23 | ] |
23 | 24 | ||
24 | for (const resolution of resolutions) { | 25 | for (const resolution of resolutions) { |
@@ -31,7 +32,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) { | |||
31 | } | 32 | } |
32 | 33 | ||
33 | async function getVideoFileSize (path: string) { | 34 | async function getVideoFileSize (path: string) { |
34 | const videoStream = await getVideoFileStream(path) | 35 | const videoStream = await getVideoStreamFromFile(path) |
35 | 36 | ||
36 | return { | 37 | return { |
37 | width: videoStream.width, | 38 | width: videoStream.width, |
@@ -49,7 +50,7 @@ async function getVideoFileResolution (path: string) { | |||
49 | } | 50 | } |
50 | 51 | ||
51 | async function getVideoFileFPS (path: string) { | 52 | async function getVideoFileFPS (path: string) { |
52 | const videoStream = await getVideoFileStream(path) | 53 | const videoStream = await getVideoStreamFromFile(path) |
53 | 54 | ||
54 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { | 55 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { |
55 | const valuesText: string = videoStream[key] | 56 | const valuesText: string = videoStream[key] |
@@ -117,25 +118,50 @@ async function generateImageFromVideoFile (fromPath: string, folder: string, ima | |||
117 | } | 118 | } |
118 | } | 119 | } |
119 | 120 | ||
120 | type TranscodeOptions = { | 121 | type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' |
122 | |||
123 | interface BaseTranscodeOptions { | ||
124 | type: TranscodeOptionsType | ||
121 | inputPath: string | 125 | inputPath: string |
122 | outputPath: string | 126 | outputPath: string |
123 | resolution: VideoResolution | 127 | resolution: VideoResolution |
124 | isPortraitMode?: boolean | 128 | isPortraitMode?: boolean |
129 | } | ||
125 | 130 | ||
126 | hlsPlaylist?: { | 131 | interface HLSTranscodeOptions extends BaseTranscodeOptions { |
132 | type: 'hls' | ||
133 | hlsPlaylist: { | ||
127 | videoFilename: string | 134 | videoFilename: string |
128 | } | 135 | } |
129 | } | 136 | } |
130 | 137 | ||
138 | interface QuickTranscodeOptions extends BaseTranscodeOptions { | ||
139 | type: 'quick-transcode' | ||
140 | } | ||
141 | |||
142 | interface VideoTranscodeOptions extends BaseTranscodeOptions { | ||
143 | type: 'video' | ||
144 | } | ||
145 | |||
146 | interface MergeAudioTranscodeOptions extends BaseTranscodeOptions { | ||
147 | type: 'merge-audio' | ||
148 | audioPath: string | ||
149 | } | ||
150 | |||
151 | type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | QuickTranscodeOptions | ||
152 | |||
131 | function transcode (options: TranscodeOptions) { | 153 | function transcode (options: TranscodeOptions) { |
132 | return new Promise<void>(async (res, rej) => { | 154 | return new Promise<void>(async (res, rej) => { |
133 | try { | 155 | try { |
134 | let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) | 156 | let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) |
135 | .output(options.outputPath) | 157 | .output(options.outputPath) |
136 | 158 | ||
137 | if (options.hlsPlaylist) { | 159 | if (options.type === 'quick-transcode') { |
160 | command = await buildQuickTranscodeCommand(command) | ||
161 | } else if (options.type === 'hls') { | ||
138 | command = await buildHLSCommand(command, options) | 162 | command = await buildHLSCommand(command, options) |
163 | } else if (options.type === 'merge-audio') { | ||
164 | command = await buildAudioMergeCommand(command, options) | ||
139 | } else { | 165 | } else { |
140 | command = await buildx264Command(command, options) | 166 | command = await buildx264Command(command, options) |
141 | } | 167 | } |
@@ -151,7 +177,7 @@ function transcode (options: TranscodeOptions) { | |||
151 | return rej(err) | 177 | return rej(err) |
152 | }) | 178 | }) |
153 | .on('end', () => { | 179 | .on('end', () => { |
154 | return onTranscodingSuccess(options) | 180 | return fixHLSPlaylistIfNeeded(options) |
155 | .then(() => res()) | 181 | .then(() => res()) |
156 | .catch(err => rej(err)) | 182 | .catch(err => rej(err)) |
157 | }) | 183 | }) |
@@ -162,6 +188,30 @@ function transcode (options: TranscodeOptions) { | |||
162 | }) | 188 | }) |
163 | } | 189 | } |
164 | 190 | ||
191 | async function canDoQuickTranscode (path: string): Promise<boolean> { | ||
192 | // NOTE: This could be optimized by running ffprobe only once (but it runs fast anyway) | ||
193 | const videoStream = await getVideoStreamFromFile(path) | ||
194 | const parsedAudio = await audio.get(path) | ||
195 | const fps = await getVideoFileFPS(path) | ||
196 | const bitRate = await getVideoFileBitrate(path) | ||
197 | const resolution = await getVideoFileResolution(path) | ||
198 | |||
199 | // check video params | ||
200 | if (videoStream[ 'codec_name' ] !== 'h264') return false | ||
201 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false | ||
202 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false | ||
203 | |||
204 | // check audio params (if audio stream exists) | ||
205 | if (parsedAudio.audioStream) { | ||
206 | if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false | ||
207 | |||
208 | const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ]) | ||
209 | if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false | ||
210 | } | ||
211 | |||
212 | return true | ||
213 | } | ||
214 | |||
165 | // --------------------------------------------------------------------------- | 215 | // --------------------------------------------------------------------------- |
166 | 216 | ||
167 | export { | 217 | export { |
@@ -169,16 +219,19 @@ export { | |||
169 | getVideoFileResolution, | 219 | getVideoFileResolution, |
170 | getDurationFromVideoFile, | 220 | getDurationFromVideoFile, |
171 | generateImageFromVideoFile, | 221 | generateImageFromVideoFile, |
222 | TranscodeOptions, | ||
223 | TranscodeOptionsType, | ||
172 | transcode, | 224 | transcode, |
173 | getVideoFileFPS, | 225 | getVideoFileFPS, |
174 | computeResolutionsToTranscode, | 226 | computeResolutionsToTranscode, |
175 | audio, | 227 | audio, |
176 | getVideoFileBitrate | 228 | getVideoFileBitrate, |
229 | canDoQuickTranscode | ||
177 | } | 230 | } |
178 | 231 | ||
179 | // --------------------------------------------------------------------------- | 232 | // --------------------------------------------------------------------------- |
180 | 233 | ||
181 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 234 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: VideoTranscodeOptions) { |
182 | let fps = await getVideoFileFPS(options.inputPath) | 235 | let fps = await getVideoFileFPS(options.inputPath) |
183 | // On small/medium resolutions, limit FPS | 236 | // On small/medium resolutions, limit FPS |
184 | if ( | 237 | if ( |
@@ -189,7 +242,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco | |||
189 | fps = VIDEO_TRANSCODING_FPS.AVERAGE | 242 | fps = VIDEO_TRANSCODING_FPS.AVERAGE |
190 | } | 243 | } |
191 | 244 | ||
192 | command = await presetH264(command, options.resolution, fps) | 245 | command = await presetH264(command, options.inputPath, options.resolution, fps) |
193 | 246 | ||
194 | if (options.resolution !== undefined) { | 247 | if (options.resolution !== undefined) { |
195 | // '?x720' or '720x?' for example | 248 | // '?x720' or '720x?' for example |
@@ -208,7 +261,29 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco | |||
208 | return command | 261 | return command |
209 | } | 262 | } |
210 | 263 | ||
211 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 264 | async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: MergeAudioTranscodeOptions) { |
265 | command = command.loop(undefined) | ||
266 | |||
267 | command = await presetH264VeryFast(command, options.audioPath, options.resolution) | ||
268 | |||
269 | command = command.input(options.audioPath) | ||
270 | .videoFilter('scale=trunc(iw/2)*2:trunc(ih/2)*2') // Avoid "height not divisible by 2" error | ||
271 | .outputOption('-tune stillimage') | ||
272 | .outputOption('-shortest') | ||
273 | |||
274 | return command | ||
275 | } | ||
276 | |||
277 | async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { | ||
278 | command = await presetCopy(command) | ||
279 | |||
280 | command = command.outputOption('-map_metadata -1') // strip all metadata | ||
281 | .outputOption('-movflags faststart') | ||
282 | |||
283 | return command | ||
284 | } | ||
285 | |||
286 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { | ||
212 | const videoPath = getHLSVideoPath(options) | 287 | const videoPath = getHLSVideoPath(options) |
213 | 288 | ||
214 | command = await presetCopy(command) | 289 | command = await presetCopy(command) |
@@ -224,26 +299,26 @@ async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: Transcod | |||
224 | return command | 299 | return command |
225 | } | 300 | } |
226 | 301 | ||
227 | function getHLSVideoPath (options: TranscodeOptions) { | 302 | function getHLSVideoPath (options: HLSTranscodeOptions) { |
228 | return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` | 303 | return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` |
229 | } | 304 | } |
230 | 305 | ||
231 | async function onTranscodingSuccess (options: TranscodeOptions) { | 306 | async function fixHLSPlaylistIfNeeded (options: TranscodeOptions) { |
232 | if (!options.hlsPlaylist) return | 307 | if (options.type !== 'hls') return |
233 | 308 | ||
234 | // Fix wrong mapping with some ffmpeg versions | ||
235 | const fileContent = await readFile(options.outputPath) | 309 | const fileContent = await readFile(options.outputPath) |
236 | 310 | ||
237 | const videoFileName = options.hlsPlaylist.videoFilename | 311 | const videoFileName = options.hlsPlaylist.videoFilename |
238 | const videoFilePath = getHLSVideoPath(options) | 312 | const videoFilePath = getHLSVideoPath(options) |
239 | 313 | ||
314 | // Fix wrong mapping with some ffmpeg versions | ||
240 | const newContent = fileContent.toString() | 315 | const newContent = fileContent.toString() |
241 | .replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`) | 316 | .replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`) |
242 | 317 | ||
243 | await writeFile(options.outputPath, newContent) | 318 | await writeFile(options.outputPath, newContent) |
244 | } | 319 | } |
245 | 320 | ||
246 | function getVideoFileStream (path: string) { | 321 | function getVideoStreamFromFile (path: string) { |
247 | return new Promise<any>((res, rej) => { | 322 | return new Promise<any>((res, rej) => { |
248 | ffmpeg.ffprobe(path, (err, metadata) => { | 323 | ffmpeg.ffprobe(path, (err, metadata) => { |
249 | if (err) return rej(err) | 324 | if (err) return rej(err) |
@@ -263,44 +338,27 @@ function getVideoFileStream (path: string) { | |||
263 | * and quality. Superfast and ultrafast will give you better | 338 | * and quality. Superfast and ultrafast will give you better |
264 | * performance, but then quality is noticeably worse. | 339 | * performance, but then quality is noticeably worse. |
265 | */ | 340 | */ |
266 | async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { | 341 | async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) { |
267 | let localCommand = await presetH264(command, resolution, fps) | 342 | let localCommand = await presetH264(command, input, resolution, fps) |
343 | |||
268 | localCommand = localCommand.outputOption('-preset:v veryfast') | 344 | localCommand = localCommand.outputOption('-preset:v veryfast') |
269 | .outputOption([ '--aq-mode=2', '--aq-strength=1.3' ]) | 345 | |
270 | /* | 346 | /* |
271 | MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html | 347 | MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html |
272 | Our target situation is closer to a livestream than a stream, | 348 | Our target situation is closer to a livestream than a stream, |
273 | since we want to reduce as much a possible the encoding burden, | 349 | since we want to reduce as much a possible the encoding burden, |
274 | altough not to the point of a livestream where there is a hard | 350 | although not to the point of a livestream where there is a hard |
275 | constraint on the frames per second to be encoded. | 351 | constraint on the frames per second to be encoded. |
276 | |||
277 | why '--aq-mode=2 --aq-strength=1.3' instead of '-profile:v main'? | ||
278 | Make up for most of the loss of grain and macroblocking | ||
279 | with less computing power. | ||
280 | */ | 352 | */ |
281 | 353 | ||
282 | return localCommand | 354 | return localCommand |
283 | } | 355 | } |
284 | 356 | ||
285 | /** | 357 | /** |
286 | * A preset optimised for a stillimage audio video | ||
287 | */ | ||
288 | async function presetStillImageWithAudio ( | ||
289 | command: ffmpeg.FfmpegCommand, | ||
290 | resolution: VideoResolution, | ||
291 | fps: number | ||
292 | ): Promise<ffmpeg.FfmpegCommand> { | ||
293 | let localCommand = await presetH264VeryFast(command, resolution, fps) | ||
294 | localCommand = localCommand.outputOption('-tune stillimage') | ||
295 | |||
296 | return localCommand | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * A toolbox to play with audio | 358 | * A toolbox to play with audio |
301 | */ | 359 | */ |
302 | namespace audio { | 360 | namespace audio { |
303 | export const get = (option: ffmpeg.FfmpegCommand | string) => { | 361 | export const get = (option: string) => { |
304 | // without position, ffprobe considers the last input only | 362 | // without position, ffprobe considers the last input only |
305 | // we make it consider the first input only | 363 | // we make it consider the first input only |
306 | // if you pass a file path to pos, then ffprobe acts on that file directly | 364 | // if you pass a file path to pos, then ffprobe acts on that file directly |
@@ -322,11 +380,7 @@ namespace audio { | |||
322 | return res({ absolutePath: data.format.filename }) | 380 | return res({ absolutePath: data.format.filename }) |
323 | } | 381 | } |
324 | 382 | ||
325 | if (typeof option === 'string') { | 383 | return ffmpeg.ffprobe(option, parseFfprobe) |
326 | return ffmpeg.ffprobe(option, parseFfprobe) | ||
327 | } | ||
328 | |||
329 | return option.ffprobe(parseFfprobe) | ||
330 | }) | 384 | }) |
331 | } | 385 | } |
332 | 386 | ||
@@ -368,7 +422,7 @@ namespace audio { | |||
368 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel | 422 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel |
369 | * See https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_vbr | 423 | * See https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_vbr |
370 | */ | 424 | */ |
371 | async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { | 425 | async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) { |
372 | let localCommand = command | 426 | let localCommand = command |
373 | .format('mp4') | 427 | .format('mp4') |
374 | .videoCodec('libx264') | 428 | .videoCodec('libx264') |
@@ -379,7 +433,7 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol | |||
379 | .outputOption('-map_metadata -1') // strip all metadata | 433 | .outputOption('-map_metadata -1') // strip all metadata |
380 | .outputOption('-movflags faststart') | 434 | .outputOption('-movflags faststart') |
381 | 435 | ||
382 | const parsedAudio = await audio.get(localCommand) | 436 | const parsedAudio = await audio.get(input) |
383 | 437 | ||
384 | if (!parsedAudio.audioStream) { | 438 | if (!parsedAudio.audioStream) { |
385 | localCommand = localCommand.noAudio() | 439 | localCommand = localCommand.noAudio() |
@@ -388,28 +442,30 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol | |||
388 | .audioCodec('libfdk_aac') | 442 | .audioCodec('libfdk_aac') |
389 | .audioQuality(5) | 443 | .audioQuality(5) |
390 | } else { | 444 | } else { |
391 | // we try to reduce the ceiling bitrate by making rough correspondances of bitrates | 445 | // we try to reduce the ceiling bitrate by making rough matches of bitrates |
392 | // of course this is far from perfect, but it might save some space in the end | 446 | // of course this is far from perfect, but it might save some space in the end |
447 | localCommand = localCommand.audioCodec('aac') | ||
448 | |||
393 | const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] | 449 | const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] |
394 | let bitrate: number | ||
395 | if (audio.bitrate[ audioCodecName ]) { | ||
396 | localCommand = localCommand.audioCodec('aac') | ||
397 | 450 | ||
398 | bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) | 451 | if (audio.bitrate[ audioCodecName ]) { |
452 | const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) | ||
399 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) | 453 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) |
400 | } | 454 | } |
401 | } | 455 | } |
402 | 456 | ||
403 | // Constrained Encoding (VBV) | 457 | if (fps) { |
404 | // https://slhck.info/video/2017/03/01/rate-control.html | 458 | // Constrained Encoding (VBV) |
405 | // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate | 459 | // https://slhck.info/video/2017/03/01/rate-control.html |
406 | const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS) | 460 | // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate |
407 | localCommand = localCommand.outputOptions([`-maxrate ${ targetBitrate }`, `-bufsize ${ targetBitrate * 2 }`]) | 461 | const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS) |
408 | 462 | localCommand = localCommand.outputOptions([ `-maxrate ${targetBitrate}`, `-bufsize ${targetBitrate * 2}` ]) | |
409 | // Keyframe interval of 2 seconds for faster seeking and resolution switching. | 463 | |
410 | // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html | 464 | // Keyframe interval of 2 seconds for faster seeking and resolution switching. |
411 | // https://superuser.com/a/908325 | 465 | // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html |
412 | localCommand = localCommand.outputOption(`-g ${ fps * 2 }`) | 466 | // https://superuser.com/a/908325 |
467 | localCommand = localCommand.outputOption(`-g ${fps * 2}`) | ||
468 | } | ||
413 | 469 | ||
414 | return localCommand | 470 | return localCommand |
415 | } | 471 | } |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 4f77e144d..2be300a57 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -44,6 +44,14 @@ const CONFIG = { | |||
44 | CA_FILE: config.get<string>('smtp.ca_file'), | 44 | CA_FILE: config.get<string>('smtp.ca_file'), |
45 | FROM_ADDRESS: config.get<string>('smtp.from_address') | 45 | FROM_ADDRESS: config.get<string>('smtp.from_address') |
46 | }, | 46 | }, |
47 | EMAIL: { | ||
48 | BODY: { | ||
49 | SIGNATURE: config.get<string>('email.body.signature') | ||
50 | }, | ||
51 | OBJECT: { | ||
52 | PREFIX: config.get<string>('email.object.prefix') + ' ' | ||
53 | } | ||
54 | }, | ||
47 | STORAGE: { | 55 | STORAGE: { |
48 | TMP_DIR: buildPath(config.get<string>('storage.tmp')), | 56 | TMP_DIR: buildPath(config.get<string>('storage.tmp')), |
49 | AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), | 57 | AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), |
@@ -140,6 +148,7 @@ const CONFIG = { | |||
140 | TRANSCODING: { | 148 | TRANSCODING: { |
141 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, | 149 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, |
142 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, | 150 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, |
151 | get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') }, | ||
143 | get THREADS () { return config.get<number>('transcoding.threads') }, | 152 | get THREADS () { return config.get<number>('transcoding.threads') }, |
144 | RESOLUTIONS: { | 153 | RESOLUTIONS: { |
145 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, | 154 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index b5f8fc0bc..be30be463 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { JobType, VideoRateType, VideoState } from '../../shared/models' | 2 | import { JobType, VideoRateType, VideoResolution, VideoState } from '../../shared/models' |
3 | import { ActivityPubActorType } from '../../shared/models/activitypub' | 3 | import { ActivityPubActorType } from '../../shared/models/activitypub' |
4 | import { FollowState } from '../../shared/models/actors' | 4 | import { FollowState } from '../../shared/models/actors' |
5 | import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' | 5 | import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' |
6 | // Do not use barrels, remain constants as independent as possible | 6 | // Do not use barrels, remain constants as independent as possible |
7 | import { isTestInstance, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' | 7 | import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils' |
8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
9 | import { invert } from 'lodash' | 9 | import { invert } from 'lodash' |
10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' | 10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' |
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
14 | 14 | ||
15 | // --------------------------------------------------------------------------- | 15 | // --------------------------------------------------------------------------- |
16 | 16 | ||
17 | const LAST_MIGRATION_VERSION = 380 | 17 | const LAST_MIGRATION_VERSION = 385 |
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
@@ -228,7 +228,7 @@ let CONSTRAINTS_FIELDS = { | |||
228 | max: 2 * 1024 * 1024 // 2MB | 228 | max: 2 * 1024 * 1024 // 2MB |
229 | } | 229 | } |
230 | }, | 230 | }, |
231 | EXTNAME: buildVideosExtname(), | 231 | EXTNAME: [] as string[], |
232 | INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 | 232 | INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 |
233 | DURATION: { min: 0 }, // Number | 233 | DURATION: { min: 0 }, // Number |
234 | TAGS: { min: 0, max: 5 }, // Number of total tags | 234 | TAGS: { min: 0, max: 5 }, // Number of total tags |
@@ -300,6 +300,8 @@ const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { | |||
300 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) | 300 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) |
301 | } | 301 | } |
302 | 302 | ||
303 | const DEFAULT_AUDIO_RESOLUTION = VideoResolution.H_480P | ||
304 | |||
303 | const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = { | 305 | const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = { |
304 | LIKE: 'like', | 306 | LIKE: 'like', |
305 | DISLIKE: 'dislike' | 307 | DISLIKE: 'dislike' |
@@ -380,8 +382,18 @@ const VIDEO_PLAYLIST_TYPES = { | |||
380 | } | 382 | } |
381 | 383 | ||
382 | const MIMETYPES = { | 384 | const MIMETYPES = { |
385 | AUDIO: { | ||
386 | MIMETYPE_EXT: { | ||
387 | 'audio/mpeg': '.mp3', | ||
388 | 'audio/mp3': '.mp3', | ||
389 | 'application/ogg': '.ogg', | ||
390 | 'audio/ogg': '.ogg', | ||
391 | 'audio/flac': '.flac' | ||
392 | }, | ||
393 | EXT_MIMETYPE: null as { [ id: string ]: string } | ||
394 | }, | ||
383 | VIDEO: { | 395 | VIDEO: { |
384 | MIMETYPE_EXT: buildVideoMimetypeExt(), | 396 | MIMETYPE_EXT: null as { [ id: string ]: string }, |
385 | EXT_MIMETYPE: null as { [ id: string ]: string } | 397 | EXT_MIMETYPE: null as { [ id: string ]: string } |
386 | }, | 398 | }, |
387 | IMAGE: { | 399 | IMAGE: { |
@@ -403,7 +415,7 @@ const MIMETYPES = { | |||
403 | } | 415 | } |
404 | } | 416 | } |
405 | } | 417 | } |
406 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) | 418 | MIMETYPES.AUDIO.EXT_MIMETYPE = invert(MIMETYPES.AUDIO.MIMETYPE_EXT) |
407 | 419 | ||
408 | // --------------------------------------------------------------------------- | 420 | // --------------------------------------------------------------------------- |
409 | 421 | ||
@@ -429,7 +441,7 @@ const ACTIVITY_PUB = { | |||
429 | COLLECTION_ITEMS_PER_PAGE: 10, | 441 | COLLECTION_ITEMS_PER_PAGE: 10, |
430 | FETCH_PAGE_LIMIT: 100, | 442 | FETCH_PAGE_LIMIT: 100, |
431 | URL_MIME_TYPES: { | 443 | URL_MIME_TYPES: { |
432 | VIDEO: Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT), | 444 | VIDEO: [] as string[], |
433 | TORRENT: [ 'application/x-bittorrent' ], | 445 | TORRENT: [ 'application/x-bittorrent' ], |
434 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] | 446 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] |
435 | }, | 447 | }, |
@@ -497,8 +509,8 @@ const THUMBNAILS_SIZE = { | |||
497 | height: 122 | 509 | height: 122 |
498 | } | 510 | } |
499 | const PREVIEWS_SIZE = { | 511 | const PREVIEWS_SIZE = { |
500 | width: 560, | 512 | width: 850, |
501 | height: 315 | 513 | height: 480 |
502 | } | 514 | } |
503 | const AVATARS_SIZE = { | 515 | const AVATARS_SIZE = { |
504 | width: 120, | 516 | width: 120, |
@@ -543,6 +555,10 @@ const REDUNDANCY = { | |||
543 | 555 | ||
544 | const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) | 556 | const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) |
545 | 557 | ||
558 | const ASSETS_PATH = { | ||
559 | DEFAULT_AUDIO_BACKGROUND: join(root(), 'server', 'assets', 'default-audio-background.jpg') | ||
560 | } | ||
561 | |||
546 | // --------------------------------------------------------------------------- | 562 | // --------------------------------------------------------------------------- |
547 | 563 | ||
548 | const CUSTOM_HTML_TAG_COMMENTS = { | 564 | const CUSTOM_HTML_TAG_COMMENTS = { |
@@ -612,6 +628,7 @@ if (isTestInstance() === true) { | |||
612 | } | 628 | } |
613 | 629 | ||
614 | updateWebserverUrls() | 630 | updateWebserverUrls() |
631 | updateWebserverConfig() | ||
615 | 632 | ||
616 | registerConfigChangedHandler(() => { | 633 | registerConfigChangedHandler(() => { |
617 | updateWebserverUrls() | 634 | updateWebserverUrls() |
@@ -681,12 +698,14 @@ export { | |||
681 | RATES_LIMIT, | 698 | RATES_LIMIT, |
682 | MIMETYPES, | 699 | MIMETYPES, |
683 | CRAWL_REQUEST_CONCURRENCY, | 700 | CRAWL_REQUEST_CONCURRENCY, |
701 | DEFAULT_AUDIO_RESOLUTION, | ||
684 | JOB_COMPLETED_LIFETIME, | 702 | JOB_COMPLETED_LIFETIME, |
685 | HTTP_SIGNATURE, | 703 | HTTP_SIGNATURE, |
686 | VIDEO_IMPORT_STATES, | 704 | VIDEO_IMPORT_STATES, |
687 | VIDEO_VIEW_LIFETIME, | 705 | VIDEO_VIEW_LIFETIME, |
688 | CONTACT_FORM_LIFETIME, | 706 | CONTACT_FORM_LIFETIME, |
689 | VIDEO_PLAYLIST_PRIVACIES, | 707 | VIDEO_PLAYLIST_PRIVACIES, |
708 | ASSETS_PATH, | ||
690 | loadLanguages, | 709 | loadLanguages, |
691 | buildLanguages | 710 | buildLanguages |
692 | } | 711 | } |
@@ -700,15 +719,21 @@ function buildVideoMimetypeExt () { | |||
700 | 'video/mp4': '.mp4' | 719 | 'video/mp4': '.mp4' |
701 | } | 720 | } |
702 | 721 | ||
703 | if (CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) { | 722 | if (CONFIG.TRANSCODING.ENABLED) { |
704 | Object.assign(data, { | 723 | if (CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) { |
705 | 'video/quicktime': '.mov', | 724 | Object.assign(data, { |
706 | 'video/x-msvideo': '.avi', | 725 | 'video/quicktime': '.mov', |
707 | 'video/x-flv': '.flv', | 726 | 'video/x-msvideo': '.avi', |
708 | 'video/x-matroska': '.mkv', | 727 | 'video/x-flv': '.flv', |
709 | 'application/octet-stream': '.mkv', | 728 | 'video/x-matroska': '.mkv', |
710 | 'video/avi': '.avi' | 729 | 'application/octet-stream': '.mkv', |
711 | }) | 730 | 'video/avi': '.avi' |
731 | }) | ||
732 | } | ||
733 | |||
734 | if (CONFIG.TRANSCODING.ALLOW_AUDIO_FILES) { | ||
735 | Object.assign(data, MIMETYPES.AUDIO.MIMETYPE_EXT) | ||
736 | } | ||
712 | } | 737 | } |
713 | 738 | ||
714 | return data | 739 | return data |
@@ -724,16 +749,15 @@ function updateWebserverUrls () { | |||
724 | } | 749 | } |
725 | 750 | ||
726 | function updateWebserverConfig () { | 751 | function updateWebserverConfig () { |
727 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname() | ||
728 | |||
729 | MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt() | 752 | MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt() |
730 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) | 753 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) |
754 | ACTIVITY_PUB.URL_MIME_TYPES.VIDEO = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT) | ||
755 | |||
756 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname() | ||
731 | } | 757 | } |
732 | 758 | ||
733 | function buildVideosExtname () { | 759 | function buildVideosExtname () { |
734 | return CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS | 760 | return Object.keys(MIMETYPES.VIDEO.EXT_MIMETYPE) |
735 | ? [ '.mp4', '.ogv', '.webm', '.mkv', '.mov', '.avi', '.flv' ] | ||
736 | : [ '.mp4', '.ogv', '.webm' ] | ||
737 | } | 761 | } |
738 | 762 | ||
739 | function loadLanguages () { | 763 | function loadLanguages () { |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 127449577..e14554ede 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts | |||
@@ -128,6 +128,8 @@ async function createOAuthAdminIfNotExist () { | |||
128 | 128 | ||
129 | // Our password is weak so do not validate it | 129 | // Our password is weak so do not validate it |
130 | validatePassword = false | 130 | validatePassword = false |
131 | } else if (process.env.PT_INITIAL_ROOT_PASSWORD) { | ||
132 | password = process.env.PT_INITIAL_ROOT_PASSWORD | ||
131 | } else { | 133 | } else { |
132 | password = passwordGenerator(16, true) | 134 | password = passwordGenerator(16, true) |
133 | } | 135 | } |
@@ -144,7 +146,7 @@ async function createOAuthAdminIfNotExist () { | |||
144 | } | 146 | } |
145 | const user = new UserModel(userData) | 147 | const user = new UserModel(userData) |
146 | 148 | ||
147 | await createUserAccountAndChannelAndPlaylist(user, validatePassword) | 149 | await createUserAccountAndChannelAndPlaylist(user, undefined, validatePassword) |
148 | logger.info('Username: ' + username) | 150 | logger.info('Username: ' + username) |
149 | logger.info('User password: ' + password) | 151 | logger.info('User password: ' + password) |
150 | } | 152 | } |
diff --git a/server/initializers/migrations/0385-remove-actor-uuid.ts b/server/initializers/migrations/0385-remove-actor-uuid.ts new file mode 100644 index 000000000..032c0562b --- /dev/null +++ b/server/initializers/migrations/0385-remove-actor-uuid.ts | |||
@@ -0,0 +1,19 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction, | ||
5 | queryInterface: Sequelize.QueryInterface, | ||
6 | sequelize: Sequelize.Sequelize, | ||
7 | db: any | ||
8 | }): Promise<void> { | ||
9 | await utils.queryInterface.removeColumn('actor', 'uuid') | ||
10 | } | ||
11 | |||
12 | function down (options) { | ||
13 | throw new Error('Not implemented.') | ||
14 | } | ||
15 | |||
16 | export { | ||
17 | up, | ||
18 | down | ||
19 | } | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 25cd40905..38eb87d1e 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -5,7 +5,7 @@ import * as uuidv4 from 'uuid/v4' | |||
5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' | 5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' |
6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
7 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' | 7 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' |
8 | import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
11 | import { logger } from '../../helpers/logger' | 11 | import { logger } from '../../helpers/logger' |
@@ -33,7 +33,7 @@ function setAsyncActorKeys (actor: ActorModel) { | |||
33 | return actor.save() | 33 | return actor.save() |
34 | }) | 34 | }) |
35 | .catch(err => { | 35 | .catch(err => { |
36 | logger.error('Cannot set public/private keys of actor %d.', actor.uuid, { err }) | 36 | logger.error('Cannot set public/private keys of actor %d.', actor.url, { err }) |
37 | return actor | 37 | return actor |
38 | }) | 38 | }) |
39 | } | 39 | } |
@@ -128,18 +128,17 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ | |||
128 | const followersCount = await fetchActorTotalItems(attributes.followers) | 128 | const followersCount = await fetchActorTotalItems(attributes.followers) |
129 | const followingCount = await fetchActorTotalItems(attributes.following) | 129 | const followingCount = await fetchActorTotalItems(attributes.following) |
130 | 130 | ||
131 | actorInstance.set('type', attributes.type) | 131 | actorInstance.type = attributes.type |
132 | actorInstance.set('uuid', attributes.uuid) | 132 | actorInstance.preferredUsername = attributes.preferredUsername |
133 | actorInstance.set('preferredUsername', attributes.preferredUsername) | 133 | actorInstance.url = attributes.id |
134 | actorInstance.set('url', attributes.id) | 134 | actorInstance.publicKey = attributes.publicKey.publicKeyPem |
135 | actorInstance.set('publicKey', attributes.publicKey.publicKeyPem) | 135 | actorInstance.followersCount = followersCount |
136 | actorInstance.set('followersCount', followersCount) | 136 | actorInstance.followingCount = followingCount |
137 | actorInstance.set('followingCount', followingCount) | 137 | actorInstance.inboxUrl = attributes.inbox |
138 | actorInstance.set('inboxUrl', attributes.inbox) | 138 | actorInstance.outboxUrl = attributes.outbox |
139 | actorInstance.set('outboxUrl', attributes.outbox) | 139 | actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox |
140 | actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox) | 140 | actorInstance.followersUrl = attributes.followers |
141 | actorInstance.set('followersUrl', attributes.followers) | 141 | actorInstance.followingUrl = attributes.following |
142 | actorInstance.set('followingUrl', attributes.following) | ||
143 | } | 142 | } |
144 | 143 | ||
145 | async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { | 144 | async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { |
@@ -370,10 +369,9 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe | |||
370 | logger.info('Fetching remote actor %s.', actorUrl) | 369 | logger.info('Fetching remote actor %s.', actorUrl) |
371 | 370 | ||
372 | const requestResult = await doRequest<ActivityPubActor>(options) | 371 | const requestResult = await doRequest<ActivityPubActor>(options) |
373 | normalizeActor(requestResult.body) | ||
374 | |||
375 | const actorJSON = requestResult.body | 372 | const actorJSON = requestResult.body |
376 | if (isActorObjectValid(actorJSON) === false) { | 373 | |
374 | if (sanitizeAndCheckActorObject(actorJSON) === false) { | ||
377 | logger.debug('Remote actor JSON is not valid.', { actorJSON }) | 375 | logger.debug('Remote actor JSON is not valid.', { actorJSON }) |
378 | return { result: undefined, statusCode: requestResult.response.statusCode } | 376 | return { result: undefined, statusCode: requestResult.response.statusCode } |
379 | } | 377 | } |
@@ -388,7 +386,6 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe | |||
388 | 386 | ||
389 | const actor = new ActorModel({ | 387 | const actor = new ActorModel({ |
390 | type: actorJSON.type, | 388 | type: actorJSON.type, |
391 | uuid: actorJSON.uuid, | ||
392 | preferredUsername: actorJSON.preferredUsername, | 389 | preferredUsername: actorJSON.preferredUsername, |
393 | url: actorJSON.id, | 390 | url: actorJSON.id, |
394 | publicKey: actorJSON.publicKey.publicKeyPem, | 391 | publicKey: actorJSON.publicKey.publicKeyPem, |
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts index 686eef04d..9e469e3e6 100644 --- a/server/lib/activitypub/crawl.ts +++ b/server/lib/activitypub/crawl.ts | |||
@@ -28,13 +28,22 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T> | |||
28 | let i = 0 | 28 | let i = 0 |
29 | let nextLink = firstBody.first | 29 | let nextLink = firstBody.first |
30 | while (nextLink && i < limit) { | 30 | while (nextLink && i < limit) { |
31 | // Don't crawl ourselves | 31 | let body: any |
32 | const remoteHost = parse(nextLink).host | ||
33 | if (remoteHost === WEBSERVER.HOST) continue | ||
34 | 32 | ||
35 | options.uri = nextLink | 33 | if (typeof nextLink === 'string') { |
34 | // Don't crawl ourselves | ||
35 | const remoteHost = parse(nextLink).host | ||
36 | if (remoteHost === WEBSERVER.HOST) continue | ||
37 | |||
38 | options.uri = nextLink | ||
39 | |||
40 | const res = await doRequest<ActivityPubOrderedCollection<T>>(options) | ||
41 | body = res.body | ||
42 | } else { | ||
43 | // nextLink is already the object we want | ||
44 | body = nextLink | ||
45 | } | ||
36 | 46 | ||
37 | const { body } = await doRequest<ActivityPubOrderedCollection<T>>(options) | ||
38 | nextLink = body.next | 47 | nextLink = body.next |
39 | i++ | 48 | i++ |
40 | 49 | ||
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 23310b41e..bbf1bd3a8 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts | |||
@@ -5,8 +5,9 @@ import { ActorModel } from '../../../models/activitypub/actor' | |||
5 | import { VideoShareModel } from '../../../models/video/video-share' | 5 | import { VideoShareModel } from '../../../models/video/video-share' |
6 | import { forwardVideoRelatedActivity } from '../send/utils' | 6 | import { forwardVideoRelatedActivity } from '../send/utils' |
7 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' | 7 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' |
8 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
9 | import { Notifier } from '../../notifier' | 8 | import { Notifier } from '../../notifier' |
9 | import { VideoModel } from '../../../models/video/video' | ||
10 | import { logger } from '../../../helpers/logger' | ||
10 | 11 | ||
11 | async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) { | 12 | async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) { |
12 | return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity) | 13 | return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity) |
@@ -23,7 +24,17 @@ export { | |||
23 | async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { | 24 | async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { |
24 | const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id | 25 | const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id |
25 | 26 | ||
26 | const { video, created: videoCreated } = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri }) | 27 | let video: VideoModel |
28 | let videoCreated: boolean | ||
29 | |||
30 | try { | ||
31 | const result = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri }) | ||
32 | video = result.video | ||
33 | videoCreated = result.created | ||
34 | } catch (err) { | ||
35 | logger.debug('Cannot process share of %s. Maybe this is not a video object, so just skipping.', objectUri, { err }) | ||
36 | return | ||
37 | } | ||
27 | 38 | ||
28 | await sequelizeTypescript.transaction(async t => { | 39 | await sequelizeTypescript.transaction(async t => { |
29 | // Add share entry | 40 | // Add share entry |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index e882669ce..daf846513 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -9,28 +9,14 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' | |||
9 | import { forwardVideoRelatedActivity } from '../send/utils' | 9 | import { forwardVideoRelatedActivity } from '../send/utils' |
10 | import { createOrUpdateCacheFile } from '../cache-file' | 10 | import { createOrUpdateCacheFile } from '../cache-file' |
11 | import { Notifier } from '../../notifier' | 11 | import { Notifier } from '../../notifier' |
12 | import { processViewActivity } from './process-view' | ||
13 | import { processDislikeActivity } from './process-dislike' | ||
14 | import { processFlagActivity } from './process-flag' | ||
15 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | 12 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' |
16 | import { createOrUpdateVideoPlaylist } from '../playlist' | 13 | import { createOrUpdateVideoPlaylist } from '../playlist' |
14 | import { VideoModel } from '../../../models/video/video' | ||
17 | 15 | ||
18 | async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) { | 16 | async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) { |
19 | const activityObject = activity.object | 17 | const activityObject = activity.object |
20 | const activityType = activityObject.type | 18 | const activityType = activityObject.type |
21 | 19 | ||
22 | if (activityType === 'View') { | ||
23 | return processViewActivity(activity, byActor) | ||
24 | } | ||
25 | |||
26 | if (activityType === 'Dislike') { | ||
27 | return retryTransactionWrapper(processDislikeActivity, activity, byActor) | ||
28 | } | ||
29 | |||
30 | if (activityType === 'Flag') { | ||
31 | return retryTransactionWrapper(processFlagActivity, activity, byActor) | ||
32 | } | ||
33 | |||
34 | if (activityType === 'Video') { | 20 | if (activityType === 'Video') { |
35 | return processCreateVideo(activity) | 21 | return processCreateVideo(activity) |
36 | } | 22 | } |
@@ -91,7 +77,18 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act | |||
91 | 77 | ||
92 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) | 78 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) |
93 | 79 | ||
94 | const { video } = await resolveThread(commentObject.inReplyTo) | 80 | let video: VideoModel |
81 | try { | ||
82 | const resolveThreadResult = await resolveThread(commentObject.inReplyTo) | ||
83 | video = resolveThreadResult.video | ||
84 | } catch (err) { | ||
85 | logger.debug( | ||
86 | 'Cannot process video comment because we could not resolve thread %s. Maybe it was not a video thread, so skip it.', | ||
87 | commentObject.inReplyTo, | ||
88 | { err } | ||
89 | ) | ||
90 | return | ||
91 | } | ||
95 | 92 | ||
96 | const { comment, created } = await addVideoComment(video, commentObject.id) | 93 | const { comment, created } = await addVideoComment(video, commentObject.id) |
97 | 94 | ||
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 76f07fd8a..6f10a50bd 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts | |||
@@ -95,23 +95,23 @@ async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: | |||
95 | } | 95 | } |
96 | 96 | ||
97 | async function processDeleteAccount (accountToRemove: AccountModel) { | 97 | async function processDeleteAccount (accountToRemove: AccountModel) { |
98 | logger.debug('Removing remote account "%s".', accountToRemove.Actor.uuid) | 98 | logger.debug('Removing remote account "%s".', accountToRemove.Actor.url) |
99 | 99 | ||
100 | await sequelizeTypescript.transaction(async t => { | 100 | await sequelizeTypescript.transaction(async t => { |
101 | await accountToRemove.destroy({ transaction: t }) | 101 | await accountToRemove.destroy({ transaction: t }) |
102 | }) | 102 | }) |
103 | 103 | ||
104 | logger.info('Remote account with uuid %s removed.', accountToRemove.Actor.uuid) | 104 | logger.info('Remote account %s removed.', accountToRemove.Actor.url) |
105 | } | 105 | } |
106 | 106 | ||
107 | async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { | 107 | async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { |
108 | logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.uuid) | 108 | logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url) |
109 | 109 | ||
110 | await sequelizeTypescript.transaction(async t => { | 110 | await sequelizeTypescript.transaction(async t => { |
111 | await videoChannelToRemove.destroy({ transaction: t }) | 111 | await videoChannelToRemove.destroy({ transaction: t }) |
112 | }) | 112 | }) |
113 | 113 | ||
114 | logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.Actor.uuid) | 114 | logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) |
115 | } | 115 | } |
116 | 116 | ||
117 | function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { | 117 | function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 54a9234bb..71a16dacc 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -95,7 +95,7 @@ async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUp | |||
95 | async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) { | 95 | async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) { |
96 | const actorAttributesToUpdate = activity.object as ActivityPubActor | 96 | const actorAttributesToUpdate = activity.object as ActivityPubActor |
97 | 97 | ||
98 | logger.debug('Updating remote account "%s".', actorAttributesToUpdate.uuid) | 98 | logger.debug('Updating remote account "%s".', actorAttributesToUpdate.url) |
99 | let accountOrChannelInstance: AccountModel | VideoChannelModel | 99 | let accountOrChannelInstance: AccountModel | VideoChannelModel |
100 | let actorFieldsSave: object | 100 | let actorFieldsSave: object |
101 | let accountOrChannelFieldsSave: object | 101 | let accountOrChannelFieldsSave: object |
@@ -128,7 +128,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) | |||
128 | await accountOrChannelInstance.save({ transaction: t }) | 128 | await accountOrChannelInstance.save({ transaction: t }) |
129 | }) | 129 | }) |
130 | 130 | ||
131 | logger.info('Remote account with uuid %s updated', actorAttributesToUpdate.uuid) | 131 | logger.info('Remote account %s updated', actorAttributesToUpdate.url) |
132 | } catch (err) { | 132 | } catch (err) { |
133 | if (actor !== undefined && actorFieldsSave !== undefined) { | 133 | if (actor !== undefined && actorFieldsSave !== undefined) { |
134 | resetSequelizeInstance(actor, actorFieldsSave) | 134 | resetSequelizeInstance(actor, actorFieldsSave) |
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index 18f44d50e..c3fc6b462 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts | |||
@@ -80,7 +80,8 @@ async function addVideoComment (videoInstance: VideoModel, commentUrl: string) { | |||
80 | return { comment, created } | 80 | return { comment, created } |
81 | } | 81 | } |
82 | 82 | ||
83 | async function resolveThread (url: string, comments: VideoCommentModel[] = []) { | 83 | type ResolveThreadResult = Promise<{ video: VideoModel, parents: VideoCommentModel[] }> |
84 | async function resolveThread (url: string, comments: VideoCommentModel[] = []): ResolveThreadResult { | ||
84 | // Already have this comment? | 85 | // Already have this comment? |
85 | const commentFromDatabase = await VideoCommentModel.loadByUrlAndPopulateReplyAndVideo(url) | 86 | const commentFromDatabase = await VideoCommentModel.loadByUrlAndPopulateReplyAndVideo(url) |
86 | if (commentFromDatabase) { | 87 | if (commentFromDatabase) { |
@@ -161,7 +162,6 @@ async function resolveThread (url: string, comments: VideoCommentModel[] = []) { | |||
161 | 162 | ||
162 | return resolveThread(body.inReplyTo, comments.concat([ comment ])) | 163 | return resolveThread(body.inReplyTo, comments.concat([ comment ])) |
163 | } | 164 | } |
164 | |||
165 | } | 165 | } |
166 | 166 | ||
167 | export { | 167 | export { |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 8c06e9751..c4a5a5853 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -100,11 +100,11 @@ class Emailer { | |||
100 | `You can view it on ${videoUrl} ` + | 100 | `You can view it on ${videoUrl} ` + |
101 | `\n\n` + | 101 | `\n\n` + |
102 | `Cheers,\n` + | 102 | `Cheers,\n` + |
103 | `PeerTube.` | 103 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
104 | 104 | ||
105 | const emailPayload: EmailPayload = { | 105 | const emailPayload: EmailPayload = { |
106 | to, | 106 | to, |
107 | subject: channelName + ' just published a new video', | 107 | subject: CONFIG.EMAIL.OBJECT.PREFIX + channelName + ' just published a new video', |
108 | text | 108 | text |
109 | } | 109 | } |
110 | 110 | ||
@@ -119,11 +119,11 @@ class Emailer { | |||
119 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + | 119 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + |
120 | `\n\n` + | 120 | `\n\n` + |
121 | `Cheers,\n` + | 121 | `Cheers,\n` + |
122 | `PeerTube.` | 122 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
123 | 123 | ||
124 | const emailPayload: EmailPayload = { | 124 | const emailPayload: EmailPayload = { |
125 | to, | 125 | to, |
126 | subject: 'New follower on your channel ' + followingName, | 126 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New follower on your channel ' + followingName, |
127 | text | 127 | text |
128 | } | 128 | } |
129 | 129 | ||
@@ -137,11 +137,11 @@ class Emailer { | |||
137 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + | 137 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + |
138 | `\n\n` + | 138 | `\n\n` + |
139 | `Cheers,\n` + | 139 | `Cheers,\n` + |
140 | `PeerTube.` | 140 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
141 | 141 | ||
142 | const emailPayload: EmailPayload = { | 142 | const emailPayload: EmailPayload = { |
143 | to, | 143 | to, |
144 | subject: 'New instance follower', | 144 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New instance follower', |
145 | text | 145 | text |
146 | } | 146 | } |
147 | 147 | ||
@@ -157,11 +157,11 @@ class Emailer { | |||
157 | `You can view it on ${videoUrl} ` + | 157 | `You can view it on ${videoUrl} ` + |
158 | `\n\n` + | 158 | `\n\n` + |
159 | `Cheers,\n` + | 159 | `Cheers,\n` + |
160 | `PeerTube.` | 160 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
161 | 161 | ||
162 | const emailPayload: EmailPayload = { | 162 | const emailPayload: EmailPayload = { |
163 | to, | 163 | to, |
164 | subject: `Your video ${video.name} is published`, | 164 | subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video ${video.name} is published`, |
165 | text | 165 | text |
166 | } | 166 | } |
167 | 167 | ||
@@ -177,11 +177,11 @@ class Emailer { | |||
177 | `You can view the imported video on ${videoUrl} ` + | 177 | `You can view the imported video on ${videoUrl} ` + |
178 | `\n\n` + | 178 | `\n\n` + |
179 | `Cheers,\n` + | 179 | `Cheers,\n` + |
180 | `PeerTube.` | 180 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
181 | 181 | ||
182 | const emailPayload: EmailPayload = { | 182 | const emailPayload: EmailPayload = { |
183 | to, | 183 | to, |
184 | subject: `Your video import ${videoImport.getTargetIdentifier()} is finished`, | 184 | subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} is finished`, |
185 | text | 185 | text |
186 | } | 186 | } |
187 | 187 | ||
@@ -197,11 +197,11 @@ class Emailer { | |||
197 | `See your videos import dashboard for more information: ${importUrl}` + | 197 | `See your videos import dashboard for more information: ${importUrl}` + |
198 | `\n\n` + | 198 | `\n\n` + |
199 | `Cheers,\n` + | 199 | `Cheers,\n` + |
200 | `PeerTube.` | 200 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
201 | 201 | ||
202 | const emailPayload: EmailPayload = { | 202 | const emailPayload: EmailPayload = { |
203 | to, | 203 | to, |
204 | subject: `Your video import ${videoImport.getTargetIdentifier()} encountered an error`, | 204 | subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} encountered an error`, |
205 | text | 205 | text |
206 | } | 206 | } |
207 | 207 | ||
@@ -219,11 +219,11 @@ class Emailer { | |||
219 | `You can view it on ${commentUrl} ` + | 219 | `You can view it on ${commentUrl} ` + |
220 | `\n\n` + | 220 | `\n\n` + |
221 | `Cheers,\n` + | 221 | `Cheers,\n` + |
222 | `PeerTube.` | 222 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
223 | 223 | ||
224 | const emailPayload: EmailPayload = { | 224 | const emailPayload: EmailPayload = { |
225 | to, | 225 | to, |
226 | subject: 'New comment on your video ' + video.name, | 226 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New comment on your video ' + video.name, |
227 | text | 227 | text |
228 | } | 228 | } |
229 | 229 | ||
@@ -241,11 +241,11 @@ class Emailer { | |||
241 | `You can view the comment on ${commentUrl} ` + | 241 | `You can view the comment on ${commentUrl} ` + |
242 | `\n\n` + | 242 | `\n\n` + |
243 | `Cheers,\n` + | 243 | `Cheers,\n` + |
244 | `PeerTube.` | 244 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
245 | 245 | ||
246 | const emailPayload: EmailPayload = { | 246 | const emailPayload: EmailPayload = { |
247 | to, | 247 | to, |
248 | subject: 'Mention on video ' + video.name, | 248 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Mention on video ' + video.name, |
249 | text | 249 | text |
250 | } | 250 | } |
251 | 251 | ||
@@ -258,11 +258,11 @@ class Emailer { | |||
258 | const text = `Hi,\n\n` + | 258 | const text = `Hi,\n\n` + |
259 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + | 259 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + |
260 | `Cheers,\n` + | 260 | `Cheers,\n` + |
261 | `PeerTube.` | 261 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
262 | 262 | ||
263 | const emailPayload: EmailPayload = { | 263 | const emailPayload: EmailPayload = { |
264 | to, | 264 | to, |
265 | subject: '[PeerTube] Received a video abuse', | 265 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Received a video abuse', |
266 | text | 266 | text |
267 | } | 267 | } |
268 | 268 | ||
@@ -281,11 +281,11 @@ class Emailer { | |||
281 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + | 281 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + |
282 | `\n\n` + | 282 | `\n\n` + |
283 | `Cheers,\n` + | 283 | `Cheers,\n` + |
284 | `PeerTube.` | 284 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
285 | 285 | ||
286 | const emailPayload: EmailPayload = { | 286 | const emailPayload: EmailPayload = { |
287 | to, | 287 | to, |
288 | subject: '[PeerTube] An auto-blacklisted video is awaiting review', | 288 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'An auto-blacklisted video is awaiting review', |
289 | text | 289 | text |
290 | } | 290 | } |
291 | 291 | ||
@@ -296,11 +296,11 @@ class Emailer { | |||
296 | const text = `Hi,\n\n` + | 296 | const text = `Hi,\n\n` + |
297 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + | 297 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + |
298 | `Cheers,\n` + | 298 | `Cheers,\n` + |
299 | `PeerTube.` | 299 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
300 | 300 | ||
301 | const emailPayload: EmailPayload = { | 301 | const emailPayload: EmailPayload = { |
302 | to, | 302 | to, |
303 | subject: '[PeerTube] New user registration on ' + WEBSERVER.HOST, | 303 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New user registration on ' + WEBSERVER.HOST, |
304 | text | 304 | text |
305 | } | 305 | } |
306 | 306 | ||
@@ -318,11 +318,11 @@ class Emailer { | |||
318 | blockedString + | 318 | blockedString + |
319 | '\n\n' + | 319 | '\n\n' + |
320 | 'Cheers,\n' + | 320 | 'Cheers,\n' + |
321 | `PeerTube.` | 321 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
322 | 322 | ||
323 | const emailPayload: EmailPayload = { | 323 | const emailPayload: EmailPayload = { |
324 | to, | 324 | to, |
325 | subject: `[PeerTube] Video ${videoName} blacklisted`, | 325 | subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${videoName} blacklisted`, |
326 | text | 326 | text |
327 | } | 327 | } |
328 | 328 | ||
@@ -336,11 +336,11 @@ class Emailer { | |||
336 | `Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` + | 336 | `Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` + |
337 | '\n\n' + | 337 | '\n\n' + |
338 | 'Cheers,\n' + | 338 | 'Cheers,\n' + |
339 | `PeerTube.` | 339 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
340 | 340 | ||
341 | const emailPayload: EmailPayload = { | 341 | const emailPayload: EmailPayload = { |
342 | to, | 342 | to, |
343 | subject: `[PeerTube] Video ${video.name} unblacklisted`, | 343 | subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${video.name} unblacklisted`, |
344 | text | 344 | text |
345 | } | 345 | } |
346 | 346 | ||
@@ -353,11 +353,11 @@ class Emailer { | |||
353 | `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + | 353 | `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + |
354 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 354 | `If you are not the person who initiated this request, please ignore this email.\n\n` + |
355 | `Cheers,\n` + | 355 | `Cheers,\n` + |
356 | `PeerTube.` | 356 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
357 | 357 | ||
358 | const emailPayload: EmailPayload = { | 358 | const emailPayload: EmailPayload = { |
359 | to: [ to ], | 359 | to: [ to ], |
360 | subject: 'Reset your PeerTube password', | 360 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Reset your password', |
361 | text | 361 | text |
362 | } | 362 | } |
363 | 363 | ||
@@ -370,11 +370,11 @@ class Emailer { | |||
370 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + | 370 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + |
371 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 371 | `If you are not the person who initiated this request, please ignore this email.\n\n` + |
372 | `Cheers,\n` + | 372 | `Cheers,\n` + |
373 | `PeerTube.` | 373 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
374 | 374 | ||
375 | const emailPayload: EmailPayload = { | 375 | const emailPayload: EmailPayload = { |
376 | to: [ to ], | 376 | to: [ to ], |
377 | subject: 'Verify your PeerTube email', | 377 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Verify your email', |
378 | text | 378 | text |
379 | } | 379 | } |
380 | 380 | ||
@@ -390,12 +390,12 @@ class Emailer { | |||
390 | blockedString + | 390 | blockedString + |
391 | '\n\n' + | 391 | '\n\n' + |
392 | 'Cheers,\n' + | 392 | 'Cheers,\n' + |
393 | `PeerTube.` | 393 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
394 | 394 | ||
395 | const to = user.email | 395 | const to = user.email |
396 | const emailPayload: EmailPayload = { | 396 | const emailPayload: EmailPayload = { |
397 | to: [ to ], | 397 | to: [ to ], |
398 | subject: '[PeerTube] Account ' + blockedWord, | 398 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Account ' + blockedWord, |
399 | text | 399 | text |
400 | } | 400 | } |
401 | 401 | ||
@@ -415,7 +415,7 @@ class Emailer { | |||
415 | fromDisplayName: fromEmail, | 415 | fromDisplayName: fromEmail, |
416 | replyTo: fromEmail, | 416 | replyTo: fromEmail, |
417 | to: [ CONFIG.ADMIN.EMAIL ], | 417 | to: [ CONFIG.ADMIN.EMAIL ], |
418 | subject: '[PeerTube] Contact form submitted', | 418 | subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Contact form submitted', |
419 | text | 419 | text |
420 | } | 420 | } |
421 | 421 | ||
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts index 14be7f24a..a68619d07 100644 --- a/server/lib/files-cache/videos-preview-cache.ts +++ b/server/lib/files-cache/videos-preview-cache.ts | |||
@@ -21,7 +21,7 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | |||
21 | const video = await VideoModel.loadByUUIDWithFile(videoUUID) | 21 | const video = await VideoModel.loadByUUIDWithFile(videoUUID) |
22 | if (!video) return undefined | 22 | if (!video) return undefined |
23 | 23 | ||
24 | if (video.isOwned()) return { isOwned: true, path: join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreview().filename) } | 24 | if (video.isOwned()) return { isOwned: true, path: video.getPreview().getPath() } |
25 | 25 | ||
26 | return this.loadRemoteFile(videoUUID) | 26 | return this.loadRemoteFile(videoUUID) |
27 | } | 27 | } |
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index 921d9a083..8cacb0ef3 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { logger } from '../../../helpers/logger' | 2 | import { logger } from '../../../helpers/logger' |
3 | import { VideoModel } from '../../../models/video/video' | 3 | import { VideoModel } from '../../../models/video/video' |
4 | import { publishVideoIfNeeded } from './video-transcoding' | 4 | import { publishNewResolutionIfNeeded } from './video-transcoding' |
5 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 5 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
6 | import { copy, stat } from 'fs-extra' | 6 | import { copy, stat } from 'fs-extra' |
7 | import { VideoFileModel } from '../../../models/video/video-file' | 7 | import { VideoFileModel } from '../../../models/video/video-file' |
@@ -25,7 +25,7 @@ async function processVideoFileImport (job: Bull.Job) { | |||
25 | 25 | ||
26 | await updateVideoFile(video, payload.filePath) | 26 | await updateVideoFile(video, payload.filePath) |
27 | 27 | ||
28 | await publishVideoIfNeeded(video) | 28 | await publishNewResolutionIfNeeded(video) |
29 | return video | 29 | return video |
30 | } | 30 | } |
31 | 31 | ||
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 1650916a6..50e159245 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -209,6 +209,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide | |||
209 | if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { | 209 | if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { |
210 | // Put uuid because we don't have id auto incremented for now | 210 | // Put uuid because we don't have id auto incremented for now |
211 | const dataInput = { | 211 | const dataInput = { |
212 | type: 'optimize' as 'optimize', | ||
212 | videoUUID: videoImportUpdated.Video.uuid, | 213 | videoUUID: videoImportUpdated.Video.uuid, |
213 | isNewVideo: true | 214 | isNewVideo: true |
214 | } | 215 | } |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 48cac517e..e9b84ecd6 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -8,18 +8,39 @@ import { retryTransactionWrapper } from '../../../helpers/database-utils' | |||
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import * as Bluebird from 'bluebird' | 9 | import * as Bluebird from 'bluebird' |
10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' | 10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' |
11 | import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile } from '../../video-transcoding' | 11 | import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile, mergeAudioVideofile } from '../../video-transcoding' |
12 | import { Notifier } from '../../notifier' | 12 | import { Notifier } from '../../notifier' |
13 | import { CONFIG } from '../../../initializers/config' | 13 | import { CONFIG } from '../../../initializers/config' |
14 | 14 | ||
15 | export type VideoTranscodingPayload = { | 15 | interface BaseTranscodingPayload { |
16 | videoUUID: string | 16 | videoUUID: string |
17 | resolution?: VideoResolution | ||
18 | isNewVideo?: boolean | 17 | isNewVideo?: boolean |
18 | } | ||
19 | |||
20 | interface HLSTranscodingPayload extends BaseTranscodingPayload { | ||
21 | type: 'hls' | ||
22 | isPortraitMode?: boolean | ||
23 | resolution: VideoResolution | ||
24 | } | ||
25 | |||
26 | interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | ||
27 | type: 'new-resolution' | ||
19 | isPortraitMode?: boolean | 28 | isPortraitMode?: boolean |
20 | generateHlsPlaylist?: boolean | 29 | resolution: VideoResolution |
30 | } | ||
31 | |||
32 | interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { | ||
33 | type: 'merge-audio' | ||
34 | resolution: VideoResolution | ||
35 | } | ||
36 | |||
37 | interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | ||
38 | type: 'optimize' | ||
21 | } | 39 | } |
22 | 40 | ||
41 | export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload | ||
42 | | OptimizeTranscodingPayload | MergeAudioTranscodingPayload | ||
43 | |||
23 | async function processVideoTranscoding (job: Bull.Job) { | 44 | async function processVideoTranscoding (job: Bull.Job) { |
24 | const payload = job.data as VideoTranscodingPayload | 45 | const payload = job.data as VideoTranscodingPayload |
25 | logger.info('Processing video file in job %d.', job.id) | 46 | logger.info('Processing video file in job %d.', job.id) |
@@ -31,14 +52,18 @@ async function processVideoTranscoding (job: Bull.Job) { | |||
31 | return undefined | 52 | return undefined |
32 | } | 53 | } |
33 | 54 | ||
34 | if (payload.generateHlsPlaylist) { | 55 | if (payload.type === 'hls') { |
35 | await generateHlsPlaylist(video, payload.resolution, payload.isPortraitMode || false) | 56 | await generateHlsPlaylist(video, payload.resolution, payload.isPortraitMode || false) |
36 | 57 | ||
37 | await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video) | 58 | await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video) |
38 | } else if (payload.resolution) { // Transcoding in other resolution | 59 | } else if (payload.type === 'new-resolution') { |
39 | await transcodeOriginalVideofile(video, payload.resolution, payload.isPortraitMode || false) | 60 | await transcodeOriginalVideofile(video, payload.resolution, payload.isPortraitMode || false) |
40 | 61 | ||
41 | await retryTransactionWrapper(publishVideoIfNeeded, video, payload) | 62 | await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload) |
63 | } else if (payload.type === 'merge-audio') { | ||
64 | await mergeAudioVideofile(video, payload.resolution) | ||
65 | |||
66 | await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload) | ||
42 | } else { | 67 | } else { |
43 | await optimizeVideofile(video) | 68 | await optimizeVideofile(video) |
44 | 69 | ||
@@ -62,7 +87,7 @@ async function onHlsPlaylistGenerationSuccess (video: VideoModel) { | |||
62 | }) | 87 | }) |
63 | } | 88 | } |
64 | 89 | ||
65 | async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodingPayload) { | 90 | async function publishNewResolutionIfNeeded (video: VideoModel, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) { |
66 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { | 91 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { |
67 | // Maybe the video changed in database, refresh it | 92 | // Maybe the video changed in database, refresh it |
68 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) | 93 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) |
@@ -94,7 +119,7 @@ async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodi | |||
94 | await createHlsJobIfEnabled(payload) | 119 | await createHlsJobIfEnabled(payload) |
95 | } | 120 | } |
96 | 121 | ||
97 | async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: VideoTranscodingPayload) { | 122 | async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: OptimizeTranscodingPayload) { |
98 | if (videoArg === undefined) return undefined | 123 | if (videoArg === undefined) return undefined |
99 | 124 | ||
100 | // Outside the transaction (IO on disk) | 125 | // Outside the transaction (IO on disk) |
@@ -120,6 +145,7 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: Video | |||
120 | 145 | ||
121 | for (const resolution of resolutionsEnabled) { | 146 | for (const resolution of resolutionsEnabled) { |
122 | const dataInput = { | 147 | const dataInput = { |
148 | type: 'new-resolution' as 'new-resolution', | ||
123 | videoUUID: videoDatabase.uuid, | 149 | videoUUID: videoDatabase.uuid, |
124 | resolution | 150 | resolution |
125 | } | 151 | } |
@@ -149,27 +175,27 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: Video | |||
149 | if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) | 175 | if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) |
150 | if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase) | 176 | if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase) |
151 | 177 | ||
152 | await createHlsJobIfEnabled(Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution })) | 178 | const hlsPayload = Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution }) |
179 | await createHlsJobIfEnabled(hlsPayload) | ||
153 | } | 180 | } |
154 | 181 | ||
155 | // --------------------------------------------------------------------------- | 182 | // --------------------------------------------------------------------------- |
156 | 183 | ||
157 | export { | 184 | export { |
158 | processVideoTranscoding, | 185 | processVideoTranscoding, |
159 | publishVideoIfNeeded | 186 | publishNewResolutionIfNeeded |
160 | } | 187 | } |
161 | 188 | ||
162 | // --------------------------------------------------------------------------- | 189 | // --------------------------------------------------------------------------- |
163 | 190 | ||
164 | function createHlsJobIfEnabled (payload?: VideoTranscodingPayload) { | 191 | function createHlsJobIfEnabled (payload?: { videoUUID: string, resolution: number, isPortraitMode?: boolean }) { |
165 | // Generate HLS playlist? | 192 | // Generate HLS playlist? |
166 | if (payload && CONFIG.TRANSCODING.HLS.ENABLED) { | 193 | if (payload && CONFIG.TRANSCODING.HLS.ENABLED) { |
167 | const hlsTranscodingPayload = { | 194 | const hlsTranscodingPayload = { |
195 | type: 'hls' as 'hls', | ||
168 | videoUUID: payload.videoUUID, | 196 | videoUUID: payload.videoUUID, |
169 | resolution: payload.resolution, | 197 | resolution: payload.resolution, |
170 | isPortraitMode: payload.isPortraitMode, | 198 | isPortraitMode: payload.isPortraitMode |
171 | |||
172 | generateHlsPlaylist: true | ||
173 | } | 199 | } |
174 | 200 | ||
175 | return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload }) | 201 | return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload }) |
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index 950b14c3b..18bdcded4 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoFileModel } from '../models/video/video-file' | 1 | import { VideoFileModel } from '../models/video/video-file' |
2 | import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' | 2 | import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' |
3 | import { CONFIG } from '../initializers/config' | 3 | import { CONFIG } from '../initializers/config' |
4 | import { PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants' | 4 | import { PREVIEWS_SIZE, THUMBNAILS_SIZE, ASSETS_PATH } from '../initializers/constants' |
5 | import { VideoModel } from '../models/video/video' | 5 | import { VideoModel } from '../models/video/video' |
6 | import { ThumbnailModel } from '../models/video/thumbnail' | 6 | import { ThumbnailModel } from '../models/video/thumbnail' |
7 | import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' | 7 | import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' |
@@ -45,8 +45,10 @@ function createVideoMiniatureFromExisting (inputPath: string, video: VideoModel, | |||
45 | function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) { | 45 | function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) { |
46 | const input = video.getVideoFilePath(videoFile) | 46 | const input = video.getVideoFilePath(videoFile) |
47 | 47 | ||
48 | const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type) | 48 | const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type) |
49 | const thumbnailCreator = () => generateImageFromVideoFile(input, basePath, filename, { height, width }) | 49 | const thumbnailCreator = videoFile.isAudio() |
50 | ? () => processImage(ASSETS_PATH.DEFAULT_AUDIO_BACKGROUND, outputPath, { width, height }, true) | ||
51 | : () => generateImageFromVideoFile(input, basePath, filename, { height, width }) | ||
50 | 52 | ||
51 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail }) | 53 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail }) |
52 | } | 54 | } |
diff --git a/server/lib/user.ts b/server/lib/user.ts index 7badb3e72..d9fd89e15 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -13,7 +13,8 @@ import { UserNotificationSetting, UserNotificationSettingValue } from '../../sha | |||
13 | import { createWatchLaterPlaylist } from './video-playlist' | 13 | import { createWatchLaterPlaylist } from './video-playlist' |
14 | import { sequelizeTypescript } from '../initializers/database' | 14 | import { sequelizeTypescript } from '../initializers/database' |
15 | 15 | ||
16 | async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, validateUser = true) { | 16 | type ChannelNames = { name: string, displayName: string } |
17 | async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, channelNames?: ChannelNames, validateUser = true) { | ||
17 | const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { | 18 | const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { |
18 | const userOptions = { | 19 | const userOptions = { |
19 | transaction: t, | 20 | transaction: t, |
@@ -26,18 +27,8 @@ async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, | |||
26 | const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t) | 27 | const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t) |
27 | userCreated.Account = accountCreated | 28 | userCreated.Account = accountCreated |
28 | 29 | ||
29 | let channelName = userCreated.username + '_channel' | 30 | const channelAttributes = await buildChannelAttributes(userCreated, channelNames) |
30 | 31 | const videoChannel = await createVideoChannel(channelAttributes, accountCreated, t) | |
31 | // Conflict, generate uuid instead | ||
32 | const actor = await ActorModel.loadLocalByName(channelName) | ||
33 | if (actor) channelName = uuidv4() | ||
34 | |||
35 | const videoChannelDisplayName = `Main ${userCreated.username} channel` | ||
36 | const videoChannelInfo = { | ||
37 | name: channelName, | ||
38 | displayName: videoChannelDisplayName | ||
39 | } | ||
40 | const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t) | ||
41 | 32 | ||
42 | const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) | 33 | const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) |
43 | 34 | ||
@@ -116,3 +107,20 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Tr | |||
116 | 107 | ||
117 | return UserNotificationSettingModel.create(values, { transaction: t }) | 108 | return UserNotificationSettingModel.create(values, { transaction: t }) |
118 | } | 109 | } |
110 | |||
111 | async function buildChannelAttributes (user: UserModel, channelNames?: ChannelNames) { | ||
112 | if (channelNames) return channelNames | ||
113 | |||
114 | let channelName = user.username + '_channel' | ||
115 | |||
116 | // Conflict, generate uuid instead | ||
117 | const actor = await ActorModel.loadLocalByName(channelName) | ||
118 | if (actor) channelName = uuidv4() | ||
119 | |||
120 | const videoChannelDisplayName = `Main ${user.username} channel` | ||
121 | |||
122 | return { | ||
123 | name: channelName, | ||
124 | displayName: videoChannelDisplayName | ||
125 | } | ||
126 | } | ||
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index 0fe95ca09..ee0482c36 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts | |||
@@ -3,7 +3,8 @@ import * as uuidv4 from 'uuid/v4' | |||
3 | import { VideoChannelCreate } from '../../shared/models' | 3 | import { VideoChannelCreate } from '../../shared/models' |
4 | import { AccountModel } from '../models/account/account' | 4 | import { AccountModel } from '../models/account/account' |
5 | import { VideoChannelModel } from '../models/video/video-channel' | 5 | import { VideoChannelModel } from '../models/video/video-channel' |
6 | import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub' | 6 | import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub' |
7 | import { VideoModel } from '../models/video/video' | ||
7 | 8 | ||
8 | async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { | 9 | async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { |
9 | const uuid = uuidv4() | 10 | const uuid = uuidv4() |
@@ -33,8 +34,19 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account | |||
33 | return videoChannelCreated | 34 | return videoChannelCreated |
34 | } | 35 | } |
35 | 36 | ||
37 | async function federateAllVideosOfChannel (videoChannel: VideoChannelModel) { | ||
38 | const videoIds = await VideoModel.getAllIdsFromChannel(videoChannel) | ||
39 | |||
40 | for (const videoId of videoIds) { | ||
41 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) | ||
42 | |||
43 | await federateVideoIfNeeded(video, false) | ||
44 | } | ||
45 | } | ||
46 | |||
36 | // --------------------------------------------------------------------------- | 47 | // --------------------------------------------------------------------------- |
37 | 48 | ||
38 | export { | 49 | export { |
39 | createVideoChannel | 50 | createVideoChannel, |
51 | federateAllVideosOfChannel | ||
40 | } | 52 | } |
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index 0fe0ff12a..8d786e0ef 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' | 1 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' |
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils' | 3 | import { canDoQuickTranscode, getVideoFileFPS, transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' |
4 | import { ensureDir, move, remove, stat } from 'fs-extra' | 4 | import { ensureDir, move, remove, stat } from 'fs-extra' |
5 | import { logger } from '../helpers/logger' | 5 | import { logger } from '../helpers/logger' |
6 | import { VideoResolution } from '../../shared/models/videos' | 6 | import { VideoResolution } from '../../shared/models/videos' |
@@ -11,15 +11,24 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla | |||
11 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' | 11 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' |
12 | import { CONFIG } from '../initializers/config' | 12 | import { CONFIG } from '../initializers/config' |
13 | 13 | ||
14 | /** | ||
15 | * Optimize the original video file and replace it. The resolution is not changed. | ||
16 | */ | ||
14 | async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { | 17 | async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { |
15 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | 18 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR |
19 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | ||
16 | const newExtname = '.mp4' | 20 | const newExtname = '.mp4' |
17 | 21 | ||
18 | const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile() | 22 | const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile() |
19 | const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) | 23 | const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) |
20 | const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname) | 24 | const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname) |
21 | 25 | ||
22 | const transcodeOptions = { | 26 | const transcodeType: TranscodeOptionsType = await canDoQuickTranscode(videoInputPath) |
27 | ? 'quick-transcode' | ||
28 | : 'video' | ||
29 | |||
30 | const transcodeOptions: TranscodeOptions = { | ||
31 | type: transcodeType as any, // FIXME: typing issue | ||
23 | inputPath: videoInputPath, | 32 | inputPath: videoInputPath, |
24 | outputPath: videoTranscodedPath, | 33 | outputPath: videoTranscodedPath, |
25 | resolution: inputVideoFile.resolution | 34 | resolution: inputVideoFile.resolution |
@@ -32,18 +41,11 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi | |||
32 | await remove(videoInputPath) | 41 | await remove(videoInputPath) |
33 | 42 | ||
34 | // Important to do this before getVideoFilename() to take in account the new file extension | 43 | // Important to do this before getVideoFilename() to take in account the new file extension |
35 | inputVideoFile.set('extname', newExtname) | 44 | inputVideoFile.extname = newExtname |
36 | 45 | ||
37 | const videoOutputPath = video.getVideoFilePath(inputVideoFile) | 46 | const videoOutputPath = video.getVideoFilePath(inputVideoFile) |
38 | await move(videoTranscodedPath, videoOutputPath) | ||
39 | const stats = await stat(videoOutputPath) | ||
40 | const fps = await getVideoFileFPS(videoOutputPath) | ||
41 | 47 | ||
42 | inputVideoFile.set('size', stats.size) | 48 | await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) |
43 | inputVideoFile.set('fps', fps) | ||
44 | |||
45 | await video.createTorrentAndSetInfoHash(inputVideoFile) | ||
46 | await inputVideoFile.save() | ||
47 | } catch (err) { | 49 | } catch (err) { |
48 | // Auto destruction... | 50 | // Auto destruction... |
49 | video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err })) | 51 | video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err })) |
@@ -52,8 +54,12 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi | |||
52 | } | 54 | } |
53 | } | 55 | } |
54 | 56 | ||
57 | /** | ||
58 | * Transcode the original video file to a lower resolution. | ||
59 | */ | ||
55 | async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { | 60 | async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { |
56 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | 61 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR |
62 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | ||
57 | const extname = '.mp4' | 63 | const extname = '.mp4' |
58 | 64 | ||
59 | // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed | 65 | // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed |
@@ -66,27 +72,49 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR | |||
66 | videoId: video.id | 72 | videoId: video.id |
67 | }) | 73 | }) |
68 | const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile)) | 74 | const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile)) |
75 | const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile)) | ||
69 | 76 | ||
70 | const transcodeOptions = { | 77 | const transcodeOptions = { |
78 | type: 'video' as 'video', | ||
71 | inputPath: videoInputPath, | 79 | inputPath: videoInputPath, |
72 | outputPath: videoOutputPath, | 80 | outputPath: videoTranscodedPath, |
73 | resolution, | 81 | resolution, |
74 | isPortraitMode: isPortrait | 82 | isPortraitMode: isPortrait |
75 | } | 83 | } |
76 | 84 | ||
77 | await transcode(transcodeOptions) | 85 | await transcode(transcodeOptions) |
78 | 86 | ||
79 | const stats = await stat(videoOutputPath) | 87 | return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) |
80 | const fps = await getVideoFileFPS(videoOutputPath) | 88 | } |
89 | |||
90 | async function mergeAudioVideofile (video: VideoModel, resolution: VideoResolution) { | ||
91 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | ||
92 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | ||
93 | const newExtname = '.mp4' | ||
94 | |||
95 | const inputVideoFile = video.getOriginalFile() | ||
81 | 96 | ||
82 | newVideoFile.set('size', stats.size) | 97 | const audioInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile())) |
83 | newVideoFile.set('fps', fps) | 98 | const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname) |
84 | 99 | ||
85 | await video.createTorrentAndSetInfoHash(newVideoFile) | 100 | const transcodeOptions = { |
101 | type: 'merge-audio' as 'merge-audio', | ||
102 | inputPath: video.getPreview().getPath(), | ||
103 | outputPath: videoTranscodedPath, | ||
104 | audioPath: audioInputPath, | ||
105 | resolution | ||
106 | } | ||
107 | |||
108 | await transcode(transcodeOptions) | ||
86 | 109 | ||
87 | await newVideoFile.save() | 110 | await remove(audioInputPath) |
88 | 111 | ||
89 | video.VideoFiles.push(newVideoFile) | 112 | // Important to do this before getVideoFilename() to take in account the new file extension |
113 | inputVideoFile.extname = newExtname | ||
114 | |||
115 | const videoOutputPath = video.getVideoFilePath(inputVideoFile) | ||
116 | |||
117 | return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) | ||
90 | } | 118 | } |
91 | 119 | ||
92 | async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { | 120 | async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { |
@@ -97,6 +125,7 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti | |||
97 | const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution)) | 125 | const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution)) |
98 | 126 | ||
99 | const transcodeOptions = { | 127 | const transcodeOptions = { |
128 | type: 'hls' as 'hls', | ||
100 | inputPath: videoInputPath, | 129 | inputPath: videoInputPath, |
101 | outputPath, | 130 | outputPath, |
102 | resolution, | 131 | resolution, |
@@ -125,8 +154,34 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti | |||
125 | }) | 154 | }) |
126 | } | 155 | } |
127 | 156 | ||
157 | // --------------------------------------------------------------------------- | ||
158 | |||
128 | export { | 159 | export { |
129 | generateHlsPlaylist, | 160 | generateHlsPlaylist, |
130 | optimizeVideofile, | 161 | optimizeVideofile, |
131 | transcodeOriginalVideofile | 162 | transcodeOriginalVideofile, |
163 | mergeAudioVideofile | ||
164 | } | ||
165 | |||
166 | // --------------------------------------------------------------------------- | ||
167 | |||
168 | async function onVideoFileTranscoding (video: VideoModel, videoFile: VideoFileModel, transcodingPath: string, outputPath: string) { | ||
169 | const stats = await stat(transcodingPath) | ||
170 | const fps = await getVideoFileFPS(transcodingPath) | ||
171 | |||
172 | await move(transcodingPath, outputPath) | ||
173 | |||
174 | videoFile.set('size', stats.size) | ||
175 | videoFile.set('fps', fps) | ||
176 | |||
177 | await video.createTorrentAndSetInfoHash(videoFile) | ||
178 | |||
179 | const updatedVideoFile = await videoFile.save() | ||
180 | |||
181 | // Add it if this is a new created file | ||
182 | if (video.VideoFiles.some(f => f.id === videoFile.id) === false) { | ||
183 | video.VideoFiles.push(updatedVideoFile) | ||
184 | } | ||
185 | |||
186 | return video | ||
132 | } | 187 | } |
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts index e4f5c98fe..dd362619d 100644 --- a/server/middlewares/validators/feeds.ts +++ b/server/middlewares/validators/feeds.ts | |||
@@ -1,21 +1,20 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { param, query } from 'express-validator/check' | 2 | import { param, query } from 'express-validator/check' |
3 | import { doesAccountIdExist, isAccountNameValid, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' | 3 | import { doesAccountIdExist, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' |
4 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc' |
5 | import { logger } from '../../helpers/logger' | 5 | import { logger } from '../../helpers/logger' |
6 | import { areValidationErrors } from './utils' | 6 | import { areValidationErrors } from './utils' |
7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' | 7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' |
8 | import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' | 8 | import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' |
9 | import { doesVideoExist } from '../../helpers/custom-validators/videos' | 9 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
10 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' | ||
11 | 10 | ||
12 | const videoFeedsValidator = [ | 11 | const videoFeedsValidator = [ |
13 | param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), | 12 | param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), |
14 | query('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), | 13 | query('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), |
15 | query('accountId').optional().custom(isIdOrUUIDValid), | 14 | query('accountId').optional().custom(isIdValid), |
16 | query('accountName').optional().custom(isAccountNameValid), | 15 | query('accountName').optional(), |
17 | query('videoChannelId').optional().custom(isIdOrUUIDValid), | 16 | query('videoChannelId').optional().custom(isIdValid), |
18 | query('videoChannelName').optional().custom(isActorPreferredUsernameValid), | 17 | query('videoChannelName').optional(), |
19 | 18 | ||
20 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 19 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
21 | logger.debug('Checking feeds parameters', { parameters: req.query }) | 20 | logger.debug('Checking feeds parameters', { parameters: req.query }) |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 6d8cd7894..7a081af33 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -25,6 +25,10 @@ import { Redis } from '../../lib/redis' | |||
25 | import { UserModel } from '../../models/account/user' | 25 | import { UserModel } from '../../models/account/user' |
26 | import { areValidationErrors } from './utils' | 26 | import { areValidationErrors } from './utils' |
27 | import { ActorModel } from '../../models/activitypub/actor' | 27 | import { ActorModel } from '../../models/activitypub/actor' |
28 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' | ||
29 | import { isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' | ||
30 | import { UserCreate } from '../../../shared/models/users' | ||
31 | import { UserRegister } from '../../../shared/models/users/user-register.model' | ||
28 | 32 | ||
29 | const usersAddValidator = [ | 33 | const usersAddValidator = [ |
30 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), | 34 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), |
@@ -49,6 +53,8 @@ const usersRegisterValidator = [ | |||
49 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'), | 53 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'), |
50 | body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), | 54 | body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), |
51 | body('email').isEmail().withMessage('Should have a valid email'), | 55 | body('email').isEmail().withMessage('Should have a valid email'), |
56 | body('channel.name').optional().custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), | ||
57 | body('channel.displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), | ||
52 | 58 | ||
53 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 59 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
54 | logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') }) | 60 | logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') }) |
@@ -56,6 +62,28 @@ const usersRegisterValidator = [ | |||
56 | if (areValidationErrors(req, res)) return | 62 | if (areValidationErrors(req, res)) return |
57 | if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return | 63 | if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return |
58 | 64 | ||
65 | const body: UserRegister = req.body | ||
66 | if (body.channel) { | ||
67 | if (!body.channel.name || !body.channel.displayName) { | ||
68 | return res.status(400) | ||
69 | .send({ error: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' }) | ||
70 | .end() | ||
71 | } | ||
72 | |||
73 | if (body.channel.name === body.username) { | ||
74 | return res.status(400) | ||
75 | .send({ error: 'Channel name cannot be the same than user username.' }) | ||
76 | .end() | ||
77 | } | ||
78 | |||
79 | const existing = await ActorModel.loadLocalByName(body.channel.name) | ||
80 | if (existing) { | ||
81 | return res.status(409) | ||
82 | .send({ error: `Channel with name ${body.channel.name} already exists.` }) | ||
83 | .end() | ||
84 | } | ||
85 | } | ||
86 | |||
59 | return next() | 87 | return next() |
60 | } | 88 | } |
61 | ] | 89 | ] |
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts index 4b26f0bc4..f5a59cacb 100644 --- a/server/middlewares/validators/videos/video-channels.ts +++ b/server/middlewares/validators/videos/video-channels.ts | |||
@@ -14,6 +14,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel' | |||
14 | import { areValidationErrors } from '../utils' | 14 | import { areValidationErrors } from '../utils' |
15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' | 15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' |
16 | import { ActorModel } from '../../../models/activitypub/actor' | 16 | import { ActorModel } from '../../../models/activitypub/actor' |
17 | import { isBooleanValid } from '../../../helpers/custom-validators/misc' | ||
17 | 18 | ||
18 | const videoChannelsAddValidator = [ | 19 | const videoChannelsAddValidator = [ |
19 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), | 20 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), |
@@ -40,9 +41,18 @@ const videoChannelsAddValidator = [ | |||
40 | 41 | ||
41 | const videoChannelsUpdateValidator = [ | 42 | const videoChannelsUpdateValidator = [ |
42 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), | 43 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), |
43 | body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), | 44 | body('displayName') |
44 | body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), | 45 | .optional() |
45 | body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), | 46 | .custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), |
47 | body('description') | ||
48 | .optional() | ||
49 | .custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), | ||
50 | body('support') | ||
51 | .optional() | ||
52 | .custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), | ||
53 | body('bulkVideosSupportUpdate') | ||
54 | .optional() | ||
55 | .custom(isBooleanValid).withMessage('Should have a valid bulkVideosSupportUpdate boolean field'), | ||
46 | 56 | ||
47 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 57 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
48 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) | 58 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) |
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts index f68eeeeb3..9c88dd291 100644 --- a/server/middlewares/validators/videos/video-playlists.ts +++ b/server/middlewares/validators/videos/video-playlists.ts | |||
@@ -24,6 +24,9 @@ import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/ | |||
24 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' | 24 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' |
25 | 25 | ||
26 | const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ | 26 | const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ |
27 | body('displayName') | ||
28 | .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'), | ||
29 | |||
27 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 30 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
28 | logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body }) | 31 | logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body }) |
29 | 32 | ||
@@ -46,6 +49,10 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([ | |||
46 | param('playlistId') | 49 | param('playlistId') |
47 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | 50 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), |
48 | 51 | ||
52 | body('displayName') | ||
53 | .optional() | ||
54 | .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'), | ||
55 | |||
49 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 56 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
50 | logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body }) | 57 | logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body }) |
51 | 58 | ||
@@ -61,12 +68,6 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([ | |||
61 | 68 | ||
62 | const body: VideoPlaylistUpdate = req.body | 69 | const body: VideoPlaylistUpdate = req.body |
63 | 70 | ||
64 | if (videoPlaylist.privacy !== VideoPlaylistPrivacy.PRIVATE && body.privacy === VideoPlaylistPrivacy.PRIVATE) { | ||
65 | cleanUpReqFiles(req) | ||
66 | return res.status(400) | ||
67 | .json({ error: 'Cannot set "private" a video playlist that was not private.' }) | ||
68 | } | ||
69 | |||
70 | const newPrivacy = body.privacy || videoPlaylist.privacy | 71 | const newPrivacy = body.privacy || videoPlaylist.privacy |
71 | if (newPrivacy === VideoPlaylistPrivacy.PUBLIC && | 72 | if (newPrivacy === VideoPlaylistPrivacy.PUBLIC && |
72 | ( | 73 | ( |
@@ -368,8 +369,6 @@ function getCommonPlaylistEditAttributes () { | |||
368 | + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') | 369 | + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') |
369 | ), | 370 | ), |
370 | 371 | ||
371 | body('displayName') | ||
372 | .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'), | ||
373 | body('description') | 372 | body('description') |
374 | .optional() | 373 | .optional() |
375 | .customSanitizer(toValueOrNull) | 374 | .customSanitizer(toValueOrNull) |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 2b01f108d..b1c05ab2d 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -111,18 +111,10 @@ const videosUpdateValidator = getCommonVideoEditAttributes().concat([ | |||
111 | if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req) | 111 | if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req) |
112 | if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req) | 112 | if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req) |
113 | 113 | ||
114 | const video = res.locals.video | ||
115 | |||
116 | // Check if the user who did the request is able to update the video | 114 | // Check if the user who did the request is able to update the video |
117 | const user = res.locals.oauth.token.User | 115 | const user = res.locals.oauth.token.User |
118 | if (!checkUserCanManageVideo(user, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req) | 116 | if (!checkUserCanManageVideo(user, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req) |
119 | 117 | ||
120 | if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) { | ||
121 | cleanUpReqFiles(req) | ||
122 | return res.status(409) | ||
123 | .json({ error: 'Cannot set "private" a video that was not private.' }) | ||
124 | } | ||
125 | |||
126 | if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) | 118 | if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) |
127 | 119 | ||
128 | return next() | 120 | return next() |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 2b04acd86..09cada096 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -47,7 +47,7 @@ export enum ScopeNames { | |||
47 | attributes: [ 'id', 'name' ], | 47 | attributes: [ 'id', 'name' ], |
48 | include: [ | 48 | include: [ |
49 | { | 49 | { |
50 | attributes: [ 'id', 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ], | 50 | attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ], |
51 | model: ActorModel.unscoped(), | 51 | model: ActorModel.unscoped(), |
52 | required: true, | 52 | required: true, |
53 | where: whereActor, | 53 | where: whereActor, |
@@ -180,22 +180,6 @@ export class AccountModel extends Model<AccountModel> { | |||
180 | return AccountModel.findByPk(id, { transaction }) | 180 | return AccountModel.findByPk(id, { transaction }) |
181 | } | 181 | } |
182 | 182 | ||
183 | static loadByUUID (uuid: string) { | ||
184 | const query = { | ||
185 | include: [ | ||
186 | { | ||
187 | model: ActorModel, | ||
188 | required: true, | ||
189 | where: { | ||
190 | uuid | ||
191 | } | ||
192 | } | ||
193 | ] | ||
194 | } | ||
195 | |||
196 | return AccountModel.findOne(query) | ||
197 | } | ||
198 | |||
199 | static loadByNameWithHost (nameWithHost: string) { | 183 | static loadByNameWithHost (nameWithHost: string) { |
200 | const [ accountName, host ] = nameWithHost.split('@') | 184 | const [ accountName, host ] = nameWithHost.split('@') |
201 | 185 | ||
@@ -332,7 +316,6 @@ export class AccountModel extends Model<AccountModel> { | |||
332 | 316 | ||
333 | return { | 317 | return { |
334 | id: this.id, | 318 | id: this.id, |
335 | uuid: actor.uuid, | ||
336 | name: actor.name, | 319 | name: actor.name, |
337 | displayName: this.getDisplayName(), | 320 | displayName: this.getDisplayName(), |
338 | url: actor.url, | 321 | url: actor.url, |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 4a466441c..bd6a2c8fd 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -7,13 +7,11 @@ import { | |||
7 | Column, | 7 | Column, |
8 | CreatedAt, | 8 | CreatedAt, |
9 | DataType, | 9 | DataType, |
10 | Default, | ||
11 | DefaultScope, | 10 | DefaultScope, |
12 | ForeignKey, | 11 | ForeignKey, |
13 | HasMany, | 12 | HasMany, |
14 | HasOne, | 13 | HasOne, |
15 | Is, | 14 | Is, |
16 | IsUUID, | ||
17 | Model, | 15 | Model, |
18 | Scopes, | 16 | Scopes, |
19 | Table, | 17 | Table, |
@@ -120,10 +118,6 @@ export const unusedActorAttributesForAPI = [ | |||
120 | fields: [ 'avatarId' ] | 118 | fields: [ 'avatarId' ] |
121 | }, | 119 | }, |
122 | { | 120 | { |
123 | fields: [ 'uuid' ], | ||
124 | unique: true | ||
125 | }, | ||
126 | { | ||
127 | fields: [ 'followersUrl' ] | 121 | fields: [ 'followersUrl' ] |
128 | } | 122 | } |
129 | ] | 123 | ] |
@@ -135,12 +129,6 @@ export class ActorModel extends Model<ActorModel> { | |||
135 | type: ActivityPubActorType | 129 | type: ActivityPubActorType |
136 | 130 | ||
137 | @AllowNull(false) | 131 | @AllowNull(false) |
138 | @Default(DataType.UUIDV4) | ||
139 | @IsUUID(4) | ||
140 | @Column(DataType.UUID) | ||
141 | uuid: string | ||
142 | |||
143 | @AllowNull(false) | ||
144 | @Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username')) | 132 | @Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username')) |
145 | @Column | 133 | @Column |
146 | preferredUsername: string | 134 | preferredUsername: string |
@@ -408,7 +396,6 @@ export class ActorModel extends Model<ActorModel> { | |||
408 | return { | 396 | return { |
409 | id: this.id, | 397 | id: this.id, |
410 | url: this.url, | 398 | url: this.url, |
411 | uuid: this.uuid, | ||
412 | name: this.preferredUsername, | 399 | name: this.preferredUsername, |
413 | host: this.getHost(), | 400 | host: this.getHost(), |
414 | hostRedundancyAllowed: this.getRedundancyAllowed(), | 401 | hostRedundancyAllowed: this.getRedundancyAllowed(), |
@@ -454,7 +441,6 @@ export class ActorModel extends Model<ActorModel> { | |||
454 | endpoints: { | 441 | endpoints: { |
455 | sharedInbox: this.sharedInboxUrl | 442 | sharedInbox: this.sharedInboxUrl |
456 | }, | 443 | }, |
457 | uuid: this.uuid, | ||
458 | publicKey: { | 444 | publicKey: { |
459 | id: this.getPublicKeyUrl(), | 445 | id: this.getPublicKeyUrl(), |
460 | owner: this.url, | 446 | owner: this.url, |
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index 206e9a3d6..8faf0adba 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts | |||
@@ -107,10 +107,12 @@ export class ThumbnailModel extends Model<ThumbnailModel> { | |||
107 | return WEBSERVER.URL + staticPath + this.filename | 107 | return WEBSERVER.URL + staticPath + this.filename |
108 | } | 108 | } |
109 | 109 | ||
110 | removeThumbnail () { | 110 | getPath () { |
111 | const directory = ThumbnailModel.types[this.type].directory | 111 | const directory = ThumbnailModel.types[this.type].directory |
112 | const thumbnailPath = join(directory, this.filename) | 112 | return join(directory, this.filename) |
113 | } | ||
113 | 114 | ||
114 | return remove(thumbnailPath) | 115 | removeThumbnail () { |
116 | return remove(this.getPath()) | ||
115 | } | 117 | } |
116 | } | 118 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index fb70e6625..b0b261c88 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -72,7 +72,7 @@ type AvailableForListOptions = { | |||
72 | attributes: [ 'name', 'description', 'id', 'actorId' ], | 72 | attributes: [ 'name', 'description', 'id', 'actorId' ], |
73 | include: [ | 73 | include: [ |
74 | { | 74 | { |
75 | attributes: [ 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ], | 75 | attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ], |
76 | model: ActorModel.unscoped(), | 76 | model: ActorModel.unscoped(), |
77 | required: true, | 77 | required: true, |
78 | include: [ | 78 | include: [ |
@@ -334,14 +334,21 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
334 | }) | 334 | }) |
335 | } | 335 | } |
336 | 336 | ||
337 | static listByAccount (accountId: number) { | 337 | static listByAccount (options: { |
338 | accountId: number, | ||
339 | start: number, | ||
340 | count: number, | ||
341 | sort: string | ||
342 | }) { | ||
338 | const query = { | 343 | const query = { |
339 | order: getSort('createdAt'), | 344 | offset: options.start, |
345 | limit: options.count, | ||
346 | order: getSort(options.sort), | ||
340 | include: [ | 347 | include: [ |
341 | { | 348 | { |
342 | model: AccountModel, | 349 | model: AccountModel, |
343 | where: { | 350 | where: { |
344 | id: accountId | 351 | id: options.accountId |
345 | }, | 352 | }, |
346 | required: true | 353 | required: true |
347 | } | 354 | } |
@@ -380,24 +387,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
380 | .findByPk(id) | 387 | .findByPk(id) |
381 | } | 388 | } |
382 | 389 | ||
383 | static loadByUUIDAndPopulateAccount (uuid: string) { | ||
384 | const query = { | ||
385 | include: [ | ||
386 | { | ||
387 | model: ActorModel, | ||
388 | required: true, | ||
389 | where: { | ||
390 | uuid | ||
391 | } | ||
392 | } | ||
393 | ] | ||
394 | } | ||
395 | |||
396 | return VideoChannelModel | ||
397 | .scope([ ScopeNames.WITH_ACCOUNT ]) | ||
398 | .findOne(query) | ||
399 | } | ||
400 | |||
401 | static loadByUrlAndPopulateAccount (url: string) { | 390 | static loadByUrlAndPopulateAccount (url: string) { |
402 | const query = { | 391 | const query = { |
403 | include: [ | 392 | include: [ |
@@ -503,7 +492,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
503 | 492 | ||
504 | return { | 493 | return { |
505 | id: this.id, | 494 | id: this.id, |
506 | uuid: actor.uuid, | ||
507 | name: actor.name, | 495 | name: actor.name, |
508 | displayName: this.getDisplayName(), | 496 | displayName: this.getDisplayName(), |
509 | url: actor.url, | 497 | url: actor.url, |
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 2203a7aba..05c490759 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -24,6 +24,7 @@ import { VideoModel } from './video' | |||
24 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 24 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' | 26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' |
27 | import { MIMETYPES } from '../../initializers/constants' | ||
27 | 28 | ||
28 | @Table({ | 29 | @Table({ |
29 | tableName: 'videoFile', | 30 | tableName: 'videoFile', |
@@ -161,6 +162,10 @@ export class VideoFileModel extends Model<VideoFileModel> { | |||
161 | })) | 162 | })) |
162 | } | 163 | } |
163 | 164 | ||
165 | isAudio () { | ||
166 | return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname] | ||
167 | } | ||
168 | |||
164 | hasSameUniqueKeysThan (other: VideoFileModel) { | 169 | hasSameUniqueKeysThan (other: VideoFileModel) { |
165 | return this.fps === other.fps && | 170 | return this.fps === other.fps && |
166 | this.resolution === other.resolution && | 171 | this.resolution === other.resolution && |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index c0a7892a4..eccf0a4fa 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1515,6 +1515,29 @@ export class VideoModel extends Model<VideoModel> { | |||
1515 | .then(results => results.length === 1) | 1515 | .then(results => results.length === 1) |
1516 | } | 1516 | } |
1517 | 1517 | ||
1518 | static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) { | ||
1519 | const options = { | ||
1520 | where: { | ||
1521 | channelId: videoChannel.id | ||
1522 | }, | ||
1523 | transaction: t | ||
1524 | } | ||
1525 | |||
1526 | return VideoModel.update({ support: videoChannel.support }, options) | ||
1527 | } | ||
1528 | |||
1529 | static getAllIdsFromChannel (videoChannel: VideoChannelModel) { | ||
1530 | const query = { | ||
1531 | attributes: [ 'id' ], | ||
1532 | where: { | ||
1533 | channelId: videoChannel.id | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | return VideoModel.findAll(query) | ||
1538 | .then(videos => videos.map(v => v.id)) | ||
1539 | } | ||
1540 | |||
1518 | // threshold corresponds to how many video the field should have to be returned | 1541 | // threshold corresponds to how many video the field should have to be returned |
1519 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { | 1542 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { |
1520 | const serverActor = await getServerActor() | 1543 | const serverActor = await getServerActor() |
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts index edf588c16..34c6be49b 100644 --- a/server/tests/api/activitypub/client.ts +++ b/server/tests/api/activitypub/client.ts | |||
@@ -3,6 +3,7 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | doubleFollow, | 7 | doubleFollow, |
7 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
8 | flushTests, | 9 | flushTests, |
@@ -39,7 +40,7 @@ describe('Test activitypub', function () { | |||
39 | const object = res.body | 40 | const object = res.body |
40 | 41 | ||
41 | expect(object.type).to.equal('Person') | 42 | expect(object.type).to.equal('Person') |
42 | expect(object.id).to.equal('http://localhost:9001/accounts/root') | 43 | expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root') |
43 | expect(object.name).to.equal('root') | 44 | expect(object.name).to.equal('root') |
44 | expect(object.preferredUsername).to.equal('root') | 45 | expect(object.preferredUsername).to.equal('root') |
45 | }) | 46 | }) |
@@ -49,17 +50,17 @@ describe('Test activitypub', function () { | |||
49 | const object = res.body | 50 | const object = res.body |
50 | 51 | ||
51 | expect(object.type).to.equal('Video') | 52 | expect(object.type).to.equal('Video') |
52 | expect(object.id).to.equal('http://localhost:9001/videos/watch/' + videoUUID) | 53 | expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID) |
53 | expect(object.name).to.equal('video') | 54 | expect(object.name).to.equal('video') |
54 | }) | 55 | }) |
55 | 56 | ||
56 | it('Should redirect to the origin video object', async function () { | 57 | it('Should redirect to the origin video object', async function () { |
57 | const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302) | 58 | const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302) |
58 | 59 | ||
59 | expect(res.header.location).to.equal('http://localhost:9001/videos/watch/' + videoUUID) | 60 | expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID) |
60 | }) | 61 | }) |
61 | 62 | ||
62 | after(function () { | 63 | after(async function () { |
63 | killallServers(servers) | 64 | await cleanupTests(servers) |
64 | }) | 65 | }) |
65 | }) | 66 | }) |
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts index 7240bb0fb..3a1c0d321 100644 --- a/server/tests/api/activitypub/fetch.ts +++ b/server/tests/api/activitypub/fetch.ts | |||
@@ -3,6 +3,7 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | closeAllSequelize, | 7 | closeAllSequelize, |
7 | createUser, | 8 | createUser, |
8 | doubleFollow, | 9 | doubleFollow, |
@@ -48,8 +49,16 @@ describe('Test ActivityPub fetcher', function () { | |||
48 | const badVideoUUID = res.body.video.uuid | 49 | const badVideoUUID = res.body.video.uuid |
49 | await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' }) | 50 | await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' }) |
50 | 51 | ||
51 | await setActorField(1, 'http://localhost:9001/accounts/user1', 'url', 'http://localhost:9002/accounts/user1') | 52 | { |
52 | await setVideoField(1, badVideoUUID, 'url', 'http://localhost:9003/videos/watch/' + badVideoUUID) | 53 | const to = 'http://localhost:' + servers[0].port + '/accounts/user1' |
54 | const value = 'http://localhost:' + servers[1].port + '/accounts/user1' | ||
55 | await setActorField(servers[0].internalServerNumber, to, 'url', value) | ||
56 | } | ||
57 | |||
58 | { | ||
59 | const value = 'http://localhost:' + servers[2].port + '/videos/watch/' + badVideoUUID | ||
60 | await setVideoField(servers[0].internalServerNumber, badVideoUUID, 'url', value) | ||
61 | } | ||
53 | }) | 62 | }) |
54 | 63 | ||
55 | it('Should add only the video with a valid actor URL', async function () { | 64 | it('Should add only the video with a valid actor URL', async function () { |
@@ -78,7 +87,9 @@ describe('Test ActivityPub fetcher', function () { | |||
78 | }) | 87 | }) |
79 | 88 | ||
80 | after(async function () { | 89 | after(async function () { |
81 | killallServers(servers) | 90 | this.timeout(10000) |
91 | |||
92 | await cleanupTests(servers) | ||
82 | 93 | ||
83 | await closeAllSequelize(servers) | 94 | await closeAllSequelize(servers) |
84 | }) | 95 | }) |
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts index 9be9aa495..921ee874c 100644 --- a/server/tests/api/activitypub/refresher.ts +++ b/server/tests/api/activitypub/refresher.ts | |||
@@ -2,13 +2,14 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
5 | cleanupTests, closeAllSequelize, | ||
5 | createVideoPlaylist, | 6 | createVideoPlaylist, |
6 | doubleFollow, | 7 | doubleFollow, |
7 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
8 | generateUserAccessToken, | 9 | generateUserAccessToken, |
9 | getVideo, | 10 | getVideo, |
10 | getVideoPlaylist, | 11 | getVideoPlaylist, |
11 | killallServers, rateVideo, | 12 | killallServers, |
12 | reRunServer, | 13 | reRunServer, |
13 | ServerInfo, | 14 | ServerInfo, |
14 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
@@ -48,26 +49,26 @@ describe('Test AP refresher', function () { | |||
48 | } | 49 | } |
49 | 50 | ||
50 | { | 51 | { |
51 | const a1 = await generateUserAccessToken(servers[1], 'user1') | 52 | const a1 = await generateUserAccessToken(servers[ 1 ], 'user1') |
52 | await uploadVideo(servers[1].url, a1, { name: 'video4' }) | 53 | await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' }) |
53 | 54 | ||
54 | const a2 = await generateUserAccessToken(servers[1], 'user2') | 55 | const a2 = await generateUserAccessToken(servers[ 1 ], 'user2') |
55 | await uploadVideo(servers[1].url, a2, { name: 'video5' }) | 56 | await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' }) |
56 | } | 57 | } |
57 | 58 | ||
58 | { | 59 | { |
59 | const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } | 60 | const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } |
60 | const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) | 61 | const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) |
61 | playlistUUID1 = res.body.videoPlaylist.uuid | 62 | playlistUUID1 = res.body.videoPlaylist.uuid |
62 | } | 63 | } |
63 | 64 | ||
64 | { | 65 | { |
65 | const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } | 66 | const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } |
66 | const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) | 67 | const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) |
67 | playlistUUID2 = res.body.videoPlaylist.uuid | 68 | playlistUUID2 = res.body.videoPlaylist.uuid |
68 | } | 69 | } |
69 | 70 | ||
70 | await doubleFollow(servers[0], servers[1]) | 71 | await doubleFollow(servers[ 0 ], servers[ 1 ]) |
71 | }) | 72 | }) |
72 | 73 | ||
73 | describe('Videos refresher', function () { | 74 | describe('Videos refresher', function () { |
@@ -78,7 +79,7 @@ describe('Test AP refresher', function () { | |||
78 | await wait(10000) | 79 | await wait(10000) |
79 | 80 | ||
80 | // Change UUID so the remote server returns a 404 | 81 | // Change UUID so the remote server returns a 404 |
81 | await setVideoField(2, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') | 82 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') |
82 | 83 | ||
83 | await getVideo(servers[ 0 ].url, videoUUID1) | 84 | await getVideo(servers[ 0 ].url, videoUUID1) |
84 | await getVideo(servers[ 0 ].url, videoUUID2) | 85 | await getVideo(servers[ 0 ].url, videoUUID2) |
@@ -94,7 +95,7 @@ describe('Test AP refresher', function () { | |||
94 | 95 | ||
95 | killallServers([ servers[ 1 ] ]) | 96 | killallServers([ servers[ 1 ] ]) |
96 | 97 | ||
97 | await setVideoField(2, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') | 98 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') |
98 | 99 | ||
99 | // Video will need a refresh | 100 | // Video will need a refresh |
100 | await wait(10000) | 101 | await wait(10000) |
@@ -121,15 +122,16 @@ describe('Test AP refresher', function () { | |||
121 | await wait(10000) | 122 | await wait(10000) |
122 | 123 | ||
123 | // Change actor name so the remote server returns a 404 | 124 | // Change actor name so the remote server returns a 404 |
124 | await setActorField(2, 'http://localhost:9002/accounts/user2', 'preferredUsername', 'toto') | 125 | const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2' |
126 | await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto') | ||
125 | 127 | ||
126 | await getAccount(servers[ 0 ].url, 'user1@localhost:9002') | 128 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port) |
127 | await getAccount(servers[ 0 ].url, 'user2@localhost:9002') | 129 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port) |
128 | 130 | ||
129 | await waitJobs(servers) | 131 | await waitJobs(servers) |
130 | 132 | ||
131 | await getAccount(servers[ 0 ].url, 'user1@localhost:9002', 200) | 133 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200) |
132 | await getAccount(servers[ 0 ].url, 'user2@localhost:9002', 404) | 134 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404) |
133 | }) | 135 | }) |
134 | }) | 136 | }) |
135 | 137 | ||
@@ -141,7 +143,7 @@ describe('Test AP refresher', function () { | |||
141 | await wait(10000) | 143 | await wait(10000) |
142 | 144 | ||
143 | // Change UUID so the remote server returns a 404 | 145 | // Change UUID so the remote server returns a 404 |
144 | await setPlaylistField(2, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') | 146 | await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') |
145 | 147 | ||
146 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) | 148 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) |
147 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) | 149 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) |
@@ -153,7 +155,11 @@ describe('Test AP refresher', function () { | |||
153 | }) | 155 | }) |
154 | }) | 156 | }) |
155 | 157 | ||
156 | after(function () { | 158 | after(async function () { |
157 | killallServers(servers) | 159 | this.timeout(10000) |
160 | |||
161 | await cleanupTests(servers) | ||
162 | |||
163 | await closeAllSequelize(servers) | ||
158 | }) | 164 | }) |
159 | }) | 165 | }) |
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index 11e6859bf..dc960c5c3 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts | |||
@@ -3,9 +3,9 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | closeAllSequelize, | 7 | closeAllSequelize, |
7 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
8 | flushTests, | ||
9 | killallServers, | 9 | killallServers, |
10 | ServerInfo, | 10 | ServerInfo, |
11 | setActorField | 11 | setActorField |
@@ -18,18 +18,26 @@ import { makeFollowRequest, makePOSTAPRequest } from '../../../../shared/extra-u | |||
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
21 | function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) { | 21 | function setKeysOfServer (onServer: ServerInfo, ofServer: ServerInfo, publicKey: string, privateKey: string) { |
22 | return Promise.all([ | 22 | return Promise.all([ |
23 | setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey), | 23 | setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'publicKey', publicKey), |
24 | setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey) | 24 | setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'privateKey', privateKey) |
25 | ]) | 25 | ]) |
26 | } | 26 | } |
27 | 27 | ||
28 | function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) { | 28 | function getAnnounceWithoutContext (server2: ServerInfo) { |
29 | return Promise.all([ | 29 | const json = require('./json/peertube/announce-without-context.json') |
30 | setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey), | 30 | const result: typeof json = {} |
31 | setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey) | 31 | |
32 | ]) | 32 | for (const key of Object.keys(json)) { |
33 | if (Array.isArray(json[key])) { | ||
34 | result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) | ||
35 | } else { | ||
36 | result[ key ] = json[ key ].replace(':9002', `:${server2.port}`) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return result | ||
33 | } | 41 | } |
34 | 42 | ||
35 | describe('Test ActivityPub security', function () { | 43 | describe('Test ActivityPub security', function () { |
@@ -38,13 +46,13 @@ describe('Test ActivityPub security', function () { | |||
38 | 46 | ||
39 | const keys = require('./json/peertube/keys.json') | 47 | const keys = require('./json/peertube/keys.json') |
40 | const invalidKeys = require('./json/peertube/invalid-keys.json') | 48 | const invalidKeys = require('./json/peertube/invalid-keys.json') |
41 | const baseHttpSignature = { | 49 | const baseHttpSignature = () => ({ |
42 | algorithm: HTTP_SIGNATURE.ALGORITHM, | 50 | algorithm: HTTP_SIGNATURE.ALGORITHM, |
43 | authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, | 51 | authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, |
44 | keyId: 'acct:peertube@localhost:9002', | 52 | keyId: 'acct:peertube@localhost:' + servers[1].port, |
45 | key: keys.privateKey, | 53 | key: keys.privateKey, |
46 | headers: HTTP_SIGNATURE.HEADERS_TO_SIGN | 54 | headers: HTTP_SIGNATURE.HEADERS_TO_SIGN |
47 | } | 55 | }) |
48 | 56 | ||
49 | // --------------------------------------------------------------- | 57 | // --------------------------------------------------------------- |
50 | 58 | ||
@@ -55,56 +63,56 @@ describe('Test ActivityPub security', function () { | |||
55 | 63 | ||
56 | url = servers[0].url + '/inbox' | 64 | url = servers[0].url + '/inbox' |
57 | 65 | ||
58 | await setKeysOfServer2(1, keys.publicKey, keys.privateKey) | 66 | await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey) |
59 | 67 | ||
60 | const to = { url: 'http://localhost:9001/accounts/peertube' } | 68 | const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' } |
61 | const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } | 69 | const by = { url: 'http://localhost:' + servers[1].port + '/accounts/peertube', privateKey: keys.privateKey } |
62 | await makeFollowRequest(to, by) | 70 | await makeFollowRequest(to, by) |
63 | }) | 71 | }) |
64 | 72 | ||
65 | describe('When checking HTTP signature', function () { | 73 | describe('When checking HTTP signature', function () { |
66 | 74 | ||
67 | it('Should fail with an invalid digest', async function () { | 75 | it('Should fail with an invalid digest', async function () { |
68 | const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) | 76 | const body = activityPubContextify(getAnnounceWithoutContext(servers[1])) |
69 | const headers = { | 77 | const headers = { |
70 | Digest: buildDigest({ hello: 'coucou' }) | 78 | Digest: buildDigest({ hello: 'coucou' }) |
71 | } | 79 | } |
72 | 80 | ||
73 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) | 81 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers) |
74 | 82 | ||
75 | expect(response.statusCode).to.equal(403) | 83 | expect(response.statusCode).to.equal(403) |
76 | }) | 84 | }) |
77 | 85 | ||
78 | it('Should fail with an invalid date', async function () { | 86 | it('Should fail with an invalid date', async function () { |
79 | const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) | 87 | const body = activityPubContextify(getAnnounceWithoutContext(servers[1])) |
80 | const headers = buildGlobalHeaders(body) | 88 | const headers = buildGlobalHeaders(body) |
81 | headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' | 89 | headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' |
82 | 90 | ||
83 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) | 91 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers) |
84 | 92 | ||
85 | expect(response.statusCode).to.equal(403) | 93 | expect(response.statusCode).to.equal(403) |
86 | }) | 94 | }) |
87 | 95 | ||
88 | it('Should fail with bad keys', async function () { | 96 | it('Should fail with bad keys', async function () { |
89 | await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey) | 97 | await setKeysOfServer(servers[0], servers[1], invalidKeys.publicKey, invalidKeys.privateKey) |
90 | await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey) | 98 | await setKeysOfServer(servers[1], servers[1], invalidKeys.publicKey, invalidKeys.privateKey) |
91 | 99 | ||
92 | const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) | 100 | const body = activityPubContextify(getAnnounceWithoutContext(servers[1])) |
93 | const headers = buildGlobalHeaders(body) | 101 | const headers = buildGlobalHeaders(body) |
94 | 102 | ||
95 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) | 103 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers) |
96 | 104 | ||
97 | expect(response.statusCode).to.equal(403) | 105 | expect(response.statusCode).to.equal(403) |
98 | }) | 106 | }) |
99 | 107 | ||
100 | it('Should succeed with a valid HTTP signature', async function () { | 108 | it('Should succeed with a valid HTTP signature', async function () { |
101 | await setKeysOfServer2(1, keys.publicKey, keys.privateKey) | 109 | await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey) |
102 | await setKeysOfServer2(2, keys.publicKey, keys.privateKey) | 110 | await setKeysOfServer(servers[1], servers[1], keys.publicKey, keys.privateKey) |
103 | 111 | ||
104 | const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) | 112 | const body = activityPubContextify(getAnnounceWithoutContext(servers[1])) |
105 | const headers = buildGlobalHeaders(body) | 113 | const headers = buildGlobalHeaders(body) |
106 | 114 | ||
107 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) | 115 | const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers) |
108 | 116 | ||
109 | expect(response.statusCode).to.equal(204) | 117 | expect(response.statusCode).to.equal(204) |
110 | }) | 118 | }) |
@@ -112,28 +120,28 @@ describe('Test ActivityPub security', function () { | |||
112 | 120 | ||
113 | describe('When checking Linked Data Signature', function () { | 121 | describe('When checking Linked Data Signature', function () { |
114 | before(async () => { | 122 | before(async () => { |
115 | await setKeysOfServer3(3, keys.publicKey, keys.privateKey) | 123 | await setKeysOfServer(servers[2], servers[2], keys.publicKey, keys.privateKey) |
116 | 124 | ||
117 | const to = { url: 'http://localhost:9001/accounts/peertube' } | 125 | const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' } |
118 | const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey } | 126 | const by = { url: 'http://localhost:' + servers[2].port + '/accounts/peertube', privateKey: keys.privateKey } |
119 | await makeFollowRequest(to, by) | 127 | await makeFollowRequest(to, by) |
120 | }) | 128 | }) |
121 | 129 | ||
122 | it('Should fail with bad keys', async function () { | 130 | it('Should fail with bad keys', async function () { |
123 | this.timeout(10000) | 131 | this.timeout(10000) |
124 | 132 | ||
125 | await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey) | 133 | await setKeysOfServer(servers[0], servers[2], invalidKeys.publicKey, invalidKeys.privateKey) |
126 | await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey) | 134 | await setKeysOfServer(servers[2], servers[2], invalidKeys.publicKey, invalidKeys.privateKey) |
127 | 135 | ||
128 | const body = require('./json/peertube/announce-without-context.json') | 136 | const body = getAnnounceWithoutContext(servers[1]) |
129 | body.actor = 'http://localhost:9003/accounts/peertube' | 137 | body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube' |
130 | 138 | ||
131 | const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' } | 139 | const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' } |
132 | const signedBody = await buildSignedActivity(signer, body) | 140 | const signedBody = await buildSignedActivity(signer, body) |
133 | 141 | ||
134 | const headers = buildGlobalHeaders(signedBody) | 142 | const headers = buildGlobalHeaders(signedBody) |
135 | 143 | ||
136 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) | 144 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) |
137 | 145 | ||
138 | expect(response.statusCode).to.equal(403) | 146 | expect(response.statusCode).to.equal(403) |
139 | }) | 147 | }) |
@@ -141,20 +149,20 @@ describe('Test ActivityPub security', function () { | |||
141 | it('Should fail with an altered body', async function () { | 149 | it('Should fail with an altered body', async function () { |
142 | this.timeout(10000) | 150 | this.timeout(10000) |
143 | 151 | ||
144 | await setKeysOfServer3(1, keys.publicKey, keys.privateKey) | 152 | await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey) |
145 | await setKeysOfServer3(3, keys.publicKey, keys.privateKey) | 153 | await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey) |
146 | 154 | ||
147 | const body = require('./json/peertube/announce-without-context.json') | 155 | const body = getAnnounceWithoutContext(servers[1]) |
148 | body.actor = 'http://localhost:9003/accounts/peertube' | 156 | body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube' |
149 | 157 | ||
150 | const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } | 158 | const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' } |
151 | const signedBody = await buildSignedActivity(signer, body) | 159 | const signedBody = await buildSignedActivity(signer, body) |
152 | 160 | ||
153 | signedBody.actor = 'http://localhost:9003/account/peertube' | 161 | signedBody.actor = 'http://localhost:' + servers[2].port + '/account/peertube' |
154 | 162 | ||
155 | const headers = buildGlobalHeaders(signedBody) | 163 | const headers = buildGlobalHeaders(signedBody) |
156 | 164 | ||
157 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) | 165 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) |
158 | 166 | ||
159 | expect(response.statusCode).to.equal(403) | 167 | expect(response.statusCode).to.equal(403) |
160 | }) | 168 | }) |
@@ -162,22 +170,24 @@ describe('Test ActivityPub security', function () { | |||
162 | it('Should succeed with a valid signature', async function () { | 170 | it('Should succeed with a valid signature', async function () { |
163 | this.timeout(10000) | 171 | this.timeout(10000) |
164 | 172 | ||
165 | const body = require('./json/peertube/announce-without-context.json') | 173 | const body = getAnnounceWithoutContext(servers[1]) |
166 | body.actor = 'http://localhost:9003/accounts/peertube' | 174 | body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube' |
167 | 175 | ||
168 | const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } | 176 | const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' } |
169 | const signedBody = await buildSignedActivity(signer, body) | 177 | const signedBody = await buildSignedActivity(signer, body) |
170 | 178 | ||
171 | const headers = buildGlobalHeaders(signedBody) | 179 | const headers = buildGlobalHeaders(signedBody) |
172 | 180 | ||
173 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) | 181 | const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) |
174 | 182 | ||
175 | expect(response.statusCode).to.equal(204) | 183 | expect(response.statusCode).to.equal(204) |
176 | }) | 184 | }) |
177 | }) | 185 | }) |
178 | 186 | ||
179 | after(async function () { | 187 | after(async function () { |
180 | killallServers(servers) | 188 | this.timeout(10000) |
189 | |||
190 | await cleanupTests(servers) | ||
181 | 191 | ||
182 | await closeAllSequelize(servers) | 192 | await closeAllSequelize(servers) |
183 | }) | 193 | }) |
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 2a2ec606a..8155e11ab 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -59,6 +59,7 @@ describe('Test config API validators', function () { | |||
59 | transcoding: { | 59 | transcoding: { |
60 | enabled: true, | 60 | enabled: true, |
61 | allowAdditionalExtensions: true, | 61 | allowAdditionalExtensions: true, |
62 | allowAudioFiles: true, | ||
62 | threads: 1, | 63 | threads: 1, |
63 | resolutions: { | 64 | resolutions: { |
64 | '240p': false, | 65 | '240p': false, |
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 5935104a5..95097817b 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -6,6 +6,7 @@ import { join } from 'path' | |||
6 | import { UserRole, VideoImport, VideoImportState } from '../../../../shared' | 6 | import { UserRole, VideoImport, VideoImportState } from '../../../../shared' |
7 | 7 | ||
8 | import { | 8 | import { |
9 | addVideoChannel, | ||
9 | blockUser, | 10 | blockUser, |
10 | cleanupTests, | 11 | cleanupTests, |
11 | createUser, | 12 | createUser, |
@@ -638,7 +639,7 @@ describe('Test users API validators', function () { | |||
638 | }) | 639 | }) |
639 | }) | 640 | }) |
640 | 641 | ||
641 | describe('When register a new user', function () { | 642 | describe('When registering a new user', function () { |
642 | const registrationPath = path + '/register' | 643 | const registrationPath = path + '/register' |
643 | const baseCorrectParams = { | 644 | const baseCorrectParams = { |
644 | username: 'user3', | 645 | username: 'user3', |
@@ -724,12 +725,42 @@ describe('Test users API validators', function () { | |||
724 | }) | 725 | }) |
725 | }) | 726 | }) |
726 | 727 | ||
728 | it('Should fail with a bad channel name', async function () { | ||
729 | const fields = immutableAssign(baseCorrectParams, { channel: { name: '[]azf', displayName: 'toto' } }) | ||
730 | |||
731 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
732 | }) | ||
733 | |||
734 | it('Should fail with a bad channel display name', async function () { | ||
735 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'toto', displayName: '' } }) | ||
736 | |||
737 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
738 | }) | ||
739 | |||
740 | it('Should fail with a channel name that is the same than user username', async function () { | ||
741 | const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } } | ||
742 | const fields = immutableAssign(baseCorrectParams, source) | ||
743 | |||
744 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
745 | }) | ||
746 | |||
747 | it('Should fail with an existing channel', async function () { | ||
748 | const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' } | ||
749 | await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg) | ||
750 | |||
751 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'existing_channel', displayName: 'toto' } }) | ||
752 | |||
753 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields, statusCodeExpected: 409 }) | ||
754 | }) | ||
755 | |||
727 | it('Should succeed with the correct params', async function () { | 756 | it('Should succeed with the correct params', async function () { |
757 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'super_channel', displayName: 'toto' } }) | ||
758 | |||
728 | await makePostBodyRequest({ | 759 | await makePostBodyRequest({ |
729 | url: server.url, | 760 | url: server.url, |
730 | path: registrationPath, | 761 | path: registrationPath, |
731 | token: server.accessToken, | 762 | token: server.accessToken, |
732 | fields: baseCorrectParams, | 763 | fields: fields, |
733 | statusCodeExpected: 204 | 764 | statusCodeExpected: 204 |
734 | }) | 765 | }) |
735 | }) | 766 | }) |
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index 65bc20613..de88298d1 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts | |||
@@ -24,6 +24,7 @@ import { | |||
24 | checkBadStartPagination | 24 | checkBadStartPagination |
25 | } from '../../../../shared/extra-utils/requests/check-api-params' | 25 | } from '../../../../shared/extra-utils/requests/check-api-params' |
26 | import { join } from 'path' | 26 | import { join } from 'path' |
27 | import { VideoChannelUpdate } from '../../../../shared/models/videos' | ||
27 | 28 | ||
28 | const expect = chai.expect | 29 | const expect = chai.expect |
29 | 30 | ||
@@ -67,8 +68,30 @@ describe('Test video channels API validator', function () { | |||
67 | }) | 68 | }) |
68 | 69 | ||
69 | describe('When listing account video channels', function () { | 70 | describe('When listing account video channels', function () { |
71 | const accountChannelPath = '/api/v1/accounts/fake/video-channels' | ||
72 | |||
73 | it('Should fail with a bad start pagination', async function () { | ||
74 | await checkBadStartPagination(server.url, accountChannelPath, server.accessToken) | ||
75 | }) | ||
76 | |||
77 | it('Should fail with a bad count pagination', async function () { | ||
78 | await checkBadCountPagination(server.url, accountChannelPath, server.accessToken) | ||
79 | }) | ||
80 | |||
81 | it('Should fail with an incorrect sort', async function () { | ||
82 | await checkBadSortPagination(server.url, accountChannelPath, server.accessToken) | ||
83 | }) | ||
84 | |||
70 | it('Should fail with a unknown account', async function () { | 85 | it('Should fail with a unknown account', async function () { |
71 | await getAccountVideoChannelsList(server.url, 'unknown', 404) | 86 | await getAccountVideoChannelsList({ url: server.url, accountName: 'unknown', specialStatus: 404 }) |
87 | }) | ||
88 | |||
89 | it('Should succeed with the correct parameters', async function () { | ||
90 | await makeGetRequest({ | ||
91 | url: server.url, | ||
92 | path: accountChannelPath, | ||
93 | statusCodeExpected: 200 | ||
94 | }) | ||
72 | }) | 95 | }) |
73 | }) | 96 | }) |
74 | 97 | ||
@@ -147,9 +170,11 @@ describe('Test video channels API validator', function () { | |||
147 | }) | 170 | }) |
148 | 171 | ||
149 | describe('When updating a video channel', function () { | 172 | describe('When updating a video channel', function () { |
150 | const baseCorrectParams = { | 173 | const baseCorrectParams: VideoChannelUpdate = { |
151 | displayName: 'hello', | 174 | displayName: 'hello', |
152 | description: 'super description' | 175 | description: 'super description', |
176 | support: 'toto', | ||
177 | bulkVideosSupportUpdate: false | ||
153 | } | 178 | } |
154 | let path: string | 179 | let path: string |
155 | 180 | ||
@@ -192,6 +217,11 @@ describe('Test video channels API validator', function () { | |||
192 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | 217 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) |
193 | }) | 218 | }) |
194 | 219 | ||
220 | it('Should fail with a bad bulkVideosSupportUpdate field', async function () { | ||
221 | const fields = immutableAssign(baseCorrectParams, { bulkVideosSupportUpdate: 'super' }) | ||
222 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
223 | }) | ||
224 | |||
195 | it('Should succeed with the correct parameters', async function () { | 225 | it('Should succeed with the correct parameters', async function () { |
196 | await makePutBodyRequest({ | 226 | await makePutBodyRequest({ |
197 | url: server.url, | 227 | url: server.url, |
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts index b7b94c035..8c5e44bdd 100644 --- a/server/tests/api/check-params/video-playlists.ts +++ b/server/tests/api/check-params/video-playlists.ts | |||
@@ -205,7 +205,6 @@ describe('Test video playlists API validator', function () { | |||
205 | const params = getBase({ displayName: undefined }) | 205 | const params = getBase({ displayName: undefined }) |
206 | 206 | ||
207 | await createVideoPlaylist(params) | 207 | await createVideoPlaylist(params) |
208 | await updateVideoPlaylist(getUpdate(params, playlistUUID)) | ||
209 | }) | 208 | }) |
210 | 209 | ||
211 | it('Should fail with an incorrect display name', async function () { | 210 | it('Should fail with an incorrect display name', async function () { |
@@ -269,17 +268,6 @@ describe('Test video playlists API validator', function () { | |||
269 | )) | 268 | )) |
270 | }) | 269 | }) |
271 | 270 | ||
272 | it('Should fail to update to private a public/unlisted playlist', async function () { | ||
273 | const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC }, { expectedStatus: 200 }) | ||
274 | |||
275 | const res = await createVideoPlaylist(params) | ||
276 | const playlist = res.body.videoPlaylist | ||
277 | |||
278 | const paramsUpdate = getBase({ privacy: VideoPlaylistPrivacy.PRIVATE }, { expectedStatus: 400 }) | ||
279 | |||
280 | await updateVideoPlaylist(getUpdate(paramsUpdate, playlist.id)) | ||
281 | }) | ||
282 | |||
283 | it('Should fail to update the watch later playlist', async function () { | 271 | it('Should fail to update the watch later playlist', async function () { |
284 | await updateVideoPlaylist(getUpdate( | 272 | await updateVideoPlaylist(getUpdate( |
285 | getBase({}, { expectedStatus: 400 }), | 273 | getBase({}, { expectedStatus: 400 }), |
diff --git a/server/tests/api/index-1.ts b/server/tests/api/index-1.ts deleted file mode 100644 index 75cdd9025..000000000 --- a/server/tests/api/index-1.ts +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | import './check-params' | ||
2 | import './notifications' | ||
3 | import './search' | ||
diff --git a/server/tests/api/index-2.ts b/server/tests/api/index-2.ts deleted file mode 100644 index ed93faa91..000000000 --- a/server/tests/api/index-2.ts +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | import './server' | ||
2 | import './users' | ||
diff --git a/server/tests/api/index-3.ts b/server/tests/api/index-3.ts deleted file mode 100644 index 39823b82c..000000000 --- a/server/tests/api/index-3.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | import './videos' | ||
diff --git a/server/tests/api/index-4.ts b/server/tests/api/index-4.ts deleted file mode 100644 index 7d8be2b3d..000000000 --- a/server/tests/api/index-4.ts +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | import './redundancy' | ||
2 | import './activitypub' | ||
diff --git a/server/tests/api/index.ts b/server/tests/api/index.ts index bc140f860..bac77ab2e 100644 --- a/server/tests/api/index.ts +++ b/server/tests/api/index.ts | |||
@@ -1,5 +1,9 @@ | |||
1 | // Order of the tests we want to execute | 1 | // Order of the tests we want to execute |
2 | import './index-1' | 2 | import './activitypub' |
3 | import './index-2' | 3 | import './check-params' |
4 | import './index-3' | 4 | import './notifications' |
5 | import './index-4' | 5 | import './redundancy' |
6 | import './search' | ||
7 | import './server' | ||
8 | import './users' | ||
9 | import './videos' | ||
diff --git a/server/tests/api/notifications/index.ts b/server/tests/api/notifications/index.ts index 95ac8fc51..b573f850e 100644 --- a/server/tests/api/notifications/index.ts +++ b/server/tests/api/notifications/index.ts | |||
@@ -1 +1 @@ | |||
export * from './user-notifications' | import './user-notifications' | ||
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts index f479e1785..662b64e05 100644 --- a/server/tests/api/notifications/user-notifications.ts +++ b/server/tests/api/notifications/user-notifications.ts | |||
@@ -114,11 +114,12 @@ describe('Test users notifications', function () { | |||
114 | before(async function () { | 114 | before(async function () { |
115 | this.timeout(120000) | 115 | this.timeout(120000) |
116 | 116 | ||
117 | await MockSmtpServer.Instance.collectEmails(emails) | 117 | const port = await MockSmtpServer.Instance.collectEmails(emails) |
118 | 118 | ||
119 | const overrideConfig = { | 119 | const overrideConfig = { |
120 | smtp: { | 120 | smtp: { |
121 | hostname: 'localhost' | 121 | hostname: 'localhost', |
122 | port | ||
122 | } | 123 | } |
123 | } | 124 | } |
124 | servers = await flushAndRunMultipleServers(3, overrideConfig) | 125 | servers = await flushAndRunMultipleServers(3, overrideConfig) |
@@ -194,7 +195,7 @@ describe('Test users notifications', function () { | |||
194 | it('Should send a new video notification if the user follows the local video publisher', async function () { | 195 | it('Should send a new video notification if the user follows the local video publisher', async function () { |
195 | this.timeout(15000) | 196 | this.timeout(15000) |
196 | 197 | ||
197 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9001') | 198 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[0].port) |
198 | await waitJobs(servers) | 199 | await waitJobs(servers) |
199 | 200 | ||
200 | const { name, uuid } = await uploadVideoByLocalAccount(servers) | 201 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
@@ -204,7 +205,7 @@ describe('Test users notifications', function () { | |||
204 | it('Should send a new video notification from a remote account', async function () { | 205 | it('Should send a new video notification from a remote account', async function () { |
205 | this.timeout(50000) // Server 2 has transcoding enabled | 206 | this.timeout(50000) // Server 2 has transcoding enabled |
206 | 207 | ||
207 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9002') | 208 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[1].port) |
208 | await waitJobs(servers) | 209 | await waitJobs(servers) |
209 | 210 | ||
210 | const { name, uuid } = await uploadVideoByRemoteAccount(servers) | 211 | const { name, uuid } = await uploadVideoByRemoteAccount(servers) |
@@ -578,7 +579,9 @@ describe('Test users notifications', function () { | |||
578 | const uuid = resVideo.body.video.uuid | 579 | const uuid = resVideo.body.video.uuid |
579 | 580 | ||
580 | await waitJobs(servers) | 581 | await waitJobs(servers) |
581 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'hello @user_1@localhost:9001 1') | 582 | |
583 | const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1` | ||
584 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) | ||
582 | const server2ThreadId = resThread.body.comment.id | 585 | const server2ThreadId = resThread.body.comment.id |
583 | 586 | ||
584 | await waitJobs(servers) | 587 | await waitJobs(servers) |
@@ -588,8 +591,8 @@ describe('Test users notifications', function () { | |||
588 | const server1ThreadId = resThread2.body.data[0].id | 591 | const server1ThreadId = resThread2.body.data[0].id |
589 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') | 592 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') |
590 | 593 | ||
591 | const text = '@user_1@localhost:9001 hello 2 @root@localhost:9001' | 594 | const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}` |
592 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text) | 595 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) |
593 | 596 | ||
594 | await waitJobs(servers) | 597 | await waitJobs(servers) |
595 | 598 | ||
@@ -889,10 +892,10 @@ describe('Test users notifications', function () { | |||
889 | 892 | ||
890 | await waitJobs(servers) | 893 | await waitJobs(servers) |
891 | 894 | ||
892 | await checkNewInstanceFollower(baseParams, 'localhost:9003', 'presence') | 895 | await checkNewInstanceFollower(baseParams, 'localhost:' + servers[2].port, 'presence') |
893 | 896 | ||
894 | const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } | 897 | const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } |
895 | await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:9003', 'absence') | 898 | await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:' + servers[2].port, 'absence') |
896 | }) | 899 | }) |
897 | }) | 900 | }) |
898 | 901 | ||
@@ -933,29 +936,29 @@ describe('Test users notifications', function () { | |||
933 | it('Should notify when a local channel is following one of our channel', async function () { | 936 | it('Should notify when a local channel is following one of our channel', async function () { |
934 | this.timeout(10000) | 937 | this.timeout(10000) |
935 | 938 | ||
936 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') | 939 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
937 | await waitJobs(servers) | 940 | await waitJobs(servers) |
938 | 941 | ||
939 | await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence') | 942 | await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence') |
940 | 943 | ||
941 | await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') | 944 | await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
942 | }) | 945 | }) |
943 | 946 | ||
944 | it('Should notify when a remote channel is following one of our channel', async function () { | 947 | it('Should notify when a remote channel is following one of our channel', async function () { |
945 | this.timeout(10000) | 948 | this.timeout(10000) |
946 | 949 | ||
947 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') | 950 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
948 | await waitJobs(servers) | 951 | await waitJobs(servers) |
949 | 952 | ||
950 | await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence') | 953 | await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence') |
951 | 954 | ||
952 | await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') | 955 | await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
953 | }) | 956 | }) |
954 | 957 | ||
955 | it('Should notify when a local account is following one of our channel', async function () { | 958 | it('Should notify when a local account is following one of our channel', async function () { |
956 | this.timeout(10000) | 959 | this.timeout(10000) |
957 | 960 | ||
958 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:9001') | 961 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:' + servers[0].port) |
959 | 962 | ||
960 | await waitJobs(servers) | 963 | await waitJobs(servers) |
961 | 964 | ||
@@ -965,7 +968,7 @@ describe('Test users notifications', function () { | |||
965 | it('Should notify when a remote account is following one of our channel', async function () { | 968 | it('Should notify when a remote account is following one of our channel', async function () { |
966 | this.timeout(10000) | 969 | this.timeout(10000) |
967 | 970 | ||
968 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:9001') | 971 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:' + servers[0].port) |
969 | 972 | ||
970 | await waitJobs(servers) | 973 | await waitJobs(servers) |
971 | 974 | ||
@@ -1019,8 +1022,8 @@ describe('Test users notifications', function () { | |||
1019 | autoBlacklistTestsCustomConfig.transcoding.enabled = true | 1022 | autoBlacklistTestsCustomConfig.transcoding.enabled = true |
1020 | await updateCustomConfig(servers[0].url, servers[0].accessToken, autoBlacklistTestsCustomConfig) | 1023 | await updateCustomConfig(servers[0].url, servers[0].accessToken, autoBlacklistTestsCustomConfig) |
1021 | 1024 | ||
1022 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') | 1025 | await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
1023 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') | 1026 | await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
1024 | 1027 | ||
1025 | }) | 1028 | }) |
1026 | 1029 | ||
@@ -1142,8 +1145,8 @@ describe('Test users notifications', function () { | |||
1142 | after(async () => { | 1145 | after(async () => { |
1143 | await updateCustomConfig(servers[0].url, servers[0].accessToken, currentCustomConfig) | 1146 | await updateCustomConfig(servers[0].url, servers[0].accessToken, currentCustomConfig) |
1144 | 1147 | ||
1145 | await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') | 1148 | await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
1146 | await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') | 1149 | await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port) |
1147 | }) | 1150 | }) |
1148 | }) | 1151 | }) |
1149 | 1152 | ||
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index e31329c25..6f2c59076 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts | |||
@@ -100,7 +100,7 @@ async function check1WebSeed (videoUUID?: string) { | |||
100 | if (!videoUUID) videoUUID = video1Server2UUID | 100 | if (!videoUUID) videoUUID = video1Server2UUID |
101 | 101 | ||
102 | const webseeds = [ | 102 | const webseeds = [ |
103 | 'http://localhost:9002/static/webseed/' + videoUUID | 103 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` |
104 | ] | 104 | ] |
105 | 105 | ||
106 | for (const server of servers) { | 106 | for (const server of servers) { |
@@ -118,8 +118,8 @@ async function check2Webseeds (videoUUID?: string) { | |||
118 | if (!videoUUID) videoUUID = video1Server2UUID | 118 | if (!videoUUID) videoUUID = video1Server2UUID |
119 | 119 | ||
120 | const webseeds = [ | 120 | const webseeds = [ |
121 | 'http://localhost:9001/static/redundancy/' + videoUUID, | 121 | `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`, |
122 | 'http://localhost:9002/static/webseed/' + videoUUID | 122 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` |
123 | ] | 123 | ] |
124 | 124 | ||
125 | for (const server of servers) { | 125 | for (const server of servers) { |
@@ -145,7 +145,12 @@ async function check2Webseeds (videoUUID?: string) { | |||
145 | } | 145 | } |
146 | } | 146 | } |
147 | 147 | ||
148 | for (const directory of [ 'test1/redundancy', 'test2/videos' ]) { | 148 | const directories = [ |
149 | 'test' + servers[0].internalServerNumber + '/redundancy', | ||
150 | 'test' + servers[1].internalServerNumber + '/videos' | ||
151 | ] | ||
152 | |||
153 | for (const directory of directories) { | ||
149 | const files = await readdir(join(root(), directory)) | 154 | const files = await readdir(join(root(), directory)) |
150 | expect(files).to.have.length.at.least(4) | 155 | expect(files).to.have.length.at.least(4) |
151 | 156 | ||
@@ -194,7 +199,12 @@ async function check1PlaylistRedundancies (videoUUID?: string) { | |||
194 | await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist) | 199 | await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist) |
195 | } | 200 | } |
196 | 201 | ||
197 | for (const directory of [ 'test1/redundancy/hls', 'test2/streaming-playlists/hls' ]) { | 202 | const directories = [ |
203 | 'test' + servers[0].internalServerNumber + '/redundancy/hls', | ||
204 | 'test' + servers[1].internalServerNumber + '/streaming-playlists/hls' | ||
205 | ] | ||
206 | |||
207 | for (const directory of directories) { | ||
198 | const files = await readdir(join(root(), directory, videoUUID)) | 208 | const files = await readdir(join(root(), directory, videoUUID)) |
199 | expect(files).to.have.length.at.least(4) | 209 | expect(files).to.have.length.at.least(4) |
200 | 210 | ||
@@ -239,8 +249,8 @@ async function enableRedundancyOnServer1 () { | |||
239 | 249 | ||
240 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') | 250 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') |
241 | const follows: ActorFollow[] = res.body.data | 251 | const follows: ActorFollow[] = res.body.data |
242 | const server2 = follows.find(f => f.following.host === 'localhost:9002') | 252 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) |
243 | const server3 = follows.find(f => f.following.host === 'localhost:9003') | 253 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) |
244 | 254 | ||
245 | expect(server3).to.not.be.undefined | 255 | expect(server3).to.not.be.undefined |
246 | expect(server3.following.hostRedundancyAllowed).to.be.false | 256 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -254,8 +264,8 @@ async function disableRedundancyOnServer1 () { | |||
254 | 264 | ||
255 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') | 265 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') |
256 | const follows: ActorFollow[] = res.body.data | 266 | const follows: ActorFollow[] = res.body.data |
257 | const server2 = follows.find(f => f.following.host === 'localhost:9002') | 267 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) |
258 | const server3 = follows.find(f => f.following.host === 'localhost:9003') | 268 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) |
259 | 269 | ||
260 | expect(server3).to.not.be.undefined | 270 | expect(server3).to.not.be.undefined |
261 | expect(server3.following.hostRedundancyAllowed).to.be.false | 271 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -475,12 +485,12 @@ describe('Test videos redundancy', function () { | |||
475 | await wait(10000) | 485 | await wait(10000) |
476 | 486 | ||
477 | try { | 487 | try { |
478 | await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') | 488 | await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port) |
479 | } catch { | 489 | } catch { |
480 | // Maybe a server deleted a redundancy in the scheduler | 490 | // Maybe a server deleted a redundancy in the scheduler |
481 | await wait(2000) | 491 | await wait(2000) |
482 | 492 | ||
483 | await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') | 493 | await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port) |
484 | } | 494 | } |
485 | }) | 495 | }) |
486 | 496 | ||
@@ -491,7 +501,7 @@ describe('Test videos redundancy', function () { | |||
491 | 501 | ||
492 | await wait(15000) | 502 | await wait(15000) |
493 | 503 | ||
494 | await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A9001') | 504 | await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A' + servers[0].port) |
495 | }) | 505 | }) |
496 | 506 | ||
497 | after(async function () { | 507 | after(async function () { |
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts index 4d1ceb767..8a008b8c6 100644 --- a/server/tests/api/search/search-activitypub-video-channels.ts +++ b/server/tests/api/search/search-activitypub-video-channels.ts | |||
@@ -3,16 +3,17 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | addVideoChannel, cleanupTests, | 6 | addVideoChannel, |
7 | cleanupTests, | ||
7 | createUser, | 8 | createUser, |
8 | deleteVideoChannel, | 9 | deleteVideoChannel, |
9 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
10 | flushTests, | 11 | getVideoChannelsList, |
11 | getVideoChannelsList, getVideoChannelVideos, | 12 | getVideoChannelVideos, |
12 | killallServers, | ||
13 | ServerInfo, | 13 | ServerInfo, |
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | updateMyUser, updateVideo, | 15 | updateMyUser, |
16 | updateVideo, | ||
16 | updateVideoChannel, | 17 | updateVideoChannel, |
17 | uploadVideo, | 18 | uploadVideo, |
18 | userLogin, | 19 | userLogin, |
@@ -24,7 +25,7 @@ import { searchVideoChannel } from '../../../../shared/extra-utils/search/video- | |||
24 | 25 | ||
25 | const expect = chai.expect | 26 | const expect = chai.expect |
26 | 27 | ||
27 | describe('Test a ActivityPub video channels search', function () { | 28 | describe('Test ActivityPub video channels search', function () { |
28 | let servers: ServerInfo[] | 29 | let servers: ServerInfo[] |
29 | let userServer2Token: string | 30 | let userServer2Token: string |
30 | let videoServer2UUID: string | 31 | let videoServer2UUID: string |
@@ -67,7 +68,7 @@ describe('Test a ActivityPub video channels search', function () { | |||
67 | 68 | ||
68 | it('Should not find a remote video channel', async function () { | 69 | it('Should not find a remote video channel', async function () { |
69 | { | 70 | { |
70 | const search = 'http://localhost:9002/video-channels/channel1_server3' | 71 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3' |
71 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 72 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) |
72 | 73 | ||
73 | expect(res.body.total).to.equal(0) | 74 | expect(res.body.total).to.equal(0) |
@@ -77,7 +78,7 @@ describe('Test a ActivityPub video channels search', function () { | |||
77 | 78 | ||
78 | { | 79 | { |
79 | // Without token | 80 | // Without token |
80 | const search = 'http://localhost:9002/video-channels/channel1_server2' | 81 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' |
81 | const res = await searchVideoChannel(servers[0].url, search) | 82 | const res = await searchVideoChannel(servers[0].url, search) |
82 | 83 | ||
83 | expect(res.body.total).to.equal(0) | 84 | expect(res.body.total).to.equal(0) |
@@ -88,8 +89,8 @@ describe('Test a ActivityPub video channels search', function () { | |||
88 | 89 | ||
89 | it('Should search a local video channel', async function () { | 90 | it('Should search a local video channel', async function () { |
90 | const searches = [ | 91 | const searches = [ |
91 | 'http://localhost:9001/video-channels/channel1_server1', | 92 | 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1', |
92 | 'channel1_server1@localhost:9001' | 93 | 'channel1_server1@localhost:' + servers[ 0 ].port |
93 | ] | 94 | ] |
94 | 95 | ||
95 | for (const search of searches) { | 96 | for (const search of searches) { |
@@ -105,8 +106,8 @@ describe('Test a ActivityPub video channels search', function () { | |||
105 | 106 | ||
106 | it('Should search a remote video channel with URL or handle', async function () { | 107 | it('Should search a remote video channel with URL or handle', async function () { |
107 | const searches = [ | 108 | const searches = [ |
108 | 'http://localhost:9002/video-channels/channel1_server2', | 109 | 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2', |
109 | 'channel1_server2@localhost:9002' | 110 | 'channel1_server2@localhost:' + servers[ 1 ].port |
110 | ] | 111 | ] |
111 | 112 | ||
112 | for (const search of searches) { | 113 | for (const search of searches) { |
@@ -134,13 +135,13 @@ describe('Test a ActivityPub video channels search', function () { | |||
134 | 135 | ||
135 | await waitJobs(servers) | 136 | await waitJobs(servers) |
136 | 137 | ||
137 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:9002', 0, 5) | 138 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) |
138 | expect(res.body.total).to.equal(0) | 139 | expect(res.body.total).to.equal(0) |
139 | expect(res.body.data).to.have.lengthOf(0) | 140 | expect(res.body.data).to.have.lengthOf(0) |
140 | }) | 141 | }) |
141 | 142 | ||
142 | it('Should list video channel videos of server 2 with token', async function () { | 143 | it('Should list video channel videos of server 2 with token', async function () { |
143 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5) | 144 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) |
144 | 145 | ||
145 | expect(res.body.total).to.equal(1) | 146 | expect(res.body.total).to.equal(1) |
146 | expect(res.body.data[0].name).to.equal('video 1 server 2') | 147 | expect(res.body.data[0].name).to.equal('video 1 server 2') |
@@ -156,7 +157,7 @@ describe('Test a ActivityPub video channels search', function () { | |||
156 | // Expire video channel | 157 | // Expire video channel |
157 | await wait(10000) | 158 | await wait(10000) |
158 | 159 | ||
159 | const search = 'http://localhost:9002/video-channels/channel1_server2' | 160 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' |
160 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 161 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
161 | expect(res.body.total).to.equal(1) | 162 | expect(res.body.total).to.equal(1) |
162 | expect(res.body.data).to.have.lengthOf(1) | 163 | expect(res.body.data).to.have.lengthOf(1) |
@@ -179,12 +180,13 @@ describe('Test a ActivityPub video channels search', function () { | |||
179 | // Expire video channel | 180 | // Expire video channel |
180 | await wait(10000) | 181 | await wait(10000) |
181 | 182 | ||
182 | const search = 'http://localhost:9002/video-channels/channel1_server2' | 183 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' |
183 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 184 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
184 | 185 | ||
185 | await waitJobs(servers) | 186 | await waitJobs(servers) |
186 | 187 | ||
187 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5, '-createdAt') | 188 | const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port |
189 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') | ||
188 | 190 | ||
189 | expect(res.body.total).to.equal(2) | 191 | expect(res.body.total).to.equal(2) |
190 | expect(res.body.data[0].name).to.equal('video 2 server 2') | 192 | expect(res.body.data[0].name).to.equal('video 2 server 2') |
@@ -200,7 +202,8 @@ describe('Test a ActivityPub video channels search', function () { | |||
200 | // Expire video | 202 | // Expire video |
201 | await wait(10000) | 203 | await wait(10000) |
202 | 204 | ||
203 | const res = await searchVideoChannel(servers[0].url, 'http://localhost:9002/video-channels/channel1_server2', servers[0].accessToken) | 205 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' |
206 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | ||
204 | expect(res.body.total).to.equal(0) | 207 | expect(res.body.total).to.equal(0) |
205 | expect(res.body.data).to.have.lengthOf(0) | 208 | expect(res.body.data).to.have.lengthOf(0) |
206 | }) | 209 | }) |
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts index e039961cb..dbfefadda 100644 --- a/server/tests/api/search/search-activitypub-videos.ts +++ b/server/tests/api/search/search-activitypub-videos.ts | |||
@@ -4,25 +4,24 @@ import * as chai from 'chai' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | addVideoChannel, | 6 | addVideoChannel, |
7 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
8 | flushTests, | ||
9 | getVideosList, | 9 | getVideosList, |
10 | killallServers, | ||
11 | removeVideo, | 10 | removeVideo, |
11 | searchVideo, | ||
12 | searchVideoWithToken, | 12 | searchVideoWithToken, |
13 | ServerInfo, | 13 | ServerInfo, |
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | updateVideo, | 15 | updateVideo, |
16 | uploadVideo, | 16 | uploadVideo, |
17 | wait, | 17 | wait |
18 | searchVideo, cleanupTests | ||
19 | } from '../../../../shared/extra-utils' | 18 | } from '../../../../shared/extra-utils' |
20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
21 | import { Video, VideoPrivacy } from '../../../../shared/models/videos' | 20 | import { Video, VideoPrivacy } from '../../../../shared/models/videos' |
22 | 21 | ||
23 | const expect = chai.expect | 22 | const expect = chai.expect |
24 | 23 | ||
25 | describe('Test a ActivityPub videos search', function () { | 24 | describe('Test ActivityPub videos search', function () { |
26 | let servers: ServerInfo[] | 25 | let servers: ServerInfo[] |
27 | let videoServer1UUID: string | 26 | let videoServer1UUID: string |
28 | let videoServer2UUID: string | 27 | let videoServer2UUID: string |
@@ -49,7 +48,8 @@ describe('Test a ActivityPub videos search', function () { | |||
49 | 48 | ||
50 | it('Should not find a remote video', async function () { | 49 | it('Should not find a remote video', async function () { |
51 | { | 50 | { |
52 | const res = await searchVideoWithToken(servers[ 0 ].url, 'http://localhost:9002/videos/watch/43', servers[ 0 ].accessToken) | 51 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' |
52 | const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken) | ||
53 | 53 | ||
54 | expect(res.body.total).to.equal(0) | 54 | expect(res.body.total).to.equal(0) |
55 | expect(res.body.data).to.be.an('array') | 55 | expect(res.body.data).to.be.an('array') |
@@ -58,7 +58,8 @@ describe('Test a ActivityPub videos search', function () { | |||
58 | 58 | ||
59 | { | 59 | { |
60 | // Without token | 60 | // Without token |
61 | const res = await searchVideo(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID) | 61 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID |
62 | const res = await searchVideo(servers[0].url, search) | ||
62 | 63 | ||
63 | expect(res.body.total).to.equal(0) | 64 | expect(res.body.total).to.equal(0) |
64 | expect(res.body.data).to.be.an('array') | 65 | expect(res.body.data).to.be.an('array') |
@@ -67,7 +68,8 @@ describe('Test a ActivityPub videos search', function () { | |||
67 | }) | 68 | }) |
68 | 69 | ||
69 | it('Should search a local video', async function () { | 70 | it('Should search a local video', async function () { |
70 | const res = await searchVideo(servers[0].url, 'http://localhost:9001/videos/watch/' + videoServer1UUID) | 71 | const search = 'http://localhost:' + servers[0].port + '/videos/watch/' + videoServer1UUID |
72 | const res = await searchVideo(servers[0].url, search) | ||
71 | 73 | ||
72 | expect(res.body.total).to.equal(1) | 74 | expect(res.body.total).to.equal(1) |
73 | expect(res.body.data).to.be.an('array') | 75 | expect(res.body.data).to.be.an('array') |
@@ -76,7 +78,8 @@ describe('Test a ActivityPub videos search', function () { | |||
76 | }) | 78 | }) |
77 | 79 | ||
78 | it('Should search a remote video', async function () { | 80 | it('Should search a remote video', async function () { |
79 | const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) | 81 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID |
82 | const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) | ||
80 | 83 | ||
81 | expect(res.body.total).to.equal(1) | 84 | expect(res.body.total).to.equal(1) |
82 | expect(res.body.data).to.be.an('array') | 85 | expect(res.body.data).to.be.an('array') |
@@ -114,12 +117,13 @@ describe('Test a ActivityPub videos search', function () { | |||
114 | await wait(10000) | 117 | await wait(10000) |
115 | 118 | ||
116 | // Will run refresh async | 119 | // Will run refresh async |
117 | await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) | 120 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID |
121 | await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) | ||
118 | 122 | ||
119 | // Wait refresh | 123 | // Wait refresh |
120 | await wait(5000) | 124 | await wait(5000) |
121 | 125 | ||
122 | const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) | 126 | const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) |
123 | expect(res.body.total).to.equal(1) | 127 | expect(res.body.total).to.equal(1) |
124 | expect(res.body.data).to.have.lengthOf(1) | 128 | expect(res.body.data).to.have.lengthOf(1) |
125 | 129 | ||
@@ -139,12 +143,13 @@ describe('Test a ActivityPub videos search', function () { | |||
139 | await wait(10000) | 143 | await wait(10000) |
140 | 144 | ||
141 | // Will run refresh async | 145 | // Will run refresh async |
142 | await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) | 146 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID |
147 | await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) | ||
143 | 148 | ||
144 | // Wait refresh | 149 | // Wait refresh |
145 | await wait(5000) | 150 | await wait(5000) |
146 | 151 | ||
147 | const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) | 152 | const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) |
148 | expect(res.body.total).to.equal(0) | 153 | expect(res.body.total).to.equal(0) |
149 | expect(res.body.data).to.have.lengthOf(0) | 154 | expect(res.body.data).to.have.lengthOf(0) |
150 | }) | 155 | }) |
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts index 1a086b33a..92cc0dc71 100644 --- a/server/tests/api/search/search-videos.ts +++ b/server/tests/api/search/search-videos.ts | |||
@@ -4,21 +4,19 @@ import * as chai from 'chai' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | advancedVideosSearch, | 6 | advancedVideosSearch, |
7 | flushTests, | 7 | cleanupTests, |
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
9 | immutableAssign, | ||
10 | searchVideo, | 10 | searchVideo, |
11 | ServerInfo, | 11 | ServerInfo, |
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | uploadVideo, | 13 | uploadVideo, |
14 | wait, | 14 | wait |
15 | immutableAssign, | ||
16 | cleanupTests | ||
17 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
18 | 16 | ||
19 | const expect = chai.expect | 17 | const expect = chai.expect |
20 | 18 | ||
21 | describe('Test a videos search', function () { | 19 | describe('Test videos search', function () { |
22 | let server: ServerInfo = null | 20 | let server: ServerInfo = null |
23 | let startDate: string | 21 | let startDate: string |
24 | 22 | ||
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index c0d11914b..8ea21158a 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -11,17 +11,17 @@ import { | |||
11 | getAbout, | 11 | getAbout, |
12 | getConfig, | 12 | getConfig, |
13 | getCustomConfig, | 13 | getCustomConfig, |
14 | killallServers, | 14 | killallServers, parallelTests, |
15 | registerUser, | 15 | registerUser, |
16 | reRunServer, | 16 | reRunServer, ServerInfo, |
17 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
18 | updateCustomConfig | 18 | updateCustomConfig, uploadVideo |
19 | } from '../../../../shared/extra-utils' | 19 | } from '../../../../shared/extra-utils' |
20 | import { ServerConfig } from '../../../../shared/models' | 20 | import { ServerConfig } from '../../../../shared/models' |
21 | 21 | ||
22 | const expect = chai.expect | 22 | const expect = chai.expect |
23 | 23 | ||
24 | function checkInitialConfig (data: CustomConfig) { | 24 | function checkInitialConfig (server: ServerInfo, data: CustomConfig) { |
25 | expect(data.instance.name).to.equal('PeerTube') | 25 | expect(data.instance.name).to.equal('PeerTube') |
26 | expect(data.instance.shortDescription).to.equal( | 26 | expect(data.instance.shortDescription).to.equal( |
27 | 'PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser ' + | 27 | 'PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser ' + |
@@ -45,13 +45,14 @@ function checkInitialConfig (data: CustomConfig) { | |||
45 | expect(data.signup.limit).to.equal(4) | 45 | expect(data.signup.limit).to.equal(4) |
46 | expect(data.signup.requiresEmailVerification).to.be.false | 46 | expect(data.signup.requiresEmailVerification).to.be.false |
47 | 47 | ||
48 | expect(data.admin.email).to.equal('admin1@example.com') | 48 | expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
49 | expect(data.contactForm.enabled).to.be.true | 49 | expect(data.contactForm.enabled).to.be.true |
50 | 50 | ||
51 | expect(data.user.videoQuota).to.equal(5242880) | 51 | expect(data.user.videoQuota).to.equal(5242880) |
52 | expect(data.user.videoQuotaDaily).to.equal(-1) | 52 | expect(data.user.videoQuotaDaily).to.equal(-1) |
53 | expect(data.transcoding.enabled).to.be.false | 53 | expect(data.transcoding.enabled).to.be.false |
54 | expect(data.transcoding.allowAdditionalExtensions).to.be.false | 54 | expect(data.transcoding.allowAdditionalExtensions).to.be.false |
55 | expect(data.transcoding.allowAudioFiles).to.be.false | ||
55 | expect(data.transcoding.threads).to.equal(2) | 56 | expect(data.transcoding.threads).to.equal(2) |
56 | expect(data.transcoding.resolutions['240p']).to.be.true | 57 | expect(data.transcoding.resolutions['240p']).to.be.true |
57 | expect(data.transcoding.resolutions['360p']).to.be.true | 58 | expect(data.transcoding.resolutions['360p']).to.be.true |
@@ -89,7 +90,11 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
89 | expect(data.signup.limit).to.equal(5) | 90 | expect(data.signup.limit).to.equal(5) |
90 | expect(data.signup.requiresEmailVerification).to.be.false | 91 | expect(data.signup.requiresEmailVerification).to.be.false |
91 | 92 | ||
92 | expect(data.admin.email).to.equal('superadmin1@example.com') | 93 | // We override admin email in parallel tests, so skip this exception |
94 | if (parallelTests() === false) { | ||
95 | expect(data.admin.email).to.equal('superadmin1@example.com') | ||
96 | } | ||
97 | |||
93 | expect(data.contactForm.enabled).to.be.false | 98 | expect(data.contactForm.enabled).to.be.false |
94 | 99 | ||
95 | expect(data.user.videoQuota).to.equal(5242881) | 100 | expect(data.user.videoQuota).to.equal(5242881) |
@@ -98,6 +103,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
98 | expect(data.transcoding.enabled).to.be.true | 103 | expect(data.transcoding.enabled).to.be.true |
99 | expect(data.transcoding.threads).to.equal(1) | 104 | expect(data.transcoding.threads).to.equal(1) |
100 | expect(data.transcoding.allowAdditionalExtensions).to.be.true | 105 | expect(data.transcoding.allowAdditionalExtensions).to.be.true |
106 | expect(data.transcoding.allowAudioFiles).to.be.true | ||
101 | expect(data.transcoding.resolutions['240p']).to.be.false | 107 | expect(data.transcoding.resolutions['240p']).to.be.false |
102 | expect(data.transcoding.resolutions['360p']).to.be.true | 108 | expect(data.transcoding.resolutions['360p']).to.be.true |
103 | expect(data.transcoding.resolutions['480p']).to.be.true | 109 | expect(data.transcoding.resolutions['480p']).to.be.true |
@@ -118,6 +124,7 @@ describe('Test config', function () { | |||
118 | 124 | ||
119 | before(async function () { | 125 | before(async function () { |
120 | this.timeout(30000) | 126 | this.timeout(30000) |
127 | |||
121 | server = await flushAndRunServer(1) | 128 | server = await flushAndRunServer(1) |
122 | await setAccessTokensToServers([ server ]) | 129 | await setAccessTokensToServers([ server ]) |
123 | }) | 130 | }) |
@@ -153,6 +160,9 @@ describe('Test config', function () { | |||
153 | expect(data.video.file.extensions).to.contain('.webm') | 160 | expect(data.video.file.extensions).to.contain('.webm') |
154 | expect(data.video.file.extensions).to.contain('.ogv') | 161 | expect(data.video.file.extensions).to.contain('.ogv') |
155 | 162 | ||
163 | await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 400) | ||
164 | await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 400) | ||
165 | |||
156 | expect(data.contactForm.enabled).to.be.true | 166 | expect(data.contactForm.enabled).to.be.true |
157 | }) | 167 | }) |
158 | 168 | ||
@@ -160,7 +170,7 @@ describe('Test config', function () { | |||
160 | const res = await getCustomConfig(server.url, server.accessToken) | 170 | const res = await getCustomConfig(server.url, server.accessToken) |
161 | const data = res.body as CustomConfig | 171 | const data = res.body as CustomConfig |
162 | 172 | ||
163 | checkInitialConfig(data) | 173 | checkInitialConfig(server, data) |
164 | }) | 174 | }) |
165 | 175 | ||
166 | it('Should update the customized configuration', async function () { | 176 | it('Should update the customized configuration', async function () { |
@@ -210,6 +220,7 @@ describe('Test config', function () { | |||
210 | transcoding: { | 220 | transcoding: { |
211 | enabled: true, | 221 | enabled: true, |
212 | allowAdditionalExtensions: true, | 222 | allowAdditionalExtensions: true, |
223 | allowAudioFiles: true, | ||
213 | threads: 1, | 224 | threads: 1, |
214 | resolutions: { | 225 | resolutions: { |
215 | '240p': false, | 226 | '240p': false, |
@@ -264,6 +275,12 @@ describe('Test config', function () { | |||
264 | expect(data.video.file.extensions).to.contain('.ogv') | 275 | expect(data.video.file.extensions).to.contain('.ogv') |
265 | expect(data.video.file.extensions).to.contain('.flv') | 276 | expect(data.video.file.extensions).to.contain('.flv') |
266 | expect(data.video.file.extensions).to.contain('.mkv') | 277 | expect(data.video.file.extensions).to.contain('.mkv') |
278 | expect(data.video.file.extensions).to.contain('.mp3') | ||
279 | expect(data.video.file.extensions).to.contain('.ogg') | ||
280 | expect(data.video.file.extensions).to.contain('.flac') | ||
281 | |||
282 | await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 200) | ||
283 | await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 200) | ||
267 | }) | 284 | }) |
268 | 285 | ||
269 | it('Should have the configuration updated after a restart', async function () { | 286 | it('Should have the configuration updated after a restart', async function () { |
@@ -297,7 +314,7 @@ describe('Test config', function () { | |||
297 | const res = await getCustomConfig(server.url, server.accessToken) | 314 | const res = await getCustomConfig(server.url, server.accessToken) |
298 | const data = res.body | 315 | const data = res.body |
299 | 316 | ||
300 | checkInitialConfig(data) | 317 | checkInitialConfig(server, data) |
301 | }) | 318 | }) |
302 | 319 | ||
303 | after(async function () { | 320 | after(async function () { |
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index ba51198b3..87e55060c 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts | |||
@@ -24,11 +24,12 @@ describe('Test contact form', function () { | |||
24 | before(async function () { | 24 | before(async function () { |
25 | this.timeout(30000) | 25 | this.timeout(30000) |
26 | 26 | ||
27 | await MockSmtpServer.Instance.collectEmails(emails) | 27 | const port = await MockSmtpServer.Instance.collectEmails(emails) |
28 | 28 | ||
29 | const overrideConfig = { | 29 | const overrideConfig = { |
30 | smtp: { | 30 | smtp: { |
31 | hostname: 'localhost' | 31 | hostname: 'localhost', |
32 | port | ||
32 | } | 33 | } |
33 | } | 34 | } |
34 | server = await flushAndRunServer(1, overrideConfig) | 35 | server = await flushAndRunServer(1, overrideConfig) |
@@ -53,7 +54,7 @@ describe('Test contact form', function () { | |||
53 | 54 | ||
54 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 55 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
55 | expect(email['from'][0]['name']).equal('toto@example.com') | 56 | expect(email['from'][0]['name']).equal('toto@example.com') |
56 | expect(email['to'][0]['address']).equal('admin1@example.com') | 57 | expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com') |
57 | expect(email['subject']).contains('Contact form') | 58 | expect(email['subject']).contains('Contact form') |
58 | expect(email['text']).contains('my super message') | 59 | expect(email['text']).contains('my super message') |
59 | }) | 60 | }) |
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index bacdf1b1b..5929a3adb 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -7,18 +7,18 @@ import { | |||
7 | askResetPassword, | 7 | askResetPassword, |
8 | askSendVerifyEmail, | 8 | askSendVerifyEmail, |
9 | blockUser, | 9 | blockUser, |
10 | createUser, removeVideoFromBlacklist, | 10 | cleanupTests, |
11 | createUser, | ||
12 | flushAndRunServer, | ||
13 | removeVideoFromBlacklist, | ||
11 | reportVideoAbuse, | 14 | reportVideoAbuse, |
12 | resetPassword, | 15 | resetPassword, |
13 | flushAndRunServer, | 16 | ServerInfo, |
17 | setAccessTokensToServers, | ||
14 | unblockUser, | 18 | unblockUser, |
15 | uploadVideo, | 19 | uploadVideo, |
16 | userLogin, | 20 | userLogin, |
17 | verifyEmail, | 21 | verifyEmail |
18 | flushTests, | ||
19 | killallServers, | ||
20 | ServerInfo, | ||
21 | setAccessTokensToServers, cleanupTests | ||
22 | } from '../../../../shared/extra-utils' | 22 | } from '../../../../shared/extra-utils' |
23 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 23 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
24 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 24 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -37,15 +37,17 @@ describe('Test emails', function () { | |||
37 | username: 'user_1', | 37 | username: 'user_1', |
38 | password: 'super_password' | 38 | password: 'super_password' |
39 | } | 39 | } |
40 | let emailPort: number | ||
40 | 41 | ||
41 | before(async function () { | 42 | before(async function () { |
42 | this.timeout(30000) | 43 | this.timeout(30000) |
43 | 44 | ||
44 | await MockSmtpServer.Instance.collectEmails(emails) | 45 | emailPort = await MockSmtpServer.Instance.collectEmails(emails) |
45 | 46 | ||
46 | const overrideConfig = { | 47 | const overrideConfig = { |
47 | smtp: { | 48 | smtp: { |
48 | hostname: 'localhost' | 49 | hostname: 'localhost', |
50 | port: emailPort | ||
49 | } | 51 | } |
50 | } | 52 | } |
51 | server = await flushAndRunServer(1, overrideConfig) | 53 | server = await flushAndRunServer(1, overrideConfig) |
@@ -87,7 +89,7 @@ describe('Test emails', function () { | |||
87 | 89 | ||
88 | const email = emails[0] | 90 | const email = emails[0] |
89 | 91 | ||
90 | expect(email['from'][0]['name']).equal('localhost:9001') | 92 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
91 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 93 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
92 | expect(email['to'][0]['address']).equal('user_1@example.com') | 94 | expect(email['to'][0]['address']).equal('user_1@example.com') |
93 | expect(email['subject']).contains('password') | 95 | expect(email['subject']).contains('password') |
@@ -132,9 +134,9 @@ describe('Test emails', function () { | |||
132 | 134 | ||
133 | const email = emails[1] | 135 | const email = emails[1] |
134 | 136 | ||
135 | expect(email['from'][0]['name']).equal('localhost:9001') | 137 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
136 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 138 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
137 | expect(email['to'][0]['address']).equal('admin1@example.com') | 139 | expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com') |
138 | expect(email['subject']).contains('abuse') | 140 | expect(email['subject']).contains('abuse') |
139 | expect(email['text']).contains(videoUUID) | 141 | expect(email['text']).contains(videoUUID) |
140 | }) | 142 | }) |
@@ -153,7 +155,7 @@ describe('Test emails', function () { | |||
153 | 155 | ||
154 | const email = emails[2] | 156 | const email = emails[2] |
155 | 157 | ||
156 | expect(email['from'][0]['name']).equal('localhost:9001') | 158 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
157 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 159 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
158 | expect(email['to'][0]['address']).equal('user_1@example.com') | 160 | expect(email['to'][0]['address']).equal('user_1@example.com') |
159 | expect(email['subject']).contains(' blocked') | 161 | expect(email['subject']).contains(' blocked') |
@@ -171,7 +173,7 @@ describe('Test emails', function () { | |||
171 | 173 | ||
172 | const email = emails[3] | 174 | const email = emails[3] |
173 | 175 | ||
174 | expect(email['from'][0]['name']).equal('localhost:9001') | 176 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
175 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 177 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
176 | expect(email['to'][0]['address']).equal('user_1@example.com') | 178 | expect(email['to'][0]['address']).equal('user_1@example.com') |
177 | expect(email['subject']).contains(' unblocked') | 179 | expect(email['subject']).contains(' unblocked') |
@@ -191,7 +193,7 @@ describe('Test emails', function () { | |||
191 | 193 | ||
192 | const email = emails[4] | 194 | const email = emails[4] |
193 | 195 | ||
194 | expect(email['from'][0]['name']).equal('localhost:9001') | 196 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
195 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 197 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
196 | expect(email['to'][0]['address']).equal('user_1@example.com') | 198 | expect(email['to'][0]['address']).equal('user_1@example.com') |
197 | expect(email['subject']).contains(' blacklisted') | 199 | expect(email['subject']).contains(' blacklisted') |
@@ -209,7 +211,7 @@ describe('Test emails', function () { | |||
209 | 211 | ||
210 | const email = emails[5] | 212 | const email = emails[5] |
211 | 213 | ||
212 | expect(email['from'][0]['name']).equal('localhost:9001') | 214 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
213 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 215 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
214 | expect(email['to'][0]['address']).equal('user_1@example.com') | 216 | expect(email['to'][0]['address']).equal('user_1@example.com') |
215 | expect(email['subject']).contains(' unblacklisted') | 217 | expect(email['subject']).contains(' unblacklisted') |
@@ -229,7 +231,7 @@ describe('Test emails', function () { | |||
229 | 231 | ||
230 | const email = emails[6] | 232 | const email = emails[6] |
231 | 233 | ||
232 | expect(email['from'][0]['name']).equal('localhost:9001') | 234 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
233 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 235 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
234 | expect(email['to'][0]['address']).equal('user_1@example.com') | 236 | expect(email['to'][0]['address']).equal('user_1@example.com') |
235 | expect(email['subject']).contains('Verify') | 237 | expect(email['subject']).contains('Verify') |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 4285a9e7a..ac3ff37f0 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -3,16 +3,16 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | doubleFollow, | 7 | doubleFollow, |
8 | flushAndRunMultipleServers, | ||
7 | getAccountVideos, | 9 | getAccountVideos, |
8 | getVideo, | 10 | getVideo, |
9 | getVideoChannelVideos, | 11 | getVideoChannelVideos, |
10 | getVideoWithToken, | 12 | getVideoWithToken, |
11 | flushAndRunMultipleServers, | ||
12 | killallServers, | ||
13 | ServerInfo, | 13 | ServerInfo, |
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | uploadVideo, cleanupTests | 15 | uploadVideo |
16 | } from '../../../../shared/extra-utils' | 16 | } from '../../../../shared/extra-utils' |
17 | import { unfollow } from '../../../../shared/extra-utils/server/follows' | 17 | import { unfollow } from '../../../../shared/extra-utils/server/follows' |
18 | import { userLogin } from '../../../../shared/extra-utils/users/login' | 18 | import { userLogin } from '../../../../shared/extra-utils/users/login' |
@@ -66,28 +66,30 @@ describe('Test follow constraints', function () { | |||
66 | }) | 66 | }) |
67 | 67 | ||
68 | it('Should list local account videos', async function () { | 68 | it('Should list local account videos', async function () { |
69 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5) | 69 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5) |
70 | 70 | ||
71 | expect(res.body.total).to.equal(1) | 71 | expect(res.body.total).to.equal(1) |
72 | expect(res.body.data).to.have.lengthOf(1) | 72 | expect(res.body.data).to.have.lengthOf(1) |
73 | }) | 73 | }) |
74 | 74 | ||
75 | it('Should list remote account videos', async function () { | 75 | it('Should list remote account videos', async function () { |
76 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5) | 76 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5) |
77 | 77 | ||
78 | expect(res.body.total).to.equal(1) | 78 | expect(res.body.total).to.equal(1) |
79 | expect(res.body.data).to.have.lengthOf(1) | 79 | expect(res.body.data).to.have.lengthOf(1) |
80 | }) | 80 | }) |
81 | 81 | ||
82 | it('Should list local channel videos', async function () { | 82 | it('Should list local channel videos', async function () { |
83 | const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5) | 83 | const videoChannelName = 'root_channel@localhost:' + servers[0].port |
84 | const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5) | ||
84 | 85 | ||
85 | expect(res.body.total).to.equal(1) | 86 | expect(res.body.total).to.equal(1) |
86 | expect(res.body.data).to.have.lengthOf(1) | 87 | expect(res.body.data).to.have.lengthOf(1) |
87 | }) | 88 | }) |
88 | 89 | ||
89 | it('Should list remote channel videos', async function () { | 90 | it('Should list remote channel videos', async function () { |
90 | const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5) | 91 | const videoChannelName = 'root_channel@localhost:' + servers[1].port |
92 | const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5) | ||
91 | 93 | ||
92 | expect(res.body.total).to.equal(1) | 94 | expect(res.body.total).to.equal(1) |
93 | expect(res.body.data).to.have.lengthOf(1) | 95 | expect(res.body.data).to.have.lengthOf(1) |
@@ -104,28 +106,30 @@ describe('Test follow constraints', function () { | |||
104 | }) | 106 | }) |
105 | 107 | ||
106 | it('Should list local account videos', async function () { | 108 | it('Should list local account videos', async function () { |
107 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5) | 109 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5) |
108 | 110 | ||
109 | expect(res.body.total).to.equal(1) | 111 | expect(res.body.total).to.equal(1) |
110 | expect(res.body.data).to.have.lengthOf(1) | 112 | expect(res.body.data).to.have.lengthOf(1) |
111 | }) | 113 | }) |
112 | 114 | ||
113 | it('Should list remote account videos', async function () { | 115 | it('Should list remote account videos', async function () { |
114 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5) | 116 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5) |
115 | 117 | ||
116 | expect(res.body.total).to.equal(1) | 118 | expect(res.body.total).to.equal(1) |
117 | expect(res.body.data).to.have.lengthOf(1) | 119 | expect(res.body.data).to.have.lengthOf(1) |
118 | }) | 120 | }) |
119 | 121 | ||
120 | it('Should list local channel videos', async function () { | 122 | it('Should list local channel videos', async function () { |
121 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5) | 123 | const videoChannelName = 'root_channel@localhost:' + servers[0].port |
124 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5) | ||
122 | 125 | ||
123 | expect(res.body.total).to.equal(1) | 126 | expect(res.body.total).to.equal(1) |
124 | expect(res.body.data).to.have.lengthOf(1) | 127 | expect(res.body.data).to.have.lengthOf(1) |
125 | }) | 128 | }) |
126 | 129 | ||
127 | it('Should list remote channel videos', async function () { | 130 | it('Should list remote channel videos', async function () { |
128 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5) | 131 | const videoChannelName = 'root_channel@localhost:' + servers[1].port |
132 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5) | ||
129 | 133 | ||
130 | expect(res.body.total).to.equal(1) | 134 | expect(res.body.total).to.equal(1) |
131 | expect(res.body.data).to.have.lengthOf(1) | 135 | expect(res.body.data).to.have.lengthOf(1) |
@@ -152,28 +156,30 @@ describe('Test follow constraints', function () { | |||
152 | }) | 156 | }) |
153 | 157 | ||
154 | it('Should list local account videos', async function () { | 158 | it('Should list local account videos', async function () { |
155 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5) | 159 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5) |
156 | 160 | ||
157 | expect(res.body.total).to.equal(1) | 161 | expect(res.body.total).to.equal(1) |
158 | expect(res.body.data).to.have.lengthOf(1) | 162 | expect(res.body.data).to.have.lengthOf(1) |
159 | }) | 163 | }) |
160 | 164 | ||
161 | it('Should not list remote account videos', async function () { | 165 | it('Should not list remote account videos', async function () { |
162 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5) | 166 | const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5) |
163 | 167 | ||
164 | expect(res.body.total).to.equal(0) | 168 | expect(res.body.total).to.equal(0) |
165 | expect(res.body.data).to.have.lengthOf(0) | 169 | expect(res.body.data).to.have.lengthOf(0) |
166 | }) | 170 | }) |
167 | 171 | ||
168 | it('Should list local channel videos', async function () { | 172 | it('Should list local channel videos', async function () { |
169 | const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5) | 173 | const videoChannelName = 'root_channel@localhost:' + servers[0].port |
174 | const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5) | ||
170 | 175 | ||
171 | expect(res.body.total).to.equal(1) | 176 | expect(res.body.total).to.equal(1) |
172 | expect(res.body.data).to.have.lengthOf(1) | 177 | expect(res.body.data).to.have.lengthOf(1) |
173 | }) | 178 | }) |
174 | 179 | ||
175 | it('Should not list remote channel videos', async function () { | 180 | it('Should not list remote channel videos', async function () { |
176 | const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5) | 181 | const videoChannelName = 'root_channel@localhost:' + servers[1].port |
182 | const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5) | ||
177 | 183 | ||
178 | expect(res.body.total).to.equal(0) | 184 | expect(res.body.total).to.equal(0) |
179 | expect(res.body.data).to.have.lengthOf(0) | 185 | expect(res.body.data).to.have.lengthOf(0) |
@@ -190,28 +196,30 @@ describe('Test follow constraints', function () { | |||
190 | }) | 196 | }) |
191 | 197 | ||
192 | it('Should list local account videos', async function () { | 198 | it('Should list local account videos', async function () { |
193 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5) | 199 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5) |
194 | 200 | ||
195 | expect(res.body.total).to.equal(1) | 201 | expect(res.body.total).to.equal(1) |
196 | expect(res.body.data).to.have.lengthOf(1) | 202 | expect(res.body.data).to.have.lengthOf(1) |
197 | }) | 203 | }) |
198 | 204 | ||
199 | it('Should list remote account videos', async function () { | 205 | it('Should list remote account videos', async function () { |
200 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5) | 206 | const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5) |
201 | 207 | ||
202 | expect(res.body.total).to.equal(1) | 208 | expect(res.body.total).to.equal(1) |
203 | expect(res.body.data).to.have.lengthOf(1) | 209 | expect(res.body.data).to.have.lengthOf(1) |
204 | }) | 210 | }) |
205 | 211 | ||
206 | it('Should list local channel videos', async function () { | 212 | it('Should list local channel videos', async function () { |
207 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5) | 213 | const videoChannelName = 'root_channel@localhost:' + servers[0].port |
214 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5) | ||
208 | 215 | ||
209 | expect(res.body.total).to.equal(1) | 216 | expect(res.body.total).to.equal(1) |
210 | expect(res.body.data).to.have.lengthOf(1) | 217 | expect(res.body.data).to.have.lengthOf(1) |
211 | }) | 218 | }) |
212 | 219 | ||
213 | it('Should list remote channel videos', async function () { | 220 | it('Should list remote channel videos', async function () { |
214 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5) | 221 | const videoChannelName = 'root_channel@localhost:' + servers[1].port |
222 | const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5) | ||
215 | 223 | ||
216 | expect(res.body.total).to.equal(1) | 224 | expect(res.body.total).to.equal(1) |
217 | expect(res.body.data).to.have.lengthOf(1) | 225 | expect(res.body.data).to.have.lengthOf(1) |
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts index 2a3a4d5c8..a82acdb34 100644 --- a/server/tests/api/server/follows-moderation.ts +++ b/server/tests/api/server/follows-moderation.ts | |||
@@ -3,9 +3,9 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | acceptFollower, cleanupTests, | 6 | acceptFollower, |
7 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
8 | killallServers, | ||
9 | ServerInfo, | 9 | ServerInfo, |
10 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
11 | updateCustomSubConfig | 11 | updateCustomSubConfig |
@@ -14,8 +14,8 @@ import { | |||
14 | follow, | 14 | follow, |
15 | getFollowersListPaginationAndSort, | 15 | getFollowersListPaginationAndSort, |
16 | getFollowingListPaginationAndSort, | 16 | getFollowingListPaginationAndSort, |
17 | removeFollower, | 17 | rejectFollower, |
18 | rejectFollower | 18 | removeFollower |
19 | } from '../../../../shared/extra-utils/server/follows' | 19 | } from '../../../../shared/extra-utils/server/follows' |
20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
21 | import { ActorFollow } from '../../../../shared/models/actors' | 21 | import { ActorFollow } from '../../../../shared/models/actors' |
@@ -29,8 +29,8 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
29 | 29 | ||
30 | const follow = res.body.data[0] as ActorFollow | 30 | const follow = res.body.data[0] as ActorFollow |
31 | expect(follow.state).to.equal(state) | 31 | expect(follow.state).to.equal(state) |
32 | expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube') | 32 | expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube') |
33 | expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube') | 33 | expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube') |
34 | } | 34 | } |
35 | 35 | ||
36 | { | 36 | { |
@@ -39,8 +39,8 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
39 | 39 | ||
40 | const follow = res.body.data[0] as ActorFollow | 40 | const follow = res.body.data[0] as ActorFollow |
41 | expect(follow.state).to.equal(state) | 41 | expect(follow.state).to.equal(state) |
42 | expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube') | 42 | expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube') |
43 | expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube') | 43 | expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube') |
44 | } | 44 | } |
45 | } | 45 | } |
46 | 46 | ||
@@ -151,7 +151,7 @@ describe('Test follows moderation', function () { | |||
151 | }) | 151 | }) |
152 | 152 | ||
153 | it('Should accept a follower', async function () { | 153 | it('Should accept a follower', async function () { |
154 | await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:9001') | 154 | await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port) |
155 | await waitJobs(servers) | 155 | await waitJobs(servers) |
156 | 156 | ||
157 | await checkServer1And2HasFollowers(servers) | 157 | await checkServer1And2HasFollowers(servers) |
@@ -178,7 +178,7 @@ describe('Test follows moderation', function () { | |||
178 | expect(res.body.total).to.equal(1) | 178 | expect(res.body.total).to.equal(1) |
179 | } | 179 | } |
180 | 180 | ||
181 | await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:9001') | 181 | await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:' + servers[0].port) |
182 | await waitJobs(servers) | 182 | await waitJobs(servers) |
183 | 183 | ||
184 | await checkServer1And2HasFollowers(servers) | 184 | await checkServer1And2HasFollowers(servers) |
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts index 397093cdb..e8d6f5138 100644 --- a/server/tests/api/server/follows.ts +++ b/server/tests/api/server/follows.ts | |||
@@ -8,7 +8,6 @@ import { cleanupTests, completeVideoCheck } from '../../../../shared/extra-utils | |||
8 | import { | 8 | import { |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | getVideosList, | 10 | getVideosList, |
11 | killallServers, | ||
12 | ServerInfo, | 11 | ServerInfo, |
13 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
14 | uploadVideo | 13 | uploadVideo |
@@ -89,8 +88,8 @@ describe('Test follows', function () { | |||
89 | res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt') | 88 | res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt') |
90 | follows = follows.concat(res.body.data) | 89 | follows = follows.concat(res.body.data) |
91 | 90 | ||
92 | const server2Follow = follows.find(f => f.following.host === 'localhost:9002') | 91 | const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) |
93 | const server3Follow = follows.find(f => f.following.host === 'localhost:9003') | 92 | const server3Follow = follows.find(f => f.following.host === 'localhost:' + servers[2].port) |
94 | 93 | ||
95 | expect(server2Follow).to.not.be.undefined | 94 | expect(server2Follow).to.not.be.undefined |
96 | expect(server3Follow).to.not.be.undefined | 95 | expect(server3Follow).to.not.be.undefined |
@@ -100,12 +99,12 @@ describe('Test follows', function () { | |||
100 | 99 | ||
101 | it('Should search followings on server 1', async function () { | 100 | it('Should search followings on server 1', async function () { |
102 | { | 101 | { |
103 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':9002') | 102 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':' + servers[1].port) |
104 | const follows = res.body.data | 103 | const follows = res.body.data |
105 | 104 | ||
106 | expect(res.body.total).to.equal(1) | 105 | expect(res.body.total).to.equal(1) |
107 | expect(follows.length).to.equal(1) | 106 | expect(follows.length).to.equal(1) |
108 | expect(follows[ 0 ].following.host).to.equal('localhost:9002') | 107 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port) |
109 | } | 108 | } |
110 | 109 | ||
111 | { | 110 | { |
@@ -136,18 +135,18 @@ describe('Test follows', function () { | |||
136 | expect(res.body.total).to.equal(1) | 135 | expect(res.body.total).to.equal(1) |
137 | expect(follows).to.be.an('array') | 136 | expect(follows).to.be.an('array') |
138 | expect(follows.length).to.equal(1) | 137 | expect(follows.length).to.equal(1) |
139 | expect(follows[0].follower.host).to.equal('localhost:9001') | 138 | expect(follows[0].follower.host).to.equal('localhost:' + servers[0].port) |
140 | } | 139 | } |
141 | }) | 140 | }) |
142 | 141 | ||
143 | it('Should search followers on server 2', async function () { | 142 | it('Should search followers on server 2', async function () { |
144 | { | 143 | { |
145 | const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', '9001') | 144 | const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', servers[0].port + '') |
146 | const follows = res.body.data | 145 | const follows = res.body.data |
147 | 146 | ||
148 | expect(res.body.total).to.equal(1) | 147 | expect(res.body.total).to.equal(1) |
149 | expect(follows.length).to.equal(1) | 148 | expect(follows.length).to.equal(1) |
150 | expect(follows[ 0 ].following.host).to.equal('localhost:9003') | 149 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port) |
151 | } | 150 | } |
152 | 151 | ||
153 | { | 152 | { |
@@ -169,16 +168,16 @@ describe('Test follows', function () { | |||
169 | }) | 168 | }) |
170 | 169 | ||
171 | it('Should have the correct follows counts', async function () { | 170 | it('Should have the correct follows counts', async function () { |
172 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2) | 171 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2) |
173 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) | 172 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
174 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0) | 173 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0) |
175 | 174 | ||
176 | // Server 2 and 3 does not know server 1 follow another server (there was not a refresh) | 175 | // Server 2 and 3 does not know server 1 follow another server (there was not a refresh) |
177 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) | 176 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1) |
178 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) | 177 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
179 | 178 | ||
180 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1) | 179 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 1) |
181 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0) | 180 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0) |
182 | }) | 181 | }) |
183 | 182 | ||
184 | it('Should unfollow server 3 on server 1', async function () { | 183 | it('Should unfollow server 3 on server 1', async function () { |
@@ -197,7 +196,7 @@ describe('Test follows', function () { | |||
197 | expect(follows).to.be.an('array') | 196 | expect(follows).to.be.an('array') |
198 | expect(follows.length).to.equal(1) | 197 | expect(follows.length).to.equal(1) |
199 | 198 | ||
200 | expect(follows[0].following.host).to.equal('localhost:9002') | 199 | expect(follows[0].following.host).to.equal('localhost:' + servers[1].port) |
201 | }) | 200 | }) |
202 | 201 | ||
203 | it('Should not have server 1 as follower on server 3 anymore', async function () { | 202 | it('Should not have server 1 as follower on server 3 anymore', async function () { |
@@ -210,14 +209,14 @@ describe('Test follows', function () { | |||
210 | }) | 209 | }) |
211 | 210 | ||
212 | it('Should have the correct follows counts 2', async function () { | 211 | it('Should have the correct follows counts 2', async function () { |
213 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 1) | 212 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 1) |
214 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) | 213 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
215 | 214 | ||
216 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) | 215 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1) |
217 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) | 216 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
218 | 217 | ||
219 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 0) | 218 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 0) |
220 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 0, 0) | 219 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 0, 0) |
221 | }) | 220 | }) |
222 | 221 | ||
223 | it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { | 222 | it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { |
@@ -310,15 +309,15 @@ describe('Test follows', function () { | |||
310 | }) | 309 | }) |
311 | 310 | ||
312 | it('Should have the correct follows counts 3', async function () { | 311 | it('Should have the correct follows counts 3', async function () { |
313 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2) | 312 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2) |
314 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) | 313 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
315 | await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0) | 314 | await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0) |
316 | 315 | ||
317 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) | 316 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1) |
318 | await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) | 317 | await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0) |
319 | 318 | ||
320 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 2) | 319 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 2) |
321 | await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0) | 320 | await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0) |
322 | }) | 321 | }) |
323 | 322 | ||
324 | it('Should have propagated videos', async function () { | 323 | it('Should have propagated videos', async function () { |
@@ -344,7 +343,7 @@ describe('Test follows', function () { | |||
344 | support: 'my super support text', | 343 | support: 'my super support text', |
345 | account: { | 344 | account: { |
346 | name: 'root', | 345 | name: 'root', |
347 | host: 'localhost:9003' | 346 | host: 'localhost:' + servers[2].port |
348 | }, | 347 | }, |
349 | isLocal, | 348 | isLocal, |
350 | commentsEnabled: true, | 349 | commentsEnabled: true, |
@@ -384,7 +383,7 @@ describe('Test follows', function () { | |||
384 | expect(comment.videoId).to.equal(video4.id) | 383 | expect(comment.videoId).to.equal(video4.id) |
385 | expect(comment.id).to.equal(comment.threadId) | 384 | expect(comment.id).to.equal(comment.threadId) |
386 | expect(comment.account.name).to.equal('root') | 385 | expect(comment.account.name).to.equal('root') |
387 | expect(comment.account.host).to.equal('localhost:9003') | 386 | expect(comment.account.host).to.equal('localhost:' + servers[2].port) |
388 | expect(comment.totalReplies).to.equal(3) | 387 | expect(comment.totalReplies).to.equal(3) |
389 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 388 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
390 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 389 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index 19010dbc1..068654d8c 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts | |||
@@ -60,48 +60,50 @@ describe('Test handle downs', function () { | |||
60 | privacy: VideoPrivacy.UNLISTED | 60 | privacy: VideoPrivacy.UNLISTED |
61 | }) | 61 | }) |
62 | 62 | ||
63 | const checkAttributes = { | 63 | let checkAttributes: any |
64 | name: 'my super name for server 1', | 64 | let unlistedCheckAttributes: any |
65 | category: 5, | ||
66 | licence: 4, | ||
67 | language: 'ja', | ||
68 | nsfw: true, | ||
69 | description: 'my super description for server 1', | ||
70 | support: 'my super support text for server 1', | ||
71 | account: { | ||
72 | name: 'root', | ||
73 | host: 'localhost:9001' | ||
74 | }, | ||
75 | isLocal: false, | ||
76 | duration: 10, | ||
77 | tags: [ 'tag1p1', 'tag2p1' ], | ||
78 | privacy: VideoPrivacy.PUBLIC, | ||
79 | commentsEnabled: true, | ||
80 | downloadEnabled: true, | ||
81 | channel: { | ||
82 | name: 'root_channel', | ||
83 | displayName: 'Main root channel', | ||
84 | description: '', | ||
85 | isLocal: false | ||
86 | }, | ||
87 | fixture: 'video_short1.webm', | ||
88 | files: [ | ||
89 | { | ||
90 | resolution: 720, | ||
91 | size: 572456 | ||
92 | } | ||
93 | ] | ||
94 | } | ||
95 | |||
96 | const unlistedCheckAttributes = immutableAssign(checkAttributes, { | ||
97 | privacy: VideoPrivacy.UNLISTED | ||
98 | }) | ||
99 | 65 | ||
100 | before(async function () { | 66 | before(async function () { |
101 | this.timeout(30000) | 67 | this.timeout(30000) |
102 | 68 | ||
103 | servers = await flushAndRunMultipleServers(3) | 69 | servers = await flushAndRunMultipleServers(3) |
104 | 70 | ||
71 | checkAttributes = { | ||
72 | name: 'my super name for server 1', | ||
73 | category: 5, | ||
74 | licence: 4, | ||
75 | language: 'ja', | ||
76 | nsfw: true, | ||
77 | description: 'my super description for server 1', | ||
78 | support: 'my super support text for server 1', | ||
79 | account: { | ||
80 | name: 'root', | ||
81 | host: 'localhost:' + servers[0].port | ||
82 | }, | ||
83 | isLocal: false, | ||
84 | duration: 10, | ||
85 | tags: [ 'tag1p1', 'tag2p1' ], | ||
86 | privacy: VideoPrivacy.PUBLIC, | ||
87 | commentsEnabled: true, | ||
88 | downloadEnabled: true, | ||
89 | channel: { | ||
90 | name: 'root_channel', | ||
91 | displayName: 'Main root channel', | ||
92 | description: '', | ||
93 | isLocal: false | ||
94 | }, | ||
95 | fixture: 'video_short1.webm', | ||
96 | files: [ | ||
97 | { | ||
98 | resolution: 720, | ||
99 | size: 572456 | ||
100 | } | ||
101 | ] | ||
102 | } | ||
103 | unlistedCheckAttributes = immutableAssign(checkAttributes, { | ||
104 | privacy: VideoPrivacy.UNLISTED | ||
105 | }) | ||
106 | |||
105 | // Get the access tokens | 107 | // Get the access tokens |
106 | await setAccessTokensToServers(servers) | 108 | await setAccessTokensToServers(servers) |
107 | }) | 109 | }) |
@@ -172,7 +174,7 @@ describe('Test handle downs', function () { | |||
172 | const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') | 174 | const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') |
173 | expect(res.body.data).to.be.an('array') | 175 | expect(res.body.data).to.be.an('array') |
174 | expect(res.body.data).to.have.lengthOf(1) | 176 | expect(res.body.data).to.have.lengthOf(1) |
175 | expect(res.body.data[0].follower.host).to.equal('localhost:9003') | 177 | expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) |
176 | }) | 178 | }) |
177 | 179 | ||
178 | it('Should not have pending/processing jobs anymore', async function () { | 180 | it('Should not have pending/processing jobs anymore', async function () { |
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts index 634654626..3ab2fe120 100644 --- a/server/tests/api/server/jobs.ts +++ b/server/tests/api/server/jobs.ts | |||
@@ -26,7 +26,7 @@ describe('Test jobs', function () { | |||
26 | }) | 26 | }) |
27 | 27 | ||
28 | it('Should create some jobs', async function () { | 28 | it('Should create some jobs', async function () { |
29 | this.timeout(30000) | 29 | this.timeout(60000) |
30 | 30 | ||
31 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video1' }) | 31 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video1' }) |
32 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' }) | 32 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' }) |
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts index 3644fa0d3..68f442199 100644 --- a/server/tests/api/server/logs.ts +++ b/server/tests/api/server/logs.ts | |||
@@ -45,7 +45,7 @@ describe('Test logs', function () { | |||
45 | }) | 45 | }) |
46 | 46 | ||
47 | it('Should get logs with an end date', async function () { | 47 | it('Should get logs with an end date', async function () { |
48 | this.timeout(10000) | 48 | this.timeout(20000) |
49 | 49 | ||
50 | await uploadVideo(server.url, server.accessToken, { name: 'video 3' }) | 50 | await uploadVideo(server.url, server.accessToken, { name: 'video 3' }) |
51 | await waitJobs([ server ]) | 51 | await waitJobs([ server ]) |
diff --git a/server/tests/api/travis-1.sh b/server/tests/api/travis-1.sh new file mode 100644 index 000000000..db4021b25 --- /dev/null +++ b/server/tests/api/travis-1.sh | |||
@@ -0,0 +1,10 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | |||
3 | set -eu | ||
4 | |||
5 | checkParamFiles=$(find server/tests/api/check-params -type f | grep -v index.ts | xargs echo) | ||
6 | notificationsFiles=$(find server/tests/api/notifications -type f | grep -v index.ts | xargs echo) | ||
7 | searchFiles=$(find server/tests/api/search -type f | grep -v index.ts | xargs echo) | ||
8 | |||
9 | MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \ | ||
10 | $notificationsFiles $searchFiles $checkParamFiles | ||
diff --git a/server/tests/api/travis-2.sh b/server/tests/api/travis-2.sh new file mode 100644 index 000000000..ba7a061b0 --- /dev/null +++ b/server/tests/api/travis-2.sh | |||
@@ -0,0 +1,9 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | |||
3 | set -eu | ||
4 | |||
5 | serverFiles=$(find server/tests/api/server -type f | grep -v index.ts | xargs echo) | ||
6 | usersFiles=$(find server/tests/api/users -type f | grep -v index.ts | xargs echo) | ||
7 | |||
8 | MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \ | ||
9 | $serverFiles $usersFiles | ||
diff --git a/server/tests/api/travis-3.sh b/server/tests/api/travis-3.sh new file mode 100644 index 000000000..82457222c --- /dev/null +++ b/server/tests/api/travis-3.sh | |||
@@ -0,0 +1,8 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | |||
3 | set -eu | ||
4 | |||
5 | videosFiles=$(find server/tests/api/videos -type f | grep -v index.ts | xargs echo) | ||
6 | |||
7 | MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \ | ||
8 | $videosFiles | ||
diff --git a/server/tests/api/travis-4.sh b/server/tests/api/travis-4.sh new file mode 100644 index 000000000..875986182 --- /dev/null +++ b/server/tests/api/travis-4.sh | |||
@@ -0,0 +1,9 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | |||
3 | set -eu | ||
4 | |||
5 | redundancyFiles=$(find server/tests/api/redundancy -type f | grep -v index.ts | xargs echo) | ||
6 | activitypubFiles=$(find server/tests/api/activitypub -type f | grep -v index.ts | xargs echo) | ||
7 | |||
8 | MOCHA_PARALLEL=true mocha-parallel-tests --max-parallel $1 --timeout 5000 --exit --require ts-node/register --bail \ | ||
9 | $redundancyFiles $activitypubFiles | ||
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts index fbc57e0ef..c25e85ada 100644 --- a/server/tests/api/users/blocklist.ts +++ b/server/tests/api/users/blocklist.ts | |||
@@ -144,7 +144,7 @@ describe('Test blocklist', function () { | |||
144 | }) | 144 | }) |
145 | 145 | ||
146 | it('Should block a remote account', async function () { | 146 | it('Should block a remote account', async function () { |
147 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') | 147 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) |
148 | }) | 148 | }) |
149 | 149 | ||
150 | it('Should hide its videos', async function () { | 150 | it('Should hide its videos', async function () { |
@@ -209,7 +209,7 @@ describe('Test blocklist', function () { | |||
209 | expect(block.byAccount.name).to.equal('root') | 209 | expect(block.byAccount.name).to.equal('root') |
210 | expect(block.blockedAccount.displayName).to.equal('user2') | 210 | expect(block.blockedAccount.displayName).to.equal('user2') |
211 | expect(block.blockedAccount.name).to.equal('user2') | 211 | expect(block.blockedAccount.name).to.equal('user2') |
212 | expect(block.blockedAccount.host).to.equal('localhost:9002') | 212 | expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port) |
213 | } | 213 | } |
214 | 214 | ||
215 | { | 215 | { |
@@ -223,12 +223,12 @@ describe('Test blocklist', function () { | |||
223 | expect(block.byAccount.name).to.equal('root') | 223 | expect(block.byAccount.name).to.equal('root') |
224 | expect(block.blockedAccount.displayName).to.equal('user1') | 224 | expect(block.blockedAccount.displayName).to.equal('user1') |
225 | expect(block.blockedAccount.name).to.equal('user1') | 225 | expect(block.blockedAccount.name).to.equal('user1') |
226 | expect(block.blockedAccount.host).to.equal('localhost:9001') | 226 | expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port) |
227 | } | 227 | } |
228 | }) | 228 | }) |
229 | 229 | ||
230 | it('Should unblock the remote account', async function () { | 230 | it('Should unblock the remote account', async function () { |
231 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') | 231 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) |
232 | }) | 232 | }) |
233 | 233 | ||
234 | it('Should display its videos', async function () { | 234 | it('Should display its videos', async function () { |
@@ -260,7 +260,7 @@ describe('Test blocklist', function () { | |||
260 | }) | 260 | }) |
261 | 261 | ||
262 | it('Should block a remote server', async function () { | 262 | it('Should block a remote server', async function () { |
263 | await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') | 263 | await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) |
264 | }) | 264 | }) |
265 | 265 | ||
266 | it('Should hide its videos', async function () { | 266 | it('Should hide its videos', async function () { |
@@ -291,11 +291,11 @@ describe('Test blocklist', function () { | |||
291 | const block = blocks[ 0 ] | 291 | const block = blocks[ 0 ] |
292 | expect(block.byAccount.displayName).to.equal('root') | 292 | expect(block.byAccount.displayName).to.equal('root') |
293 | expect(block.byAccount.name).to.equal('root') | 293 | expect(block.byAccount.name).to.equal('root') |
294 | expect(block.blockedServer.host).to.equal('localhost:9002') | 294 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
295 | }) | 295 | }) |
296 | 296 | ||
297 | it('Should unblock the remote server', async function () { | 297 | it('Should unblock the remote server', async function () { |
298 | await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') | 298 | await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) |
299 | }) | 299 | }) |
300 | 300 | ||
301 | it('Should display its videos', function () { | 301 | it('Should display its videos', function () { |
@@ -324,7 +324,7 @@ describe('Test blocklist', function () { | |||
324 | }) | 324 | }) |
325 | 325 | ||
326 | it('Should block a remote account', async function () { | 326 | it('Should block a remote account', async function () { |
327 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') | 327 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) |
328 | }) | 328 | }) |
329 | 329 | ||
330 | it('Should hide its videos', async function () { | 330 | it('Should hide its videos', async function () { |
@@ -387,7 +387,7 @@ describe('Test blocklist', function () { | |||
387 | expect(block.byAccount.name).to.equal('peertube') | 387 | expect(block.byAccount.name).to.equal('peertube') |
388 | expect(block.blockedAccount.displayName).to.equal('user2') | 388 | expect(block.blockedAccount.displayName).to.equal('user2') |
389 | expect(block.blockedAccount.name).to.equal('user2') | 389 | expect(block.blockedAccount.name).to.equal('user2') |
390 | expect(block.blockedAccount.host).to.equal('localhost:9002') | 390 | expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port) |
391 | } | 391 | } |
392 | 392 | ||
393 | { | 393 | { |
@@ -401,12 +401,12 @@ describe('Test blocklist', function () { | |||
401 | expect(block.byAccount.name).to.equal('peertube') | 401 | expect(block.byAccount.name).to.equal('peertube') |
402 | expect(block.blockedAccount.displayName).to.equal('user1') | 402 | expect(block.blockedAccount.displayName).to.equal('user1') |
403 | expect(block.blockedAccount.name).to.equal('user1') | 403 | expect(block.blockedAccount.name).to.equal('user1') |
404 | expect(block.blockedAccount.host).to.equal('localhost:9001') | 404 | expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port) |
405 | } | 405 | } |
406 | }) | 406 | }) |
407 | 407 | ||
408 | it('Should unblock the remote account', async function () { | 408 | it('Should unblock the remote account', async function () { |
409 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') | 409 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) |
410 | }) | 410 | }) |
411 | 411 | ||
412 | it('Should display its videos', async function () { | 412 | it('Should display its videos', async function () { |
@@ -446,7 +446,7 @@ describe('Test blocklist', function () { | |||
446 | }) | 446 | }) |
447 | 447 | ||
448 | it('Should block a remote server', async function () { | 448 | it('Should block a remote server', async function () { |
449 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') | 449 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) |
450 | }) | 450 | }) |
451 | 451 | ||
452 | it('Should hide its videos', async function () { | 452 | it('Should hide its videos', async function () { |
@@ -478,11 +478,11 @@ describe('Test blocklist', function () { | |||
478 | const block = blocks[ 0 ] | 478 | const block = blocks[ 0 ] |
479 | expect(block.byAccount.displayName).to.equal('peertube') | 479 | expect(block.byAccount.displayName).to.equal('peertube') |
480 | expect(block.byAccount.name).to.equal('peertube') | 480 | expect(block.byAccount.name).to.equal('peertube') |
481 | expect(block.blockedServer.host).to.equal('localhost:9002') | 481 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
482 | }) | 482 | }) |
483 | 483 | ||
484 | it('Should unblock the remote server', async function () { | 484 | it('Should unblock the remote server', async function () { |
485 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') | 485 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) |
486 | }) | 486 | }) |
487 | 487 | ||
488 | it('Should list all videos', async function () { | 488 | it('Should list all videos', async function () { |
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts index 48811e647..c8a89d6be 100644 --- a/server/tests/api/users/user-subscriptions.ts +++ b/server/tests/api/users/user-subscriptions.ts | |||
@@ -71,8 +71,8 @@ describe('Test users subscriptions', function () { | |||
71 | it('User of server 1 should follow user of server 3 and root of server 1', async function () { | 71 | it('User of server 1 should follow user of server 3 and root of server 1', async function () { |
72 | this.timeout(60000) | 72 | this.timeout(60000) |
73 | 73 | ||
74 | await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') | 74 | await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port) |
75 | await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001') | 75 | await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port) |
76 | 76 | ||
77 | await waitJobs(servers) | 77 | await waitJobs(servers) |
78 | 78 | ||
@@ -116,22 +116,22 @@ describe('Test users subscriptions', function () { | |||
116 | 116 | ||
117 | it('Should get subscription', async function () { | 117 | it('Should get subscription', async function () { |
118 | { | 118 | { |
119 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:9003') | 119 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port) |
120 | const videoChannel: VideoChannel = res.body | 120 | const videoChannel: VideoChannel = res.body |
121 | 121 | ||
122 | expect(videoChannel.name).to.equal('user3_channel') | 122 | expect(videoChannel.name).to.equal('user3_channel') |
123 | expect(videoChannel.host).to.equal('localhost:9003') | 123 | expect(videoChannel.host).to.equal('localhost:' + servers[2].port) |
124 | expect(videoChannel.displayName).to.equal('Main user3 channel') | 124 | expect(videoChannel.displayName).to.equal('Main user3 channel') |
125 | expect(videoChannel.followingCount).to.equal(0) | 125 | expect(videoChannel.followingCount).to.equal(0) |
126 | expect(videoChannel.followersCount).to.equal(1) | 126 | expect(videoChannel.followersCount).to.equal(1) |
127 | } | 127 | } |
128 | 128 | ||
129 | { | 129 | { |
130 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:9001') | 130 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port) |
131 | const videoChannel: VideoChannel = res.body | 131 | const videoChannel: VideoChannel = res.body |
132 | 132 | ||
133 | expect(videoChannel.name).to.equal('root_channel') | 133 | expect(videoChannel.name).to.equal('root_channel') |
134 | expect(videoChannel.host).to.equal('localhost:9001') | 134 | expect(videoChannel.host).to.equal('localhost:' + servers[0].port) |
135 | expect(videoChannel.displayName).to.equal('Main root channel') | 135 | expect(videoChannel.displayName).to.equal('Main root channel') |
136 | expect(videoChannel.followingCount).to.equal(0) | 136 | expect(videoChannel.followingCount).to.equal(0) |
137 | expect(videoChannel.followersCount).to.equal(1) | 137 | expect(videoChannel.followersCount).to.equal(1) |
@@ -140,19 +140,19 @@ describe('Test users subscriptions', function () { | |||
140 | 140 | ||
141 | it('Should return the existing subscriptions', async function () { | 141 | it('Should return the existing subscriptions', async function () { |
142 | const uris = [ | 142 | const uris = [ |
143 | 'user3_channel@localhost:9003', | 143 | 'user3_channel@localhost:' + servers[2].port, |
144 | 'root2_channel@localhost:9001', | 144 | 'root2_channel@localhost:' + servers[0].port, |
145 | 'root_channel@localhost:9001', | 145 | 'root_channel@localhost:' + servers[0].port, |
146 | 'user3_channel@localhost:9001' | 146 | 'user3_channel@localhost:' + servers[0].port |
147 | ] | 147 | ] |
148 | 148 | ||
149 | const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) | 149 | const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) |
150 | const body = res.body | 150 | const body = res.body |
151 | 151 | ||
152 | expect(body['user3_channel@localhost:9003']).to.be.true | 152 | expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true |
153 | expect(body['root2_channel@localhost:9001']).to.be.false | 153 | expect(body['root2_channel@localhost:' + servers[0].port]).to.be.false |
154 | expect(body['root_channel@localhost:9001']).to.be.true | 154 | expect(body['root_channel@localhost:' + servers[0].port]).to.be.true |
155 | expect(body['user3_channel@localhost:9001']).to.be.false | 155 | expect(body['user3_channel@localhost:' + servers[0].port]).to.be.false |
156 | }) | 156 | }) |
157 | 157 | ||
158 | it('Should list subscription videos', async function () { | 158 | it('Should list subscription videos', async function () { |
@@ -291,7 +291,7 @@ describe('Test users subscriptions', function () { | |||
291 | it('Should remove user of server 3 subscription', async function () { | 291 | it('Should remove user of server 3 subscription', async function () { |
292 | this.timeout(30000) | 292 | this.timeout(30000) |
293 | 293 | ||
294 | await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') | 294 | await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port) |
295 | 295 | ||
296 | await waitJobs(servers) | 296 | await waitJobs(servers) |
297 | }) | 297 | }) |
@@ -312,7 +312,7 @@ describe('Test users subscriptions', function () { | |||
312 | it('Should remove the root subscription and not display the videos anymore', async function () { | 312 | it('Should remove the root subscription and not display the videos anymore', async function () { |
313 | this.timeout(30000) | 313 | this.timeout(30000) |
314 | 314 | ||
315 | await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001') | 315 | await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port) |
316 | 316 | ||
317 | await waitJobs(servers) | 317 | await waitJobs(servers) |
318 | 318 | ||
@@ -340,7 +340,7 @@ describe('Test users subscriptions', function () { | |||
340 | it('Should follow user of server 3 again', async function () { | 340 | it('Should follow user of server 3 again', async function () { |
341 | this.timeout(60000) | 341 | this.timeout(60000) |
342 | 342 | ||
343 | await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') | 343 | await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port) |
344 | 344 | ||
345 | await waitJobs(servers) | 345 | await waitJobs(servers) |
346 | 346 | ||
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index 9a971adb3..791418318 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -5,7 +5,8 @@ import 'mocha' | |||
5 | import { Account } from '../../../../shared/models/actors' | 5 | import { Account } from '../../../../shared/models/actors' |
6 | import { | 6 | import { |
7 | checkTmpIsEmpty, | 7 | checkTmpIsEmpty, |
8 | checkVideoFilesWereRemoved, cleanupTests, | 8 | checkVideoFilesWereRemoved, |
9 | cleanupTests, | ||
9 | createUser, | 10 | createUser, |
10 | doubleFollow, | 11 | doubleFollow, |
11 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
@@ -15,14 +16,7 @@ import { | |||
15 | updateMyUser, | 16 | updateMyUser, |
16 | userLogin | 17 | userLogin |
17 | } from '../../../../shared/extra-utils' | 18 | } from '../../../../shared/extra-utils' |
18 | import { | 19 | import { getMyUserInformation, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../../../shared/extra-utils/index' |
19 | getMyUserInformation, | ||
20 | killallServers, | ||
21 | ServerInfo, | ||
22 | testImage, | ||
23 | updateMyAvatar, | ||
24 | uploadVideo | ||
25 | } from '../../../../shared/extra-utils/index' | ||
26 | import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts' | 20 | import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts' |
27 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 21 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
28 | import { User } from '../../../../shared/models/users' | 22 | import { User } from '../../../../shared/models/users' |
@@ -34,12 +28,10 @@ const expect = chai.expect | |||
34 | describe('Test users with multiple servers', function () { | 28 | describe('Test users with multiple servers', function () { |
35 | let servers: ServerInfo[] = [] | 29 | let servers: ServerInfo[] = [] |
36 | let user: User | 30 | let user: User |
37 | let userAccountName: string | ||
38 | let userAccountUUID: string | ||
39 | let userVideoChannelUUID: string | ||
40 | let userId: number | 31 | let userId: number |
41 | let videoUUID: string | 32 | let videoUUID: string |
42 | let userAccessToken: string | 33 | let userAccessToken: string |
34 | let userAvatarFilename: string | ||
43 | 35 | ||
44 | before(async function () { | 36 | before(async function () { |
45 | this.timeout(120000) | 37 | this.timeout(120000) |
@@ -75,19 +67,6 @@ describe('Test users with multiple servers', function () { | |||
75 | } | 67 | } |
76 | 68 | ||
77 | { | 69 | { |
78 | const res = await getMyUserInformation(servers[0].url, userAccessToken) | ||
79 | const account: Account = res.body.account | ||
80 | userAccountName = account.name + '@' + account.host | ||
81 | userAccountUUID = account.uuid | ||
82 | } | ||
83 | |||
84 | { | ||
85 | const res = await getMyUserInformation(servers[ 0 ].url, servers[ 0 ].accessToken) | ||
86 | const user: User = res.body | ||
87 | userVideoChannelUUID = user.videoChannels[0].uuid | ||
88 | } | ||
89 | |||
90 | { | ||
91 | const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) | 70 | const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) |
92 | videoUUID = resVideo.body.video.uuid | 71 | videoUUID = resVideo.body.video.uuid |
93 | } | 72 | } |
@@ -106,6 +85,8 @@ describe('Test users with multiple servers', function () { | |||
106 | 85 | ||
107 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 86 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
108 | user = res.body | 87 | user = res.body |
88 | |||
89 | const account: Account = user.account | ||
109 | expect(user.account.displayName).to.equal('my super display name') | 90 | expect(user.account.displayName).to.equal('my super display name') |
110 | 91 | ||
111 | await waitJobs(servers) | 92 | await waitJobs(servers) |
@@ -142,7 +123,9 @@ describe('Test users with multiple servers', function () { | |||
142 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 123 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
143 | user = res.body | 124 | user = res.body |
144 | 125 | ||
145 | await testImage(servers[0].url, 'avatar2-resized', user.account.avatar.path, '.png') | 126 | userAvatarFilename = user.account.avatar.path |
127 | |||
128 | await testImage(servers[0].url, 'avatar2-resized', userAvatarFilename, '.png') | ||
146 | 129 | ||
147 | await waitJobs(servers) | 130 | await waitJobs(servers) |
148 | }) | 131 | }) |
@@ -151,13 +134,13 @@ describe('Test users with multiple servers', function () { | |||
151 | for (const server of servers) { | 134 | for (const server of servers) { |
152 | const resAccounts = await getAccountsList(server.url, '-createdAt') | 135 | const resAccounts = await getAccountsList(server.url, '-createdAt') |
153 | 136 | ||
154 | const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:9001') as Account | 137 | const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account |
155 | expect(rootServer1List).not.to.be.undefined | 138 | expect(rootServer1List).not.to.be.undefined |
156 | 139 | ||
157 | const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host) | 140 | const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host) |
158 | const rootServer1Get = resAccount.body as Account | 141 | const rootServer1Get = resAccount.body as Account |
159 | expect(rootServer1Get.name).to.equal('root') | 142 | expect(rootServer1Get.name).to.equal('root') |
160 | expect(rootServer1Get.host).to.equal('localhost:9001') | 143 | expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port) |
161 | expect(rootServer1Get.displayName).to.equal('my super display name') | 144 | expect(rootServer1Get.displayName).to.equal('my super display name') |
162 | expect(rootServer1Get.description).to.equal('my super description updated') | 145 | expect(rootServer1Get.description).to.equal('my super description updated') |
163 | 146 | ||
@@ -173,7 +156,7 @@ describe('Test users with multiple servers', function () { | |||
173 | 156 | ||
174 | it('Should list account videos', async function () { | 157 | it('Should list account videos', async function () { |
175 | for (const server of servers) { | 158 | for (const server of servers) { |
176 | const res = await getAccountVideos(server.url, server.accessToken, userAccountName, 0, 5) | 159 | const res = await getAccountVideos(server.url, server.accessToken, 'user1@localhost:' + servers[0].port, 0, 5) |
177 | 160 | ||
178 | expect(res.body.total).to.equal(1) | 161 | expect(res.body.total).to.equal(1) |
179 | expect(res.body.data).to.be.an('array') | 162 | expect(res.body.data).to.be.an('array') |
@@ -188,12 +171,12 @@ describe('Test users with multiple servers', function () { | |||
188 | for (const server of servers) { | 171 | for (const server of servers) { |
189 | const resAccounts = await getAccountsList(server.url, '-createdAt') | 172 | const resAccounts = await getAccountsList(server.url, '-createdAt') |
190 | 173 | ||
191 | const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account | 174 | const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account |
192 | expect(accountDeleted).not.to.be.undefined | 175 | expect(accountDeleted).not.to.be.undefined |
193 | 176 | ||
194 | const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) | 177 | const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) |
195 | const videoChannelDeleted = resVideoChannels.body.data.find(a => { | 178 | const videoChannelDeleted = resVideoChannels.body.data.find(a => { |
196 | return a.displayName === 'Main user1 channel' && a.host === 'localhost:9001' | 179 | return a.displayName === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port |
197 | }) as VideoChannel | 180 | }) as VideoChannel |
198 | expect(videoChannelDeleted).not.to.be.undefined | 181 | expect(videoChannelDeleted).not.to.be.undefined |
199 | } | 182 | } |
@@ -205,12 +188,12 @@ describe('Test users with multiple servers', function () { | |||
205 | for (const server of servers) { | 188 | for (const server of servers) { |
206 | const resAccounts = await getAccountsList(server.url, '-createdAt') | 189 | const resAccounts = await getAccountsList(server.url, '-createdAt') |
207 | 190 | ||
208 | const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account | 191 | const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account |
209 | expect(accountDeleted).to.be.undefined | 192 | expect(accountDeleted).to.be.undefined |
210 | 193 | ||
211 | const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) | 194 | const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) |
212 | const videoChannelDeleted = resVideoChannels.body.data.find(a => { | 195 | const videoChannelDeleted = resVideoChannels.body.data.find(a => { |
213 | return a.name === 'Main user1 channel' && a.host === 'localhost:9001' | 196 | return a.name === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port |
214 | }) as VideoChannel | 197 | }) as VideoChannel |
215 | expect(videoChannelDeleted).to.be.undefined | 198 | expect(videoChannelDeleted).to.be.undefined |
216 | } | 199 | } |
@@ -218,14 +201,13 @@ describe('Test users with multiple servers', function () { | |||
218 | 201 | ||
219 | it('Should not have actor files', async () => { | 202 | it('Should not have actor files', async () => { |
220 | for (const server of servers) { | 203 | for (const server of servers) { |
221 | await checkActorFilesWereRemoved(userAccountUUID, server.serverNumber) | 204 | await checkActorFilesWereRemoved(userAvatarFilename, server.internalServerNumber) |
222 | await checkActorFilesWereRemoved(userVideoChannelUUID, server.serverNumber) | ||
223 | } | 205 | } |
224 | }) | 206 | }) |
225 | 207 | ||
226 | it('Should not have video files', async () => { | 208 | it('Should not have video files', async () => { |
227 | for (const server of servers) { | 209 | for (const server of servers) { |
228 | await checkVideoFilesWereRemoved(videoUUID, server.serverNumber) | 210 | await checkVideoFilesWereRemoved(videoUUID, server.internalServerNumber) |
229 | } | 211 | } |
230 | }) | 212 | }) |
231 | 213 | ||
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts index 514acf2e7..3b37a26cf 100644 --- a/server/tests/api/users/users-verification.ts +++ b/server/tests/api/users/users-verification.ts | |||
@@ -30,11 +30,12 @@ describe('Test users account verification', function () { | |||
30 | before(async function () { | 30 | before(async function () { |
31 | this.timeout(30000) | 31 | this.timeout(30000) |
32 | 32 | ||
33 | await MockSmtpServer.Instance.collectEmails(emails) | 33 | const port = await MockSmtpServer.Instance.collectEmails(emails) |
34 | 34 | ||
35 | const overrideConfig = { | 35 | const overrideConfig = { |
36 | smtp: { | 36 | smtp: { |
37 | hostname: 'localhost' | 37 | hostname: 'localhost', |
38 | port | ||
38 | } | 39 | } |
39 | } | 40 | } |
40 | server = await flushAndRunServer(1, overrideConfig) | 41 | server = await flushAndRunServer(1, overrideConfig) |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index c8e32f3f5..9d2ef786f 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -31,7 +31,8 @@ import { | |||
31 | updateMyUser, | 31 | updateMyUser, |
32 | updateUser, | 32 | updateUser, |
33 | uploadVideo, | 33 | uploadVideo, |
34 | userLogin | 34 | userLogin, |
35 | registerUserWithChannel, getVideoChannel | ||
35 | } from '../../../../shared/extra-utils' | 36 | } from '../../../../shared/extra-utils' |
36 | import { follow } from '../../../../shared/extra-utils/server/follows' | 37 | import { follow } from '../../../../shared/extra-utils/server/follows' |
37 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 38 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
@@ -316,7 +317,7 @@ describe('Test users', function () { | |||
316 | 317 | ||
317 | const rootUser = users[ 1 ] | 318 | const rootUser = users[ 1 ] |
318 | expect(rootUser.username).to.equal('root') | 319 | expect(rootUser.username).to.equal('root') |
319 | expect(rootUser.email).to.equal('admin1@example.com') | 320 | expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
320 | expect(user.nsfwPolicy).to.equal('display') | 321 | expect(user.nsfwPolicy).to.equal('display') |
321 | 322 | ||
322 | userId = user.id | 323 | userId = user.id |
@@ -334,7 +335,7 @@ describe('Test users', function () { | |||
334 | 335 | ||
335 | const user = users[ 0 ] | 336 | const user = users[ 0 ] |
336 | expect(user.username).to.equal('root') | 337 | expect(user.username).to.equal('root') |
337 | expect(user.email).to.equal('admin1@example.com') | 338 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
338 | expect(user.roleLabel).to.equal('Administrator') | 339 | expect(user.roleLabel).to.equal('Administrator') |
339 | expect(user.nsfwPolicy).to.equal('display') | 340 | expect(user.nsfwPolicy).to.equal('display') |
340 | }) | 341 | }) |
@@ -379,7 +380,7 @@ describe('Test users', function () { | |||
379 | expect(users.length).to.equal(2) | 380 | expect(users.length).to.equal(2) |
380 | 381 | ||
381 | expect(users[ 0 ].username).to.equal('root') | 382 | expect(users[ 0 ].username).to.equal('root') |
382 | expect(users[ 0 ].email).to.equal('admin1@example.com') | 383 | expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com') |
383 | expect(users[ 0 ].nsfwPolicy).to.equal('display') | 384 | expect(users[ 0 ].nsfwPolicy).to.equal('display') |
384 | 385 | ||
385 | expect(users[ 1 ].username).to.equal('user_1') | 386 | expect(users[ 1 ].username).to.equal('user_1') |
@@ -617,7 +618,10 @@ describe('Test users', function () { | |||
617 | 618 | ||
618 | describe('Registering a new user', function () { | 619 | describe('Registering a new user', function () { |
619 | it('Should register a new user', async function () { | 620 | it('Should register a new user', async function () { |
620 | await registerUser(server.url, 'user_15', 'my super password') | 621 | const user = { username: 'user_15', password: 'my super password' } |
622 | const channel = { name: 'my_user_15_channel', displayName: 'my channel rocks' } | ||
623 | |||
624 | await registerUserWithChannel({ url: server.url, user, channel }) | ||
621 | }) | 625 | }) |
622 | 626 | ||
623 | it('Should be able to login with this registered user', async function () { | 627 | it('Should be able to login with this registered user', async function () { |
@@ -636,6 +640,12 @@ describe('Test users', function () { | |||
636 | expect(user.videoQuota).to.equal(5 * 1024 * 1024) | 640 | expect(user.videoQuota).to.equal(5 * 1024 * 1024) |
637 | }) | 641 | }) |
638 | 642 | ||
643 | it('Should have created the channel', async function () { | ||
644 | const res = await getVideoChannel(server.url, 'my_user_15_channel') | ||
645 | |||
646 | expect(res.body.displayName).to.equal('my channel rocks') | ||
647 | }) | ||
648 | |||
639 | it('Should remove me', async function () { | 649 | it('Should remove me', async function () { |
640 | { | 650 | { |
641 | const res = await getUsersList(server.url, server.accessToken) | 651 | const res = await getUsersList(server.url, server.accessToken) |
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index 68c1e9a8d..e9625e5f7 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -9,18 +9,17 @@ import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/ | |||
9 | import { | 9 | import { |
10 | addVideoChannel, | 10 | addVideoChannel, |
11 | checkTmpIsEmpty, | 11 | checkTmpIsEmpty, |
12 | checkVideoFilesWereRemoved, cleanupTests, | 12 | checkVideoFilesWereRemoved, |
13 | cleanupTests, | ||
13 | completeVideoCheck, | 14 | completeVideoCheck, |
14 | createUser, | 15 | createUser, |
15 | dateIsValid, | 16 | dateIsValid, |
16 | doubleFollow, | 17 | doubleFollow, |
17 | flushAndRunMultipleServers, | 18 | flushAndRunMultipleServers, |
18 | flushTests, | ||
19 | getLocalVideos, | 19 | getLocalVideos, |
20 | getVideo, | 20 | getVideo, |
21 | getVideoChannelsList, | 21 | getVideoChannelsList, |
22 | getVideosList, | 22 | getVideosList, |
23 | killallServers, | ||
24 | rateVideo, | 23 | rateVideo, |
25 | removeVideo, | 24 | removeVideo, |
26 | ServerInfo, | 25 | ServerInfo, |
@@ -110,7 +109,7 @@ describe('Test multiple servers', function () { | |||
110 | // All servers should have this video | 109 | // All servers should have this video |
111 | let publishedAt: string = null | 110 | let publishedAt: string = null |
112 | for (const server of servers) { | 111 | for (const server of servers) { |
113 | const isLocal = server.url === 'http://localhost:9001' | 112 | const isLocal = server.port === servers[0].port |
114 | const checkAttributes = { | 113 | const checkAttributes = { |
115 | name: 'my super name for server 1', | 114 | name: 'my super name for server 1', |
116 | category: 5, | 115 | category: 5, |
@@ -122,7 +121,7 @@ describe('Test multiple servers', function () { | |||
122 | originallyPublishedAt: '2019-02-10T13:38:14.449Z', | 121 | originallyPublishedAt: '2019-02-10T13:38:14.449Z', |
123 | account: { | 122 | account: { |
124 | name: 'root', | 123 | name: 'root', |
125 | host: 'localhost:9001' | 124 | host: 'localhost:' + servers[0].port |
126 | }, | 125 | }, |
127 | isLocal, | 126 | isLocal, |
128 | publishedAt, | 127 | publishedAt, |
@@ -187,7 +186,7 @@ describe('Test multiple servers', function () { | |||
187 | 186 | ||
188 | // All servers should have this video | 187 | // All servers should have this video |
189 | for (const server of servers) { | 188 | for (const server of servers) { |
190 | const isLocal = server.url === 'http://localhost:9002' | 189 | const isLocal = server.url === 'http://localhost:' + servers[1].port |
191 | const checkAttributes = { | 190 | const checkAttributes = { |
192 | name: 'my super name for server 2', | 191 | name: 'my super name for server 2', |
193 | category: 4, | 192 | category: 4, |
@@ -198,7 +197,7 @@ describe('Test multiple servers', function () { | |||
198 | support: 'my super support text for server 2', | 197 | support: 'my super support text for server 2', |
199 | account: { | 198 | account: { |
200 | name: 'user1', | 199 | name: 'user1', |
201 | host: 'localhost:9002' | 200 | host: 'localhost:' + servers[1].port |
202 | }, | 201 | }, |
203 | isLocal, | 202 | isLocal, |
204 | commentsEnabled: true, | 203 | commentsEnabled: true, |
@@ -216,7 +215,7 @@ describe('Test multiple servers', function () { | |||
216 | files: [ | 215 | files: [ |
217 | { | 216 | { |
218 | resolution: 240, | 217 | resolution: 240, |
219 | size: 187000 | 218 | size: 189000 |
220 | }, | 219 | }, |
221 | { | 220 | { |
222 | resolution: 360, | 221 | resolution: 360, |
@@ -224,7 +223,7 @@ describe('Test multiple servers', function () { | |||
224 | }, | 223 | }, |
225 | { | 224 | { |
226 | resolution: 480, | 225 | resolution: 480, |
227 | size: 383000 | 226 | size: 384000 |
228 | }, | 227 | }, |
229 | { | 228 | { |
230 | resolution: 720, | 229 | resolution: 720, |
@@ -278,7 +277,7 @@ describe('Test multiple servers', function () { | |||
278 | 277 | ||
279 | // All servers should have this video | 278 | // All servers should have this video |
280 | for (const server of servers) { | 279 | for (const server of servers) { |
281 | const isLocal = server.url === 'http://localhost:9003' | 280 | const isLocal = server.url === 'http://localhost:' + servers[2].port |
282 | const res = await getVideosList(server.url) | 281 | const res = await getVideosList(server.url) |
283 | 282 | ||
284 | const videos = res.body.data | 283 | const videos = res.body.data |
@@ -306,7 +305,7 @@ describe('Test multiple servers', function () { | |||
306 | support: 'my super support text for server 3', | 305 | support: 'my super support text for server 3', |
307 | account: { | 306 | account: { |
308 | name: 'root', | 307 | name: 'root', |
309 | host: 'localhost:9003' | 308 | host: 'localhost:' + servers[2].port |
310 | }, | 309 | }, |
311 | isLocal, | 310 | isLocal, |
312 | duration: 5, | 311 | duration: 5, |
@@ -340,7 +339,7 @@ describe('Test multiple servers', function () { | |||
340 | support: 'my super support text for server 3-2', | 339 | support: 'my super support text for server 3-2', |
341 | account: { | 340 | account: { |
342 | name: 'root', | 341 | name: 'root', |
343 | host: 'localhost:9003' | 342 | host: 'localhost:' + servers[2].port |
344 | }, | 343 | }, |
345 | commentsEnabled: true, | 344 | commentsEnabled: true, |
346 | downloadEnabled: true, | 345 | downloadEnabled: true, |
@@ -646,7 +645,7 @@ describe('Test multiple servers', function () { | |||
646 | const videoUpdated = videos.find(video => video.name === 'my super video updated') | 645 | const videoUpdated = videos.find(video => video.name === 'my super video updated') |
647 | expect(!!videoUpdated).to.be.true | 646 | expect(!!videoUpdated).to.be.true |
648 | 647 | ||
649 | const isLocal = server.url === 'http://localhost:9003' | 648 | const isLocal = server.url === 'http://localhost:' + servers[2].port |
650 | const checkAttributes = { | 649 | const checkAttributes = { |
651 | name: 'my super video updated', | 650 | name: 'my super video updated', |
652 | category: 10, | 651 | category: 10, |
@@ -658,7 +657,7 @@ describe('Test multiple servers', function () { | |||
658 | originallyPublishedAt: '2019-02-11T13:38:14.449Z', | 657 | originallyPublishedAt: '2019-02-11T13:38:14.449Z', |
659 | account: { | 658 | account: { |
660 | name: 'root', | 659 | name: 'root', |
661 | host: 'localhost:9003' | 660 | host: 'localhost:' + servers[2].port |
662 | }, | 661 | }, |
663 | isLocal, | 662 | isLocal, |
664 | duration: 5, | 663 | duration: 5, |
@@ -813,7 +812,7 @@ describe('Test multiple servers', function () { | |||
813 | expect(comment).to.not.be.undefined | 812 | expect(comment).to.not.be.undefined |
814 | expect(comment.inReplyToCommentId).to.be.null | 813 | expect(comment.inReplyToCommentId).to.be.null |
815 | expect(comment.account.name).to.equal('root') | 814 | expect(comment.account.name).to.equal('root') |
816 | expect(comment.account.host).to.equal('localhost:9001') | 815 | expect(comment.account.host).to.equal('localhost:' + servers[0].port) |
817 | expect(comment.totalReplies).to.equal(3) | 816 | expect(comment.totalReplies).to.equal(3) |
818 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 817 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
819 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 818 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
@@ -824,7 +823,7 @@ describe('Test multiple servers', function () { | |||
824 | expect(comment).to.not.be.undefined | 823 | expect(comment).to.not.be.undefined |
825 | expect(comment.inReplyToCommentId).to.be.null | 824 | expect(comment.inReplyToCommentId).to.be.null |
826 | expect(comment.account.name).to.equal('root') | 825 | expect(comment.account.name).to.equal('root') |
827 | expect(comment.account.host).to.equal('localhost:9003') | 826 | expect(comment.account.host).to.equal('localhost:' + servers[2].port) |
828 | expect(comment.totalReplies).to.equal(0) | 827 | expect(comment.totalReplies).to.equal(0) |
829 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 828 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
830 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 829 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
@@ -842,25 +841,25 @@ describe('Test multiple servers', function () { | |||
842 | const tree: VideoCommentThreadTree = res2.body | 841 | const tree: VideoCommentThreadTree = res2.body |
843 | expect(tree.comment.text).equal('my super first comment') | 842 | expect(tree.comment.text).equal('my super first comment') |
844 | expect(tree.comment.account.name).equal('root') | 843 | expect(tree.comment.account.name).equal('root') |
845 | expect(tree.comment.account.host).equal('localhost:9001') | 844 | expect(tree.comment.account.host).equal('localhost:' + servers[0].port) |
846 | expect(tree.children).to.have.lengthOf(2) | 845 | expect(tree.children).to.have.lengthOf(2) |
847 | 846 | ||
848 | const firstChild = tree.children[0] | 847 | const firstChild = tree.children[0] |
849 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') | 848 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') |
850 | expect(firstChild.comment.account.name).equal('root') | 849 | expect(firstChild.comment.account.name).equal('root') |
851 | expect(firstChild.comment.account.host).equal('localhost:9002') | 850 | expect(firstChild.comment.account.host).equal('localhost:' + servers[1].port) |
852 | expect(firstChild.children).to.have.lengthOf(1) | 851 | expect(firstChild.children).to.have.lengthOf(1) |
853 | 852 | ||
854 | childOfFirstChild = firstChild.children[0] | 853 | childOfFirstChild = firstChild.children[0] |
855 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') | 854 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') |
856 | expect(childOfFirstChild.comment.account.name).equal('root') | 855 | expect(childOfFirstChild.comment.account.name).equal('root') |
857 | expect(childOfFirstChild.comment.account.host).equal('localhost:9003') | 856 | expect(childOfFirstChild.comment.account.host).equal('localhost:' + servers[2].port) |
858 | expect(childOfFirstChild.children).to.have.lengthOf(0) | 857 | expect(childOfFirstChild.children).to.have.lengthOf(0) |
859 | 858 | ||
860 | const secondChild = tree.children[1] | 859 | const secondChild = tree.children[1] |
861 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') | 860 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') |
862 | expect(secondChild.comment.account.name).equal('root') | 861 | expect(secondChild.comment.account.name).equal('root') |
863 | expect(secondChild.comment.account.host).equal('localhost:9003') | 862 | expect(secondChild.comment.account.host).equal('localhost:' + servers[2].port) |
864 | expect(secondChild.children).to.have.lengthOf(0) | 863 | expect(secondChild.children).to.have.lengthOf(0) |
865 | } | 864 | } |
866 | }) | 865 | }) |
@@ -915,7 +914,7 @@ describe('Test multiple servers', function () { | |||
915 | expect(comment).to.not.be.undefined | 914 | expect(comment).to.not.be.undefined |
916 | expect(comment.inReplyToCommentId).to.be.null | 915 | expect(comment.inReplyToCommentId).to.be.null |
917 | expect(comment.account.name).to.equal('root') | 916 | expect(comment.account.name).to.equal('root') |
918 | expect(comment.account.host).to.equal('localhost:9003') | 917 | expect(comment.account.host).to.equal('localhost:' + servers[2].port) |
919 | expect(comment.totalReplies).to.equal(0) | 918 | expect(comment.totalReplies).to.equal(0) |
920 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 919 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
921 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 920 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
@@ -971,7 +970,7 @@ describe('Test multiple servers', function () { | |||
971 | const res = await getVideosList(server.url) | 970 | const res = await getVideosList(server.url) |
972 | const video = res.body.data.find(v => v.name === 'minimum parameters') | 971 | const video = res.body.data.find(v => v.name === 'minimum parameters') |
973 | 972 | ||
974 | const isLocal = server.url === 'http://localhost:9002' | 973 | const isLocal = server.url === 'http://localhost:' + servers[1].port |
975 | const checkAttributes = { | 974 | const checkAttributes = { |
976 | name: 'minimum parameters', | 975 | name: 'minimum parameters', |
977 | category: null, | 976 | category: null, |
@@ -982,7 +981,7 @@ describe('Test multiple servers', function () { | |||
982 | support: null, | 981 | support: null, |
983 | account: { | 982 | account: { |
984 | name: 'root', | 983 | name: 'root', |
985 | host: 'localhost:9002' | 984 | host: 'localhost:' + servers[1].port |
986 | }, | 985 | }, |
987 | isLocal, | 986 | isLocal, |
988 | duration: 5, | 987 | duration: 5, |
diff --git a/server/tests/api/videos/services.ts b/server/tests/api/videos/services.ts index e9ad947b2..17172331f 100644 --- a/server/tests/api/videos/services.ts +++ b/server/tests/api/videos/services.ts | |||
@@ -27,13 +27,13 @@ describe('Test services', function () { | |||
27 | }) | 27 | }) |
28 | 28 | ||
29 | it('Should have a valid oEmbed response', async function () { | 29 | it('Should have a valid oEmbed response', async function () { |
30 | const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid | 30 | const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid |
31 | 31 | ||
32 | const res = await getOEmbed(server.url, oembedUrl) | 32 | const res = await getOEmbed(server.url, oembedUrl) |
33 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + | 33 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + |
34 | `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` + | 34 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + |
35 | 'frameborder="0" allowfullscreen></iframe>' | 35 | 'frameborder="0" allowfullscreen></iframe>' |
36 | const expectedThumbnailUrl = 'http://localhost:9001/static/previews/' + server.video.uuid + '.jpg' | 36 | const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg' |
37 | 37 | ||
38 | expect(res.body.html).to.equal(expectedHtml) | 38 | expect(res.body.html).to.equal(expectedHtml) |
39 | expect(res.body.title).to.equal(server.video.name) | 39 | expect(res.body.title).to.equal(server.video.name) |
@@ -41,19 +41,19 @@ describe('Test services', function () { | |||
41 | expect(res.body.width).to.equal(560) | 41 | expect(res.body.width).to.equal(560) |
42 | expect(res.body.height).to.equal(315) | 42 | expect(res.body.height).to.equal(315) |
43 | expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) | 43 | expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) |
44 | expect(res.body.thumbnail_width).to.equal(560) | 44 | expect(res.body.thumbnail_width).to.equal(850) |
45 | expect(res.body.thumbnail_height).to.equal(315) | 45 | expect(res.body.thumbnail_height).to.equal(480) |
46 | }) | 46 | }) |
47 | 47 | ||
48 | it('Should have a valid oEmbed response with small max height query', async function () { | 48 | it('Should have a valid oEmbed response with small max height query', async function () { |
49 | const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid | 49 | const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid |
50 | const format = 'json' | 50 | const format = 'json' |
51 | const maxHeight = 50 | 51 | const maxHeight = 50 |
52 | const maxWidth = 50 | 52 | const maxWidth = 50 |
53 | 53 | ||
54 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) | 54 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) |
55 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + | 55 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + |
56 | `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` + | 56 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + |
57 | 'frameborder="0" allowfullscreen></iframe>' | 57 | 'frameborder="0" allowfullscreen></iframe>' |
58 | 58 | ||
59 | expect(res.body.html).to.equal(expectedHtml) | 59 | expect(res.body.html).to.equal(expectedHtml) |
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts index 1f366b642..d8f394ac7 100644 --- a/server/tests/api/videos/single-server.ts +++ b/server/tests/api/videos/single-server.ts | |||
@@ -37,7 +37,7 @@ describe('Test a single server', function () { | |||
37 | let videoUUID = '' | 37 | let videoUUID = '' |
38 | let videosListBase: any[] = null | 38 | let videosListBase: any[] = null |
39 | 39 | ||
40 | const getCheckAttributes = { | 40 | const getCheckAttributes = () => ({ |
41 | name: 'my super name', | 41 | name: 'my super name', |
42 | category: 2, | 42 | category: 2, |
43 | licence: 6, | 43 | licence: 6, |
@@ -47,7 +47,7 @@ describe('Test a single server', function () { | |||
47 | support: 'my super support text', | 47 | support: 'my super support text', |
48 | account: { | 48 | account: { |
49 | name: 'root', | 49 | name: 'root', |
50 | host: 'localhost:9001' | 50 | host: 'localhost:' + server.port |
51 | }, | 51 | }, |
52 | isLocal: true, | 52 | isLocal: true, |
53 | duration: 5, | 53 | duration: 5, |
@@ -68,9 +68,9 @@ describe('Test a single server', function () { | |||
68 | size: 218910 | 68 | size: 218910 |
69 | } | 69 | } |
70 | ] | 70 | ] |
71 | } | 71 | }) |
72 | 72 | ||
73 | const updateCheckAttributes = { | 73 | const updateCheckAttributes = () => ({ |
74 | name: 'my super video updated', | 74 | name: 'my super video updated', |
75 | category: 4, | 75 | category: 4, |
76 | licence: 2, | 76 | licence: 2, |
@@ -80,7 +80,7 @@ describe('Test a single server', function () { | |||
80 | support: 'my super support text updated', | 80 | support: 'my super support text updated', |
81 | account: { | 81 | account: { |
82 | name: 'root', | 82 | name: 'root', |
83 | host: 'localhost:9001' | 83 | host: 'localhost:' + server.port |
84 | }, | 84 | }, |
85 | isLocal: true, | 85 | isLocal: true, |
86 | tags: [ 'tagup1', 'tagup2' ], | 86 | tags: [ 'tagup1', 'tagup2' ], |
@@ -101,7 +101,7 @@ describe('Test a single server', function () { | |||
101 | size: 292677 | 101 | size: 292677 |
102 | } | 102 | } |
103 | ] | 103 | ] |
104 | } | 104 | }) |
105 | 105 | ||
106 | before(async function () { | 106 | before(async function () { |
107 | this.timeout(30000) | 107 | this.timeout(30000) |
@@ -182,7 +182,7 @@ describe('Test a single server', function () { | |||
182 | expect(res.body.data.length).to.equal(1) | 182 | expect(res.body.data.length).to.equal(1) |
183 | 183 | ||
184 | const video = res.body.data[0] | 184 | const video = res.body.data[0] |
185 | await completeVideoCheck(server.url, video, getCheckAttributes) | 185 | await completeVideoCheck(server.url, video, getCheckAttributes()) |
186 | }) | 186 | }) |
187 | 187 | ||
188 | it('Should get the video by UUID', async function () { | 188 | it('Should get the video by UUID', async function () { |
@@ -191,7 +191,7 @@ describe('Test a single server', function () { | |||
191 | const res = await getVideo(server.url, videoUUID) | 191 | const res = await getVideo(server.url, videoUUID) |
192 | 192 | ||
193 | const video = res.body | 193 | const video = res.body |
194 | await completeVideoCheck(server.url, video, getCheckAttributes) | 194 | await completeVideoCheck(server.url, video, getCheckAttributes()) |
195 | }) | 195 | }) |
196 | 196 | ||
197 | it('Should have the views updated', async function () { | 197 | it('Should have the views updated', async function () { |
@@ -376,7 +376,7 @@ describe('Test a single server', function () { | |||
376 | const res = await getVideo(server.url, videoId) | 376 | const res = await getVideo(server.url, videoId) |
377 | const video = res.body | 377 | const video = res.body |
378 | 378 | ||
379 | await completeVideoCheck(server.url, video, updateCheckAttributes) | 379 | await completeVideoCheck(server.url, video, updateCheckAttributes()) |
380 | }) | 380 | }) |
381 | 381 | ||
382 | it('Should update only the tags of a video', async function () { | 382 | it('Should update only the tags of a video', async function () { |
@@ -388,7 +388,7 @@ describe('Test a single server', function () { | |||
388 | const res = await getVideo(server.url, videoId) | 388 | const res = await getVideo(server.url, videoId) |
389 | const video = res.body | 389 | const video = res.body |
390 | 390 | ||
391 | await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes)) | 391 | await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes)) |
392 | }) | 392 | }) |
393 | 393 | ||
394 | it('Should update only the description of a video', async function () { | 394 | it('Should update only the description of a video', async function () { |
@@ -400,7 +400,8 @@ describe('Test a single server', function () { | |||
400 | const res = await getVideo(server.url, videoId) | 400 | const res = await getVideo(server.url, videoId) |
401 | const video = res.body | 401 | const video = res.body |
402 | 402 | ||
403 | await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes)) | 403 | const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes) |
404 | await completeVideoCheck(server.url, video, expectedAttributes) | ||
404 | }) | 405 | }) |
405 | 406 | ||
406 | it('Should like a video', async function () { | 407 | it('Should like a video', async function () { |
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts index 7318497d5..a2f3ee161 100644 --- a/server/tests/api/videos/video-abuse.ts +++ b/server/tests/api/videos/video-abuse.ts | |||
@@ -9,7 +9,6 @@ import { | |||
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | getVideoAbusesList, | 10 | getVideoAbusesList, |
11 | getVideosList, | 11 | getVideosList, |
12 | killallServers, | ||
13 | reportVideoAbuse, | 12 | reportVideoAbuse, |
14 | ServerInfo, | 13 | ServerInfo, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
@@ -90,7 +89,7 @@ describe('Test video abuses', function () { | |||
90 | const abuse: VideoAbuse = res1.body.data[0] | 89 | const abuse: VideoAbuse = res1.body.data[0] |
91 | expect(abuse.reason).to.equal('my super bad reason') | 90 | expect(abuse.reason).to.equal('my super bad reason') |
92 | expect(abuse.reporterAccount.name).to.equal('root') | 91 | expect(abuse.reporterAccount.name).to.equal('root') |
93 | expect(abuse.reporterAccount.host).to.equal('localhost:9001') | 92 | expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port) |
94 | expect(abuse.video.id).to.equal(servers[0].video.id) | 93 | expect(abuse.video.id).to.equal(servers[0].video.id) |
95 | 94 | ||
96 | const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 95 | const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) |
@@ -118,7 +117,7 @@ describe('Test video abuses', function () { | |||
118 | const abuse1: VideoAbuse = res1.body.data[0] | 117 | const abuse1: VideoAbuse = res1.body.data[0] |
119 | expect(abuse1.reason).to.equal('my super bad reason') | 118 | expect(abuse1.reason).to.equal('my super bad reason') |
120 | expect(abuse1.reporterAccount.name).to.equal('root') | 119 | expect(abuse1.reporterAccount.name).to.equal('root') |
121 | expect(abuse1.reporterAccount.host).to.equal('localhost:9001') | 120 | expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port) |
122 | expect(abuse1.video.id).to.equal(servers[0].video.id) | 121 | expect(abuse1.video.id).to.equal(servers[0].video.id) |
123 | expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING) | 122 | expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING) |
124 | expect(abuse1.state.label).to.equal('Pending') | 123 | expect(abuse1.state.label).to.equal('Pending') |
@@ -127,7 +126,7 @@ describe('Test video abuses', function () { | |||
127 | const abuse2: VideoAbuse = res1.body.data[1] | 126 | const abuse2: VideoAbuse = res1.body.data[1] |
128 | expect(abuse2.reason).to.equal('my super bad reason 2') | 127 | expect(abuse2.reason).to.equal('my super bad reason 2') |
129 | expect(abuse2.reporterAccount.name).to.equal('root') | 128 | expect(abuse2.reporterAccount.name).to.equal('root') |
130 | expect(abuse2.reporterAccount.host).to.equal('localhost:9001') | 129 | expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port) |
131 | expect(abuse2.video.id).to.equal(servers[1].video.id) | 130 | expect(abuse2.video.id).to.equal(servers[1].video.id) |
132 | expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING) | 131 | expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING) |
133 | expect(abuse2.state.label).to.equal('Pending') | 132 | expect(abuse2.state.label).to.equal('Pending') |
@@ -141,7 +140,7 @@ describe('Test video abuses', function () { | |||
141 | abuseServer2 = res2.body.data[0] | 140 | abuseServer2 = res2.body.data[0] |
142 | expect(abuseServer2.reason).to.equal('my super bad reason 2') | 141 | expect(abuseServer2.reason).to.equal('my super bad reason 2') |
143 | expect(abuseServer2.reporterAccount.name).to.equal('root') | 142 | expect(abuseServer2.reporterAccount.name).to.equal('root') |
144 | expect(abuseServer2.reporterAccount.host).to.equal('localhost:9001') | 143 | expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port) |
145 | expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING) | 144 | expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING) |
146 | expect(abuseServer2.state.label).to.equal('Pending') | 145 | expect(abuseServer2.state.label).to.equal('Pending') |
147 | expect(abuseServer2.moderationComment).to.be.null | 146 | expect(abuseServer2.moderationComment).to.be.null |
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index 1c0327d40..3a3add71b 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts | |||
@@ -4,7 +4,8 @@ import * as chai from 'chai' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | acceptChangeOwnership, | 6 | acceptChangeOwnership, |
7 | changeVideoOwnership, cleanupTests, | 7 | changeVideoOwnership, |
8 | cleanupTests, | ||
8 | createUser, | 9 | createUser, |
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
@@ -13,7 +14,6 @@ import { | |||
13 | getVideo, | 14 | getVideo, |
14 | getVideoChangeOwnershipList, | 15 | getVideoChangeOwnershipList, |
15 | getVideosList, | 16 | getVideosList, |
16 | killallServers, | ||
17 | refuseChangeOwnership, | 17 | refuseChangeOwnership, |
18 | ServerInfo, | 18 | ServerInfo, |
19 | setAccessTokensToServers, | 19 | setAccessTokensToServers, |
@@ -203,8 +203,8 @@ describe('Test video change ownership - nominal', function () { | |||
203 | } | 203 | } |
204 | }) | 204 | }) |
205 | 205 | ||
206 | after(function () { | 206 | after(async function () { |
207 | killallServers(servers) | 207 | await cleanupTests(servers) |
208 | }) | 208 | }) |
209 | }) | 209 | }) |
210 | 210 | ||
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index 345e96f43..4f600cae8 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { User, Video } from '../../../../shared/index' | 5 | import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, getVideo, |
11 | getVideoChannelVideos, | 11 | getVideoChannelVideos, |
12 | testImage, | 12 | testImage, |
13 | updateVideo, | 13 | updateVideo, |
@@ -18,12 +18,10 @@ import { | |||
18 | import { | 18 | import { |
19 | addVideoChannel, | 19 | addVideoChannel, |
20 | deleteVideoChannel, | 20 | deleteVideoChannel, |
21 | flushTests, | ||
22 | getAccountVideoChannelsList, | 21 | getAccountVideoChannelsList, |
23 | getMyUserInformation, | 22 | getMyUserInformation, |
24 | getVideoChannel, | 23 | getVideoChannel, |
25 | getVideoChannelsList, | 24 | getVideoChannelsList, |
26 | killallServers, | ||
27 | ServerInfo, | 25 | ServerInfo, |
28 | setAccessTokensToServers, | 26 | setAccessTokensToServers, |
29 | updateVideoChannel | 27 | updateVideoChannel |
@@ -35,13 +33,12 @@ const expect = chai.expect | |||
35 | describe('Test video channels', function () { | 33 | describe('Test video channels', function () { |
36 | let servers: ServerInfo[] | 34 | let servers: ServerInfo[] |
37 | let userInfo: User | 35 | let userInfo: User |
38 | let accountUUID: string | ||
39 | let firstVideoChannelId: number | 36 | let firstVideoChannelId: number |
40 | let secondVideoChannelId: number | 37 | let secondVideoChannelId: number |
41 | let videoUUID: string | 38 | let videoUUID: string |
42 | 39 | ||
43 | before(async function () { | 40 | before(async function () { |
44 | this.timeout(30000) | 41 | this.timeout(60000) |
45 | 42 | ||
46 | servers = await flushAndRunMultipleServers(2) | 43 | servers = await flushAndRunMultipleServers(2) |
47 | 44 | ||
@@ -51,7 +48,6 @@ describe('Test video channels', function () { | |||
51 | { | 48 | { |
52 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 49 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
53 | const user: User = res.body | 50 | const user: User = res.body |
54 | accountUUID = user.account.uuid | ||
55 | 51 | ||
56 | firstVideoChannelId = user.videoChannels[0].id | 52 | firstVideoChannelId = user.videoChannels[0].id |
57 | } | 53 | } |
@@ -83,7 +79,8 @@ describe('Test video channels', function () { | |||
83 | 79 | ||
84 | // The channel is 1 is propagated to servers 2 | 80 | // The channel is 1 is propagated to servers 2 |
85 | { | 81 | { |
86 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name', channelId: secondVideoChannelId }) | 82 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } |
83 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg) | ||
87 | videoUUID = res.body.video.uuid | 84 | videoUUID = res.body.video.uuid |
88 | } | 85 | } |
89 | 86 | ||
@@ -108,7 +105,11 @@ describe('Test video channels', function () { | |||
108 | }) | 105 | }) |
109 | 106 | ||
110 | it('Should have two video channels when getting account channels on server 1', async function () { | 107 | it('Should have two video channels when getting account channels on server 1', async function () { |
111 | const res = await getAccountVideoChannelsList(servers[0].url, userInfo.account.name + '@' + userInfo.account.host) | 108 | const res = await getAccountVideoChannelsList({ |
109 | url: servers[ 0 ].url, | ||
110 | accountName: userInfo.account.name + '@' + userInfo.account.host | ||
111 | }) | ||
112 | |||
112 | expect(res.body.total).to.equal(2) | 113 | expect(res.body.total).to.equal(2) |
113 | expect(res.body.data).to.be.an('array') | 114 | expect(res.body.data).to.be.an('array') |
114 | expect(res.body.data).to.have.lengthOf(2) | 115 | expect(res.body.data).to.have.lengthOf(2) |
@@ -123,8 +124,62 @@ describe('Test video channels', function () { | |||
123 | expect(videoChannels[1].support).to.equal('super video channel support text') | 124 | expect(videoChannels[1].support).to.equal('super video channel support text') |
124 | }) | 125 | }) |
125 | 126 | ||
127 | it('Should paginate and sort account channels', async function () { | ||
128 | { | ||
129 | const res = await getAccountVideoChannelsList({ | ||
130 | url: servers[ 0 ].url, | ||
131 | accountName: userInfo.account.name + '@' + userInfo.account.host, | ||
132 | start: 0, | ||
133 | count: 1, | ||
134 | sort: 'createdAt' | ||
135 | }) | ||
136 | |||
137 | expect(res.body.total).to.equal(2) | ||
138 | expect(res.body.data).to.have.lengthOf(1) | ||
139 | |||
140 | const videoChannel: VideoChannel = res.body.data[ 0 ] | ||
141 | expect(videoChannel.name).to.equal('root_channel') | ||
142 | } | ||
143 | |||
144 | { | ||
145 | const res = await getAccountVideoChannelsList({ | ||
146 | url: servers[ 0 ].url, | ||
147 | accountName: userInfo.account.name + '@' + userInfo.account.host, | ||
148 | start: 0, | ||
149 | count: 1, | ||
150 | sort: '-createdAt' | ||
151 | }) | ||
152 | |||
153 | expect(res.body.total).to.equal(2) | ||
154 | expect(res.body.data).to.have.lengthOf(1) | ||
155 | |||
156 | const videoChannel: VideoChannel = res.body.data[ 0 ] | ||
157 | expect(videoChannel.name).to.equal('second_video_channel') | ||
158 | } | ||
159 | |||
160 | { | ||
161 | const res = await getAccountVideoChannelsList({ | ||
162 | url: servers[ 0 ].url, | ||
163 | accountName: userInfo.account.name + '@' + userInfo.account.host, | ||
164 | start: 1, | ||
165 | count: 1, | ||
166 | sort: '-createdAt' | ||
167 | }) | ||
168 | |||
169 | expect(res.body.total).to.equal(2) | ||
170 | expect(res.body.data).to.have.lengthOf(1) | ||
171 | |||
172 | const videoChannel: VideoChannel = res.body.data[ 0 ] | ||
173 | expect(videoChannel.name).to.equal('root_channel') | ||
174 | } | ||
175 | }) | ||
176 | |||
126 | it('Should have one video channel when getting account channels on server 2', async function () { | 177 | it('Should have one video channel when getting account channels on server 2', async function () { |
127 | const res = await getAccountVideoChannelsList(servers[1].url, userInfo.account.name + '@' + userInfo.account.host) | 178 | const res = await getAccountVideoChannelsList({ |
179 | url: servers[ 1 ].url, | ||
180 | accountName: userInfo.account.name + '@' + userInfo.account.host | ||
181 | }) | ||
182 | |||
128 | expect(res.body.total).to.equal(1) | 183 | expect(res.body.total).to.equal(1) |
129 | expect(res.body.data).to.be.an('array') | 184 | expect(res.body.data).to.be.an('array') |
130 | expect(res.body.data).to.have.lengthOf(1) | 185 | expect(res.body.data).to.have.lengthOf(1) |
@@ -147,12 +202,12 @@ describe('Test video channels', function () { | |||
147 | }) | 202 | }) |
148 | 203 | ||
149 | it('Should update video channel', async function () { | 204 | it('Should update video channel', async function () { |
150 | this.timeout(5000) | 205 | this.timeout(15000) |
151 | 206 | ||
152 | const videoChannelAttributes = { | 207 | const videoChannelAttributes = { |
153 | displayName: 'video channel updated', | 208 | displayName: 'video channel updated', |
154 | description: 'video channel description updated', | 209 | description: 'video channel description updated', |
155 | support: 'video channel support text updated' | 210 | support: 'support updated' |
156 | } | 211 | } |
157 | 212 | ||
158 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) | 213 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) |
@@ -170,7 +225,36 @@ describe('Test video channels', function () { | |||
170 | expect(res.body.data[0].name).to.equal('second_video_channel') | 225 | expect(res.body.data[0].name).to.equal('second_video_channel') |
171 | expect(res.body.data[0].displayName).to.equal('video channel updated') | 226 | expect(res.body.data[0].displayName).to.equal('video channel updated') |
172 | expect(res.body.data[0].description).to.equal('video channel description updated') | 227 | expect(res.body.data[0].description).to.equal('video channel description updated') |
173 | expect(res.body.data[0].support).to.equal('video channel support text updated') | 228 | expect(res.body.data[0].support).to.equal('support updated') |
229 | } | ||
230 | }) | ||
231 | |||
232 | it('Should not have updated the video support field', async function () { | ||
233 | for (const server of servers) { | ||
234 | const res = await getVideo(server.url, videoUUID) | ||
235 | const video: VideoDetails = res.body | ||
236 | |||
237 | expect(video.support).to.equal('video support field') | ||
238 | } | ||
239 | }) | ||
240 | |||
241 | it('Should update the channel support field and update videos too', async function () { | ||
242 | this.timeout(35000) | ||
243 | |||
244 | const videoChannelAttributes = { | ||
245 | support: 'video channel support text updated', | ||
246 | bulkVideosSupportUpdate: true | ||
247 | } | ||
248 | |||
249 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) | ||
250 | |||
251 | await waitJobs(servers) | ||
252 | |||
253 | for (const server of servers) { | ||
254 | const res = await getVideo(server.url, videoUUID) | ||
255 | const video: VideoDetails = res.body | ||
256 | |||
257 | expect(video.support).to.equal(videoChannelAttributes.support) | ||
174 | } | 258 | } |
175 | }) | 259 | }) |
176 | 260 | ||
@@ -213,7 +297,7 @@ describe('Test video channels', function () { | |||
213 | this.timeout(10000) | 297 | this.timeout(10000) |
214 | 298 | ||
215 | for (const server of servers) { | 299 | for (const server of servers) { |
216 | const channelURI = 'second_video_channel@localhost:9001' | 300 | const channelURI = 'second_video_channel@localhost:' + servers[0].port |
217 | const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) | 301 | const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) |
218 | expect(res1.body.total).to.equal(1) | 302 | expect(res1.body.total).to.equal(1) |
219 | expect(res1.body.data).to.be.an('array') | 303 | expect(res1.body.data).to.be.an('array') |
@@ -234,11 +318,11 @@ describe('Test video channels', function () { | |||
234 | this.timeout(10000) | 318 | this.timeout(10000) |
235 | 319 | ||
236 | for (const server of servers) { | 320 | for (const server of servers) { |
237 | const secondChannelURI = 'second_video_channel@localhost:9001' | 321 | const secondChannelURI = 'second_video_channel@localhost:' + servers[0].port |
238 | const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5) | 322 | const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5) |
239 | expect(res1.body.total).to.equal(0) | 323 | expect(res1.body.total).to.equal(0) |
240 | 324 | ||
241 | const channelURI = 'root_channel@localhost:9001' | 325 | const channelURI = 'root_channel@localhost:' + servers[0].port |
242 | const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) | 326 | const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) |
243 | expect(res2.body.total).to.equal(1) | 327 | expect(res2.body.total).to.equal(1) |
244 | 328 | ||
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts index 22fd8c058..82182cc7c 100644 --- a/server/tests/api/videos/video-comments.ts +++ b/server/tests/api/videos/video-comments.ts | |||
@@ -66,8 +66,8 @@ describe('Test video comments', function () { | |||
66 | expect(comment.videoId).to.equal(videoId) | 66 | expect(comment.videoId).to.equal(videoId) |
67 | expect(comment.id).to.equal(comment.threadId) | 67 | expect(comment.id).to.equal(comment.threadId) |
68 | expect(comment.account.name).to.equal('root') | 68 | expect(comment.account.name).to.equal('root') |
69 | expect(comment.account.host).to.equal('localhost:9001') | 69 | expect(comment.account.host).to.equal('localhost:' + server.port) |
70 | expect(comment.account.url).to.equal('http://localhost:9001/accounts/root') | 70 | expect(comment.account.url).to.equal('http://localhost:' + server.port + '/accounts/root') |
71 | expect(comment.totalReplies).to.equal(0) | 71 | expect(comment.totalReplies).to.equal(0) |
72 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 72 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
73 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 73 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
@@ -86,7 +86,7 @@ describe('Test video comments', function () { | |||
86 | expect(comment.videoId).to.equal(videoId) | 86 | expect(comment.videoId).to.equal(videoId) |
87 | expect(comment.id).to.equal(comment.threadId) | 87 | expect(comment.id).to.equal(comment.threadId) |
88 | expect(comment.account.name).to.equal('root') | 88 | expect(comment.account.name).to.equal('root') |
89 | expect(comment.account.host).to.equal('localhost:9001') | 89 | expect(comment.account.host).to.equal('localhost:' + server.port) |
90 | 90 | ||
91 | await testImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png') | 91 | await testImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png') |
92 | 92 | ||
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index 22031c18b..39178bb1a 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts | |||
@@ -5,13 +5,12 @@ import 'mocha' | |||
5 | import { | 5 | import { |
6 | checkDirectoryIsEmpty, | 6 | checkDirectoryIsEmpty, |
7 | checkSegmentHash, | 7 | checkSegmentHash, |
8 | checkTmpIsEmpty, cleanupTests, | 8 | checkTmpIsEmpty, |
9 | cleanupTests, | ||
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | getPlaylist, | 12 | getPlaylist, |
13 | getVideo, | 13 | getVideo, |
14 | killallServers, | ||
15 | removeVideo, | 14 | removeVideo, |
16 | ServerInfo, | 15 | ServerInfo, |
17 | setAccessTokensToServers, | 16 | setAccessTokensToServers, |
@@ -22,12 +21,11 @@ import { | |||
22 | import { VideoDetails } from '../../../../shared/models/videos' | 21 | import { VideoDetails } from '../../../../shared/models/videos' |
23 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
24 | import { join } from 'path' | 23 | import { join } from 'path' |
24 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | ||
25 | 25 | ||
26 | const expect = chai.expect | 26 | const expect = chai.expect |
27 | 27 | ||
28 | async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { | 28 | async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, resolutions = [ 240, 360, 480, 720 ]) { |
29 | const resolutions = [ 240, 360, 480, 720 ] | ||
30 | |||
31 | for (const server of servers) { | 29 | for (const server of servers) { |
32 | const res = await getVideo(server.url, videoUUID) | 30 | const res = await getVideo(server.url, videoUUID) |
33 | const videoDetails: VideoDetails = res.body | 31 | const videoDetails: VideoDetails = res.body |
@@ -42,16 +40,15 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { | |||
42 | 40 | ||
43 | const masterPlaylist = res2.text | 41 | const masterPlaylist = res2.text |
44 | 42 | ||
45 | expect(masterPlaylist).to.contain('#EXT-X-STREAM-INF:BANDWIDTH=55472,RESOLUTION=640x360,FRAME-RATE=25') | ||
46 | |||
47 | for (const resolution of resolutions) { | 43 | for (const resolution of resolutions) { |
44 | expect(masterPlaylist).to.match(new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+')) | ||
48 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | 45 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) |
49 | } | 46 | } |
50 | } | 47 | } |
51 | 48 | ||
52 | { | 49 | { |
53 | for (const resolution of resolutions) { | 50 | for (const resolution of resolutions) { |
54 | const res2 = await getPlaylist(`http://localhost:9001/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`) | 51 | const res2 = await getPlaylist(`http://localhost:${servers[0].port}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`) |
55 | 52 | ||
56 | const subPlaylist = res2.text | 53 | const subPlaylist = res2.text |
57 | expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`) | 54 | expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`) |
@@ -59,7 +56,7 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { | |||
59 | } | 56 | } |
60 | 57 | ||
61 | { | 58 | { |
62 | const baseUrl = 'http://localhost:9001/static/streaming-playlists/hls' | 59 | const baseUrl = 'http://localhost:' + servers[0].port + '/static/streaming-playlists/hls' |
63 | 60 | ||
64 | for (const resolution of resolutions) { | 61 | for (const resolution of resolutions) { |
65 | await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist) | 62 | await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist) |
@@ -71,11 +68,21 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { | |||
71 | describe('Test HLS videos', function () { | 68 | describe('Test HLS videos', function () { |
72 | let servers: ServerInfo[] = [] | 69 | let servers: ServerInfo[] = [] |
73 | let videoUUID = '' | 70 | let videoUUID = '' |
71 | let videoAudioUUID = '' | ||
74 | 72 | ||
75 | before(async function () { | 73 | before(async function () { |
76 | this.timeout(120000) | 74 | this.timeout(120000) |
77 | 75 | ||
78 | servers = await flushAndRunMultipleServers(2, { transcoding: { enabled: true, hls: { enabled: true } } }) | 76 | const configOverride = { |
77 | transcoding: { | ||
78 | enabled: true, | ||
79 | allow_audio_files: true, | ||
80 | hls: { | ||
81 | enabled: true | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | servers = await flushAndRunMultipleServers(2, configOverride) | ||
79 | 86 | ||
80 | // Get the access tokens | 87 | // Get the access tokens |
81 | await setAccessTokensToServers(servers) | 88 | await setAccessTokensToServers(servers) |
@@ -87,17 +94,28 @@ describe('Test HLS videos', function () { | |||
87 | it('Should upload a video and transcode it to HLS', async function () { | 94 | it('Should upload a video and transcode it to HLS', async function () { |
88 | this.timeout(120000) | 95 | this.timeout(120000) |
89 | 96 | ||
90 | { | 97 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) |
91 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) | 98 | videoUUID = res.body.video.uuid |
92 | videoUUID = res.body.video.uuid | ||
93 | } | ||
94 | 99 | ||
95 | await waitJobs(servers) | 100 | await waitJobs(servers) |
96 | 101 | ||
97 | await checkHlsPlaylist(servers, videoUUID) | 102 | await checkHlsPlaylist(servers, videoUUID) |
98 | }) | 103 | }) |
99 | 104 | ||
105 | it('Should upload an audio file and transcode it to HLS', async function () { | ||
106 | this.timeout(120000) | ||
107 | |||
108 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) | ||
109 | videoAudioUUID = res.body.video.uuid | ||
110 | |||
111 | await waitJobs(servers) | ||
112 | |||
113 | await checkHlsPlaylist(servers, videoAudioUUID, [ DEFAULT_AUDIO_RESOLUTION ]) | ||
114 | }) | ||
115 | |||
100 | it('Should update the video', async function () { | 116 | it('Should update the video', async function () { |
117 | this.timeout(10000) | ||
118 | |||
101 | await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) | 119 | await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) |
102 | 120 | ||
103 | await waitJobs(servers) | 121 | await waitJobs(servers) |
@@ -105,13 +123,17 @@ describe('Test HLS videos', function () { | |||
105 | await checkHlsPlaylist(servers, videoUUID) | 123 | await checkHlsPlaylist(servers, videoUUID) |
106 | }) | 124 | }) |
107 | 125 | ||
108 | it('Should delete the video', async function () { | 126 | it('Should delete videos', async function () { |
127 | this.timeout(10000) | ||
128 | |||
109 | await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) | 129 | await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) |
130 | await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID) | ||
110 | 131 | ||
111 | await waitJobs(servers) | 132 | await waitJobs(servers) |
112 | 133 | ||
113 | for (const server of servers) { | 134 | for (const server of servers) { |
114 | await getVideo(server.url, videoUUID, 404) | 135 | await getVideo(server.url, videoUUID, 404) |
136 | await getVideo(server.url, videoAudioUUID, 404) | ||
115 | } | 137 | } |
116 | }) | 138 | }) |
117 | 139 | ||
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index fd5e4c4be..8690327c4 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts | |||
@@ -371,7 +371,7 @@ describe('Test video playlists', function () { | |||
371 | 371 | ||
372 | for (const server of servers) { | 372 | for (const server of servers) { |
373 | const results = [ | 373 | const results = [ |
374 | await getAccountPlaylistsList(server.url, 'root@localhost:9002', 0, 5, '-createdAt'), | 374 | await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'), |
375 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') | 375 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') |
376 | ] | 376 | ] |
377 | 377 | ||
@@ -754,6 +754,40 @@ describe('Test video playlists', function () { | |||
754 | } | 754 | } |
755 | }) | 755 | }) |
756 | 756 | ||
757 | |||
758 | it('Should be able to create a public playlist, and set it to private', async function () { | ||
759 | this.timeout(30000) | ||
760 | |||
761 | const res = await createVideoPlaylist({ | ||
762 | url: servers[0].url, | ||
763 | token: servers[0].accessToken, | ||
764 | playlistAttrs: { | ||
765 | displayName: 'my super public playlist', | ||
766 | privacy: VideoPlaylistPrivacy.PUBLIC, | ||
767 | videoChannelId: servers[0].videoChannel.id | ||
768 | } | ||
769 | }) | ||
770 | const videoPlaylistIds = res.body.videoPlaylist | ||
771 | |||
772 | await waitJobs(servers) | ||
773 | |||
774 | for (const server of servers) { | ||
775 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200) | ||
776 | } | ||
777 | |||
778 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } | ||
779 | await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) | ||
780 | |||
781 | await waitJobs(servers) | ||
782 | |||
783 | for (const server of [ servers[1], servers[2] ]) { | ||
784 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) | ||
785 | } | ||
786 | await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401) | ||
787 | |||
788 | await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200) | ||
789 | }) | ||
790 | |||
757 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { | 791 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { |
758 | this.timeout(30000) | 792 | this.timeout(30000) |
759 | 793 | ||
@@ -770,7 +804,7 @@ describe('Test video playlists', function () { | |||
770 | this.timeout(30000) | 804 | this.timeout(30000) |
771 | 805 | ||
772 | for (const server of servers) { | 806 | for (const server of servers) { |
773 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.serverNumber) | 807 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber) |
774 | } | 808 | } |
775 | }) | 809 | }) |
776 | 810 | ||
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index ef1cf0f07..40b539106 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts | |||
@@ -6,8 +6,7 @@ import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enu | |||
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
9 | getVideosList, | 9 | getVideosList, getVideosListWithToken, |
10 | killallServers, | ||
11 | ServerInfo, | 10 | ServerInfo, |
12 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
13 | uploadVideo | 12 | uploadVideo |
@@ -153,6 +152,29 @@ describe('Test video privacy', function () { | |||
153 | } | 152 | } |
154 | }) | 153 | }) |
155 | 154 | ||
155 | it('Should set this new video as private', async function () { | ||
156 | this.timeout(10000) | ||
157 | |||
158 | await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.PRIVATE }) | ||
159 | |||
160 | await waitJobs(servers) | ||
161 | |||
162 | for (const server of servers) { | ||
163 | const res = await getVideosList(server.url) | ||
164 | |||
165 | expect(res.body.total).to.equal(0) | ||
166 | expect(res.body.data).to.have.lengthOf(0) | ||
167 | } | ||
168 | |||
169 | { | ||
170 | const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5) | ||
171 | |||
172 | expect(res.body.total).to.equal(1) | ||
173 | expect(res.body.data).to.have.lengthOf(1) | ||
174 | expect(res.body.data[0].name).to.equal('super video public') | ||
175 | } | ||
176 | }) | ||
177 | |||
156 | after(async function () { | 178 | after(async function () { |
157 | await cleanupTests(servers) | 179 | await cleanupTests(servers) |
158 | }) | 180 | }) |
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts index 3cd43e99b..90ade1652 100644 --- a/server/tests/api/videos/video-transcoder.ts +++ b/server/tests/api/videos/video-transcoder.ts | |||
@@ -4,24 +4,25 @@ import * as chai from 'chai' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' | 6 | import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' |
7 | import { audio, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 7 | import { audio, canDoQuickTranscode, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
8 | import { | 8 | import { |
9 | buildAbsoluteFixturePath, cleanupTests, | 9 | buildAbsoluteFixturePath, |
10 | cleanupTests, | ||
10 | doubleFollow, | 11 | doubleFollow, |
11 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
12 | generateHighBitrateVideo, | 13 | generateHighBitrateVideo, |
13 | getMyVideos, | 14 | getMyVideos, |
14 | getVideo, | 15 | getVideo, |
15 | getVideosList, | 16 | getVideosList, |
16 | killallServers, | 17 | makeGetRequest, |
17 | root, | 18 | root, |
18 | ServerInfo, | 19 | ServerInfo, |
19 | setAccessTokensToServers, | 20 | setAccessTokensToServers, |
20 | uploadVideo, | 21 | uploadVideo, |
22 | waitJobs, | ||
21 | webtorrentAdd | 23 | webtorrentAdd |
22 | } from '../../../../shared/extra-utils' | 24 | } from '../../../../shared/extra-utils' |
23 | import { extname, join } from 'path' | 25 | import { join } from 'path' |
24 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | ||
25 | import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' | 26 | import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' |
26 | 27 | ||
27 | const expect = chai.expect | 28 | const expect = chai.expect |
@@ -121,7 +122,7 @@ describe('Test video transcoding', function () { | |||
121 | 122 | ||
122 | expect(videoDetails.files).to.have.lengthOf(4) | 123 | expect(videoDetails.files).to.have.lengthOf(4) |
123 | 124 | ||
124 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 125 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4') |
125 | const probe = await audio.get(path) | 126 | const probe = await audio.get(path) |
126 | 127 | ||
127 | if (probe.audioStream) { | 128 | if (probe.audioStream) { |
@@ -152,7 +153,7 @@ describe('Test video transcoding', function () { | |||
152 | const videoDetails: VideoDetails = res2.body | 153 | const videoDetails: VideoDetails = res2.body |
153 | 154 | ||
154 | expect(videoDetails.files).to.have.lengthOf(4) | 155 | expect(videoDetails.files).to.have.lengthOf(4) |
155 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 156 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4') |
156 | const probe = await audio.get(path) | 157 | const probe = await audio.get(path) |
157 | expect(probe).to.not.have.property('audioStream') | 158 | expect(probe).to.not.have.property('audioStream') |
158 | } | 159 | } |
@@ -179,7 +180,7 @@ describe('Test video transcoding', function () { | |||
179 | expect(videoDetails.files).to.have.lengthOf(4) | 180 | expect(videoDetails.files).to.have.lengthOf(4) |
180 | const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture) | 181 | const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture) |
181 | const fixtureVideoProbe = await audio.get(fixturePath) | 182 | const fixtureVideoProbe = await audio.get(fixturePath) |
182 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 183 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4') |
183 | const videoProbe = await audio.get(path) | 184 | const videoProbe = await audio.get(path) |
184 | if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { | 185 | if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { |
185 | const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] | 186 | const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] |
@@ -216,13 +217,13 @@ describe('Test video transcoding', function () { | |||
216 | expect(videoDetails.files[ 3 ].fps).to.be.below(31) | 217 | expect(videoDetails.files[ 3 ].fps).to.be.below(31) |
217 | 218 | ||
218 | for (const resolution of [ '240', '360', '480' ]) { | 219 | for (const resolution of [ '240', '360', '480' ]) { |
219 | const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') | 220 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
220 | const fps = await getVideoFileFPS(path) | 221 | const fps = await getVideoFileFPS(path) |
221 | 222 | ||
222 | expect(fps).to.be.below(31) | 223 | expect(fps).to.be.below(31) |
223 | } | 224 | } |
224 | 225 | ||
225 | const path = join(root(), 'test2', 'videos', video.uuid + '-720.mp4') | 226 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4') |
226 | const fps = await getVideoFileFPS(path) | 227 | const fps = await getVideoFileFPS(path) |
227 | 228 | ||
228 | expect(fps).to.be.above(58).and.below(62) | 229 | expect(fps).to.be.above(58).and.below(62) |
@@ -310,7 +311,7 @@ describe('Test video transcoding', function () { | |||
310 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 311 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
311 | 312 | ||
312 | for (const resolution of ['240', '360', '480', '720', '1080']) { | 313 | for (const resolution of ['240', '360', '480', '720', '1080']) { |
313 | const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') | 314 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
314 | const bitrate = await getVideoFileBitrate(path) | 315 | const bitrate = await getVideoFileBitrate(path) |
315 | const fps = await getVideoFileFPS(path) | 316 | const fps = await getVideoFileFPS(path) |
316 | const resolution2 = await getVideoFileResolution(path) | 317 | const resolution2 = await getVideoFileResolution(path) |
@@ -324,6 +325,15 @@ describe('Test video transcoding', function () { | |||
324 | it('Should accept and transcode additional extensions', async function () { | 325 | it('Should accept and transcode additional extensions', async function () { |
325 | this.timeout(300000) | 326 | this.timeout(300000) |
326 | 327 | ||
328 | let tempFixturePath: string | ||
329 | |||
330 | { | ||
331 | tempFixturePath = await generateHighBitrateVideo() | ||
332 | |||
333 | const bitrate = await getVideoFileBitrate(tempFixturePath) | ||
334 | expect(bitrate).to.be.above(getMaxBitrate(VideoResolution.H_1080P, 60, VIDEO_TRANSCODING_FPS)) | ||
335 | } | ||
336 | |||
327 | for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) { | 337 | for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) { |
328 | const videoAttributes = { | 338 | const videoAttributes = { |
329 | name: fixture, | 339 | name: fixture, |
@@ -349,6 +359,63 @@ describe('Test video transcoding', function () { | |||
349 | } | 359 | } |
350 | }) | 360 | }) |
351 | 361 | ||
362 | it('Should correctly detect if quick transcode is possible', async function () { | ||
363 | this.timeout(10000) | ||
364 | |||
365 | expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.mp4'))).to.be.true | ||
366 | expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.webm'))).to.be.false | ||
367 | }) | ||
368 | |||
369 | it('Should merge an audio file with the preview file', async function () { | ||
370 | this.timeout(60000) | ||
371 | |||
372 | const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } | ||
373 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | ||
374 | |||
375 | await waitJobs(servers) | ||
376 | |||
377 | for (const server of servers) { | ||
378 | const res = await getVideosList(server.url) | ||
379 | |||
380 | const video = res.body.data.find(v => v.name === 'audio_with_preview') | ||
381 | const res2 = await getVideo(server.url, video.id) | ||
382 | const videoDetails: VideoDetails = res2.body | ||
383 | |||
384 | expect(videoDetails.files).to.have.lengthOf(1) | ||
385 | |||
386 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | ||
387 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | ||
388 | |||
389 | const magnetUri = videoDetails.files[ 0 ].magnetUri | ||
390 | expect(magnetUri).to.contain('.mp4') | ||
391 | } | ||
392 | }) | ||
393 | |||
394 | it('Should upload an audio file and choose a default background image', async function () { | ||
395 | this.timeout(60000) | ||
396 | |||
397 | const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } | ||
398 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | ||
399 | |||
400 | await waitJobs(servers) | ||
401 | |||
402 | for (const server of servers) { | ||
403 | const res = await getVideosList(server.url) | ||
404 | |||
405 | const video = res.body.data.find(v => v.name === 'audio_without_preview') | ||
406 | const res2 = await getVideo(server.url, video.id) | ||
407 | const videoDetails = res2.body | ||
408 | |||
409 | expect(videoDetails.files).to.have.lengthOf(1) | ||
410 | |||
411 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | ||
412 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | ||
413 | |||
414 | const magnetUri = videoDetails.files[ 0 ].magnetUri | ||
415 | expect(magnetUri).to.contain('.mp4') | ||
416 | } | ||
417 | }) | ||
418 | |||
352 | after(async function () { | 419 | after(async function () { |
353 | await cleanupTests(servers) | 420 | await cleanupTests(servers) |
354 | }) | 421 | }) |
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts index c21d46d56..fbddd40f4 100644 --- a/server/tests/api/videos/videos-views-cleaner.ts +++ b/server/tests/api/videos/videos-views-cleaner.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | flushAndRunServer, | 10 | flushAndRunServer, |
11 | ServerInfo, | 11 | ServerInfo, |
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests | 13 | uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize |
14 | } from '../../../../shared/extra-utils' | 14 | } from '../../../../shared/extra-utils' |
15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' | 15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' |
16 | import { VideosOverview } from '../../../../shared/models/overviews' | 16 | import { VideosOverview } from '../../../../shared/models/overviews' |
@@ -58,14 +58,14 @@ describe('Test video views cleaner', function () { | |||
58 | 58 | ||
59 | { | 59 | { |
60 | for (const server of servers) { | 60 | for (const server of servers) { |
61 | const total = await countVideoViewsOf(server.serverNumber, videoIdServer1) | 61 | const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1) |
62 | expect(total).to.equal(2) | 62 | expect(total).to.equal(2) |
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | { | 66 | { |
67 | for (const server of servers) { | 67 | for (const server of servers) { |
68 | const total = await countVideoViewsOf(server.serverNumber, videoIdServer2) | 68 | const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer2) |
69 | expect(total).to.equal(2) | 69 | expect(total).to.equal(2) |
70 | } | 70 | } |
71 | } | 71 | } |
@@ -74,8 +74,6 @@ describe('Test video views cleaner', function () { | |||
74 | it('Should clean old video views', async function () { | 74 | it('Should clean old video views', async function () { |
75 | this.timeout(50000) | 75 | this.timeout(50000) |
76 | 76 | ||
77 | this.timeout(50000) | ||
78 | |||
79 | killallServers([ servers[0] ]) | 77 | killallServers([ servers[0] ]) |
80 | 78 | ||
81 | await reRunServer(servers[0], { views: { videos: { remote: { max_age: '5 seconds' } } } }) | 79 | await reRunServer(servers[0], { views: { videos: { remote: { max_age: '5 seconds' } } } }) |
@@ -86,21 +84,23 @@ describe('Test video views cleaner', function () { | |||
86 | 84 | ||
87 | { | 85 | { |
88 | for (const server of servers) { | 86 | for (const server of servers) { |
89 | const total = await countVideoViewsOf(server.serverNumber, videoIdServer1) | 87 | const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1) |
90 | expect(total).to.equal(2) | 88 | expect(total).to.equal(2) |
91 | } | 89 | } |
92 | } | 90 | } |
93 | 91 | ||
94 | { | 92 | { |
95 | const totalServer1 = await countVideoViewsOf(servers[0].serverNumber, videoIdServer2) | 93 | const totalServer1 = await countVideoViewsOf(servers[0].internalServerNumber, videoIdServer2) |
96 | expect(totalServer1).to.equal(0) | 94 | expect(totalServer1).to.equal(0) |
97 | 95 | ||
98 | const totalServer2 = await countVideoViewsOf(servers[1].serverNumber, videoIdServer2) | 96 | const totalServer2 = await countVideoViewsOf(servers[1].internalServerNumber, videoIdServer2) |
99 | expect(totalServer2).to.equal(2) | 97 | expect(totalServer2).to.equal(2) |
100 | } | 98 | } |
101 | }) | 99 | }) |
102 | 100 | ||
103 | after(async function () { | 101 | after(async function () { |
102 | await closeAllSequelize(servers) | ||
103 | |||
104 | await cleanupTests(servers) | 104 | await cleanupTests(servers) |
105 | }) | 105 | }) |
106 | }) | 106 | }) |
diff --git a/server/tests/cli/optimize-old-videos.ts b/server/tests/cli/optimize-old-videos.ts index 5e12c0089..3822fca42 100644 --- a/server/tests/cli/optimize-old-videos.ts +++ b/server/tests/cli/optimize-old-videos.ts | |||
@@ -8,14 +8,16 @@ import { | |||
8 | doubleFollow, | 8 | doubleFollow, |
9 | execCLI, | 9 | execCLI, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | flushTests, generateHighBitrateVideo, | 11 | generateHighBitrateVideo, |
12 | getEnvCli, | 12 | getEnvCli, |
13 | getVideo, | 13 | getVideo, |
14 | getVideosList, | 14 | getVideosList, |
15 | killallServers, root, | 15 | root, |
16 | ServerInfo, | 16 | ServerInfo, |
17 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
18 | uploadVideo, viewVideo, wait | 18 | uploadVideo, |
19 | viewVideo, | ||
20 | wait | ||
19 | } from '../../../shared/extra-utils' | 21 | } from '../../../shared/extra-utils' |
20 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' | 22 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' |
21 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils' | 23 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils' |
@@ -102,7 +104,7 @@ describe('Test optimize old videos', function () { | |||
102 | 104 | ||
103 | expect(file.size).to.be.below(5000000) | 105 | expect(file.size).to.be.below(5000000) |
104 | 106 | ||
105 | const path = join(root(), 'test1', 'videos', video.uuid + '-' + file.resolution.id + '.mp4') | 107 | const path = join(root(), 'test' + servers[0].internalServerNumber, 'videos', video.uuid + '-' + file.resolution.id + '.mp4') |
106 | const bitrate = await getVideoFileBitrate(path) | 108 | const bitrate = await getVideoFileBitrate(path) |
107 | const fps = await getVideoFileFPS(path) | 109 | const fps = await getVideoFileFPS(path) |
108 | const resolution = await getVideoFileResolution(path) | 110 | const resolution = await getVideoFileResolution(path) |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 0dcdf09cf..437470327 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -7,13 +7,13 @@ import { | |||
7 | createUser, | 7 | createUser, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | flushTests, | 10 | getJSONfeed, |
11 | getJSONfeed, getMyUserInformation, | 11 | getMyUserInformation, |
12 | getXMLfeed, | 12 | getXMLfeed, |
13 | killallServers, | ||
14 | ServerInfo, | 13 | ServerInfo, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
16 | uploadVideo, userLogin | 15 | uploadVideo, |
16 | userLogin | ||
17 | } from '../../../shared/extra-utils' | 17 | } from '../../../shared/extra-utils' |
18 | import * as libxmljs from 'libxmljs' | 18 | import * as libxmljs from 'libxmljs' |
19 | import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' | 19 | import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' |
@@ -28,10 +28,10 @@ const expect = chai.expect | |||
28 | describe('Test syndication feeds', () => { | 28 | describe('Test syndication feeds', () => { |
29 | let servers: ServerInfo[] = [] | 29 | let servers: ServerInfo[] = [] |
30 | let userAccessToken: string | 30 | let userAccessToken: string |
31 | let rootAccountUUID: string | 31 | let rootAccountId: number |
32 | let rootChannelUUID: string | 32 | let rootChannelId: number |
33 | let userAccountUUID: string | 33 | let userAccountId: number |
34 | let userChannelUUID: string | 34 | let userChannelId: number |
35 | 35 | ||
36 | before(async function () { | 36 | before(async function () { |
37 | this.timeout(120000) | 37 | this.timeout(120000) |
@@ -45,8 +45,8 @@ describe('Test syndication feeds', () => { | |||
45 | { | 45 | { |
46 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 46 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
47 | const user: User = res.body | 47 | const user: User = res.body |
48 | rootAccountUUID = user.account.uuid | 48 | rootAccountId = user.account.id |
49 | rootChannelUUID = user.videoChannels[0].uuid | 49 | rootChannelId = user.videoChannels[0].id |
50 | } | 50 | } |
51 | 51 | ||
52 | { | 52 | { |
@@ -56,8 +56,8 @@ describe('Test syndication feeds', () => { | |||
56 | 56 | ||
57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) | 57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) |
58 | const user: User = res.body | 58 | const user: User = res.body |
59 | userAccountUUID = user.account.uuid | 59 | userAccountId = user.account.id |
60 | userChannelUUID = user.videoChannels[0].uuid | 60 | userChannelId = user.videoChannels[0].id |
61 | } | 61 | } |
62 | 62 | ||
63 | { | 63 | { |
@@ -127,71 +127,71 @@ describe('Test syndication feeds', () => { | |||
127 | }) | 127 | }) |
128 | 128 | ||
129 | it('Should filter by account', async function () { | 129 | it('Should filter by account', async function () { |
130 | { | ||
131 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) | ||
132 | const jsonObj = JSON.parse(json.text) | ||
133 | expect(jsonObj.items.length).to.be.equal(1) | ||
134 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | ||
135 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | ||
136 | } | ||
137 | |||
138 | { | ||
139 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) | ||
140 | const jsonObj = JSON.parse(json.text) | ||
141 | expect(jsonObj.items.length).to.be.equal(1) | ||
142 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | ||
143 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | ||
144 | } | ||
145 | |||
130 | for (const server of servers) { | 146 | for (const server of servers) { |
131 | { | 147 | { |
132 | const json = await getJSONfeed(server.url, 'videos', { accountId: rootAccountUUID }) | 148 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) |
133 | const jsonObj = JSON.parse(json.text) | 149 | const jsonObj = JSON.parse(json.text) |
134 | expect(jsonObj.items.length).to.be.equal(1) | 150 | expect(jsonObj.items.length).to.be.equal(1) |
135 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 151 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') |
136 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | ||
137 | } | 152 | } |
138 | 153 | ||
139 | { | 154 | { |
140 | const json = await getJSONfeed(server.url, 'videos', { accountId: userAccountUUID }) | 155 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) |
141 | const jsonObj = JSON.parse(json.text) | 156 | const jsonObj = JSON.parse(json.text) |
142 | expect(jsonObj.items.length).to.be.equal(1) | 157 | expect(jsonObj.items.length).to.be.equal(1) |
143 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 158 | expect(jsonObj.items[ 0 ].title).to.equal('user video') |
144 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | ||
145 | } | 159 | } |
146 | } | 160 | } |
161 | }) | ||
147 | 162 | ||
163 | it('Should filter by video channel', async function () { | ||
148 | { | 164 | { |
149 | const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'root' }) | 165 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) |
150 | const jsonObj = JSON.parse(json.text) | 166 | const jsonObj = JSON.parse(json.text) |
151 | expect(jsonObj.items.length).to.be.equal(1) | 167 | expect(jsonObj.items.length).to.be.equal(1) |
152 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 168 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') |
169 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | ||
153 | } | 170 | } |
154 | 171 | ||
155 | { | 172 | { |
156 | const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'john' }) | 173 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) |
157 | const jsonObj = JSON.parse(json.text) | 174 | const jsonObj = JSON.parse(json.text) |
158 | expect(jsonObj.items.length).to.be.equal(1) | 175 | expect(jsonObj.items.length).to.be.equal(1) |
159 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 176 | expect(jsonObj.items[ 0 ].title).to.equal('user video') |
177 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | ||
160 | } | 178 | } |
161 | }) | ||
162 | 179 | ||
163 | it('Should filter by video channel', async function () { | ||
164 | for (const server of servers) { | 180 | for (const server of servers) { |
165 | { | 181 | { |
166 | const json = await getJSONfeed(server.url, 'videos', { videoChannelId: rootChannelUUID }) | 182 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) |
167 | const jsonObj = JSON.parse(json.text) | 183 | const jsonObj = JSON.parse(json.text) |
168 | expect(jsonObj.items.length).to.be.equal(1) | 184 | expect(jsonObj.items.length).to.be.equal(1) |
169 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 185 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') |
170 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | ||
171 | } | 186 | } |
172 | 187 | ||
173 | { | 188 | { |
174 | const json = await getJSONfeed(server.url, 'videos', { videoChannelId: userChannelUUID }) | 189 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) |
175 | const jsonObj = JSON.parse(json.text) | 190 | const jsonObj = JSON.parse(json.text) |
176 | expect(jsonObj.items.length).to.be.equal(1) | 191 | expect(jsonObj.items.length).to.be.equal(1) |
177 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 192 | expect(jsonObj.items[ 0 ].title).to.equal('user video') |
178 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | ||
179 | } | 193 | } |
180 | } | 194 | } |
181 | |||
182 | { | ||
183 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'root_channel' }) | ||
184 | const jsonObj = JSON.parse(json.text) | ||
185 | expect(jsonObj.items.length).to.be.equal(1) | ||
186 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | ||
187 | } | ||
188 | |||
189 | { | ||
190 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'john_channel' }) | ||
191 | const jsonObj = JSON.parse(json.text) | ||
192 | expect(jsonObj.items.length).to.be.equal(1) | ||
193 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | ||
194 | } | ||
195 | }) | 195 | }) |
196 | }) | 196 | }) |
197 | 197 | ||
diff --git a/server/tests/fixtures/preview.jpg b/server/tests/fixtures/preview.jpg index c40ece838..cb5692281 100644 --- a/server/tests/fixtures/preview.jpg +++ b/server/tests/fixtures/preview.jpg | |||
Binary files differ | |||
diff --git a/server/tests/fixtures/sample.ogg b/server/tests/fixtures/sample.ogg new file mode 100644 index 000000000..0d7f43eb7 --- /dev/null +++ b/server/tests/fixtures/sample.ogg | |||
Binary files differ | |||
diff --git a/server/tests/fixtures/video_short1-preview.webm.jpg b/server/tests/fixtures/video_short1-preview.webm.jpg index d2a068b78..157d3ca9a 100644 --- a/server/tests/fixtures/video_short1-preview.webm.jpg +++ b/server/tests/fixtures/video_short1-preview.webm.jpg | |||
Binary files differ | |||
diff --git a/server/tools/package.json b/server/tools/package.json new file mode 100644 index 000000000..2d13d41cc --- /dev/null +++ b/server/tools/package.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "name": "@peertube/cli", | ||
3 | "version": "1.0.0", | ||
4 | "private": true, | ||
5 | "dependencies": { | ||
6 | "application-config": "^1.0.1", | ||
7 | "webtorrent-hybrid": "^2.1.0" | ||
8 | }, | ||
9 | "summon": { | ||
10 | "silent": true | ||
11 | } | ||
12 | } | ||
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts index bf7274aab..7c27c1364 100644 --- a/server/tools/peertube-watch.ts +++ b/server/tools/peertube-watch.ts | |||
@@ -1,21 +1,15 @@ | |||
1 | import * as program from 'commander' | 1 | import * as program from 'commander' |
2 | import * as summon from 'summon-install' | ||
3 | import { join } from 'path' | 2 | import { join } from 'path' |
4 | import { execSync } from 'child_process' | 3 | import { execSync } from 'child_process' |
5 | import { root } from '../helpers/core-utils' | ||
6 | |||
7 | let videoURL | ||
8 | 4 | ||
9 | program | 5 | program |
10 | .name('watch') | 6 | .name('watch') |
11 | .arguments('<url>') | 7 | .arguments('<url>') |
12 | .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|ascii|xbmc)$/i, 'ascii') | 8 | .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|xbmc)$/i, 'vlc') |
13 | .option('-i, --invert', 'invert colors (ascii player only)', true) | 9 | .option('-r, --resolution <res>', 'video resolution', '480') |
14 | .option('-r, --resolution <res>', 'video resolution', /^(240|360|720|1080)$/i, '720') | ||
15 | .on('--help', function () { | 10 | .on('--help', function () { |
16 | console.log(' Available Players:') | 11 | console.log(' Available Players:') |
17 | console.log() | 12 | console.log() |
18 | console.log(' - ascii') | ||
19 | console.log(' - mpv') | 13 | console.log(' - mpv') |
20 | console.log(' - mplayer') | 14 | console.log(' - mplayer') |
21 | console.log(' - vlc') | 15 | console.log(' - vlc') |
@@ -24,7 +18,6 @@ program | |||
24 | console.log(' - airplay') | 18 | console.log(' - airplay') |
25 | console.log(' - chromecast') | 19 | console.log(' - chromecast') |
26 | console.log() | 20 | console.log() |
27 | console.log(' Note: \'ascii\' is the only option not using WebTorrent and not seeding back the video.') | ||
28 | console.log() | 21 | console.log() |
29 | console.log(' Examples:') | 22 | console.log(' Examples:') |
30 | console.log() | 23 | console.log() |
@@ -33,29 +26,25 @@ program | |||
33 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') | 26 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') |
34 | console.log() | 27 | console.log() |
35 | }) | 28 | }) |
36 | .action((url) => { | 29 | .action((url, cmd) => { |
37 | videoURL = url | 30 | run(url, cmd) |
31 | .catch(err => { | ||
32 | console.error(err) | ||
33 | process.exit(-1) | ||
34 | }) | ||
38 | }) | 35 | }) |
39 | .parse(process.argv) | 36 | .parse(process.argv) |
40 | 37 | ||
41 | if (!videoURL) { | 38 | async function run (url: string, program: any) { |
42 | console.error('<url> positional argument is required.') | 39 | if (!url) { |
43 | process.exit(-1) | 40 | console.error('<url> positional argument is required.') |
44 | } else { program['url'] = videoURL } | 41 | process.exit(-1) |
42 | } | ||
45 | 43 | ||
46 | handler(program) | 44 | const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js') |
45 | const args = ` --${program.gui} ` + | ||
46 | url.replace('videos/watch', 'download/torrents') + | ||
47 | `-${program.resolution}.torrent` | ||
47 | 48 | ||
48 | function handler (argv) { | 49 | execSync(cmd + args) |
49 | if (argv['gui'] === 'ascii') { | ||
50 | summon('peerterminal') | ||
51 | const peerterminal = summon('peerterminal') | ||
52 | peerterminal([ '--link', videoURL, '--invert', argv['invert'] ]) | ||
53 | } else { | ||
54 | summon('webtorrent-hybrid') | ||
55 | const CMD = 'node ' + join(root(), 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js') | ||
56 | const CMDargs = ` --${argv.gui} ` + | ||
57 | argv['url'].replace('videos/watch', 'download/torrents') + | ||
58 | `-${argv.resolution}.torrent` | ||
59 | execSync(CMD + CMDargs) | ||
60 | } | ||
61 | } | 50 | } |
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts index 5d3ab2815..5d3ab2815 100755..100644 --- a/server/tools/peertube.ts +++ b/server/tools/peertube.ts | |||
diff --git a/server/tools/tsconfig.json b/server/tools/tsconfig.json new file mode 100644 index 000000000..f8a1c705c --- /dev/null +++ b/server/tools/tsconfig.json | |||
@@ -0,0 +1,4 @@ | |||
1 | { | ||
2 | "extends": "../../tsconfig.json", | ||
3 | "exclude": [ ] // Overwrite exclude property | ||
4 | } | ||
diff --git a/server/tools/yarn.lock b/server/tools/yarn.lock new file mode 100644 index 000000000..3c3778d3f --- /dev/null +++ b/server/tools/yarn.lock | |||
@@ -0,0 +1,1970 @@ | |||
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
2 | # yarn lockfile v1 | ||
3 | |||
4 | |||
5 | abbrev@1: | ||
6 | version "1.1.1" | ||
7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" | ||
8 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== | ||
9 | |||
10 | addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2: | ||
11 | version "1.5.1" | ||
12 | resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208" | ||
13 | integrity sha512-bA+dyydTNuQtrEDJ0g9eR7XabNhvrM5yZY0hvTbNK3yvoeC73ZqMES6E1cEqH9WPxs4uMtMsOjfwS4FmluhsAA== | ||
14 | |||
15 | airplay-js@^0.3.0: | ||
16 | version "0.3.0" | ||
17 | resolved "https://registry.yarnpkg.com/airplay-js/-/airplay-js-0.3.0.tgz#16bac2ef91b31249382924bfdeeabaddc9db7398" | ||
18 | integrity sha1-FrrC75GzEkk4KSS/3uq63cnbc5g= | ||
19 | dependencies: | ||
20 | mdns-js "0.5.0" | ||
21 | plist-with-patches "0.5.1" | ||
22 | |||
23 | ansi-regex@^2.0.0: | ||
24 | version "2.1.1" | ||
25 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" | ||
26 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= | ||
27 | |||
28 | ansi-regex@^3.0.0: | ||
29 | version "3.0.0" | ||
30 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" | ||
31 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= | ||
32 | |||
33 | application-config-path@^0.1.0: | ||
34 | version "0.1.0" | ||
35 | resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f" | ||
36 | integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8= | ||
37 | |||
38 | application-config@^1.0.1: | ||
39 | version "1.0.1" | ||
40 | resolved "https://registry.yarnpkg.com/application-config/-/application-config-1.0.1.tgz#5aa2e2a5ed6abd2e5d1d473d3596f574044fe9e7" | ||
41 | integrity sha1-WqLipe1qvS5dHUc9NZb1dARP6ec= | ||
42 | dependencies: | ||
43 | application-config-path "^0.1.0" | ||
44 | mkdirp "^0.5.1" | ||
45 | |||
46 | aproba@^1.0.3: | ||
47 | version "1.2.0" | ||
48 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" | ||
49 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== | ||
50 | |||
51 | are-we-there-yet@~1.1.2: | ||
52 | version "1.1.5" | ||
53 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" | ||
54 | integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== | ||
55 | dependencies: | ||
56 | delegates "^1.0.0" | ||
57 | readable-stream "^2.0.6" | ||
58 | |||
59 | ascli@~0.3: | ||
60 | version "0.3.0" | ||
61 | resolved "https://registry.yarnpkg.com/ascli/-/ascli-0.3.0.tgz#5e66230e5219fe3e8952a4efb4f20fae596a813a" | ||
62 | integrity sha1-XmYjDlIZ/j6JUqTvtPIPrllqgTo= | ||
63 | dependencies: | ||
64 | colour latest | ||
65 | optjs latest | ||
66 | |||
67 | async-limiter@~1.0.0: | ||
68 | version "1.0.0" | ||
69 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" | ||
70 | integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== | ||
71 | |||
72 | balanced-match@^1.0.0: | ||
73 | version "1.0.0" | ||
74 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" | ||
75 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= | ||
76 | |||
77 | bencode@^2.0.0: | ||
78 | version "2.0.1" | ||
79 | resolved "https://registry.yarnpkg.com/bencode/-/bencode-2.0.1.tgz#667a6a31c5e038d558608333da6b7c94e836c85b" | ||
80 | integrity sha512-2uhEl8FdjSBUyb69qDTgOEeeqDTa+n3yMQzLW0cOzNf1Ow5bwcg3idf+qsWisIKRH8Bk8oC7UXL8irRcPA8ZEQ== | ||
81 | dependencies: | ||
82 | safe-buffer "^5.1.1" | ||
83 | |||
84 | binary-search@^1.3.4: | ||
85 | version "1.3.5" | ||
86 | resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce" | ||
87 | integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw== | ||
88 | |||
89 | bitfield@^2.0.0: | ||
90 | version "2.0.0" | ||
91 | resolved "https://registry.yarnpkg.com/bitfield/-/bitfield-2.0.0.tgz#fbe6767592fe5b4c87ecf1d04126294cc1bfa837" | ||
92 | integrity sha512-4xM4DYejOHQ/qWBfeqBXNA4mJ12PwcOibFYnH1kYh5U9BHciCqEJBqGNVnMJXUhm8mflujNRLSv7IiVQxovgjw== | ||
93 | |||
94 | bittorrent-dht@^9.0.0: | ||
95 | version "9.0.0" | ||
96 | resolved "https://registry.yarnpkg.com/bittorrent-dht/-/bittorrent-dht-9.0.0.tgz#08d5ebb51ed91d7e3eea5c275554f4323fb523e5" | ||
97 | integrity sha512-X5ax4G/PLtEPfqOUjqDZ2nmPENndWRMK4sT2jcQ4sXor904zhR40r4KqTyTvWYAljh5/hPPqM9DCUUtqWzRXoQ== | ||
98 | dependencies: | ||
99 | bencode "^2.0.0" | ||
100 | buffer-equals "^1.0.3" | ||
101 | debug "^3.1.0" | ||
102 | inherits "^2.0.1" | ||
103 | k-bucket "^5.0.0" | ||
104 | k-rpc "^5.0.0" | ||
105 | last-one-wins "^1.0.4" | ||
106 | lru "^3.1.0" | ||
107 | randombytes "^2.0.5" | ||
108 | record-cache "^1.0.2" | ||
109 | safe-buffer "^5.0.1" | ||
110 | simple-sha1 "^2.1.0" | ||
111 | |||
112 | bittorrent-peerid@^1.0.2: | ||
113 | version "1.3.0" | ||
114 | resolved "https://registry.yarnpkg.com/bittorrent-peerid/-/bittorrent-peerid-1.3.0.tgz#a435d3b267c887c586c528b53359845905d7c158" | ||
115 | integrity sha512-SYd5H3RbN1ex+TrWAKXkEkASFWxAR7Tk6iLt9tfAT9ehBvZb/Y3AQDVRVJynlrixcWpnmsLYKI7tkRWgp7ORoQ== | ||
116 | |||
117 | bittorrent-protocol@^3.0.0: | ||
118 | version "3.0.1" | ||
119 | resolved "https://registry.yarnpkg.com/bittorrent-protocol/-/bittorrent-protocol-3.0.1.tgz#d3948f4d2b09d538095f7e5f93f64ba5df6b5c2a" | ||
120 | integrity sha512-hnvOzAu9u+2H0OLLL5byoFdz6oz5f3bx5f7R+ItUohTHMq9TgUhEJfcjo7xWtQHSKOVciYWwYTJ4EjczF5RX2A== | ||
121 | dependencies: | ||
122 | bencode "^2.0.0" | ||
123 | bitfield "^2.0.0" | ||
124 | debug "^3.1.0" | ||
125 | randombytes "^2.0.5" | ||
126 | readable-stream "^2.3.2" | ||
127 | speedometer "^1.0.0" | ||
128 | unordered-array-remove "^1.0.2" | ||
129 | xtend "^4.0.0" | ||
130 | |||
131 | bittorrent-tracker@^9.0.0: | ||
132 | version "9.11.0" | ||
133 | resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.11.0.tgz#9911f9c14e5a29f84990a0c31b3d83dd16eb2876" | ||
134 | integrity sha512-T1zvW/kSeEnWT4I3JE+6c7aZbO5jtleZyQe911SyzIxFF9DvtUNWXud3p5ZUkXaoI2xXwfpvlks5VFj5SKEB+A== | ||
135 | dependencies: | ||
136 | bencode "^2.0.0" | ||
137 | bittorrent-peerid "^1.0.2" | ||
138 | bn.js "^4.4.0" | ||
139 | compact2string "^1.2.0" | ||
140 | debug "^4.0.1" | ||
141 | ip "^1.0.1" | ||
142 | lru "^3.0.0" | ||
143 | minimist "^1.1.1" | ||
144 | once "^1.3.0" | ||
145 | random-iterate "^1.0.1" | ||
146 | randombytes "^2.0.3" | ||
147 | run-parallel "^1.1.2" | ||
148 | run-series "^1.0.2" | ||
149 | safe-buffer "^5.0.0" | ||
150 | simple-get "^3.0.0" | ||
151 | simple-peer "^9.0.0" | ||
152 | simple-websocket "^7.0.1" | ||
153 | string2compact "^1.1.1" | ||
154 | uniq "^1.0.1" | ||
155 | unordered-array-remove "^1.0.2" | ||
156 | ws "^6.0.0" | ||
157 | optionalDependencies: | ||
158 | bufferutil "^4.0.0" | ||
159 | utf-8-validate "^5.0.1" | ||
160 | |||
161 | blob-to-buffer@^1.2.6: | ||
162 | version "1.2.8" | ||
163 | resolved "https://registry.yarnpkg.com/blob-to-buffer/-/blob-to-buffer-1.2.8.tgz#78eeeb332f1280ed0ca6fb2b60693a8c6d36903a" | ||
164 | integrity sha512-re0AIxakF504MgeMtIyJkVcZ8T5aUxtp/QmTMlmjyb3P44E1BEv5x3LATBGApWAJATyXHtkXRD+gWTmeyYLiQA== | ||
165 | |||
166 | block-stream2@^1.0.0: | ||
167 | version "1.1.0" | ||
168 | resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-1.1.0.tgz#c738e3a91ba977ebb5e1fef431e13ca11d8639e2" | ||
169 | integrity sha1-xzjjqRupd+u14f70MeE8oR2GOeI= | ||
170 | dependencies: | ||
171 | defined "^1.0.0" | ||
172 | inherits "^2.0.1" | ||
173 | readable-stream "^2.0.4" | ||
174 | |||
175 | bn.js@^4.4.0: | ||
176 | version "4.11.8" | ||
177 | resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" | ||
178 | integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== | ||
179 | |||
180 | brace-expansion@^1.1.7: | ||
181 | version "1.1.11" | ||
182 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" | ||
183 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== | ||
184 | dependencies: | ||
185 | balanced-match "^1.0.0" | ||
186 | concat-map "0.0.1" | ||
187 | |||
188 | browserify-package-json@^1.0.0: | ||
189 | version "1.0.1" | ||
190 | resolved "https://registry.yarnpkg.com/browserify-package-json/-/browserify-package-json-1.0.1.tgz#98dde8aa5c561fd6d3fe49bbaa102b74b396fdea" | ||
191 | integrity sha1-mN3oqlxWH9bT/km7qhArdLOW/eo= | ||
192 | |||
193 | buffer-alloc-unsafe@^1.1.0: | ||
194 | version "1.1.0" | ||
195 | resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" | ||
196 | integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== | ||
197 | |||
198 | buffer-alloc@^1.1.0, buffer-alloc@^1.2.0: | ||
199 | version "1.2.0" | ||
200 | resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" | ||
201 | integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== | ||
202 | dependencies: | ||
203 | buffer-alloc-unsafe "^1.1.0" | ||
204 | buffer-fill "^1.0.0" | ||
205 | |||
206 | buffer-equals@^1.0.3, buffer-equals@^1.0.4: | ||
207 | version "1.0.4" | ||
208 | resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5" | ||
209 | integrity sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U= | ||
210 | |||
211 | buffer-fill@^1.0.0: | ||
212 | version "1.0.0" | ||
213 | resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" | ||
214 | integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= | ||
215 | |||
216 | buffer-from@^1.0.0, buffer-from@^1.1.0: | ||
217 | version "1.1.1" | ||
218 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" | ||
219 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== | ||
220 | |||
221 | buffer-indexof@^1.0.0: | ||
222 | version "1.1.1" | ||
223 | resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" | ||
224 | integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== | ||
225 | |||
226 | bufferutil@^4.0.0: | ||
227 | version "4.0.1" | ||
228 | resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" | ||
229 | integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA== | ||
230 | dependencies: | ||
231 | node-gyp-build "~3.7.0" | ||
232 | |||
233 | bufferview@~1: | ||
234 | version "1.0.1" | ||
235 | resolved "https://registry.yarnpkg.com/bufferview/-/bufferview-1.0.1.tgz#7afd74a45f937fa422a1d338c08bbfdc76cd725d" | ||
236 | integrity sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0= | ||
237 | |||
238 | "bytebuffer@~3 >=3.5": | ||
239 | version "3.5.5" | ||
240 | resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-3.5.5.tgz#7a6faf1a13514b083f1fcf9541c4c9bfbe7e7fd3" | ||
241 | integrity sha1-em+vGhNRSwg/H8+VQcTJv75+f9M= | ||
242 | dependencies: | ||
243 | bufferview "~1" | ||
244 | long "~2 >=2.2.3" | ||
245 | |||
246 | camelcase@^3.0.0: | ||
247 | version "3.0.0" | ||
248 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" | ||
249 | integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= | ||
250 | |||
251 | castv2-client@^1.1.0: | ||
252 | version "1.2.0" | ||
253 | resolved "https://registry.yarnpkg.com/castv2-client/-/castv2-client-1.2.0.tgz#a9193b1a5448b8cb9a0415bd021c8811ed7b0544" | ||
254 | integrity sha1-qRk7GlRIuMuaBBW9AhyIEe17BUQ= | ||
255 | dependencies: | ||
256 | castv2 "~0.1.4" | ||
257 | debug "^2.2.0" | ||
258 | |||
259 | castv2@~0.1.4: | ||
260 | version "0.1.9" | ||
261 | resolved "https://registry.yarnpkg.com/castv2/-/castv2-0.1.9.tgz#d0b0fab1fd06b0d9cca636886716ec1293a5905a" | ||
262 | integrity sha1-0LD6sf0GsNnMpjaIZxbsEpOlkFo= | ||
263 | dependencies: | ||
264 | debug "^2.2.0" | ||
265 | protobufjs "^3.2.2" | ||
266 | |||
267 | chownr@^1.1.1: | ||
268 | version "1.1.1" | ||
269 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" | ||
270 | integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== | ||
271 | |||
272 | chromecasts@^1.5.3: | ||
273 | version "1.9.1" | ||
274 | resolved "https://registry.yarnpkg.com/chromecasts/-/chromecasts-1.9.1.tgz#67b162e8414d57d6106c49fe4a0e9b08f20bbd12" | ||
275 | integrity sha512-nsXv7ufgrpC8s5DUm6FJEa2XJ2VvE9FmbTVi6r4zGreTFTTSRSJjvqVEqLUFX/fGo/zbSre3zdoV+Pu9DGLz0A== | ||
276 | dependencies: | ||
277 | castv2-client "^1.1.0" | ||
278 | debug "^2.1.3" | ||
279 | dns-txt "^2.0.2" | ||
280 | mime "^1.3.4" | ||
281 | multicast-dns "^6.0.1" | ||
282 | simple-get "^2.0.0" | ||
283 | thunky "^0.1.0" | ||
284 | xml2js "^0.4.8" | ||
285 | optionalDependencies: | ||
286 | node-ssdp "^2.2.0" | ||
287 | |||
288 | chunk-store-stream@^3.0.1: | ||
289 | version "3.0.1" | ||
290 | resolved "https://registry.yarnpkg.com/chunk-store-stream/-/chunk-store-stream-3.0.1.tgz#8e0d739226dcb386f44447b82a005b597a1d41d9" | ||
291 | integrity sha512-GA1NIFDZKElhkjiO6QOyzfK1QbUt6M3gFhUU/aR05JYaDqXbU5d7U92cLvGKdItJEDfojky6NQefy5VL5PpDBA== | ||
292 | dependencies: | ||
293 | block-stream2 "^1.0.0" | ||
294 | readable-stream "^2.0.5" | ||
295 | |||
296 | cliui@^3.2.0: | ||
297 | version "3.2.0" | ||
298 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" | ||
299 | integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= | ||
300 | dependencies: | ||
301 | string-width "^1.0.1" | ||
302 | strip-ansi "^3.0.1" | ||
303 | wrap-ansi "^2.0.0" | ||
304 | |||
305 | clivas@^0.2.0: | ||
306 | version "0.2.0" | ||
307 | resolved "https://registry.yarnpkg.com/clivas/-/clivas-0.2.0.tgz#b8d19188b3243e390f302410bd0cb1622db82649" | ||
308 | integrity sha1-uNGRiLMkPjkPMCQQvQyxYi24Jkk= | ||
309 | |||
310 | closest-to@~2.0.0: | ||
311 | version "2.0.0" | ||
312 | resolved "https://registry.yarnpkg.com/closest-to/-/closest-to-2.0.0.tgz#bb2a860edb7769b62d04821748ae50da24dbefaa" | ||
313 | integrity sha1-uyqGDtt3abYtBIIXSK5Q2iTb76o= | ||
314 | |||
315 | code-point-at@^1.0.0: | ||
316 | version "1.1.0" | ||
317 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" | ||
318 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= | ||
319 | |||
320 | colour@latest: | ||
321 | version "0.7.1" | ||
322 | resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" | ||
323 | integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g= | ||
324 | |||
325 | compact2string@^1.2.0: | ||
326 | version "1.4.1" | ||
327 | resolved "https://registry.yarnpkg.com/compact2string/-/compact2string-1.4.1.tgz#8d34929055f8300a13cfc030ad1832e2e53c2e25" | ||
328 | integrity sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og== | ||
329 | dependencies: | ||
330 | ipaddr.js ">= 0.1.5" | ||
331 | |||
332 | concat-map@0.0.1: | ||
333 | version "0.0.1" | ||
334 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | ||
335 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | ||
336 | |||
337 | concat-stream@^1.4.8: | ||
338 | version "1.6.2" | ||
339 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" | ||
340 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== | ||
341 | dependencies: | ||
342 | buffer-from "^1.0.0" | ||
343 | inherits "^2.0.3" | ||
344 | readable-stream "^2.2.2" | ||
345 | typedarray "^0.0.6" | ||
346 | |||
347 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: | ||
348 | version "1.1.0" | ||
349 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" | ||
350 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= | ||
351 | |||
352 | core-util-is@~1.0.0: | ||
353 | version "1.0.2" | ||
354 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" | ||
355 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= | ||
356 | |||
357 | create-torrent@^3.23.1, create-torrent@^3.33.0: | ||
358 | version "3.33.0" | ||
359 | resolved "https://registry.yarnpkg.com/create-torrent/-/create-torrent-3.33.0.tgz#8a7a2aa2213a799c266c40e4c12f1468ede25105" | ||
360 | integrity sha512-KMd0KuvwVUg1grlRd5skG9ZkSbBYDDkAjDUMLnvxdRn0rL7ph3IwoOk7I8u1yLX4HYjGiLVlWYO55YWNNPjJFA== | ||
361 | dependencies: | ||
362 | bencode "^2.0.0" | ||
363 | block-stream2 "^1.0.0" | ||
364 | filestream "^4.0.0" | ||
365 | flatten "^1.0.2" | ||
366 | is-file "^1.0.0" | ||
367 | junk "^2.1.0" | ||
368 | minimist "^1.1.0" | ||
369 | multistream "^2.0.2" | ||
370 | once "^1.3.0" | ||
371 | piece-length "^1.0.0" | ||
372 | readable-stream "^3.0.2" | ||
373 | run-parallel "^1.0.0" | ||
374 | simple-sha1 "^2.0.0" | ||
375 | |||
376 | debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: | ||
377 | version "2.6.9" | ||
378 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | ||
379 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== | ||
380 | dependencies: | ||
381 | ms "2.0.0" | ||
382 | |||
383 | debug@^3.1.0, debug@^3.2.6: | ||
384 | version "3.2.6" | ||
385 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" | ||
386 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== | ||
387 | dependencies: | ||
388 | ms "^2.1.1" | ||
389 | |||
390 | debug@^4.0.1, debug@^4.1.0: | ||
391 | version "4.1.1" | ||
392 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" | ||
393 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== | ||
394 | dependencies: | ||
395 | ms "^2.1.1" | ||
396 | |||
397 | decamelize@^1.1.1: | ||
398 | version "1.2.0" | ||
399 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" | ||
400 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= | ||
401 | |||
402 | decompress-response@^3.3.0: | ||
403 | version "3.3.0" | ||
404 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" | ||
405 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= | ||
406 | dependencies: | ||
407 | mimic-response "^1.0.0" | ||
408 | |||
409 | deep-extend@^0.6.0: | ||
410 | version "0.6.0" | ||
411 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" | ||
412 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== | ||
413 | |||
414 | defined@^1.0.0: | ||
415 | version "1.0.0" | ||
416 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" | ||
417 | integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= | ||
418 | |||
419 | delegates@^1.0.0: | ||
420 | version "1.0.0" | ||
421 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" | ||
422 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= | ||
423 | |||
424 | detect-libc@^1.0.2: | ||
425 | version "1.0.3" | ||
426 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" | ||
427 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= | ||
428 | |||
429 | dlnacasts@^0.1.0: | ||
430 | version "0.1.0" | ||
431 | resolved "https://registry.yarnpkg.com/dlnacasts/-/dlnacasts-0.1.0.tgz#f805211dcac74f6bb3a4d5d5541ad783b1b67d22" | ||
432 | integrity sha1-+AUhHcrHT2uzpNXVVBrXg7G2fSI= | ||
433 | dependencies: | ||
434 | debug "^2.1.3" | ||
435 | mime "^1.3.4" | ||
436 | node-ssdp "^2.7.1" | ||
437 | run-parallel "^1.1.6" | ||
438 | simple-get "^2.1.0" | ||
439 | thunky "^0.1.0" | ||
440 | upnp-mediarenderer-client "^1.2.2" | ||
441 | xml2js "^0.4.8" | ||
442 | |||
443 | dns-packet@^1.3.1: | ||
444 | version "1.3.1" | ||
445 | resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" | ||
446 | integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== | ||
447 | dependencies: | ||
448 | ip "^1.1.0" | ||
449 | safe-buffer "^5.0.1" | ||
450 | |||
451 | dns-txt@^2.0.2: | ||
452 | version "2.0.2" | ||
453 | resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" | ||
454 | integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= | ||
455 | dependencies: | ||
456 | buffer-indexof "^1.0.0" | ||
457 | |||
458 | domexception@^1.0.1: | ||
459 | version "1.0.1" | ||
460 | resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" | ||
461 | integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== | ||
462 | dependencies: | ||
463 | webidl-conversions "^4.0.2" | ||
464 | |||
465 | ecstatic@^3.0.0: | ||
466 | version "3.3.2" | ||
467 | resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" | ||
468 | integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== | ||
469 | dependencies: | ||
470 | he "^1.1.1" | ||
471 | mime "^1.6.0" | ||
472 | minimist "^1.1.0" | ||
473 | url-join "^2.0.5" | ||
474 | |||
475 | elementtree@^0.1.6, elementtree@~0.1.6: | ||
476 | version "0.1.7" | ||
477 | resolved "https://registry.yarnpkg.com/elementtree/-/elementtree-0.1.7.tgz#9ac91be6e52fb6e6244c4e54a4ac3ed8ae8e29c0" | ||
478 | integrity sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA= | ||
479 | dependencies: | ||
480 | sax "1.1.4" | ||
481 | |||
482 | end-of-stream@^1.1.0: | ||
483 | version "1.4.1" | ||
484 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" | ||
485 | integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== | ||
486 | dependencies: | ||
487 | once "^1.4.0" | ||
488 | |||
489 | error-ex@^1.2.0: | ||
490 | version "1.3.2" | ||
491 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" | ||
492 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== | ||
493 | dependencies: | ||
494 | is-arrayish "^0.2.1" | ||
495 | |||
496 | executable@^4.0.0: | ||
497 | version "4.1.1" | ||
498 | resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" | ||
499 | integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== | ||
500 | dependencies: | ||
501 | pify "^2.2.0" | ||
502 | |||
503 | filestream@^4.0.0: | ||
504 | version "4.1.3" | ||
505 | resolved "https://registry.yarnpkg.com/filestream/-/filestream-4.1.3.tgz#948fcaade8221f715f5ecaddc54862faaacc9325" | ||
506 | integrity sha1-lI/KregiH3FfXsrdxUhi+qrMkyU= | ||
507 | dependencies: | ||
508 | inherits "^2.0.1" | ||
509 | readable-stream "^2.0.5" | ||
510 | typedarray-to-buffer "^3.0.0" | ||
511 | xtend "^4.0.1" | ||
512 | |||
513 | find-up@^1.0.0: | ||
514 | version "1.1.2" | ||
515 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" | ||
516 | integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= | ||
517 | dependencies: | ||
518 | path-exists "^2.0.0" | ||
519 | pinkie-promise "^2.0.0" | ||
520 | |||
521 | flatten@^1.0.2: | ||
522 | version "1.0.2" | ||
523 | resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" | ||
524 | integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= | ||
525 | |||
526 | fs-chunk-store@^1.6.2: | ||
527 | version "1.7.0" | ||
528 | resolved "https://registry.yarnpkg.com/fs-chunk-store/-/fs-chunk-store-1.7.0.tgz#1c4bcbe93c99af10aa04b65348f2bb27377a4010" | ||
529 | integrity sha512-KhjJmZAs2eqfhCb6PdPx4RcZtheGTz86tpTC5JTvqBn/xda+Nb+0C7dCyjOSN7T76H6a56LvH0SVXQMchLXDRw== | ||
530 | dependencies: | ||
531 | mkdirp "^0.5.1" | ||
532 | random-access-file "^2.0.1" | ||
533 | randombytes "^2.0.3" | ||
534 | rimraf "^2.4.2" | ||
535 | run-parallel "^1.1.2" | ||
536 | thunky "^1.0.1" | ||
537 | |||
538 | fs-minipass@^1.2.5: | ||
539 | version "1.2.6" | ||
540 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" | ||
541 | integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== | ||
542 | dependencies: | ||
543 | minipass "^2.2.1" | ||
544 | |||
545 | fs.realpath@^1.0.0: | ||
546 | version "1.0.0" | ||
547 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | ||
548 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | ||
549 | |||
550 | gauge@~2.7.3: | ||
551 | version "2.7.4" | ||
552 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" | ||
553 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= | ||
554 | dependencies: | ||
555 | aproba "^1.0.3" | ||
556 | console-control-strings "^1.0.0" | ||
557 | has-unicode "^2.0.0" | ||
558 | object-assign "^4.1.0" | ||
559 | signal-exit "^3.0.0" | ||
560 | string-width "^1.0.1" | ||
561 | strip-ansi "^3.0.1" | ||
562 | wide-align "^1.1.0" | ||
563 | |||
564 | get-browser-rtc@^1.0.0: | ||
565 | version "1.0.2" | ||
566 | resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" | ||
567 | integrity sha1-u81AyEUaftTvXDc7gWmkCd0dEdk= | ||
568 | |||
569 | get-caller-file@^1.0.1: | ||
570 | version "1.0.3" | ||
571 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" | ||
572 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== | ||
573 | |||
574 | get-stdin@^6.0.0: | ||
575 | version "6.0.0" | ||
576 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" | ||
577 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== | ||
578 | |||
579 | glob@^7.1.3: | ||
580 | version "7.1.4" | ||
581 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" | ||
582 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== | ||
583 | dependencies: | ||
584 | fs.realpath "^1.0.0" | ||
585 | inflight "^1.0.4" | ||
586 | inherits "2" | ||
587 | minimatch "^3.0.4" | ||
588 | once "^1.3.0" | ||
589 | path-is-absolute "^1.0.0" | ||
590 | |||
591 | graceful-fs@^4.1.2: | ||
592 | version "4.1.15" | ||
593 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" | ||
594 | integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== | ||
595 | |||
596 | has-unicode@^2.0.0: | ||
597 | version "2.0.1" | ||
598 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" | ||
599 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= | ||
600 | |||
601 | he@^1.1.1: | ||
602 | version "1.2.0" | ||
603 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" | ||
604 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== | ||
605 | |||
606 | hosted-git-info@^2.1.4: | ||
607 | version "2.7.1" | ||
608 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" | ||
609 | integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== | ||
610 | |||
611 | iconv-lite@^0.4.4: | ||
612 | version "0.4.24" | ||
613 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" | ||
614 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== | ||
615 | dependencies: | ||
616 | safer-buffer ">= 2.1.2 < 3" | ||
617 | |||
618 | ignore-walk@^3.0.1: | ||
619 | version "3.0.1" | ||
620 | resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" | ||
621 | integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== | ||
622 | dependencies: | ||
623 | minimatch "^3.0.4" | ||
624 | |||
625 | immediate-chunk-store@^2.0.0: | ||
626 | version "2.0.0" | ||
627 | resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.0.0.tgz#f313fd0cc71396d8911ad031179e1cccfda3da18" | ||
628 | integrity sha512-5s6NiCGbtWc+OQA60jrre54w12U7tynIyUNjO5LJjNA5lWwvCv6640roq8Wk/wIuaqnd4Pgtp453OyJ7hbONkQ== | ||
629 | |||
630 | inflight@^1.0.4: | ||
631 | version "1.0.6" | ||
632 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" | ||
633 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= | ||
634 | dependencies: | ||
635 | once "^1.3.0" | ||
636 | wrappy "1" | ||
637 | |||
638 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: | ||
639 | version "2.0.3" | ||
640 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" | ||
641 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= | ||
642 | |||
643 | ini@~1.3.0: | ||
644 | version "1.3.5" | ||
645 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" | ||
646 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== | ||
647 | |||
648 | invert-kv@^1.0.0: | ||
649 | version "1.0.0" | ||
650 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" | ||
651 | integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= | ||
652 | |||
653 | ip-set@^1.0.0: | ||
654 | version "1.0.2" | ||
655 | resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de" | ||
656 | integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA== | ||
657 | dependencies: | ||
658 | ip "^1.1.3" | ||
659 | |||
660 | ip@^1.0.1, ip@^1.1.0, ip@^1.1.3: | ||
661 | version "1.1.5" | ||
662 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" | ||
663 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= | ||
664 | |||
665 | "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1: | ||
666 | version "1.9.0" | ||
667 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" | ||
668 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== | ||
669 | |||
670 | is-arrayish@^0.2.1: | ||
671 | version "0.2.1" | ||
672 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" | ||
673 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= | ||
674 | |||
675 | is-ascii@^1.0.0: | ||
676 | version "1.0.0" | ||
677 | resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929" | ||
678 | integrity sha1-8CrQJZoJIc0Zn/Ic4bCeD2tOOSk= | ||
679 | |||
680 | is-file@^1.0.0: | ||
681 | version "1.0.0" | ||
682 | resolved "https://registry.yarnpkg.com/is-file/-/is-file-1.0.0.tgz#28a44cfbd9d3db193045f22b65fce8edf9620596" | ||
683 | integrity sha1-KKRM+9nT2xkwRfIrZfzo7fliBZY= | ||
684 | |||
685 | is-fullwidth-code-point@^1.0.0: | ||
686 | version "1.0.0" | ||
687 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" | ||
688 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= | ||
689 | dependencies: | ||
690 | number-is-nan "^1.0.0" | ||
691 | |||
692 | is-fullwidth-code-point@^2.0.0: | ||
693 | version "2.0.0" | ||
694 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" | ||
695 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= | ||
696 | |||
697 | is-typedarray@^1.0.0: | ||
698 | version "1.0.0" | ||
699 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" | ||
700 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= | ||
701 | |||
702 | is-utf8@^0.2.0: | ||
703 | version "0.2.1" | ||
704 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" | ||
705 | integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= | ||
706 | |||
707 | isarray@~1.0.0: | ||
708 | version "1.0.0" | ||
709 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" | ||
710 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= | ||
711 | |||
712 | isexe@^2.0.0: | ||
713 | version "2.0.0" | ||
714 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" | ||
715 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= | ||
716 | |||
717 | junk@^2.1.0: | ||
718 | version "2.1.0" | ||
719 | resolved "https://registry.yarnpkg.com/junk/-/junk-2.1.0.tgz#f431b4b7f072dc500a5f10ce7f4ec71930e70134" | ||
720 | integrity sha1-9DG0t/By3FAKXxDOf07HGTDnATQ= | ||
721 | |||
722 | k-bucket@^4.0.0: | ||
723 | version "4.0.1" | ||
724 | resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-4.0.1.tgz#3fc2e5693f0b7bff90d7b6b476edd6087955d542" | ||
725 | integrity sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ== | ||
726 | dependencies: | ||
727 | inherits "^2.0.1" | ||
728 | randombytes "^2.0.3" | ||
729 | |||
730 | k-bucket@^5.0.0: | ||
731 | version "5.0.0" | ||
732 | resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-5.0.0.tgz#ef7a401fcd4c37cd31dceaa6ae4440ca91055e01" | ||
733 | integrity sha512-r/q+wV/Kde62/tk+rqyttEJn6h0jR7x+incdMVSYTqK73zVxVrzJa70kJL49cIKen8XjIgUZKSvk8ktnrQbK4w== | ||
734 | dependencies: | ||
735 | randombytes "^2.0.3" | ||
736 | |||
737 | k-rpc-socket@^1.7.2: | ||
738 | version "1.8.0" | ||
739 | resolved "https://registry.yarnpkg.com/k-rpc-socket/-/k-rpc-socket-1.8.0.tgz#9a4dd6a4f3795ed847ffa156579cc389990bd1f2" | ||
740 | integrity sha512-f/9TynsO8YYjZ6JjNNtSSH7CJcIHcio1buy3zqByGxb/GX8AWLdL6FZEWTrN8V3/J7W4/E0ZTQQ+Jt2rVq7ELg== | ||
741 | dependencies: | ||
742 | bencode "^2.0.0" | ||
743 | buffer-equals "^1.0.4" | ||
744 | safe-buffer "^5.1.1" | ||
745 | |||
746 | k-rpc@^5.0.0: | ||
747 | version "5.0.0" | ||
748 | resolved "https://registry.yarnpkg.com/k-rpc/-/k-rpc-5.0.0.tgz#a72651860c96db440579e4c9f38dce8a42b481a8" | ||
749 | integrity sha512-vCH2rQdfMOS+MlUuTSuar1pS2EMrltURf9LmAR9xR6Jik0XPlMX3vEixgqMn17wKmFVCublJqSJ4hJIP7oKZ3Q== | ||
750 | dependencies: | ||
751 | buffer-equals "^1.0.3" | ||
752 | k-bucket "^4.0.0" | ||
753 | k-rpc-socket "^1.7.2" | ||
754 | randombytes "^2.0.5" | ||
755 | safe-buffer "^5.1.1" | ||
756 | |||
757 | last-one-wins@^1.0.4: | ||
758 | version "1.0.4" | ||
759 | resolved "https://registry.yarnpkg.com/last-one-wins/-/last-one-wins-1.0.4.tgz#c1bfd0cbcb46790ec9156b8d1aee8fcb86cda22a" | ||
760 | integrity sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio= | ||
761 | |||
762 | lcid@^1.0.0: | ||
763 | version "1.0.0" | ||
764 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" | ||
765 | integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= | ||
766 | dependencies: | ||
767 | invert-kv "^1.0.0" | ||
768 | |||
769 | load-ip-set@^2.1.0: | ||
770 | version "2.1.0" | ||
771 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b" | ||
772 | integrity sha512-taz7U6B+F7Zq90dfIKwqsB1CrFKelSEmMGC68OUqem8Cgd1QZygQBYb2Fk9i6muBSfH4xwF/Pjt4KKlAdOyWZw== | ||
773 | dependencies: | ||
774 | ip-set "^1.0.0" | ||
775 | netmask "^1.0.6" | ||
776 | once "^1.3.0" | ||
777 | simple-get "^3.0.0" | ||
778 | split "^1.0.0" | ||
779 | |||
780 | load-json-file@^1.0.0: | ||
781 | version "1.1.0" | ||
782 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" | ||
783 | integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= | ||
784 | dependencies: | ||
785 | graceful-fs "^4.1.2" | ||
786 | parse-json "^2.2.0" | ||
787 | pify "^2.0.0" | ||
788 | pinkie-promise "^2.0.0" | ||
789 | strip-bom "^2.0.0" | ||
790 | |||
791 | "long@~2 >=2.2.3": | ||
792 | version "2.4.0" | ||
793 | resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" | ||
794 | integrity sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8= | ||
795 | |||
796 | lru@^3.0.0, lru@^3.1.0: | ||
797 | version "3.1.0" | ||
798 | resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5" | ||
799 | integrity sha1-6n+4VG2DczOWoTCR12z+tMBoN9U= | ||
800 | dependencies: | ||
801 | inherits "^2.0.1" | ||
802 | |||
803 | magnet-uri@^5.1.3: | ||
804 | version "5.2.4" | ||
805 | resolved "https://registry.yarnpkg.com/magnet-uri/-/magnet-uri-5.2.4.tgz#7afe5b736af04445aff744c93a890a3710077688" | ||
806 | integrity sha512-VYaJMxhr8B9BrCiNINUsuhaEe40YnG+AQBwcqUKO66lSVaI9I3A1iH/6EmEwRI8OYUg5Gt+4lLE7achg676lrg== | ||
807 | dependencies: | ||
808 | thirty-two "^1.0.1" | ||
809 | uniq "^1.0.1" | ||
810 | |||
811 | mdns-js-packet@~0.2.0: | ||
812 | version "0.2.0" | ||
813 | resolved "https://registry.yarnpkg.com/mdns-js-packet/-/mdns-js-packet-0.2.0.tgz#642409e8183c7561cc60615bbd1420ec2fad7616" | ||
814 | integrity sha1-ZCQJ6Bg8dWHMYGFbvRQg7C+tdhY= | ||
815 | dependencies: | ||
816 | debug "^2.1.0" | ||
817 | qap "^3.1.2" | ||
818 | |||
819 | mdns-js@0.5.0: | ||
820 | version "0.5.0" | ||
821 | resolved "https://registry.yarnpkg.com/mdns-js/-/mdns-js-0.5.0.tgz#4c8abb6ba7cabdc892d39228c3faa2556e09cf87" | ||
822 | integrity sha1-TIq7a6fKvciS05Iow/qiVW4Jz4c= | ||
823 | dependencies: | ||
824 | debug "^2.1.1" | ||
825 | mdns-js-packet "~0.2.0" | ||
826 | semver "~5.1.0" | ||
827 | |||
828 | mediasource@^2.1.0, mediasource@^2.2.2: | ||
829 | version "2.3.0" | ||
830 | resolved "https://registry.yarnpkg.com/mediasource/-/mediasource-2.3.0.tgz#4c7b49e7ea4fb88f1cc181d8fcf0d94649271dc6" | ||
831 | integrity sha512-fqm86UwHvAnneIv40Uy1sDQaFtAByq/k0SQ3uCtbnEeSQNT1s5TDHCZOD1VmYCHwfY1jL2NjoZVwzZKYqy3L7A== | ||
832 | dependencies: | ||
833 | inherits "^2.0.1" | ||
834 | readable-stream "^3.0.0" | ||
835 | to-arraybuffer "^1.0.1" | ||
836 | |||
837 | memory-chunk-store@^1.2.0: | ||
838 | version "1.3.0" | ||
839 | resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4" | ||
840 | integrity sha512-6LsOpHKKhxYrLhHmOJdBCUtSO7op5rUs1pag0fhjHo0QiXRyna0bwYf4EmQuL7InUeF2J7dUMPr6VMogRyf9NA== | ||
841 | |||
842 | mime@^1.3.4, mime@^1.6.0: | ||
843 | version "1.6.0" | ||
844 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" | ||
845 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== | ||
846 | |||
847 | mime@^2.1.0, mime@^2.4.0: | ||
848 | version "2.4.3" | ||
849 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe" | ||
850 | integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw== | ||
851 | |||
852 | mimic-response@^1.0.0: | ||
853 | version "1.0.1" | ||
854 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" | ||
855 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== | ||
856 | |||
857 | minimatch@^3.0.4: | ||
858 | version "3.0.4" | ||
859 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" | ||
860 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== | ||
861 | dependencies: | ||
862 | brace-expansion "^1.1.7" | ||
863 | |||
864 | minimist@0.0.8: | ||
865 | version "0.0.8" | ||
866 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" | ||
867 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= | ||
868 | |||
869 | minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: | ||
870 | version "1.2.0" | ||
871 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" | ||
872 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= | ||
873 | |||
874 | minipass@^2.2.1, minipass@^2.3.4: | ||
875 | version "2.3.5" | ||
876 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" | ||
877 | integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== | ||
878 | dependencies: | ||
879 | safe-buffer "^5.1.2" | ||
880 | yallist "^3.0.0" | ||
881 | |||
882 | minizlib@^1.1.1: | ||
883 | version "1.2.1" | ||
884 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" | ||
885 | integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== | ||
886 | dependencies: | ||
887 | minipass "^2.2.1" | ||
888 | |||
889 | mkdirp@^0.5.0, mkdirp@^0.5.1: | ||
890 | version "0.5.1" | ||
891 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" | ||
892 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= | ||
893 | dependencies: | ||
894 | minimist "0.0.8" | ||
895 | |||
896 | moment@^2.12.0: | ||
897 | version "2.24.0" | ||
898 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" | ||
899 | integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== | ||
900 | |||
901 | mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0: | ||
902 | version "1.3.0" | ||
903 | resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48" | ||
904 | integrity sha512-U4pMLpjT/UzB8d36dxj6Mf1bG9xypEvgbuRIa1fztRXNKKTCAtRxsnFZhNOd7YDFOKtjBgssYGvo4H/Q3ZY1MA== | ||
905 | dependencies: | ||
906 | buffer-alloc "^1.2.0" | ||
907 | buffer-from "^1.1.0" | ||
908 | uint64be "^2.0.2" | ||
909 | |||
910 | mp4-stream@^2.0.0: | ||
911 | version "2.0.3" | ||
912 | resolved "https://registry.yarnpkg.com/mp4-stream/-/mp4-stream-2.0.3.tgz#30acee07709d323f8dcd87a07b3ce9c3c4bfb364" | ||
913 | integrity sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g== | ||
914 | dependencies: | ||
915 | buffer-alloc "^1.1.0" | ||
916 | inherits "^2.0.1" | ||
917 | mp4-box-encoding "^1.1.0" | ||
918 | next-event "^1.0.0" | ||
919 | readable-stream "^2.0.3" | ||
920 | |||
921 | ms@2.0.0: | ||
922 | version "2.0.0" | ||
923 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" | ||
924 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= | ||
925 | |||
926 | ms@^2.1.1: | ||
927 | version "2.1.1" | ||
928 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" | ||
929 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== | ||
930 | |||
931 | multicast-dns@^6.0.1: | ||
932 | version "6.2.3" | ||
933 | resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" | ||
934 | integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== | ||
935 | dependencies: | ||
936 | dns-packet "^1.3.1" | ||
937 | thunky "^1.0.2" | ||
938 | |||
939 | multistream@^2.0.2, multistream@^2.0.5: | ||
940 | version "2.1.1" | ||
941 | resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c" | ||
942 | integrity sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ== | ||
943 | dependencies: | ||
944 | inherits "^2.0.1" | ||
945 | readable-stream "^2.0.5" | ||
946 | |||
947 | nan@*, nan@^2.3.2: | ||
948 | version "2.14.0" | ||
949 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" | ||
950 | integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== | ||
951 | |||
952 | needle@^2.2.1: | ||
953 | version "2.4.0" | ||
954 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" | ||
955 | integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== | ||
956 | dependencies: | ||
957 | debug "^3.2.6" | ||
958 | iconv-lite "^0.4.4" | ||
959 | sax "^1.2.4" | ||
960 | |||
961 | netmask@^1.0.6: | ||
962 | version "1.0.6" | ||
963 | resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" | ||
964 | integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= | ||
965 | |||
966 | network-address@^1.0.0, network-address@^1.1.0: | ||
967 | version "1.1.2" | ||
968 | resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e" | ||
969 | integrity sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4= | ||
970 | |||
971 | next-event@^1.0.0: | ||
972 | version "1.0.0" | ||
973 | resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" | ||
974 | integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg= | ||
975 | |||
976 | node-cmake@2.3.2: | ||
977 | version "2.3.2" | ||
978 | resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0" | ||
979 | integrity sha1-4PvFSxFAWwdwXk1tQYZa6VrSidA= | ||
980 | dependencies: | ||
981 | nan "*" | ||
982 | which "^1.2.14" | ||
983 | yargs "^7.0.2" | ||
984 | |||
985 | node-gyp-build@~3.7.0: | ||
986 | version "3.7.0" | ||
987 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" | ||
988 | integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== | ||
989 | |||
990 | node-pre-gyp@0.11.x: | ||
991 | version "0.11.0" | ||
992 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" | ||
993 | integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== | ||
994 | dependencies: | ||
995 | detect-libc "^1.0.2" | ||
996 | mkdirp "^0.5.1" | ||
997 | needle "^2.2.1" | ||
998 | nopt "^4.0.1" | ||
999 | npm-packlist "^1.1.6" | ||
1000 | npmlog "^4.0.2" | ||
1001 | rc "^1.2.7" | ||
1002 | rimraf "^2.6.1" | ||
1003 | semver "^5.3.0" | ||
1004 | tar "^4" | ||
1005 | |||
1006 | node-ssdp@^2.2.0, node-ssdp@^2.7.1: | ||
1007 | version "2.9.1" | ||
1008 | resolved "https://registry.yarnpkg.com/node-ssdp/-/node-ssdp-2.9.1.tgz#2d6ba8e7eff9bf5b338564f91f7ac5d5cdddc55b" | ||
1009 | integrity sha1-LWuo5+/5v1szhWT5H3rF1c3dxVs= | ||
1010 | dependencies: | ||
1011 | debug "^2.2.0" | ||
1012 | ip "^1.0.1" | ||
1013 | |||
1014 | nodebmc@0.0.7: | ||
1015 | version "0.0.7" | ||
1016 | resolved "https://registry.yarnpkg.com/nodebmc/-/nodebmc-0.0.7.tgz#fae179165265509302cefbebeabd29bd4035184d" | ||
1017 | integrity sha1-+uF5FlJlUJMCzvvr6r0pvUA1GE0= | ||
1018 | dependencies: | ||
1019 | mdns-js "0.5.0" | ||
1020 | |||
1021 | nopt@^4.0.1: | ||
1022 | version "4.0.1" | ||
1023 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" | ||
1024 | integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= | ||
1025 | dependencies: | ||
1026 | abbrev "1" | ||
1027 | osenv "^0.1.4" | ||
1028 | |||
1029 | normalize-package-data@^2.3.2: | ||
1030 | version "2.5.0" | ||
1031 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" | ||
1032 | integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== | ||
1033 | dependencies: | ||
1034 | hosted-git-info "^2.1.4" | ||
1035 | resolve "^1.10.0" | ||
1036 | semver "2 || 3 || 4 || 5" | ||
1037 | validate-npm-package-license "^3.0.1" | ||
1038 | |||
1039 | npm-bundled@^1.0.1: | ||
1040 | version "1.0.6" | ||
1041 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" | ||
1042 | integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== | ||
1043 | |||
1044 | npm-packlist@^1.1.6: | ||
1045 | version "1.4.1" | ||
1046 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" | ||
1047 | integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== | ||
1048 | dependencies: | ||
1049 | ignore-walk "^3.0.1" | ||
1050 | npm-bundled "^1.0.1" | ||
1051 | |||
1052 | npmlog@^4.0.2: | ||
1053 | version "4.1.2" | ||
1054 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" | ||
1055 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== | ||
1056 | dependencies: | ||
1057 | are-we-there-yet "~1.1.2" | ||
1058 | console-control-strings "~1.1.0" | ||
1059 | gauge "~2.7.3" | ||
1060 | set-blocking "~2.0.0" | ||
1061 | |||
1062 | number-is-nan@^1.0.0: | ||
1063 | version "1.0.1" | ||
1064 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" | ||
1065 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= | ||
1066 | |||
1067 | object-assign@^4.1.0: | ||
1068 | version "4.1.1" | ||
1069 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" | ||
1070 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= | ||
1071 | |||
1072 | once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: | ||
1073 | version "1.4.0" | ||
1074 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" | ||
1075 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= | ||
1076 | dependencies: | ||
1077 | wrappy "1" | ||
1078 | |||
1079 | open@0.0.5: | ||
1080 | version "0.0.5" | ||
1081 | resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc" | ||
1082 | integrity sha1-QsPhjslUZra/DcQvOilFw/DK2Pw= | ||
1083 | |||
1084 | optjs@latest: | ||
1085 | version "3.2.2" | ||
1086 | resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee" | ||
1087 | integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4= | ||
1088 | |||
1089 | os-homedir@^1.0.0: | ||
1090 | version "1.0.2" | ||
1091 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" | ||
1092 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= | ||
1093 | |||
1094 | os-locale@^1.4.0: | ||
1095 | version "1.4.0" | ||
1096 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" | ||
1097 | integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= | ||
1098 | dependencies: | ||
1099 | lcid "^1.0.0" | ||
1100 | |||
1101 | os-tmpdir@^1.0.0: | ||
1102 | version "1.0.2" | ||
1103 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" | ||
1104 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= | ||
1105 | |||
1106 | osenv@^0.1.4: | ||
1107 | version "0.1.5" | ||
1108 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" | ||
1109 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== | ||
1110 | dependencies: | ||
1111 | os-homedir "^1.0.0" | ||
1112 | os-tmpdir "^1.0.0" | ||
1113 | |||
1114 | package-json-versionify@^1.0.2: | ||
1115 | version "1.0.4" | ||
1116 | resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17" | ||
1117 | integrity sha1-WGBYepRIc6a35tJujlH/siMVvxc= | ||
1118 | dependencies: | ||
1119 | browserify-package-json "^1.0.0" | ||
1120 | |||
1121 | parse-json@^2.2.0: | ||
1122 | version "2.2.0" | ||
1123 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" | ||
1124 | integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= | ||
1125 | dependencies: | ||
1126 | error-ex "^1.2.0" | ||
1127 | |||
1128 | parse-numeric-range@^0.0.2: | ||
1129 | version "0.0.2" | ||
1130 | resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" | ||
1131 | integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= | ||
1132 | |||
1133 | parse-torrent@^6.0.0, parse-torrent@^6.1.2: | ||
1134 | version "6.1.2" | ||
1135 | resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956" | ||
1136 | integrity sha512-Z/vig84sHwtrTEbOzisT4xnYTFlOgAaLQccPruMPgRahZUppVE/BUXzAos3jZM7c64o0lfukQdQ4ozWa5lN39w== | ||
1137 | dependencies: | ||
1138 | bencode "^2.0.0" | ||
1139 | blob-to-buffer "^1.2.6" | ||
1140 | get-stdin "^6.0.0" | ||
1141 | magnet-uri "^5.1.3" | ||
1142 | simple-get "^3.0.1" | ||
1143 | simple-sha1 "^2.0.0" | ||
1144 | uniq "^1.0.1" | ||
1145 | |||
1146 | path-exists@^2.0.0: | ||
1147 | version "2.1.0" | ||
1148 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" | ||
1149 | integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= | ||
1150 | dependencies: | ||
1151 | pinkie-promise "^2.0.0" | ||
1152 | |||
1153 | path-is-absolute@^1.0.0: | ||
1154 | version "1.0.1" | ||
1155 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" | ||
1156 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= | ||
1157 | |||
1158 | path-parse@^1.0.6: | ||
1159 | version "1.0.6" | ||
1160 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" | ||
1161 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== | ||
1162 | |||
1163 | path-type@^1.0.0: | ||
1164 | version "1.1.0" | ||
1165 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" | ||
1166 | integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= | ||
1167 | dependencies: | ||
1168 | graceful-fs "^4.1.2" | ||
1169 | pify "^2.0.0" | ||
1170 | pinkie-promise "^2.0.0" | ||
1171 | |||
1172 | piece-length@^1.0.0: | ||
1173 | version "1.0.0" | ||
1174 | resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-1.0.0.tgz#4db7167157fd69fef14caf7262cd39f189b24508" | ||
1175 | integrity sha1-TbcWcVf9af7xTK9yYs058YmyRQg= | ||
1176 | dependencies: | ||
1177 | closest-to "~2.0.0" | ||
1178 | |||
1179 | pify@^2.0.0, pify@^2.2.0: | ||
1180 | version "2.3.0" | ||
1181 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" | ||
1182 | integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= | ||
1183 | |||
1184 | pinkie-promise@^2.0.0: | ||
1185 | version "2.0.1" | ||
1186 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" | ||
1187 | integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= | ||
1188 | dependencies: | ||
1189 | pinkie "^2.0.0" | ||
1190 | |||
1191 | pinkie@^2.0.0: | ||
1192 | version "2.0.4" | ||
1193 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" | ||
1194 | integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= | ||
1195 | |||
1196 | plist-with-patches@0.5.1: | ||
1197 | version "0.5.1" | ||
1198 | resolved "https://registry.yarnpkg.com/plist-with-patches/-/plist-with-patches-0.5.1.tgz#868aae2e0df8989b026562b35cbc19cfd8bb780d" | ||
1199 | integrity sha1-hoquLg34mJsCZWKzXLwZz9i7eA0= | ||
1200 | dependencies: | ||
1201 | xmlbuilder "0.4.x" | ||
1202 | xmldom "0.1.x" | ||
1203 | |||
1204 | prettier-bytes@^1.0.3: | ||
1205 | version "1.0.4" | ||
1206 | resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.4.tgz#994b02aa46f699c50b6257b5faaa7fe2557e62d6" | ||
1207 | integrity sha1-mUsCqkb2mcULYle1+qp/4lV+YtY= | ||
1208 | |||
1209 | process-nextick-args@~2.0.0: | ||
1210 | version "2.0.0" | ||
1211 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" | ||
1212 | integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== | ||
1213 | |||
1214 | protobufjs@^3.2.2: | ||
1215 | version "3.8.2" | ||
1216 | resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-3.8.2.tgz#bc826e34c3af4697e8d0af7a669e4d612aedcd17" | ||
1217 | integrity sha1-vIJuNMOvRpfo0K96Zp5NYSrtzRc= | ||
1218 | dependencies: | ||
1219 | ascli "~0.3" | ||
1220 | bytebuffer "~3 >=3.5" | ||
1221 | |||
1222 | pump@^3.0.0: | ||
1223 | version "3.0.0" | ||
1224 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" | ||
1225 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== | ||
1226 | dependencies: | ||
1227 | end-of-stream "^1.1.0" | ||
1228 | once "^1.3.1" | ||
1229 | |||
1230 | qap@^3.1.2: | ||
1231 | version "3.3.1" | ||
1232 | resolved "https://registry.yarnpkg.com/qap/-/qap-3.3.1.tgz#11f9e8fa8890fe7cb99210c0f44d0613b7372cac" | ||
1233 | integrity sha1-Efno+oiQ/ny5khDA9E0GE7c3LKw= | ||
1234 | |||
1235 | random-access-file@^2.0.1: | ||
1236 | version "2.1.2" | ||
1237 | resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6" | ||
1238 | integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ== | ||
1239 | dependencies: | ||
1240 | mkdirp "^0.5.1" | ||
1241 | random-access-storage "^1.1.1" | ||
1242 | |||
1243 | random-access-storage@^1.1.1: | ||
1244 | version "1.3.0" | ||
1245 | resolved "https://registry.yarnpkg.com/random-access-storage/-/random-access-storage-1.3.0.tgz#d27e4d897b79dc4358afc2bbe553044e5c8cfe35" | ||
1246 | integrity sha512-pdS9Mcb9TB7oICypPRALlheaSuszuAKmLVEPKJMuYor7R/zDuHh5ALuQoS+ox31XRwQUL+tDwWH2GPdyspwelA== | ||
1247 | dependencies: | ||
1248 | inherits "^2.0.3" | ||
1249 | |||
1250 | random-iterate@^1.0.1: | ||
1251 | version "1.0.1" | ||
1252 | resolved "https://registry.yarnpkg.com/random-iterate/-/random-iterate-1.0.1.tgz#f7d97d92dee6665ec5f6da08c7f963cad4b2ac99" | ||
1253 | integrity sha1-99l9kt7mZl7F9toIx/ljytSyrJk= | ||
1254 | |||
1255 | randombytes@^2.0.3, randombytes@^2.0.5: | ||
1256 | version "2.1.0" | ||
1257 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" | ||
1258 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== | ||
1259 | dependencies: | ||
1260 | safe-buffer "^5.1.0" | ||
1261 | |||
1262 | range-parser@^1.2.0: | ||
1263 | version "1.2.1" | ||
1264 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" | ||
1265 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== | ||
1266 | |||
1267 | range-slice-stream@^2.0.0: | ||
1268 | version "2.0.0" | ||
1269 | resolved "https://registry.yarnpkg.com/range-slice-stream/-/range-slice-stream-2.0.0.tgz#1f25fc7a2cacf9ccd140c46f9cf670a1a7fe3ce6" | ||
1270 | integrity sha512-PPYLwZ63lXi6Tv2EZ8w3M4FzC0rVqvxivaOVS8pXSp5FMIHFnvi4MWHL3UdFLhwSy50aNtJsgjY0mBC6oFL26Q== | ||
1271 | dependencies: | ||
1272 | readable-stream "^3.0.2" | ||
1273 | |||
1274 | rc@^1.2.7: | ||
1275 | version "1.2.8" | ||
1276 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" | ||
1277 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== | ||
1278 | dependencies: | ||
1279 | deep-extend "^0.6.0" | ||
1280 | ini "~1.3.0" | ||
1281 | minimist "^1.2.0" | ||
1282 | strip-json-comments "~2.0.1" | ||
1283 | |||
1284 | read-pkg-up@^1.0.1: | ||
1285 | version "1.0.1" | ||
1286 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" | ||
1287 | integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= | ||
1288 | dependencies: | ||
1289 | find-up "^1.0.0" | ||
1290 | read-pkg "^1.0.0" | ||
1291 | |||
1292 | read-pkg@^1.0.0: | ||
1293 | version "1.1.0" | ||
1294 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" | ||
1295 | integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= | ||
1296 | dependencies: | ||
1297 | load-json-file "^1.0.0" | ||
1298 | normalize-package-data "^2.3.2" | ||
1299 | path-type "^1.0.0" | ||
1300 | |||
1301 | readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.2, readable-stream@^2.3.4: | ||
1302 | version "2.3.6" | ||
1303 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" | ||
1304 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== | ||
1305 | dependencies: | ||
1306 | core-util-is "~1.0.0" | ||
1307 | inherits "~2.0.3" | ||
1308 | isarray "~1.0.0" | ||
1309 | process-nextick-args "~2.0.0" | ||
1310 | safe-buffer "~5.1.1" | ||
1311 | string_decoder "~1.1.1" | ||
1312 | util-deprecate "~1.0.1" | ||
1313 | |||
1314 | readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6: | ||
1315 | version "3.3.0" | ||
1316 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" | ||
1317 | integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== | ||
1318 | dependencies: | ||
1319 | inherits "^2.0.3" | ||
1320 | string_decoder "^1.1.1" | ||
1321 | util-deprecate "^1.0.1" | ||
1322 | |||
1323 | record-cache@^1.0.2: | ||
1324 | version "1.1.0" | ||
1325 | resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037" | ||
1326 | integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q== | ||
1327 | |||
1328 | render-media@^3.0.0: | ||
1329 | version "3.1.3" | ||
1330 | resolved "https://registry.yarnpkg.com/render-media/-/render-media-3.1.3.tgz#aa8c8cd3f720049370067180709b551d3c566254" | ||
1331 | integrity sha512-K7ziKKlIcgYpAovRsABDiSaNn7TzDDyyuFGpRwM52cloNcajInB6sCxFPUEzOuTJUeyvKCqT/k5INOjpKLCjhQ== | ||
1332 | dependencies: | ||
1333 | debug "^3.1.0" | ||
1334 | is-ascii "^1.0.0" | ||
1335 | mediasource "^2.1.0" | ||
1336 | stream-to-blob-url "^2.0.0" | ||
1337 | videostream "^2.5.1" | ||
1338 | |||
1339 | require-directory@^2.1.1: | ||
1340 | version "2.1.1" | ||
1341 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" | ||
1342 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= | ||
1343 | |||
1344 | require-main-filename@^1.0.1: | ||
1345 | version "1.0.1" | ||
1346 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" | ||
1347 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= | ||
1348 | |||
1349 | resolve@^1.10.0: | ||
1350 | version "1.11.0" | ||
1351 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232" | ||
1352 | integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw== | ||
1353 | dependencies: | ||
1354 | path-parse "^1.0.6" | ||
1355 | |||
1356 | rimraf@^2.4.2, rimraf@^2.6.1: | ||
1357 | version "2.6.3" | ||
1358 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" | ||
1359 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== | ||
1360 | dependencies: | ||
1361 | glob "^7.1.3" | ||
1362 | |||
1363 | run-parallel-limit@^1.0.3: | ||
1364 | version "1.0.5" | ||
1365 | resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7" | ||
1366 | integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg== | ||
1367 | |||
1368 | run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6: | ||
1369 | version "1.1.9" | ||
1370 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" | ||
1371 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== | ||
1372 | |||
1373 | run-series@^1.0.2: | ||
1374 | version "1.1.8" | ||
1375 | resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36" | ||
1376 | integrity sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg== | ||
1377 | |||
1378 | rusha@^0.8.1: | ||
1379 | version "0.8.13" | ||
1380 | resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a" | ||
1381 | integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo= | ||
1382 | |||
1383 | safe-buffer@^5.0.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: | ||
1384 | version "5.1.2" | ||
1385 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" | ||
1386 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== | ||
1387 | |||
1388 | "safer-buffer@>= 2.1.2 < 3": | ||
1389 | version "2.1.2" | ||
1390 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" | ||
1391 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== | ||
1392 | |||
1393 | sax@1.1.4: | ||
1394 | version "1.1.4" | ||
1395 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.4.tgz#74b6d33c9ae1e001510f179a91168588f1aedaa9" | ||
1396 | integrity sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk= | ||
1397 | |||
1398 | sax@>=0.6.0, sax@^1.2.4: | ||
1399 | version "1.2.4" | ||
1400 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" | ||
1401 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== | ||
1402 | |||
1403 | "semver@2 || 3 || 4 || 5", semver@^5.3.0: | ||
1404 | version "5.7.0" | ||
1405 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" | ||
1406 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== | ||
1407 | |||
1408 | semver@~5.1.0: | ||
1409 | version "5.1.1" | ||
1410 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" | ||
1411 | integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk= | ||
1412 | |||
1413 | set-blocking@^2.0.0, set-blocking@~2.0.0: | ||
1414 | version "2.0.0" | ||
1415 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" | ||
1416 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= | ||
1417 | |||
1418 | signal-exit@^3.0.0: | ||
1419 | version "3.0.2" | ||
1420 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" | ||
1421 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= | ||
1422 | |||
1423 | simple-concat@^1.0.0: | ||
1424 | version "1.0.0" | ||
1425 | resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" | ||
1426 | integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= | ||
1427 | |||
1428 | simple-get@^2.0.0, simple-get@^2.1.0: | ||
1429 | version "2.8.1" | ||
1430 | resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" | ||
1431 | integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== | ||
1432 | dependencies: | ||
1433 | decompress-response "^3.3.0" | ||
1434 | once "^1.3.1" | ||
1435 | simple-concat "^1.0.0" | ||
1436 | |||
1437 | simple-get@^3.0.0, simple-get@^3.0.1: | ||
1438 | version "3.0.3" | ||
1439 | resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa" | ||
1440 | integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw== | ||
1441 | dependencies: | ||
1442 | decompress-response "^3.3.0" | ||
1443 | once "^1.3.1" | ||
1444 | simple-concat "^1.0.0" | ||
1445 | |||
1446 | simple-peer@^9.0.0: | ||
1447 | version "9.3.0" | ||
1448 | resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.3.0.tgz#85ecb126b23d8730f3904f199db65e84141e0f4e" | ||
1449 | integrity sha512-5dLDfrRomrS2LuZUuH2aO7yTGtHFEl5Eb+8ZzqM0KC0lHcYUyJudUomP9ZY/lPUKBx2broL/Eee9bQ53yycEgQ== | ||
1450 | dependencies: | ||
1451 | debug "^4.0.1" | ||
1452 | get-browser-rtc "^1.0.0" | ||
1453 | inherits "^2.0.1" | ||
1454 | randombytes "^2.0.3" | ||
1455 | readable-stream "^2.3.4" | ||
1456 | |||
1457 | simple-sha1@^2.0.0, simple-sha1@^2.0.8, simple-sha1@^2.1.0: | ||
1458 | version "2.1.2" | ||
1459 | resolved "https://registry.yarnpkg.com/simple-sha1/-/simple-sha1-2.1.2.tgz#de40cbd5aae278fde8e3bb3250a35d74c67326b1" | ||
1460 | integrity sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw== | ||
1461 | dependencies: | ||
1462 | rusha "^0.8.1" | ||
1463 | |||
1464 | simple-websocket@^7.0.1: | ||
1465 | version "7.2.0" | ||
1466 | resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-7.2.0.tgz#c3190555d74399372b96b51435f2d8c4b04611df" | ||
1467 | integrity sha512-wdxFg1fHw1yqFKWDcw+yNb4VIYqtl+vknZMlpLhvZSlR6l7/iVuwozqo+Qtl73mB1IH5QnXzonD1S+hAaLNTvQ== | ||
1468 | dependencies: | ||
1469 | debug "^3.1.0" | ||
1470 | inherits "^2.0.1" | ||
1471 | randombytes "^2.0.3" | ||
1472 | readable-stream "^2.0.5" | ||
1473 | ws "^6.0.0" | ||
1474 | |||
1475 | spdx-correct@^3.0.0: | ||
1476 | version "3.1.0" | ||
1477 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" | ||
1478 | integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== | ||
1479 | dependencies: | ||
1480 | spdx-expression-parse "^3.0.0" | ||
1481 | spdx-license-ids "^3.0.0" | ||
1482 | |||
1483 | spdx-exceptions@^2.1.0: | ||
1484 | version "2.2.0" | ||
1485 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" | ||
1486 | integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== | ||
1487 | |||
1488 | spdx-expression-parse@^3.0.0: | ||
1489 | version "3.0.0" | ||
1490 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" | ||
1491 | integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== | ||
1492 | dependencies: | ||
1493 | spdx-exceptions "^2.1.0" | ||
1494 | spdx-license-ids "^3.0.0" | ||
1495 | |||
1496 | spdx-license-ids@^3.0.0: | ||
1497 | version "3.0.4" | ||
1498 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" | ||
1499 | integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== | ||
1500 | |||
1501 | speedometer@^1.0.0: | ||
1502 | version "1.1.0" | ||
1503 | resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934" | ||
1504 | integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ== | ||
1505 | |||
1506 | split@^1.0.0: | ||
1507 | version "1.0.1" | ||
1508 | resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" | ||
1509 | integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== | ||
1510 | dependencies: | ||
1511 | through "2" | ||
1512 | |||
1513 | stream-to-blob-url@^2.0.0, stream-to-blob-url@^2.1.0: | ||
1514 | version "2.1.1" | ||
1515 | resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2" | ||
1516 | integrity sha512-DKJPEmCmIZoBfGVle9IhSfERiWaN5cuOtmfPxP2dZbLDRZxkBWZ4QbYxEJOSALk1Kf+WjBgedAMO6qkkf7Lmrg== | ||
1517 | dependencies: | ||
1518 | stream-to-blob "^1.0.0" | ||
1519 | |||
1520 | stream-to-blob@^1.0.0: | ||
1521 | version "1.0.1" | ||
1522 | resolved "https://registry.yarnpkg.com/stream-to-blob/-/stream-to-blob-1.0.1.tgz#2dc1e09b71677a234d00445f8eb7ff70c4fe9948" | ||
1523 | integrity sha512-aRy4neA4rf+qMtLT9fCRLPGWdrsIKtCx4kUdNTIPgPQ2hkHkdxbViVAvABMx9oRM6yCWfngHx6pwXfbYkVuPuw== | ||
1524 | dependencies: | ||
1525 | once "^1.3.3" | ||
1526 | |||
1527 | stream-with-known-length-to-buffer@^1.0.0: | ||
1528 | version "1.0.2" | ||
1529 | resolved "https://registry.yarnpkg.com/stream-with-known-length-to-buffer/-/stream-with-known-length-to-buffer-1.0.2.tgz#b8ea5a92086a1ed5d27fc4c529636682118c945b" | ||
1530 | integrity sha512-UxSISjxmguvfYzZdq6d4XAjc3gAocqTIOS1CjgwkDkkGT/LMTsIYiV8agIw42IHFFHf8k4lPOoroCCf4W9oqzg== | ||
1531 | dependencies: | ||
1532 | once "^1.3.3" | ||
1533 | |||
1534 | string-width@^1.0.1, string-width@^1.0.2: | ||
1535 | version "1.0.2" | ||
1536 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" | ||
1537 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= | ||
1538 | dependencies: | ||
1539 | code-point-at "^1.0.0" | ||
1540 | is-fullwidth-code-point "^1.0.0" | ||
1541 | strip-ansi "^3.0.0" | ||
1542 | |||
1543 | "string-width@^1.0.2 || 2": | ||
1544 | version "2.1.1" | ||
1545 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" | ||
1546 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== | ||
1547 | dependencies: | ||
1548 | is-fullwidth-code-point "^2.0.0" | ||
1549 | strip-ansi "^4.0.0" | ||
1550 | |||
1551 | string2compact@^1.1.1, string2compact@^1.2.5: | ||
1552 | version "1.3.0" | ||
1553 | resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3" | ||
1554 | integrity sha512-004ulKKANDuQilQsNxy2lisrpMG0qUJxBU+2YCEF7KziRyNR0Nredm2qk0f1V82nva59H3y9GWeHXE63HzGRFw== | ||
1555 | dependencies: | ||
1556 | addr-to-ip-port "^1.0.1" | ||
1557 | ipaddr.js "^1.0.1" | ||
1558 | |||
1559 | string_decoder@^1.1.1: | ||
1560 | version "1.2.0" | ||
1561 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" | ||
1562 | integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== | ||
1563 | dependencies: | ||
1564 | safe-buffer "~5.1.0" | ||
1565 | |||
1566 | string_decoder@~1.1.1: | ||
1567 | version "1.1.1" | ||
1568 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" | ||
1569 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== | ||
1570 | dependencies: | ||
1571 | safe-buffer "~5.1.0" | ||
1572 | |||
1573 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: | ||
1574 | version "3.0.1" | ||
1575 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" | ||
1576 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= | ||
1577 | dependencies: | ||
1578 | ansi-regex "^2.0.0" | ||
1579 | |||
1580 | strip-ansi@^4.0.0: | ||
1581 | version "4.0.0" | ||
1582 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" | ||
1583 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= | ||
1584 | dependencies: | ||
1585 | ansi-regex "^3.0.0" | ||
1586 | |||
1587 | strip-bom@^2.0.0: | ||
1588 | version "2.0.0" | ||
1589 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" | ||
1590 | integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= | ||
1591 | dependencies: | ||
1592 | is-utf8 "^0.2.0" | ||
1593 | |||
1594 | strip-json-comments@~2.0.1: | ||
1595 | version "2.0.1" | ||
1596 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" | ||
1597 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= | ||
1598 | |||
1599 | tar@^4: | ||
1600 | version "4.4.8" | ||
1601 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" | ||
1602 | integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== | ||
1603 | dependencies: | ||
1604 | chownr "^1.1.1" | ||
1605 | fs-minipass "^1.2.5" | ||
1606 | minipass "^2.3.4" | ||
1607 | minizlib "^1.1.1" | ||
1608 | mkdirp "^0.5.0" | ||
1609 | safe-buffer "^5.1.2" | ||
1610 | yallist "^3.0.2" | ||
1611 | |||
1612 | thirty-two@^1.0.1: | ||
1613 | version "1.0.2" | ||
1614 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" | ||
1615 | integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno= | ||
1616 | |||
1617 | through@2: | ||
1618 | version "2.3.8" | ||
1619 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" | ||
1620 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= | ||
1621 | |||
1622 | thunky@^0.1.0: | ||
1623 | version "0.1.0" | ||
1624 | resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" | ||
1625 | integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4= | ||
1626 | |||
1627 | thunky@^1.0.1, thunky@^1.0.2: | ||
1628 | version "1.0.3" | ||
1629 | resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" | ||
1630 | integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== | ||
1631 | |||
1632 | to-arraybuffer@^1.0.1: | ||
1633 | version "1.0.1" | ||
1634 | resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" | ||
1635 | integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= | ||
1636 | |||
1637 | torrent-discovery@^9.1.1: | ||
1638 | version "9.1.1" | ||
1639 | resolved "https://registry.yarnpkg.com/torrent-discovery/-/torrent-discovery-9.1.1.tgz#56704e6747b24fe00dbb75b442d202051f78d37d" | ||
1640 | integrity sha512-3mHf+bxVCVLrlkPJdAoMbPMY1hpTZVeWw5hNc2pPFm+HCc2DS0HgVFTBTSWtB8vQPWA1hSEZpqJ+3QfdXxDE1g== | ||
1641 | dependencies: | ||
1642 | bittorrent-dht "^9.0.0" | ||
1643 | bittorrent-tracker "^9.0.0" | ||
1644 | debug "^3.1.0" | ||
1645 | run-parallel "^1.1.2" | ||
1646 | |||
1647 | torrent-piece@^2.0.0: | ||
1648 | version "2.0.0" | ||
1649 | resolved "https://registry.yarnpkg.com/torrent-piece/-/torrent-piece-2.0.0.tgz#6598ae67d93699e887f178db267ba16d89d7ec9b" | ||
1650 | integrity sha512-H/Z/yCuvZJj1vl1IQHI8dvF2QrUuXRJoptT5DW5967/dsLpXlCg+uyhFR5lfNj5mNaYePUbKtnL+qKWZGXv4Nw== | ||
1651 | |||
1652 | typedarray-to-buffer@^3.0.0: | ||
1653 | version "3.1.5" | ||
1654 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" | ||
1655 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== | ||
1656 | dependencies: | ||
1657 | is-typedarray "^1.0.0" | ||
1658 | |||
1659 | typedarray@^0.0.6: | ||
1660 | version "0.0.6" | ||
1661 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" | ||
1662 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= | ||
1663 | |||
1664 | uint64be@^2.0.2: | ||
1665 | version "2.0.2" | ||
1666 | resolved "https://registry.yarnpkg.com/uint64be/-/uint64be-2.0.2.tgz#ef4a179752fe8f9ddaa29544ecfc13490031e8e5" | ||
1667 | integrity sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ== | ||
1668 | dependencies: | ||
1669 | buffer-alloc "^1.1.0" | ||
1670 | |||
1671 | uniq@^1.0.1: | ||
1672 | version "1.0.1" | ||
1673 | resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" | ||
1674 | integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= | ||
1675 | |||
1676 | unordered-array-remove@^1.0.2: | ||
1677 | version "1.0.2" | ||
1678 | resolved "https://registry.yarnpkg.com/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz#c546e8f88e317a0cf2644c97ecb57dba66d250ef" | ||
1679 | integrity sha1-xUbo+I4xegzyZEyX7LV9umbSUO8= | ||
1680 | |||
1681 | upnp-device-client@^1.0.0: | ||
1682 | version "1.0.2" | ||
1683 | resolved "https://registry.yarnpkg.com/upnp-device-client/-/upnp-device-client-1.0.2.tgz#91f84705f2349bf89082855fff4e3006ac435337" | ||
1684 | integrity sha1-kfhHBfI0m/iQgoVf/04wBqxDUzc= | ||
1685 | dependencies: | ||
1686 | concat-stream "^1.4.8" | ||
1687 | debug "^2.1.3" | ||
1688 | elementtree "~0.1.6" | ||
1689 | network-address "^1.0.0" | ||
1690 | |||
1691 | upnp-mediarenderer-client@^1.2.2: | ||
1692 | version "1.2.4" | ||
1693 | resolved "https://registry.yarnpkg.com/upnp-mediarenderer-client/-/upnp-mediarenderer-client-1.2.4.tgz#0c63a51802082b6b03b596c475cc64fc1e0877c8" | ||
1694 | integrity sha1-DGOlGAIIK2sDtZbEdcxk/B4Id8g= | ||
1695 | dependencies: | ||
1696 | debug "^2.1.3" | ||
1697 | elementtree "^0.1.6" | ||
1698 | upnp-device-client "^1.0.0" | ||
1699 | |||
1700 | url-join@^2.0.5: | ||
1701 | version "2.0.5" | ||
1702 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" | ||
1703 | integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= | ||
1704 | |||
1705 | ut_metadata@^3.3.0: | ||
1706 | version "3.3.0" | ||
1707 | resolved "https://registry.yarnpkg.com/ut_metadata/-/ut_metadata-3.3.0.tgz#a0e0e861ebc39ed96e506601d1463ade3b548a7e" | ||
1708 | integrity sha512-IK+ke9yL6a4oPLz/3oSW9TW7m9Wr4RG+5kW5aS2YulzEU1QDGAtago/NnOlno91fo3fSO7mnsqzn3NXNXdv8nA== | ||
1709 | dependencies: | ||
1710 | bencode "^2.0.0" | ||
1711 | bitfield "^2.0.0" | ||
1712 | debug "^3.1.0" | ||
1713 | simple-sha1 "^2.0.0" | ||
1714 | |||
1715 | ut_pex@^1.1.1: | ||
1716 | version "1.2.1" | ||
1717 | resolved "https://registry.yarnpkg.com/ut_pex/-/ut_pex-1.2.1.tgz#472ed0ea5e9bbc9148b833339d56d7b17cf3dad0" | ||
1718 | integrity sha512-ZrxMCbffYtxQDqvREN9kBXK2CB9tPnd5PylHoqQX9ai+3HV9/S39FnA5JnhLOC82dxIQQg0nTN2wmhtAdGNtOA== | ||
1719 | dependencies: | ||
1720 | bencode "^2.0.0" | ||
1721 | compact2string "^1.2.0" | ||
1722 | inherits "^2.0.1" | ||
1723 | string2compact "^1.2.5" | ||
1724 | |||
1725 | utf-8-validate@^5.0.1: | ||
1726 | version "5.0.2" | ||
1727 | resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3" | ||
1728 | integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw== | ||
1729 | dependencies: | ||
1730 | node-gyp-build "~3.7.0" | ||
1731 | |||
1732 | util-deprecate@^1.0.1, util-deprecate@~1.0.1: | ||
1733 | version "1.0.2" | ||
1734 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" | ||
1735 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= | ||
1736 | |||
1737 | validate-npm-package-license@^3.0.1: | ||
1738 | version "3.0.4" | ||
1739 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" | ||
1740 | integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== | ||
1741 | dependencies: | ||
1742 | spdx-correct "^3.0.0" | ||
1743 | spdx-expression-parse "^3.0.0" | ||
1744 | |||
1745 | videostream@^2.5.1: | ||
1746 | version "2.6.0" | ||
1747 | resolved "https://registry.yarnpkg.com/videostream/-/videostream-2.6.0.tgz#7f0b2b84bc457c12cfe599aa2345f5cc06241ab6" | ||
1748 | integrity sha512-nSsullx1BYClJxVSt4Fa+Ulsv0Cf7UwaHq+4LQdLkAUdmqNhY1DlGxXDWVY2gui5XV4FvDiSbXmSbGryMrrUCQ== | ||
1749 | dependencies: | ||
1750 | binary-search "^1.3.4" | ||
1751 | inherits "^2.0.1" | ||
1752 | mediasource "^2.2.2" | ||
1753 | mp4-box-encoding "^1.3.0" | ||
1754 | mp4-stream "^2.0.0" | ||
1755 | multistream "^2.0.2" | ||
1756 | pump "^3.0.0" | ||
1757 | range-slice-stream "^2.0.0" | ||
1758 | |||
1759 | vlc-command@^1.0.0: | ||
1760 | version "1.1.2" | ||
1761 | resolved "https://registry.yarnpkg.com/vlc-command/-/vlc-command-1.1.2.tgz#61a9b4249a0001c0bcac8cdaf36d3a8e674cffce" | ||
1762 | integrity sha512-KZ15RTHz96OEiQDA8oNFn1edYDWyKJIWI4gF74Am9woZo5XmVYryk5RYXSwOMvsaAgL5ejICEGCl0suQyDBu+Q== | ||
1763 | dependencies: | ||
1764 | run-parallel "^1.1.6" | ||
1765 | winreg "^1.2.1" | ||
1766 | |||
1767 | webidl-conversions@^4.0.2: | ||
1768 | version "4.0.2" | ||
1769 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" | ||
1770 | integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== | ||
1771 | |||
1772 | webtorrent-cli@^1.12.3: | ||
1773 | version "1.12.3" | ||
1774 | resolved "https://registry.yarnpkg.com/webtorrent-cli/-/webtorrent-cli-1.12.3.tgz#e6a1060cd3f104346da91e67763276ca897f238c" | ||
1775 | integrity sha512-NnBAGkD64CRsl9edM9q0QU+ku6nCX32nM0U+YC8Gs/36c8y+5m9Tya3mWIux3oZKZ54yGiVtnok4tUpqDE5tMA== | ||
1776 | dependencies: | ||
1777 | clivas "^0.2.0" | ||
1778 | create-torrent "^3.23.1" | ||
1779 | dlnacasts "^0.1.0" | ||
1780 | ecstatic "^3.0.0" | ||
1781 | executable "^4.0.0" | ||
1782 | mime "^2.1.0" | ||
1783 | minimist "^1.2.0" | ||
1784 | moment "^2.12.0" | ||
1785 | network-address "^1.1.0" | ||
1786 | open "0.0.5" | ||
1787 | parse-torrent "^6.0.0" | ||
1788 | prettier-bytes "^1.0.3" | ||
1789 | vlc-command "^1.0.0" | ||
1790 | webtorrent "0.x" | ||
1791 | winreg "^1.0.1" | ||
1792 | optionalDependencies: | ||
1793 | airplay-js "^0.3.0" | ||
1794 | chromecasts "^1.5.3" | ||
1795 | nodebmc "0.0.7" | ||
1796 | |||
1797 | webtorrent-hybrid@^2.1.0: | ||
1798 | version "2.1.0" | ||
1799 | resolved "https://registry.yarnpkg.com/webtorrent-hybrid/-/webtorrent-hybrid-2.1.0.tgz#c14d33d6769667d8ae524ca2d9dfdcd18d4cfbf2" | ||
1800 | integrity sha512-S8tUgUbPLwGazPrBMTqjsuxlmhaCZaiC+KlgS7ECRGaHVVZTJjKG2kUw8uf558DdZbsEA3jNxOOsMvXiA62sFw== | ||
1801 | dependencies: | ||
1802 | create-torrent "^3.33.0" | ||
1803 | webtorrent "^0.x" | ||
1804 | webtorrent-cli "^1.12.3" | ||
1805 | wrtc "^0.3.3" | ||
1806 | |||
1807 | webtorrent@0.x, webtorrent@^0.x: | ||
1808 | version "0.103.1" | ||
1809 | resolved "https://registry.yarnpkg.com/webtorrent/-/webtorrent-0.103.1.tgz#18ead369bbcaa60dc8ea138784c33451edd34479" | ||
1810 | integrity sha512-rqMD8sAaPzrUzEpA6gDEOgcN9Xyz4WGrQiHoVY6HlymLoNSkScMnmnEX1bsdMcIU9iOrnUlghDEW9sJ9jYCmwQ== | ||
1811 | dependencies: | ||
1812 | addr-to-ip-port "^1.4.2" | ||
1813 | bitfield "^2.0.0" | ||
1814 | bittorrent-dht "^9.0.0" | ||
1815 | bittorrent-protocol "^3.0.0" | ||
1816 | chunk-store-stream "^3.0.1" | ||
1817 | create-torrent "^3.33.0" | ||
1818 | debug "^4.1.0" | ||
1819 | end-of-stream "^1.1.0" | ||
1820 | fs-chunk-store "^1.6.2" | ||
1821 | immediate-chunk-store "^2.0.0" | ||
1822 | load-ip-set "^2.1.0" | ||
1823 | memory-chunk-store "^1.2.0" | ||
1824 | mime "^2.4.0" | ||
1825 | multistream "^2.0.5" | ||
1826 | package-json-versionify "^1.0.2" | ||
1827 | parse-numeric-range "^0.0.2" | ||
1828 | parse-torrent "^6.1.2" | ||
1829 | pump "^3.0.0" | ||
1830 | random-iterate "^1.0.1" | ||
1831 | randombytes "^2.0.3" | ||
1832 | range-parser "^1.2.0" | ||
1833 | readable-stream "^3.0.6" | ||
1834 | render-media "^3.0.0" | ||
1835 | run-parallel "^1.1.6" | ||
1836 | run-parallel-limit "^1.0.3" | ||
1837 | safe-buffer "^5.0.1" | ||
1838 | simple-concat "^1.0.0" | ||
1839 | simple-get "^3.0.1" | ||
1840 | simple-peer "^9.0.0" | ||
1841 | simple-sha1 "^2.0.8" | ||
1842 | speedometer "^1.0.0" | ||
1843 | stream-to-blob "^1.0.0" | ||
1844 | stream-to-blob-url "^2.1.0" | ||
1845 | stream-with-known-length-to-buffer "^1.0.0" | ||
1846 | torrent-discovery "^9.1.1" | ||
1847 | torrent-piece "^2.0.0" | ||
1848 | uniq "^1.0.1" | ||
1849 | unordered-array-remove "^1.0.2" | ||
1850 | ut_metadata "^3.3.0" | ||
1851 | ut_pex "^1.1.1" | ||
1852 | |||
1853 | which-module@^1.0.0: | ||
1854 | version "1.0.0" | ||
1855 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" | ||
1856 | integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= | ||
1857 | |||
1858 | which@^1.2.14: | ||
1859 | version "1.3.1" | ||
1860 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" | ||
1861 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== | ||
1862 | dependencies: | ||
1863 | isexe "^2.0.0" | ||
1864 | |||
1865 | wide-align@^1.1.0: | ||
1866 | version "1.1.3" | ||
1867 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" | ||
1868 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== | ||
1869 | dependencies: | ||
1870 | string-width "^1.0.2 || 2" | ||
1871 | |||
1872 | winreg@^1.0.1, winreg@^1.2.1: | ||
1873 | version "1.2.4" | ||
1874 | resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b" | ||
1875 | integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs= | ||
1876 | |||
1877 | wrap-ansi@^2.0.0: | ||
1878 | version "2.1.0" | ||
1879 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" | ||
1880 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= | ||
1881 | dependencies: | ||
1882 | string-width "^1.0.1" | ||
1883 | strip-ansi "^3.0.1" | ||
1884 | |||
1885 | wrappy@1: | ||
1886 | version "1.0.2" | ||
1887 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" | ||
1888 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= | ||
1889 | |||
1890 | wrtc@^0.3.3: | ||
1891 | version "0.3.7" | ||
1892 | resolved "https://registry.yarnpkg.com/wrtc/-/wrtc-0.3.7.tgz#2279f1cb3a83573e77b3d9b7e720071fab2ae4af" | ||
1893 | integrity sha512-mDFNFqAB+3IYVKlP15vpGD0EhXjsQlj/GLNje4KLpClLSq8pyTG0xqJFoU+Oq43XvDIUMmIJ/r1aNfrjT7KUQw== | ||
1894 | dependencies: | ||
1895 | nan "^2.3.2" | ||
1896 | node-cmake "2.3.2" | ||
1897 | node-pre-gyp "0.11.x" | ||
1898 | optionalDependencies: | ||
1899 | domexception "^1.0.1" | ||
1900 | |||
1901 | ws@^6.0.0: | ||
1902 | version "6.2.1" | ||
1903 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" | ||
1904 | integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== | ||
1905 | dependencies: | ||
1906 | async-limiter "~1.0.0" | ||
1907 | |||
1908 | xml2js@^0.4.8: | ||
1909 | version "0.4.19" | ||
1910 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" | ||
1911 | integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== | ||
1912 | dependencies: | ||
1913 | sax ">=0.6.0" | ||
1914 | xmlbuilder "~9.0.1" | ||
1915 | |||
1916 | xmlbuilder@0.4.x: | ||
1917 | version "0.4.3" | ||
1918 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58" | ||
1919 | integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg= | ||
1920 | |||
1921 | xmlbuilder@~9.0.1: | ||
1922 | version "9.0.7" | ||
1923 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" | ||
1924 | integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= | ||
1925 | |||
1926 | xmldom@0.1.x: | ||
1927 | version "0.1.27" | ||
1928 | resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" | ||
1929 | integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= | ||
1930 | |||
1931 | xtend@^4.0.0, xtend@^4.0.1: | ||
1932 | version "4.0.1" | ||
1933 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" | ||
1934 | integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= | ||
1935 | |||
1936 | y18n@^3.2.1: | ||
1937 | version "3.2.1" | ||
1938 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" | ||
1939 | integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= | ||
1940 | |||
1941 | yallist@^3.0.0, yallist@^3.0.2: | ||
1942 | version "3.0.3" | ||
1943 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" | ||
1944 | integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== | ||
1945 | |||
1946 | yargs-parser@^5.0.0: | ||
1947 | version "5.0.0" | ||
1948 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" | ||
1949 | integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= | ||
1950 | dependencies: | ||
1951 | camelcase "^3.0.0" | ||
1952 | |||
1953 | yargs@^7.0.2: | ||
1954 | version "7.1.0" | ||
1955 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" | ||
1956 | integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= | ||
1957 | dependencies: | ||
1958 | camelcase "^3.0.0" | ||
1959 | cliui "^3.2.0" | ||
1960 | decamelize "^1.1.1" | ||
1961 | get-caller-file "^1.0.1" | ||
1962 | os-locale "^1.4.0" | ||
1963 | read-pkg-up "^1.0.1" | ||
1964 | require-directory "^2.1.1" | ||
1965 | require-main-filename "^1.0.1" | ||
1966 | set-blocking "^2.0.0" | ||
1967 | string-width "^1.0.2" | ||
1968 | which-module "^1.0.0" | ||
1969 | y18n "^3.2.1" | ||
1970 | yargs-parser "^5.0.0" | ||