]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - shared/extra-utils/videos/videos.ts
replace numbers with typed http status codes (#3409)
[github/Chocobozzz/PeerTube.git] / shared / extra-utils / videos / videos.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
a20399c9 2
2d53be02 3import { HttpStatusCode } from '@shared/core-utils'
a20399c9 4import { expect } from 'chai'
df0b219d 5import { pathExists, readdir, readFile } from 'fs-extra'
fdbda9e3 6import * as parseTorrent from 'parse-torrent'
1d791a26 7import { extname, join } from 'path'
c5d31dba 8import * as request from 'supertest'
8eb07b01
C
9import { v4 as uuidv4 } from 'uuid'
10import validator from 'validator'
11import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants'
12import { VideoDetails, VideoPrivacy } from '../../models/videos'
ca5c612b 13import { buildAbsoluteFixturePath, buildServerDirectory, dateIsValid, immutableAssign, testImage, webtorrentAdd } from '../miscs/miscs'
8eb07b01
C
14import { makeGetRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests'
15import { waitJobs } from '../server/jobs'
16import { ServerInfo } from '../server/servers'
17import { getMyUserInformation } from '../users/users'
0e1dc3e7 18
8f0bc73d
C
19loadLanguages()
20
0e1dc3e7
C
21type VideoAttributes = {
22 name?: string
23 category?: number
24 licence?: number
9d3ef9fe 25 language?: string
0e1dc3e7 26 nsfw?: boolean
47564bbe 27 commentsEnabled?: boolean
7f2cfe3a 28 downloadEnabled?: boolean
2186386c 29 waitTranscoding?: boolean
0e1dc3e7 30 description?: string
7519127b 31 originallyPublishedAt?: string
0e1dc3e7 32 tags?: string[]
5f04dd2f 33 channelId?: number
11474c3c 34 privacy?: VideoPrivacy
0e1dc3e7 35 fixture?: string
ac81d1a0
C
36 thumbnailfile?: string
37 previewfile?: string
2baea0c7
C
38 scheduleUpdate?: {
39 updateAt: string
40 privacy?: VideoPrivacy
41 }
0e1dc3e7
C
42}
43
44function getVideoCategories (url: string) {
45 const path = '/api/v1/videos/categories'
46
eec63bbc
C
47 return makeGetRequest({
48 url,
59651eee 49 path,
2d53be02 50 statusCodeExpected: HttpStatusCode.OK_200
eec63bbc 51 })
0e1dc3e7
C
52}
53
54function getVideoLicences (url: string) {
55 const path = '/api/v1/videos/licences'
56
eec63bbc
C
57 return makeGetRequest({
58 url,
59651eee 59 path,
2d53be02 60 statusCodeExpected: HttpStatusCode.OK_200
eec63bbc 61 })
0e1dc3e7
C
62}
63
64function getVideoLanguages (url: string) {
65 const path = '/api/v1/videos/languages'
66
eec63bbc
C
67 return makeGetRequest({
68 url,
59651eee 69 path,
2d53be02 70 statusCodeExpected: HttpStatusCode.OK_200
eec63bbc 71 })
0e1dc3e7
C
72}
73
11474c3c
C
74function getVideoPrivacies (url: string) {
75 const path = '/api/v1/videos/privacies'
76
eec63bbc
C
77 return makeGetRequest({
78 url,
59651eee 79 path,
2d53be02 80 statusCodeExpected: HttpStatusCode.OK_200
eec63bbc 81 })
11474c3c
C
82}
83
2d53be02 84function getVideo (url: string, id: number | string, expectedStatus = HttpStatusCode.OK_200) {
0e1dc3e7
C
85 const path = '/api/v1/videos/' + id
86
87 return request(url)
88 .get(path)
89 .set('Accept', 'application/json')
11474c3c
C
90 .expect(expectedStatus)
91}
92
696d83fd
C
93async function getVideoIdFromUUID (url: string, uuid: string) {
94 const res = await getVideo(url, uuid)
95
96 return res.body.id
97}
98
8319d6ae
RK
99function getVideoFileMetadataUrl (url: string) {
100 return request(url)
101 .get('/')
102 .set('Accept', 'application/json')
2d53be02 103 .expect(HttpStatusCode.OK_200)
8319d6ae
RK
104 .expect('Content-Type', /json/)
105}
106
2d53be02 107function viewVideo (url: string, id: number | string, expectedStatus = HttpStatusCode.NO_CONTENT_204, xForwardedFor?: string) {
1f3e9fec
C
108 const path = '/api/v1/videos/' + id + '/views'
109
490b595a 110 const req = request(url)
1f3e9fec
C
111 .post(path)
112 .set('Accept', 'application/json')
490b595a
C
113
114 if (xForwardedFor) {
115 req.set('X-Forwarded-For', xForwardedFor)
116 }
117
118 return req.expect(expectedStatus)
1f3e9fec
C
119}
120
2d53be02 121function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = HttpStatusCode.OK_200) {
11474c3c
C
122 const path = '/api/v1/videos/' + id
123
124 return request(url)
125 .get(path)
126 .set('Authorization', 'Bearer ' + token)
127 .set('Accept', 'application/json')
128 .expect(expectedStatus)
0e1dc3e7
C
129}
130
9567011b
C
131function getVideoDescription (url: string, descriptionPath: string) {
132 return request(url)
133 .get(descriptionPath)
134 .set('Accept', 'application/json')
2d53be02 135 .expect(HttpStatusCode.OK_200)
9567011b
C
136 .expect('Content-Type', /json/)
137}
138
0e1dc3e7
C
139function getVideosList (url: string) {
140 const path = '/api/v1/videos'
141
142 return request(url)
143 .get(path)
144 .query({ sort: 'name' })
145 .set('Accept', 'application/json')
2d53be02 146 .expect(HttpStatusCode.OK_200)
0e1dc3e7
C
147 .expect('Content-Type', /json/)
148}
149
d525fc39 150function getVideosListWithToken (url: string, token: string, query: { nsfw?: boolean } = {}) {
0883b324
C
151 const path = '/api/v1/videos'
152
153 return request(url)
154 .get(path)
155 .set('Authorization', 'Bearer ' + token)
d525fc39 156 .query(immutableAssign(query, { sort: 'name' }))
0883b324
C
157 .set('Accept', 'application/json')
158 .expect(200)
159 .expect('Content-Type', /json/)
160}
161
066e94c5
C
162function getLocalVideos (url: string) {
163 const path = '/api/v1/videos'
164
165 return request(url)
166 .get(path)
167 .query({ sort: 'name', filter: 'local' })
168 .set('Accept', 'application/json')
169 .expect(200)
170 .expect('Content-Type', /json/)
171}
172
cca1e13b 173function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string, search?: string) {
11474c3c
C
174 const path = '/api/v1/users/me/videos'
175
176 const req = request(url)
177 .get(path)
178 .query({ start: start })
179 .query({ count: count })
cca1e13b 180 .query({ search: search })
11474c3c
C
181
182 if (sort) req.query({ sort })
183
184 return req.set('Accept', 'application/json')
185 .set('Authorization', 'Bearer ' + accessToken)
2d53be02 186 .expect(HttpStatusCode.OK_200)
11474c3c
C
187 .expect('Content-Type', /json/)
188}
189
d525fc39
C
190function getAccountVideos (
191 url: string,
192 accessToken: string,
193 accountName: string,
194 start: number,
195 count: number,
196 sort?: string,
197 query: { nsfw?: boolean } = {}
198) {
ad9e39fb 199 const path = '/api/v1/accounts/' + accountName + '/videos'
6b738c7a
C
200
201 return makeGetRequest({
202 url,
203 path,
d525fc39 204 query: immutableAssign(query, {
6b738c7a
C
205 start,
206 count,
207 sort
d525fc39 208 }),
6b738c7a 209 token: accessToken,
2d53be02 210 statusCodeExpected: HttpStatusCode.OK_200
6b738c7a
C
211 })
212}
213
214function getVideoChannelVideos (
215 url: string,
216 accessToken: string,
8a19bee1 217 videoChannelName: string,
6b738c7a
C
218 start: number,
219 count: number,
d525fc39
C
220 sort?: string,
221 query: { nsfw?: boolean } = {}
6b738c7a 222) {
8a19bee1 223 const path = '/api/v1/video-channels/' + videoChannelName + '/videos'
6b738c7a
C
224
225 return makeGetRequest({
226 url,
227 path,
d525fc39 228 query: immutableAssign(query, {
6b738c7a
C
229 start,
230 count,
231 sort
d525fc39 232 }),
6b738c7a 233 token: accessToken,
2d53be02 234 statusCodeExpected: HttpStatusCode.OK_200
6b738c7a
C
235 })
236}
237
418d092a
C
238function getPlaylistVideos (
239 url: string,
240 accessToken: string,
241 playlistId: number | string,
242 start: number,
243 count: number,
244 query: { nsfw?: boolean } = {}
245) {
246 const path = '/api/v1/video-playlists/' + playlistId + '/videos'
247
248 return makeGetRequest({
249 url,
250 path,
251 query: immutableAssign(query, {
252 start,
253 count
254 }),
255 token: accessToken,
2d53be02 256 statusCodeExpected: HttpStatusCode.OK_200
418d092a
C
257 })
258}
259
fe987656 260function getVideosListPagination (url: string, start: number, count: number, sort?: string, skipCount?: boolean) {
0e1dc3e7
C
261 const path = '/api/v1/videos'
262
263 const req = request(url)
264 .get(path)
265 .query({ start: start })
266 .query({ count: count })
267
268 if (sort) req.query({ sort })
fe987656 269 if (skipCount) req.query({ skipCount })
0e1dc3e7
C
270
271 return req.set('Accept', 'application/json')
2d53be02 272 .expect(HttpStatusCode.OK_200)
0e1dc3e7
C
273 .expect('Content-Type', /json/)
274}
275
276function getVideosListSort (url: string, sort: string) {
277 const path = '/api/v1/videos'
278
279 return request(url)
280 .get(path)
281 .query({ sort: sort })
282 .set('Accept', 'application/json')
2d53be02 283 .expect(HttpStatusCode.OK_200)
0e1dc3e7
C
284 .expect('Content-Type', /json/)
285}
286
d525fc39 287function getVideosWithFilters (url: string, query: { tagsAllOf: string[], categoryOneOf: number[] | number }) {
0e1dc3e7
C
288 const path = '/api/v1/videos'
289
290 return request(url)
57c36b27 291 .get(path)
d525fc39 292 .query(query)
f3aaa9a9 293 .set('Accept', 'application/json')
2d53be02 294 .expect(HttpStatusCode.OK_200)
f3aaa9a9 295 .expect('Content-Type', /json/)
0e1dc3e7
C
296}
297
2d53be02 298function removeVideo (url: string, token: string, id: number | string, expectedStatus = HttpStatusCode.NO_CONTENT_204) {
0883b324 299 const path = '/api/v1/videos'
0e1dc3e7
C
300
301 return request(url)
d525fc39 302 .delete(path + '/' + id)
0e1dc3e7 303 .set('Accept', 'application/json')
d525fc39
C
304 .set('Authorization', 'Bearer ' + token)
305 .expect(expectedStatus)
0e1dc3e7
C
306}
307
68e70a74
C
308async function removeAllVideos (server: ServerInfo) {
309 const resVideos = await getVideosList(server.url)
310
311 for (const v of resVideos.body.data) {
312 await removeVideo(server.url, server.accessToken, v.id)
313 }
314}
315
25378bc8
C
316async function checkVideoFilesWereRemoved (
317 videoUUID: string,
318 serverNumber: number,
09209296
C
319 directories = [
320 'redundancy',
321 'videos',
322 'thumbnails',
323 'torrents',
324 'previews',
325 'captions',
326 join('playlists', 'hls'),
327 join('redundancy', 'hls')
328 ]
25378bc8 329) {
25378bc8 330 for (const directory of directories) {
ca5c612b 331 const directoryPath = buildServerDirectory({ internalServerNumber: serverNumber }, directory)
f05a1c30 332
df0b219d
C
333 const directoryExists = await pathExists(directoryPath)
334 if (directoryExists === false) continue
f05a1c30 335
62689b94 336 const files = await readdir(directoryPath)
f05a1c30
C
337 for (const file of files) {
338 expect(file).to.not.contain(videoUUID)
339 }
340 }
341}
342
2d53be02 343async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = HttpStatusCode.OK_200) {
e95561cd 344 const path = '/api/v1/videos/upload'
5f04dd2f
C
345 let defaultChannelId = '1'
346
347 try {
348 const res = await getMyUserInformation(url, accessToken)
349 defaultChannelId = res.body.videoChannels[0].id
350 } catch (e) { /* empty */ }
0e1dc3e7 351
ac81d1a0
C
352 // Override default attributes
353 const attributes = Object.assign({
0e1dc3e7
C
354 name: 'my super video',
355 category: 5,
356 licence: 4,
9d3ef9fe 357 language: 'zh',
5f04dd2f 358 channelId: defaultChannelId,
0e1dc3e7 359 nsfw: true,
2186386c 360 waitTranscoding: false,
0e1dc3e7 361 description: 'my super description',
2422c46b 362 support: 'my super support text',
0e1dc3e7 363 tags: [ 'tag' ],
11474c3c 364 privacy: VideoPrivacy.PUBLIC,
47564bbe 365 commentsEnabled: true,
7f2cfe3a 366 downloadEnabled: true,
0e1dc3e7 367 fixture: 'video_short.webm'
ac81d1a0 368 }, videoAttributesArg)
0e1dc3e7
C
369
370 const req = request(url)
371 .post(path)
372 .set('Accept', 'application/json')
373 .set('Authorization', 'Bearer ' + accessToken)
374 .field('name', attributes.name)
0e1dc3e7 375 .field('nsfw', JSON.stringify(attributes.nsfw))
47564bbe 376 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
7f2cfe3a 377 .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
2186386c 378 .field('waitTranscoding', JSON.stringify(attributes.waitTranscoding))
11474c3c 379 .field('privacy', attributes.privacy.toString())
5f04dd2f 380 .field('channelId', attributes.channelId)
0e1dc3e7 381
fc8c024a
C
382 if (attributes.support !== undefined) {
383 req.field('support', attributes.support)
384 }
385
a87d467a
C
386 if (attributes.description !== undefined) {
387 req.field('description', attributes.description)
388 }
8df87ce7
C
389 if (attributes.language !== undefined) {
390 req.field('language', attributes.language.toString())
391 }
a7fea183
C
392 if (attributes.category !== undefined) {
393 req.field('category', attributes.category.toString())
394 }
395 if (attributes.licence !== undefined) {
396 req.field('licence', attributes.licence.toString())
397 }
8df87ce7 398
970ceac0
C
399 const tags = attributes.tags || []
400 for (let i = 0; i < tags.length; i++) {
2422c46b
C
401 req.field('tags[' + i + ']', attributes.tags[i])
402 }
403
ac81d1a0
C
404 if (attributes.thumbnailfile !== undefined) {
405 req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
406 }
407 if (attributes.previewfile !== undefined) {
408 req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
0e1dc3e7
C
409 }
410
2baea0c7
C
411 if (attributes.scheduleUpdate) {
412 req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt)
413
414 if (attributes.scheduleUpdate.privacy) {
415 req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy)
416 }
417 }
418
84929846
AM
419 if (attributes.originallyPublishedAt !== undefined) {
420 req.field('originallyPublishedAt', attributes.originallyPublishedAt)
421 }
422
ac81d1a0 423 return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
0e1dc3e7
C
424 .expect(specialStatus)
425}
426
2d53be02
RK
427function updateVideo (
428 url: string,
429 accessToken: string,
430 id: number | string,
431 attributes: VideoAttributes,
432 statusCodeExpected = HttpStatusCode.NO_CONTENT_204
433) {
0e1dc3e7
C
434 const path = '/api/v1/videos/' + id
435 const body = {}
436
437 if (attributes.name) body['name'] = attributes.name
438 if (attributes.category) body['category'] = attributes.category
439 if (attributes.licence) body['licence'] = attributes.licence
440 if (attributes.language) body['language'] = attributes.language
47564bbe
C
441 if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
442 if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
7f2cfe3a 443 if (attributes.downloadEnabled !== undefined) body['downloadEnabled'] = JSON.stringify(attributes.downloadEnabled)
7519127b 444 if (attributes.originallyPublishedAt !== undefined) body['originallyPublishedAt'] = attributes.originallyPublishedAt
0e1dc3e7
C
445 if (attributes.description) body['description'] = attributes.description
446 if (attributes.tags) body['tags'] = attributes.tags
11474c3c 447 if (attributes.privacy) body['privacy'] = attributes.privacy
0f320037 448 if (attributes.channelId) body['channelId'] = attributes.channelId
2baea0c7 449 if (attributes.scheduleUpdate) body['scheduleUpdate'] = attributes.scheduleUpdate
0e1dc3e7 450
ac81d1a0
C
451 // Upload request
452 if (attributes.thumbnailfile || attributes.previewfile) {
453 const attaches: any = {}
454 if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
455 if (attributes.previewfile) attaches.previewfile = attributes.previewfile
456
457 return makeUploadRequest({
458 url,
459 method: 'PUT',
460 path,
461 token: accessToken,
462 fields: body,
463 attaches,
464 statusCodeExpected
465 })
466 }
467
468 return makePutBodyRequest({
469 url,
470 path,
471 fields: body,
472 token: accessToken,
473 statusCodeExpected
474 })
0e1dc3e7
C
475}
476
2d53be02 477function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = HttpStatusCode.NO_CONTENT_204) {
0e1dc3e7
C
478 const path = '/api/v1/videos/' + id + '/rate'
479
480 return request(url)
481 .put(path)
482 .set('Accept', 'application/json')
483 .set('Authorization', 'Bearer ' + accessToken)
484 .send({ rating })
485 .expect(specialStatus)
486}
487
14d3270f 488function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
fdbda9e3 489 return new Promise<any>((res, rej) => {
14d3270f 490 const torrentName = videoUUID + '-' + resolution + '.torrent'
ca5c612b
C
491 const torrentPath = buildServerDirectory(server, join('torrents', torrentName))
492
fdbda9e3
C
493 readFile(torrentPath, (err, data) => {
494 if (err) return rej(err)
495
496 return res(parseTorrent(data))
497 })
498 })
499}
500
a20399c9
C
501async function completeVideoCheck (
502 url: string,
503 video: any,
504 attributes: {
505 name: string
506 category: number
507 licence: number
9d3ef9fe 508 language: string
a20399c9 509 nsfw: boolean
47564bbe 510 commentsEnabled: boolean
7f2cfe3a 511 downloadEnabled: boolean
a20399c9 512 description: string
53a61317 513 publishedAt?: string
2422c46b 514 support: string
a1587156 515 originallyPublishedAt?: string
b64c950a
C
516 account: {
517 name: string
518 host: string
519 }
f6eebcb3
C
520 isLocal: boolean
521 tags: string[]
522 privacy: number
523 likes?: number
524 dislikes?: number
525 duration: number
a20399c9 526 channel: {
f6eebcb3
C
527 displayName: string
528 name: string
b1f5b93e 529 description
a20399c9
C
530 isLocal: boolean
531 }
f6eebcb3 532 fixture: string
a20399c9
C
533 files: {
534 resolution: number
535 size: number
a1587156 536 }[]
ac81d1a0
C
537 thumbnailfile?: string
538 previewfile?: string
a20399c9
C
539 }
540) {
b1f5b93e
C
541 if (!attributes.likes) attributes.likes = 0
542 if (!attributes.dislikes) attributes.dislikes = 0
543
a20399c9 544 expect(video.name).to.equal(attributes.name)
09700934 545 expect(video.category.id).to.equal(attributes.category)
9d3ef9fe 546 expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Misc')
09700934 547 expect(video.licence.id).to.equal(attributes.licence)
9d3ef9fe 548 expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown')
09700934 549 expect(video.language.id).to.equal(attributes.language)
9d3ef9fe 550 expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown')
2243730c
C
551 expect(video.privacy.id).to.deep.equal(attributes.privacy)
552 expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
a20399c9
C
553 expect(video.nsfw).to.equal(attributes.nsfw)
554 expect(video.description).to.equal(attributes.description)
03e12d7c 555 expect(video.account.id).to.be.a('number')
b64c950a
C
556 expect(video.account.host).to.equal(attributes.account.host)
557 expect(video.account.name).to.equal(attributes.account.name)
f6eebcb3
C
558 expect(video.channel.displayName).to.equal(attributes.channel.displayName)
559 expect(video.channel.name).to.equal(attributes.channel.name)
b1f5b93e
C
560 expect(video.likes).to.equal(attributes.likes)
561 expect(video.dislikes).to.equal(attributes.dislikes)
a20399c9 562 expect(video.isLocal).to.equal(attributes.isLocal)
b1f5b93e 563 expect(video.duration).to.equal(attributes.duration)
a20399c9 564 expect(dateIsValid(video.createdAt)).to.be.true
c49db162 565 expect(dateIsValid(video.publishedAt)).to.be.true
a20399c9
C
566 expect(dateIsValid(video.updatedAt)).to.be.true
567
53a61317 568 if (attributes.publishedAt) {
53a61317
C
569 expect(video.publishedAt).to.equal(attributes.publishedAt)
570 }
571
7519127b
C
572 if (attributes.originallyPublishedAt) {
573 expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt)
574 } else {
575 expect(video.originallyPublishedAt).to.be.null
576 }
577
66b16caf 578 const res = await getVideo(url, video.uuid)
0f320037 579 const videoDetails: VideoDetails = res.body
a20399c9
C
580
581 expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
582 expect(videoDetails.tags).to.deep.equal(attributes.tags)
19a3b914
C
583 expect(videoDetails.account.name).to.equal(attributes.account.name)
584 expect(videoDetails.account.host).to.equal(attributes.account.host)
f6eebcb3
C
585 expect(video.channel.displayName).to.equal(attributes.channel.displayName)
586 expect(video.channel.name).to.equal(attributes.channel.name)
0f320037 587 expect(videoDetails.channel.host).to.equal(attributes.account.host)
a20399c9 588 expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
0f320037
C
589 expect(dateIsValid(videoDetails.channel.createdAt.toString())).to.be.true
590 expect(dateIsValid(videoDetails.channel.updatedAt.toString())).to.be.true
591 expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
7f2cfe3a 592 expect(videoDetails.downloadEnabled).to.equal(attributes.downloadEnabled)
a20399c9
C
593
594 for (const attributeFile of attributes.files) {
5d00a3d7 595 const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution)
a20399c9
C
596 expect(file).not.to.be.undefined
597
b1f5b93e 598 let extension = extname(attributes.fixture)
48f07b4a
C
599 // Transcoding enabled: extension will always be .mp4
600 if (attributes.files.length > 1) extension = '.mp4'
b1f5b93e 601
a20399c9 602 expect(file.magnetUri).to.have.lengthOf.above(2)
5d00a3d7
C
603 expect(file.torrentUrl).to.equal(`http://${attributes.account.host}/static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
604 expect(file.fileUrl).to.equal(`http://${attributes.account.host}/static/webseed/${videoDetails.uuid}-${file.resolution.id}${extension}`)
09700934
C
605 expect(file.resolution.id).to.equal(attributeFile.resolution)
606 expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
b1f5b93e
C
607
608 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
609 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
a1587156
C
610 expect(
611 file.size,
612 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
613 ).to.be.above(minSize).and.below(maxSize)
a20399c9 614
d7a25329 615 const torrent = await webtorrentAdd(file.magnetUri, true)
a20399c9
C
616 expect(torrent.files).to.be.an('array')
617 expect(torrent.files.length).to.equal(1)
618 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
619 }
44d4ee4f
C
620
621 await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
622
623 if (attributes.previewfile) {
624 await testImage(url, attributes.previewfile, videoDetails.previewPath)
625 }
a20399c9
C
626}
627
df0b219d
C
628async function videoUUIDToId (url: string, id: number | string) {
629 if (validator.isUUID('' + id) === false) return id
630
631 const res = await getVideo(url, id)
632 return res.body.id
633}
634
b764380a 635async function uploadVideoAndGetId (options: {
a1587156
C
636 server: ServerInfo
637 videoName: string
638 nsfw?: boolean
639 privacy?: VideoPrivacy
b764380a
C
640 token?: string
641}) {
df0b219d
C
642 const videoAttrs: any = { name: options.videoName }
643 if (options.nsfw) videoAttrs.nsfw = options.nsfw
b764380a 644 if (options.privacy) videoAttrs.privacy = options.privacy
df0b219d 645
df0b219d
C
646 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
647
648 return { id: res.body.video.id, uuid: res.body.video.uuid }
649}
650
b764380a
C
651async function getLocalIdByUUID (url: string, uuid: string) {
652 const res = await getVideo(url, uuid)
653
654 return res.body.id
655}
656
8eb07b01
C
657// serverNumber starts from 1
658async function uploadRandomVideoOnServers (servers: ServerInfo[], serverNumber: number, additionalParams: any = {}) {
659 const server = servers.find(s => s.serverNumber === serverNumber)
660 const res = await uploadRandomVideo(server, false, additionalParams)
661
662 await waitJobs(servers)
663
664 return res
665}
666
667async function uploadRandomVideo (server: ServerInfo, wait = true, additionalParams: any = {}) {
668 const prefixName = additionalParams.prefixName || ''
669 const name = prefixName + uuidv4()
670
671 const data = Object.assign({ name }, additionalParams)
672 const res = await uploadVideo(server.url, server.accessToken, data)
673
674 if (wait) await waitJobs([ server ])
675
676 return { uuid: res.body.video.uuid, name }
677}
678
0e1dc3e7
C
679// ---------------------------------------------------------------------------
680
681export {
9567011b 682 getVideoDescription,
0e1dc3e7 683 getVideoCategories,
8eb07b01 684 uploadRandomVideo,
0e1dc3e7 685 getVideoLicences,
df0b219d 686 videoUUIDToId,
11474c3c 687 getVideoPrivacies,
0e1dc3e7 688 getVideoLanguages,
11474c3c 689 getMyVideos,
6b738c7a
C
690 getAccountVideos,
691 getVideoChannelVideos,
0e1dc3e7 692 getVideo,
8319d6ae 693 getVideoFileMetadataUrl,
11474c3c 694 getVideoWithToken,
0e1dc3e7 695 getVideosList,
68e70a74 696 removeAllVideos,
0e1dc3e7
C
697 getVideosListPagination,
698 getVideosListSort,
699 removeVideo,
0883b324 700 getVideosListWithToken,
0e1dc3e7 701 uploadVideo,
d525fc39 702 getVideosWithFilters,
8eb07b01 703 uploadRandomVideoOnServers,
0e1dc3e7 704 updateVideo,
fdbda9e3 705 rateVideo,
1f3e9fec 706 viewVideo,
a20399c9 707 parseTorrentVideo,
066e94c5 708 getLocalVideos,
f05a1c30 709 completeVideoCheck,
418d092a 710 checkVideoFilesWereRemoved,
df0b219d 711 getPlaylistVideos,
b764380a 712 uploadVideoAndGetId,
696d83fd
C
713 getLocalIdByUUID,
714 getVideoIdFromUUID
0e1dc3e7 715}