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