]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - shared/extra-utils/videos/videos.ts
Fix separate SQL query for video get
[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'
90a8bd30 14import { makeGetRequest, makePutBodyRequest, makeRawRequest, makeUploadRequest } from '../requests/requests'
8eb07b01
C
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 157 .set('Accept', 'application/json')
f2eb23cd 158 .expect(HttpStatusCode.OK_200)
0883b324
C
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')
f2eb23cd 169 .expect(HttpStatusCode.OK_200)
066e94c5
C
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,
37024082
RK
197 query: {
198 nsfw?: boolean
199 search?: string
200 } = {}
d525fc39 201) {
ad9e39fb 202 const path = '/api/v1/accounts/' + accountName + '/videos'
6b738c7a
C
203
204 return makeGetRequest({
205 url,
206 path,
d525fc39 207 query: immutableAssign(query, {
6b738c7a
C
208 start,
209 count,
210 sort
d525fc39 211 }),
6b738c7a 212 token: accessToken,
2d53be02 213 statusCodeExpected: HttpStatusCode.OK_200
6b738c7a
C
214 })
215}
216
217function getVideoChannelVideos (
218 url: string,
219 accessToken: string,
8a19bee1 220 videoChannelName: string,
6b738c7a
C
221 start: number,
222 count: number,
d525fc39
C
223 sort?: string,
224 query: { nsfw?: boolean } = {}
6b738c7a 225) {
8a19bee1 226 const path = '/api/v1/video-channels/' + videoChannelName + '/videos'
6b738c7a
C
227
228 return makeGetRequest({
229 url,
230 path,
d525fc39 231 query: immutableAssign(query, {
6b738c7a
C
232 start,
233 count,
234 sort
d525fc39 235 }),
6b738c7a 236 token: accessToken,
2d53be02 237 statusCodeExpected: HttpStatusCode.OK_200
6b738c7a
C
238 })
239}
240
418d092a
C
241function getPlaylistVideos (
242 url: string,
243 accessToken: string,
244 playlistId: number | string,
245 start: number,
246 count: number,
247 query: { nsfw?: boolean } = {}
248) {
249 const path = '/api/v1/video-playlists/' + playlistId + '/videos'
250
251 return makeGetRequest({
252 url,
253 path,
254 query: immutableAssign(query, {
255 start,
256 count
257 }),
258 token: accessToken,
2d53be02 259 statusCodeExpected: HttpStatusCode.OK_200
418d092a
C
260 })
261}
262
fe987656 263function getVideosListPagination (url: string, start: number, count: number, sort?: string, skipCount?: boolean) {
0e1dc3e7
C
264 const path = '/api/v1/videos'
265
266 const req = request(url)
267 .get(path)
268 .query({ start: start })
269 .query({ count: count })
270
271 if (sort) req.query({ sort })
fe987656 272 if (skipCount) req.query({ skipCount })
0e1dc3e7
C
273
274 return req.set('Accept', 'application/json')
2d53be02 275 .expect(HttpStatusCode.OK_200)
0e1dc3e7
C
276 .expect('Content-Type', /json/)
277}
278
279function getVideosListSort (url: string, sort: string) {
280 const path = '/api/v1/videos'
281
282 return request(url)
283 .get(path)
284 .query({ sort: sort })
285 .set('Accept', 'application/json')
2d53be02 286 .expect(HttpStatusCode.OK_200)
0e1dc3e7
C
287 .expect('Content-Type', /json/)
288}
289
d525fc39 290function getVideosWithFilters (url: string, query: { tagsAllOf: string[], categoryOneOf: number[] | number }) {
0e1dc3e7
C
291 const path = '/api/v1/videos'
292
293 return request(url)
57c36b27 294 .get(path)
d525fc39 295 .query(query)
f3aaa9a9 296 .set('Accept', 'application/json')
2d53be02 297 .expect(HttpStatusCode.OK_200)
f3aaa9a9 298 .expect('Content-Type', /json/)
0e1dc3e7
C
299}
300
2d53be02 301function removeVideo (url: string, token: string, id: number | string, expectedStatus = HttpStatusCode.NO_CONTENT_204) {
0883b324 302 const path = '/api/v1/videos'
0e1dc3e7
C
303
304 return request(url)
d525fc39 305 .delete(path + '/' + id)
0e1dc3e7 306 .set('Accept', 'application/json')
d525fc39
C
307 .set('Authorization', 'Bearer ' + token)
308 .expect(expectedStatus)
0e1dc3e7
C
309}
310
68e70a74
C
311async function removeAllVideos (server: ServerInfo) {
312 const resVideos = await getVideosList(server.url)
313
314 for (const v of resVideos.body.data) {
315 await removeVideo(server.url, server.accessToken, v.id)
316 }
317}
318
25378bc8
C
319async function checkVideoFilesWereRemoved (
320 videoUUID: string,
321 serverNumber: number,
09209296
C
322 directories = [
323 'redundancy',
324 'videos',
325 'thumbnails',
326 'torrents',
327 'previews',
328 'captions',
329 join('playlists', 'hls'),
330 join('redundancy', 'hls')
331 ]
25378bc8 332) {
25378bc8 333 for (const directory of directories) {
ca5c612b 334 const directoryPath = buildServerDirectory({ internalServerNumber: serverNumber }, directory)
f05a1c30 335
df0b219d
C
336 const directoryExists = await pathExists(directoryPath)
337 if (directoryExists === false) continue
f05a1c30 338
62689b94 339 const files = await readdir(directoryPath)
f05a1c30 340 for (const file of files) {
7448551f 341 expect(file, `File ${file} should not exist in ${directoryPath}`).to.not.contain(videoUUID)
f05a1c30
C
342 }
343 }
344}
345
2d53be02 346async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = HttpStatusCode.OK_200) {
e95561cd 347 const path = '/api/v1/videos/upload'
5f04dd2f
C
348 let defaultChannelId = '1'
349
350 try {
351 const res = await getMyUserInformation(url, accessToken)
352 defaultChannelId = res.body.videoChannels[0].id
353 } catch (e) { /* empty */ }
0e1dc3e7 354
ac81d1a0
C
355 // Override default attributes
356 const attributes = Object.assign({
0e1dc3e7
C
357 name: 'my super video',
358 category: 5,
359 licence: 4,
9d3ef9fe 360 language: 'zh',
5f04dd2f 361 channelId: defaultChannelId,
0e1dc3e7 362 nsfw: true,
2186386c 363 waitTranscoding: false,
0e1dc3e7 364 description: 'my super description',
2422c46b 365 support: 'my super support text',
0e1dc3e7 366 tags: [ 'tag' ],
11474c3c 367 privacy: VideoPrivacy.PUBLIC,
47564bbe 368 commentsEnabled: true,
7f2cfe3a 369 downloadEnabled: true,
0e1dc3e7 370 fixture: 'video_short.webm'
ac81d1a0 371 }, videoAttributesArg)
0e1dc3e7
C
372
373 const req = request(url)
374 .post(path)
375 .set('Accept', 'application/json')
376 .set('Authorization', 'Bearer ' + accessToken)
377 .field('name', attributes.name)
0e1dc3e7 378 .field('nsfw', JSON.stringify(attributes.nsfw))
47564bbe 379 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
7f2cfe3a 380 .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
2186386c 381 .field('waitTranscoding', JSON.stringify(attributes.waitTranscoding))
11474c3c 382 .field('privacy', attributes.privacy.toString())
5f04dd2f 383 .field('channelId', attributes.channelId)
0e1dc3e7 384
fc8c024a
C
385 if (attributes.support !== undefined) {
386 req.field('support', attributes.support)
387 }
388
a87d467a
C
389 if (attributes.description !== undefined) {
390 req.field('description', attributes.description)
391 }
8df87ce7
C
392 if (attributes.language !== undefined) {
393 req.field('language', attributes.language.toString())
394 }
a7fea183
C
395 if (attributes.category !== undefined) {
396 req.field('category', attributes.category.toString())
397 }
398 if (attributes.licence !== undefined) {
399 req.field('licence', attributes.licence.toString())
400 }
8df87ce7 401
970ceac0
C
402 const tags = attributes.tags || []
403 for (let i = 0; i < tags.length; i++) {
2422c46b
C
404 req.field('tags[' + i + ']', attributes.tags[i])
405 }
406
ac81d1a0
C
407 if (attributes.thumbnailfile !== undefined) {
408 req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
409 }
410 if (attributes.previewfile !== undefined) {
411 req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
0e1dc3e7
C
412 }
413
2baea0c7
C
414 if (attributes.scheduleUpdate) {
415 req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt)
416
417 if (attributes.scheduleUpdate.privacy) {
418 req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy)
419 }
420 }
421
84929846
AM
422 if (attributes.originallyPublishedAt !== undefined) {
423 req.field('originallyPublishedAt', attributes.originallyPublishedAt)
424 }
425
ac81d1a0 426 return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
0e1dc3e7
C
427 .expect(specialStatus)
428}
429
2d53be02
RK
430function updateVideo (
431 url: string,
432 accessToken: string,
433 id: number | string,
434 attributes: VideoAttributes,
435 statusCodeExpected = HttpStatusCode.NO_CONTENT_204
436) {
0e1dc3e7
C
437 const path = '/api/v1/videos/' + id
438 const body = {}
439
440 if (attributes.name) body['name'] = attributes.name
441 if (attributes.category) body['category'] = attributes.category
442 if (attributes.licence) body['licence'] = attributes.licence
443 if (attributes.language) body['language'] = attributes.language
47564bbe
C
444 if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
445 if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
7f2cfe3a 446 if (attributes.downloadEnabled !== undefined) body['downloadEnabled'] = JSON.stringify(attributes.downloadEnabled)
7519127b 447 if (attributes.originallyPublishedAt !== undefined) body['originallyPublishedAt'] = attributes.originallyPublishedAt
0e1dc3e7
C
448 if (attributes.description) body['description'] = attributes.description
449 if (attributes.tags) body['tags'] = attributes.tags
11474c3c 450 if (attributes.privacy) body['privacy'] = attributes.privacy
0f320037 451 if (attributes.channelId) body['channelId'] = attributes.channelId
2baea0c7 452 if (attributes.scheduleUpdate) body['scheduleUpdate'] = attributes.scheduleUpdate
0e1dc3e7 453
ac81d1a0
C
454 // Upload request
455 if (attributes.thumbnailfile || attributes.previewfile) {
456 const attaches: any = {}
457 if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
458 if (attributes.previewfile) attaches.previewfile = attributes.previewfile
459
460 return makeUploadRequest({
461 url,
462 method: 'PUT',
463 path,
464 token: accessToken,
465 fields: body,
466 attaches,
467 statusCodeExpected
468 })
469 }
470
471 return makePutBodyRequest({
472 url,
473 path,
474 fields: body,
475 token: accessToken,
476 statusCodeExpected
477 })
0e1dc3e7
C
478}
479
2d53be02 480function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = HttpStatusCode.NO_CONTENT_204) {
0e1dc3e7
C
481 const path = '/api/v1/videos/' + id + '/rate'
482
483 return request(url)
484 .put(path)
485 .set('Accept', 'application/json')
486 .set('Authorization', 'Bearer ' + accessToken)
487 .send({ rating })
488 .expect(specialStatus)
489}
490
14d3270f 491function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
fdbda9e3 492 return new Promise<any>((res, rej) => {
14d3270f 493 const torrentName = videoUUID + '-' + resolution + '.torrent'
ca5c612b
C
494 const torrentPath = buildServerDirectory(server, join('torrents', torrentName))
495
fdbda9e3
C
496 readFile(torrentPath, (err, data) => {
497 if (err) return rej(err)
498
499 return res(parseTorrent(data))
500 })
501 })
502}
503
a20399c9
C
504async function completeVideoCheck (
505 url: string,
506 video: any,
507 attributes: {
508 name: string
509 category: number
510 licence: number
9d3ef9fe 511 language: string
a20399c9 512 nsfw: boolean
47564bbe 513 commentsEnabled: boolean
7f2cfe3a 514 downloadEnabled: boolean
a20399c9 515 description: string
53a61317 516 publishedAt?: string
2422c46b 517 support: string
a1587156 518 originallyPublishedAt?: string
b64c950a
C
519 account: {
520 name: string
521 host: string
522 }
f6eebcb3
C
523 isLocal: boolean
524 tags: string[]
525 privacy: number
526 likes?: number
527 dislikes?: number
528 duration: number
a20399c9 529 channel: {
f6eebcb3
C
530 displayName: string
531 name: string
b1f5b93e 532 description
a20399c9
C
533 isLocal: boolean
534 }
f6eebcb3 535 fixture: string
a20399c9
C
536 files: {
537 resolution: number
538 size: number
a1587156 539 }[]
ac81d1a0
C
540 thumbnailfile?: string
541 previewfile?: string
a20399c9
C
542 }
543) {
b1f5b93e
C
544 if (!attributes.likes) attributes.likes = 0
545 if (!attributes.dislikes) attributes.dislikes = 0
546
90a8bd30
C
547 const host = new URL(url).host
548 const originHost = attributes.account.host
549
a20399c9 550 expect(video.name).to.equal(attributes.name)
09700934 551 expect(video.category.id).to.equal(attributes.category)
9d3ef9fe 552 expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Misc')
09700934 553 expect(video.licence.id).to.equal(attributes.licence)
9d3ef9fe 554 expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown')
09700934 555 expect(video.language.id).to.equal(attributes.language)
9d3ef9fe 556 expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown')
2243730c
C
557 expect(video.privacy.id).to.deep.equal(attributes.privacy)
558 expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
a20399c9
C
559 expect(video.nsfw).to.equal(attributes.nsfw)
560 expect(video.description).to.equal(attributes.description)
03e12d7c 561 expect(video.account.id).to.be.a('number')
b64c950a
C
562 expect(video.account.host).to.equal(attributes.account.host)
563 expect(video.account.name).to.equal(attributes.account.name)
f6eebcb3
C
564 expect(video.channel.displayName).to.equal(attributes.channel.displayName)
565 expect(video.channel.name).to.equal(attributes.channel.name)
b1f5b93e
C
566 expect(video.likes).to.equal(attributes.likes)
567 expect(video.dislikes).to.equal(attributes.dislikes)
a20399c9 568 expect(video.isLocal).to.equal(attributes.isLocal)
b1f5b93e 569 expect(video.duration).to.equal(attributes.duration)
a20399c9 570 expect(dateIsValid(video.createdAt)).to.be.true
c49db162 571 expect(dateIsValid(video.publishedAt)).to.be.true
a20399c9
C
572 expect(dateIsValid(video.updatedAt)).to.be.true
573
53a61317 574 if (attributes.publishedAt) {
53a61317
C
575 expect(video.publishedAt).to.equal(attributes.publishedAt)
576 }
577
7519127b
C
578 if (attributes.originallyPublishedAt) {
579 expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt)
580 } else {
581 expect(video.originallyPublishedAt).to.be.null
582 }
583
66b16caf 584 const res = await getVideo(url, video.uuid)
0f320037 585 const videoDetails: VideoDetails = res.body
a20399c9
C
586
587 expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
588 expect(videoDetails.tags).to.deep.equal(attributes.tags)
19a3b914
C
589 expect(videoDetails.account.name).to.equal(attributes.account.name)
590 expect(videoDetails.account.host).to.equal(attributes.account.host)
f6eebcb3
C
591 expect(video.channel.displayName).to.equal(attributes.channel.displayName)
592 expect(video.channel.name).to.equal(attributes.channel.name)
0f320037 593 expect(videoDetails.channel.host).to.equal(attributes.account.host)
a20399c9 594 expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
0f320037
C
595 expect(dateIsValid(videoDetails.channel.createdAt.toString())).to.be.true
596 expect(dateIsValid(videoDetails.channel.updatedAt.toString())).to.be.true
597 expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
7f2cfe3a 598 expect(videoDetails.downloadEnabled).to.equal(attributes.downloadEnabled)
a20399c9
C
599
600 for (const attributeFile of attributes.files) {
5d00a3d7 601 const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution)
a20399c9
C
602 expect(file).not.to.be.undefined
603
b1f5b93e 604 let extension = extname(attributes.fixture)
48f07b4a
C
605 // Transcoding enabled: extension will always be .mp4
606 if (attributes.files.length > 1) extension = '.mp4'
b1f5b93e 607
a20399c9 608 expect(file.magnetUri).to.have.lengthOf.above(2)
90a8bd30
C
609
610 expect(file.torrentDownloadUrl).to.equal(`http://${host}/download/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
611 expect(file.torrentUrl).to.equal(`http://${host}/lazy-static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
612
613 expect(file.fileUrl).to.equal(`http://${originHost}/static/webseed/${videoDetails.uuid}-${file.resolution.id}${extension}`)
614 expect(file.fileDownloadUrl).to.equal(`http://${originHost}/download/videos/${videoDetails.uuid}-${file.resolution.id}${extension}`)
615
616 await Promise.all([
617 makeRawRequest(file.torrentUrl, 200),
618 makeRawRequest(file.torrentDownloadUrl, 200),
619 makeRawRequest(file.metadataUrl, 200),
620 // Backward compatibility
621 makeRawRequest(`http://${originHost}/static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`, 200)
622 ])
623
09700934
C
624 expect(file.resolution.id).to.equal(attributeFile.resolution)
625 expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
b1f5b93e
C
626
627 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
628 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
a1587156
C
629 expect(
630 file.size,
631 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
632 ).to.be.above(minSize).and.below(maxSize)
a20399c9 633
d7a25329 634 const torrent = await webtorrentAdd(file.magnetUri, true)
a20399c9
C
635 expect(torrent.files).to.be.an('array')
636 expect(torrent.files.length).to.equal(1)
637 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
638 }
44d4ee4f
C
639
640 await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
641
642 if (attributes.previewfile) {
643 await testImage(url, attributes.previewfile, videoDetails.previewPath)
644 }
a20399c9
C
645}
646
df0b219d
C
647async function videoUUIDToId (url: string, id: number | string) {
648 if (validator.isUUID('' + id) === false) return id
649
650 const res = await getVideo(url, id)
651 return res.body.id
652}
653
b764380a 654async function uploadVideoAndGetId (options: {
a1587156
C
655 server: ServerInfo
656 videoName: string
657 nsfw?: boolean
658 privacy?: VideoPrivacy
b764380a 659 token?: string
a8537c62 660 fixture?: string
b764380a 661}) {
df0b219d
C
662 const videoAttrs: any = { name: options.videoName }
663 if (options.nsfw) videoAttrs.nsfw = options.nsfw
b764380a 664 if (options.privacy) videoAttrs.privacy = options.privacy
a8537c62 665 if (options.fixture) videoAttrs.fixture = options.fixture
df0b219d 666
df0b219d
C
667 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
668
669 return { id: res.body.video.id, uuid: res.body.video.uuid }
670}
671
b764380a
C
672async function getLocalIdByUUID (url: string, uuid: string) {
673 const res = await getVideo(url, uuid)
674
675 return res.body.id
676}
677
8eb07b01
C
678// serverNumber starts from 1
679async function uploadRandomVideoOnServers (servers: ServerInfo[], serverNumber: number, additionalParams: any = {}) {
680 const server = servers.find(s => s.serverNumber === serverNumber)
681 const res = await uploadRandomVideo(server, false, additionalParams)
682
683 await waitJobs(servers)
684
685 return res
686}
687
688async function uploadRandomVideo (server: ServerInfo, wait = true, additionalParams: any = {}) {
689 const prefixName = additionalParams.prefixName || ''
690 const name = prefixName + uuidv4()
691
692 const data = Object.assign({ name }, additionalParams)
693 const res = await uploadVideo(server.url, server.accessToken, data)
694
695 if (wait) await waitJobs([ server ])
696
697 return { uuid: res.body.video.uuid, name }
698}
699
0e1dc3e7
C
700// ---------------------------------------------------------------------------
701
702export {
9567011b 703 getVideoDescription,
0e1dc3e7 704 getVideoCategories,
8eb07b01 705 uploadRandomVideo,
0e1dc3e7 706 getVideoLicences,
df0b219d 707 videoUUIDToId,
11474c3c 708 getVideoPrivacies,
0e1dc3e7 709 getVideoLanguages,
11474c3c 710 getMyVideos,
6b738c7a
C
711 getAccountVideos,
712 getVideoChannelVideos,
0e1dc3e7 713 getVideo,
8319d6ae 714 getVideoFileMetadataUrl,
11474c3c 715 getVideoWithToken,
0e1dc3e7 716 getVideosList,
68e70a74 717 removeAllVideos,
0e1dc3e7
C
718 getVideosListPagination,
719 getVideosListSort,
720 removeVideo,
0883b324 721 getVideosListWithToken,
0e1dc3e7 722 uploadVideo,
d525fc39 723 getVideosWithFilters,
8eb07b01 724 uploadRandomVideoOnServers,
0e1dc3e7 725 updateVideo,
fdbda9e3 726 rateVideo,
1f3e9fec 727 viewVideo,
a20399c9 728 parseTorrentVideo,
066e94c5 729 getLocalVideos,
f05a1c30 730 completeVideoCheck,
418d092a 731 checkVideoFilesWereRemoved,
df0b219d 732 getPlaylistVideos,
b764380a 733 uploadVideoAndGetId,
696d83fd
C
734 getLocalIdByUUID,
735 getVideoIdFromUUID
0e1dc3e7 736}