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