]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/tests/api/videos/video-playlists.ts
Fix broken playlist api
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / video-playlists.ts
... / ...
CommitLineData
1/* tslint:disable:no-unused-expression */
2
3import * as chai from 'chai'
4import 'mocha'
5import {
6 addVideoChannel,
7 addVideoInPlaylist,
8 addVideoToBlacklist,
9 checkPlaylistFilesWereRemoved,
10 cleanupTests,
11 createUser,
12 createVideoPlaylist,
13 deleteVideoChannel,
14 deleteVideoPlaylist,
15 doubleFollow,
16 doVideosExistInMyPlaylist,
17 flushAndRunMultipleServers,
18 generateUserAccessToken,
19 getAccessToken,
20 getAccountPlaylistsList,
21 getAccountPlaylistsListWithToken,
22 getMyUserInformation,
23 getPlaylistVideos,
24 getVideoChannelPlaylistsList,
25 getVideoPlaylist,
26 getVideoPlaylistPrivacies,
27 getVideoPlaylistsList,
28 getVideoPlaylistWithToken,
29 removeUser,
30 removeVideoFromBlacklist,
31 removeVideoFromPlaylist,
32 reorderVideosPlaylist,
33 ServerInfo,
34 setAccessTokensToServers,
35 setDefaultVideoChannel,
36 testImage,
37 unfollow,
38 updateVideo,
39 updateVideoPlaylist,
40 updateVideoPlaylistElement,
41 uploadVideo,
42 uploadVideoAndGetId,
43 userLogin,
44 waitJobs
45} from '../../../../shared/extra-utils'
46import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
47import { VideoPlaylist } from '../../../../shared/models/videos/playlist/video-playlist.model'
48import { VideoPrivacy } from '../../../../shared/models/videos'
49import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
50import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
51import { User } from '../../../../shared/models/users'
52import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
53import {
54 addAccountToAccountBlocklist,
55 addAccountToServerBlocklist,
56 addServerToAccountBlocklist,
57 addServerToServerBlocklist,
58 removeAccountFromAccountBlocklist,
59 removeAccountFromServerBlocklist,
60 removeServerFromAccountBlocklist,
61 removeServerFromServerBlocklist
62} from '../../../../shared/extra-utils/users/blocklist'
63
64const expect = chai.expect
65
66async function checkPlaylistElementType (
67 servers: ServerInfo[],
68 playlistId: string,
69 type: VideoPlaylistElementType,
70 position: number,
71 name: string,
72 total: number
73) {
74 for (const server of servers) {
75 const res = await getPlaylistVideos(server.url, server.accessToken, playlistId, 0, 10)
76 expect(res.body.total).to.equal(total)
77
78 const videoElement: VideoPlaylistElement = res.body.data.find((e: VideoPlaylistElement) => e.position === position)
79 expect(videoElement.type).to.equal(type, 'On server ' + server.url)
80
81 if (type === VideoPlaylistElementType.REGULAR) {
82 expect(videoElement.video).to.not.be.null
83 expect(videoElement.video.name).to.equal(name)
84 } else {
85 expect(videoElement.video).to.be.null
86 }
87 }
88}
89
90describe('Test video playlists', function () {
91 let servers: ServerInfo[] = []
92
93 let playlistServer2Id1: number
94 let playlistServer2Id2: number
95 let playlistServer2UUID2: number
96
97 let playlistServer1Id: number
98 let playlistServer1UUID: string
99 let playlistServer1UUID2: string
100
101 let playlistElementServer1Video4: number
102 let playlistElementServer1Video5: number
103 let playlistElementNSFW: number
104
105 let nsfwVideoServer1: number
106
107 let userAccessTokenServer1: string
108
109 before(async function () {
110 this.timeout(120000)
111
112 servers = await flushAndRunMultipleServers(3, { transcoding: { enabled: false } })
113
114 // Get the access tokens
115 await setAccessTokensToServers(servers)
116 await setDefaultVideoChannel(servers)
117
118 // Server 1 and server 2 follow each other
119 await doubleFollow(servers[0], servers[1])
120 // Server 1 and server 3 follow each other
121 await doubleFollow(servers[0], servers[2])
122
123 {
124 const serverPromises: Promise<any>[][] = []
125
126 for (const server of servers) {
127 const videoPromises: Promise<any>[] = []
128
129 for (let i = 0; i < 7; i++) {
130 videoPromises.push(
131 uploadVideo(server.url, server.accessToken, { name: `video ${i} server ${server.serverNumber}`, nsfw: false })
132 .then(res => res.body.video)
133 )
134 }
135
136 serverPromises.push(videoPromises)
137 }
138
139 servers[0].videos = await Promise.all(serverPromises[0])
140 servers[1].videos = await Promise.all(serverPromises[1])
141 servers[2].videos = await Promise.all(serverPromises[2])
142 }
143
144 nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'NSFW video', nsfw: true })).id
145
146 {
147 await createUser({
148 url: servers[ 0 ].url,
149 accessToken: servers[ 0 ].accessToken,
150 username: 'user1',
151 password: 'password'
152 })
153 userAccessTokenServer1 = await getAccessToken(servers[0].url, 'user1', 'password')
154 }
155
156 await waitJobs(servers)
157 })
158
159 describe('Get default playlists', function () {
160 it('Should list video playlist privacies', async function () {
161 const res = await getVideoPlaylistPrivacies(servers[ 0 ].url)
162
163 const privacies = res.body
164 expect(Object.keys(privacies)).to.have.length.at.least(3)
165
166 expect(privacies[ 3 ]).to.equal('Private')
167 })
168
169 it('Should list watch later playlist', async function () {
170 const url = servers[ 0 ].url
171 const accessToken = servers[ 0 ].accessToken
172
173 {
174 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
175
176 expect(res.body.total).to.equal(1)
177 expect(res.body.data).to.have.lengthOf(1)
178
179 const playlist: VideoPlaylist = res.body.data[ 0 ]
180 expect(playlist.displayName).to.equal('Watch later')
181 expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER)
182 expect(playlist.type.label).to.equal('Watch later')
183 }
184
185 {
186 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.REGULAR)
187
188 expect(res.body.total).to.equal(0)
189 expect(res.body.data).to.have.lengthOf(0)
190 }
191
192 {
193 const res = await getAccountPlaylistsList(url, 'root', 0, 5)
194 expect(res.body.total).to.equal(0)
195 expect(res.body.data).to.have.lengthOf(0)
196 }
197 })
198
199 it('Should get private playlist for a classic user', async function () {
200 const token = await generateUserAccessToken(servers[ 0 ], 'toto')
201
202 const res = await getAccountPlaylistsListWithToken(servers[ 0 ].url, token, 'toto', 0, 5)
203
204 expect(res.body.total).to.equal(1)
205 expect(res.body.data).to.have.lengthOf(1)
206
207 const playlistId = res.body.data[ 0 ].id
208 await getPlaylistVideos(servers[ 0 ].url, token, playlistId, 0, 5)
209 })
210 })
211
212 describe('Create and federate playlists', function () {
213
214 it('Should create a playlist on server 1 and have the playlist on server 2 and 3', async function () {
215 this.timeout(30000)
216
217 await createVideoPlaylist({
218 url: servers[ 0 ].url,
219 token: servers[ 0 ].accessToken,
220 playlistAttrs: {
221 displayName: 'my super playlist',
222 privacy: VideoPlaylistPrivacy.PUBLIC,
223 description: 'my super description',
224 thumbnailfile: 'thumbnail.jpg',
225 videoChannelId: servers[ 0 ].videoChannel.id
226 }
227 })
228
229 await waitJobs(servers)
230
231 for (const server of servers) {
232 const res = await getVideoPlaylistsList(server.url, 0, 5)
233 expect(res.body.total).to.equal(1)
234 expect(res.body.data).to.have.lengthOf(1)
235
236 const playlistFromList = res.body.data[ 0 ] as VideoPlaylist
237
238 const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid)
239 const playlistFromGet = res2.body
240
241 for (const playlist of [ playlistFromGet, playlistFromList ]) {
242 expect(playlist.id).to.be.a('number')
243 expect(playlist.uuid).to.be.a('string')
244
245 expect(playlist.isLocal).to.equal(server.serverNumber === 1)
246
247 expect(playlist.displayName).to.equal('my super playlist')
248 expect(playlist.description).to.equal('my super description')
249 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC)
250 expect(playlist.privacy.label).to.equal('Public')
251 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
252 expect(playlist.type.label).to.equal('Regular')
253
254 expect(playlist.videosLength).to.equal(0)
255
256 expect(playlist.ownerAccount.name).to.equal('root')
257 expect(playlist.ownerAccount.displayName).to.equal('root')
258 expect(playlist.videoChannel.name).to.equal('root_channel')
259 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
260 }
261 }
262 })
263
264 it('Should create a playlist on server 2 and have the playlist on server 1 but not on server 3', async function () {
265 this.timeout(30000)
266
267 {
268 const res = await createVideoPlaylist({
269 url: servers[ 1 ].url,
270 token: servers[ 1 ].accessToken,
271 playlistAttrs: {
272 displayName: 'playlist 2',
273 privacy: VideoPlaylistPrivacy.PUBLIC,
274 videoChannelId: servers[ 1 ].videoChannel.id
275 }
276 })
277 playlistServer2Id1 = res.body.videoPlaylist.id
278 }
279
280 {
281 const res = await createVideoPlaylist({
282 url: servers[ 1 ].url,
283 token: servers[ 1 ].accessToken,
284 playlistAttrs: {
285 displayName: 'playlist 3',
286 privacy: VideoPlaylistPrivacy.PUBLIC,
287 thumbnailfile: 'thumbnail.jpg',
288 videoChannelId: servers[ 1 ].videoChannel.id
289 }
290 })
291
292 playlistServer2Id2 = res.body.videoPlaylist.id
293 playlistServer2UUID2 = res.body.videoPlaylist.uuid
294 }
295
296 for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) {
297 await addVideoInPlaylist({
298 url: servers[ 1 ].url,
299 token: servers[ 1 ].accessToken,
300 playlistId: id,
301 elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 }
302 })
303 await addVideoInPlaylist({
304 url: servers[ 1 ].url,
305 token: servers[ 1 ].accessToken,
306 playlistId: id,
307 elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id }
308 })
309 }
310
311 await waitJobs(servers)
312
313 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
314 const res = await getVideoPlaylistsList(server.url, 0, 5)
315
316 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
317 expect(playlist2).to.not.be.undefined
318 await testImage(server.url, 'thumbnail-playlist', playlist2.thumbnailPath)
319
320 const playlist3 = res.body.data.find(p => p.displayName === 'playlist 3')
321 expect(playlist3).to.not.be.undefined
322 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath)
323 }
324
325 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
326 expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined
327 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined
328 })
329
330 it('Should have the playlist on server 3 after a new follow', async function () {
331 this.timeout(30000)
332
333 // Server 2 and server 3 follow each other
334 await doubleFollow(servers[ 1 ], servers[ 2 ])
335
336 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
337
338 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
339 expect(playlist2).to.not.be.undefined
340 await testImage(servers[ 2 ].url, 'thumbnail-playlist', playlist2.thumbnailPath)
341
342 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
343 })
344 })
345
346 describe('List playlists', function () {
347 it('Should correctly list the playlists', async function () {
348 this.timeout(30000)
349
350 {
351 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt')
352
353 expect(res.body.total).to.equal(3)
354
355 const data: VideoPlaylist[] = res.body.data
356 expect(data).to.have.lengthOf(2)
357 expect(data[ 0 ].displayName).to.equal('playlist 2')
358 expect(data[ 1 ].displayName).to.equal('playlist 3')
359 }
360
361 {
362 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt')
363
364 expect(res.body.total).to.equal(3)
365
366 const data: VideoPlaylist[] = res.body.data
367 expect(data).to.have.lengthOf(2)
368 expect(data[ 0 ].displayName).to.equal('playlist 2')
369 expect(data[ 1 ].displayName).to.equal('my super playlist')
370 }
371 })
372
373 it('Should list video channel playlists', async function () {
374 this.timeout(30000)
375
376 {
377 const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt')
378
379 expect(res.body.total).to.equal(1)
380
381 const data: VideoPlaylist[] = res.body.data
382 expect(data).to.have.lengthOf(1)
383 expect(data[ 0 ].displayName).to.equal('my super playlist')
384 }
385 })
386
387 it('Should list account playlists', async function () {
388 this.timeout(30000)
389
390 {
391 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt')
392
393 expect(res.body.total).to.equal(2)
394
395 const data: VideoPlaylist[] = res.body.data
396 expect(data).to.have.lengthOf(1)
397 expect(data[ 0 ].displayName).to.equal('playlist 2')
398 }
399
400 {
401 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt')
402
403 expect(res.body.total).to.equal(2)
404
405 const data: VideoPlaylist[] = res.body.data
406 expect(data).to.have.lengthOf(1)
407 expect(data[ 0 ].displayName).to.equal('playlist 3')
408 }
409 })
410
411 it('Should not list unlisted or private playlists', async function () {
412 this.timeout(30000)
413
414 await createVideoPlaylist({
415 url: servers[ 1 ].url,
416 token: servers[ 1 ].accessToken,
417 playlistAttrs: {
418 displayName: 'playlist unlisted',
419 privacy: VideoPlaylistPrivacy.UNLISTED
420 }
421 })
422
423 await createVideoPlaylist({
424 url: servers[ 1 ].url,
425 token: servers[ 1 ].accessToken,
426 playlistAttrs: {
427 displayName: 'playlist private',
428 privacy: VideoPlaylistPrivacy.PRIVATE
429 }
430 })
431
432 await waitJobs(servers)
433
434 for (const server of servers) {
435 const results = [
436 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'),
437 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
438 ]
439
440 expect(results[ 0 ].body.total).to.equal(2)
441 expect(results[ 1 ].body.total).to.equal(3)
442
443 for (const res of results) {
444 const data: VideoPlaylist[] = res.body.data
445 expect(data).to.have.lengthOf(2)
446 expect(data[ 0 ].displayName).to.equal('playlist 3')
447 expect(data[ 1 ].displayName).to.equal('playlist 2')
448 }
449 }
450 })
451 })
452
453 describe('Update playlists', function () {
454
455 it('Should update a playlist', async function () {
456 this.timeout(30000)
457
458 await updateVideoPlaylist({
459 url: servers[1].url,
460 token: servers[1].accessToken,
461 playlistAttrs: {
462 displayName: 'playlist 3 updated',
463 description: 'description updated',
464 privacy: VideoPlaylistPrivacy.UNLISTED,
465 thumbnailfile: 'thumbnail.jpg',
466 videoChannelId: servers[1].videoChannel.id
467 },
468 playlistId: playlistServer2Id2
469 })
470
471 await waitJobs(servers)
472
473 for (const server of servers) {
474 const res = await getVideoPlaylist(server.url, playlistServer2UUID2)
475 const playlist: VideoPlaylist = res.body
476
477 expect(playlist.displayName).to.equal('playlist 3 updated')
478 expect(playlist.description).to.equal('description updated')
479
480 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED)
481 expect(playlist.privacy.label).to.equal('Unlisted')
482
483 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
484 expect(playlist.type.label).to.equal('Regular')
485
486 expect(playlist.videosLength).to.equal(2)
487
488 expect(playlist.ownerAccount.name).to.equal('root')
489 expect(playlist.ownerAccount.displayName).to.equal('root')
490 expect(playlist.videoChannel.name).to.equal('root_channel')
491 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
492 }
493 })
494 })
495
496 describe('Element timestamps', function () {
497
498 it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () {
499 this.timeout(30000)
500
501 const addVideo = (elementAttrs: any) => {
502 return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs })
503 }
504
505 const res = await createVideoPlaylist({
506 url: servers[ 0 ].url,
507 token: servers[ 0 ].accessToken,
508 playlistAttrs: {
509 displayName: 'playlist 4',
510 privacy: VideoPlaylistPrivacy.PUBLIC,
511 videoChannelId: servers[ 0 ].videoChannel.id
512 }
513 })
514
515 playlistServer1Id = res.body.videoPlaylist.id
516 playlistServer1UUID = res.body.videoPlaylist.uuid
517
518 await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 })
519 await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 })
520 await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid })
521 {
522 const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 })
523 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
524 }
525
526 {
527 const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 })
528 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
529 }
530
531 {
532 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
533 playlistElementNSFW = res.body.videoPlaylistElement.id
534 }
535
536 await waitJobs(servers)
537 })
538
539 it('Should correctly list playlist videos', async function () {
540 this.timeout(30000)
541
542 for (const server of servers) {
543 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
544
545 expect(res.body.total).to.equal(6)
546
547 const videoElements: VideoPlaylistElement[] = res.body.data
548 expect(videoElements).to.have.lengthOf(6)
549
550 expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1')
551 expect(videoElements[ 0 ].position).to.equal(1)
552 expect(videoElements[ 0 ].startTimestamp).to.equal(15)
553 expect(videoElements[ 0 ].stopTimestamp).to.equal(28)
554
555 expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3')
556 expect(videoElements[ 1 ].position).to.equal(2)
557 expect(videoElements[ 1 ].startTimestamp).to.equal(35)
558 expect(videoElements[ 1 ].stopTimestamp).to.be.null
559
560 expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3')
561 expect(videoElements[ 2 ].position).to.equal(3)
562 expect(videoElements[ 2 ].startTimestamp).to.be.null
563 expect(videoElements[ 2 ].stopTimestamp).to.be.null
564
565 expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1')
566 expect(videoElements[ 3 ].position).to.equal(4)
567 expect(videoElements[ 3 ].startTimestamp).to.be.null
568 expect(videoElements[ 3 ].stopTimestamp).to.equal(35)
569
570 expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1')
571 expect(videoElements[ 4 ].position).to.equal(5)
572 expect(videoElements[ 4 ].startTimestamp).to.equal(45)
573 expect(videoElements[ 4 ].stopTimestamp).to.equal(60)
574
575 expect(videoElements[ 5 ].video.name).to.equal('NSFW video')
576 expect(videoElements[ 5 ].position).to.equal(6)
577 expect(videoElements[ 5 ].startTimestamp).to.equal(5)
578 expect(videoElements[ 5 ].stopTimestamp).to.be.null
579
580 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
581 expect(res3.body.data).to.have.lengthOf(2)
582 }
583 })
584 })
585
586 describe('Element type', function () {
587 let groupUser1: ServerInfo[]
588 let groupWithoutToken1: ServerInfo[]
589 let group1: ServerInfo[]
590 let group2: ServerInfo[]
591
592 let video1: string
593 let video2: string
594 let video3: string
595
596 before(async function () {
597 this.timeout(30000)
598
599 groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ]
600 groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ]
601 group1 = [ servers[ 0 ] ]
602 group2 = [ servers[ 1 ], servers[ 2 ] ]
603
604 const res = await createVideoPlaylist({
605 url: servers[ 0 ].url,
606 token: userAccessTokenServer1,
607 playlistAttrs: {
608 displayName: 'playlist 56',
609 privacy: VideoPlaylistPrivacy.PUBLIC,
610 videoChannelId: servers[ 0 ].videoChannel.id
611 }
612 })
613
614 const playlistServer1Id2 = res.body.videoPlaylist.id
615 playlistServer1UUID2 = res.body.videoPlaylist.uuid
616
617 const addVideo = (elementAttrs: any) => {
618 return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
619 }
620
621 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
622 video2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 90' })).uuid
623 video3 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 91', nsfw: true })).uuid
624
625 await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 })
626 await addVideo({ videoId: video2, startTimestamp: 35 })
627 await addVideo({ videoId: video3 })
628
629 await waitJobs(servers)
630 })
631
632 it('Should update the element type if the video is private', async function () {
633 this.timeout(20000)
634
635 const name = 'video 89'
636 const position = 1
637
638 {
639 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
640 await waitJobs(servers)
641
642 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
643 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
644 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
645 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
646 }
647
648 {
649 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
650 await waitJobs(servers)
651
652 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
653 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
654 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
655 // We deleted the video, so even if we recreated it, the old entry is still deleted
656 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
657 }
658 })
659
660 it('Should update the element type if the video is blacklisted', async function () {
661 this.timeout(20000)
662
663 const name = 'video 89'
664 const position = 1
665
666 {
667 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true)
668 await waitJobs(servers)
669
670 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
671 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
672 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
673 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
674 }
675
676 {
677 await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1)
678 await waitJobs(servers)
679
680 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
681 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
682 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
683 // We deleted the video (because unfederated), so even if we recreated it, the old entry is still deleted
684 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
685 }
686 })
687
688 it('Should update the element type if the account or server of the video is blocked', async function () {
689 this.timeout(90000)
690
691 const name = 'video 90'
692 const position = 2
693
694 {
695 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
696 await waitJobs(servers)
697
698 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
699 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
700
701 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
702 await waitJobs(servers)
703
704 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
705 }
706
707 {
708 await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
709 await waitJobs(servers)
710
711 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
712 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
713
714 await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
715 await waitJobs(servers)
716
717 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
718 }
719
720 {
721 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
722 await waitJobs(servers)
723
724 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
725 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
726
727 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
728 await waitJobs(servers)
729
730 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
731 }
732
733 {
734 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
735 await waitJobs(servers)
736
737 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
738 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
739
740 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
741 await waitJobs(servers)
742
743 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
744 }
745 })
746
747 it('Should hide the video if it is NSFW', async function () {
748 const res = await getPlaylistVideos(servers[0].url, userAccessTokenServer1, playlistServer1UUID2, 0, 10, { nsfw: false })
749 expect(res.body.total).to.equal(3)
750
751 const elements: VideoPlaylistElement[] = res.body.data
752 const element = elements.find(e => e.position === 3)
753
754 expect(element).to.exist
755 expect(element.video).to.be.null
756 expect(element.type).to.equal(VideoPlaylistElementType.UNAVAILABLE)
757 })
758
759 })
760
761 describe('Managing playlist elements', function () {
762
763 it('Should reorder the playlist', async function () {
764 this.timeout(30000)
765
766 {
767 await reorderVideosPlaylist({
768 url: servers[ 0 ].url,
769 token: servers[ 0 ].accessToken,
770 playlistId: playlistServer1Id,
771 elementAttrs: {
772 startPosition: 2,
773 insertAfterPosition: 3
774 }
775 })
776
777 await waitJobs(servers)
778
779 for (const server of servers) {
780 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
781 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
782
783 expect(names).to.deep.equal([
784 'video 0 server 1',
785 'video 2 server 3',
786 'video 1 server 3',
787 'video 3 server 1',
788 'video 4 server 1',
789 'NSFW video'
790 ])
791 }
792 }
793
794 {
795 await reorderVideosPlaylist({
796 url: servers[ 0 ].url,
797 token: servers[ 0 ].accessToken,
798 playlistId: playlistServer1Id,
799 elementAttrs: {
800 startPosition: 1,
801 reorderLength: 3,
802 insertAfterPosition: 4
803 }
804 })
805
806 await waitJobs(servers)
807
808 for (const server of servers) {
809 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
810 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
811
812 expect(names).to.deep.equal([
813 'video 3 server 1',
814 'video 0 server 1',
815 'video 2 server 3',
816 'video 1 server 3',
817 'video 4 server 1',
818 'NSFW video'
819 ])
820 }
821 }
822
823 {
824 await reorderVideosPlaylist({
825 url: servers[ 0 ].url,
826 token: servers[ 0 ].accessToken,
827 playlistId: playlistServer1Id,
828 elementAttrs: {
829 startPosition: 6,
830 insertAfterPosition: 3
831 }
832 })
833
834 await waitJobs(servers)
835
836 for (const server of servers) {
837 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
838 const elements: VideoPlaylistElement[] = res.body.data
839 const names = elements.map(v => v.video.name)
840
841 expect(names).to.deep.equal([
842 'video 3 server 1',
843 'video 0 server 1',
844 'video 2 server 3',
845 'NSFW video',
846 'video 1 server 3',
847 'video 4 server 1'
848 ])
849
850 for (let i = 1; i <= elements.length; i++) {
851 expect(elements[ i - 1 ].position).to.equal(i)
852 }
853 }
854 }
855 })
856
857 it('Should update startTimestamp/endTimestamp of some elements', async function () {
858 this.timeout(30000)
859
860 await updateVideoPlaylistElement({
861 url: servers[ 0 ].url,
862 token: servers[ 0 ].accessToken,
863 playlistId: playlistServer1Id,
864 playlistElementId: playlistElementServer1Video4,
865 elementAttrs: {
866 startTimestamp: 1
867 }
868 })
869
870 await updateVideoPlaylistElement({
871 url: servers[ 0 ].url,
872 token: servers[ 0 ].accessToken,
873 playlistId: playlistServer1Id,
874 playlistElementId: playlistElementServer1Video5,
875 elementAttrs: {
876 stopTimestamp: null
877 }
878 })
879
880 await waitJobs(servers)
881
882 for (const server of servers) {
883 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
884 const elements: VideoPlaylistElement[] = res.body.data
885
886 expect(elements[ 0 ].video.name).to.equal('video 3 server 1')
887 expect(elements[ 0 ].position).to.equal(1)
888 expect(elements[ 0 ].startTimestamp).to.equal(1)
889 expect(elements[ 0 ].stopTimestamp).to.equal(35)
890
891 expect(elements[ 5 ].video.name).to.equal('video 4 server 1')
892 expect(elements[ 5 ].position).to.equal(6)
893 expect(elements[ 5 ].startTimestamp).to.equal(45)
894 expect(elements[ 5 ].stopTimestamp).to.be.null
895 }
896 })
897
898 it('Should check videos existence in my playlist', async function () {
899 const videoIds = [
900 servers[ 0 ].videos[ 0 ].id,
901 42000,
902 servers[ 0 ].videos[ 3 ].id,
903 43000,
904 servers[ 0 ].videos[ 4 ].id
905 ]
906 const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds)
907 const obj = res.body as VideoExistInPlaylist
908
909 {
910 const elem = obj[ servers[ 0 ].videos[ 0 ].id ]
911 expect(elem).to.have.lengthOf(1)
912 expect(elem[ 0 ].playlistElementId).to.exist
913 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
914 expect(elem[ 0 ].startTimestamp).to.equal(15)
915 expect(elem[ 0 ].stopTimestamp).to.equal(28)
916 }
917
918 {
919 const elem = obj[ servers[ 0 ].videos[ 3 ].id ]
920 expect(elem).to.have.lengthOf(1)
921 expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4)
922 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
923 expect(elem[ 0 ].startTimestamp).to.equal(1)
924 expect(elem[ 0 ].stopTimestamp).to.equal(35)
925 }
926
927 {
928 const elem = obj[ servers[ 0 ].videos[ 4 ].id ]
929 expect(elem).to.have.lengthOf(1)
930 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
931 expect(elem[ 0 ].startTimestamp).to.equal(45)
932 expect(elem[ 0 ].stopTimestamp).to.equal(null)
933 }
934
935 expect(obj[ 42000 ]).to.have.lengthOf(0)
936 expect(obj[ 43000 ]).to.have.lengthOf(0)
937 })
938
939 it('Should automatically update updatedAt field of playlists', async function () {
940 const server = servers[ 1 ]
941 const videoId = servers[ 1 ].videos[ 5 ].id
942
943 async function getPlaylistNames () {
944 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
945
946 return (res.body.data as VideoPlaylist[]).map(p => p.displayName)
947 }
948
949 const elementAttrs = { videoId }
950 const res1 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id1, elementAttrs })
951 const res2 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id2, elementAttrs })
952
953 const element1 = res1.body.videoPlaylistElement.id
954 const element2 = res2.body.videoPlaylistElement.id
955
956 const names1 = await getPlaylistNames()
957 expect(names1[ 0 ]).to.equal('playlist 3 updated')
958 expect(names1[ 1 ]).to.equal('playlist 2')
959
960 await removeVideoFromPlaylist({
961 url: server.url,
962 token: server.accessToken,
963 playlistId: playlistServer2Id1,
964 playlistElementId: element1
965 })
966
967 const names2 = await getPlaylistNames()
968 expect(names2[ 0 ]).to.equal('playlist 2')
969 expect(names2[ 1 ]).to.equal('playlist 3 updated')
970
971 await removeVideoFromPlaylist({
972 url: server.url,
973 token: server.accessToken,
974 playlistId: playlistServer2Id2,
975 playlistElementId: element2
976 })
977
978 const names3 = await getPlaylistNames()
979 expect(names3[ 0 ]).to.equal('playlist 3 updated')
980 expect(names3[ 1 ]).to.equal('playlist 2')
981 })
982
983 it('Should delete some elements', async function () {
984 this.timeout(30000)
985
986 await removeVideoFromPlaylist({
987 url: servers[ 0 ].url,
988 token: servers[ 0 ].accessToken,
989 playlistId: playlistServer1Id,
990 playlistElementId: playlistElementServer1Video4
991 })
992
993 await removeVideoFromPlaylist({
994 url: servers[ 0 ].url,
995 token: servers[ 0 ].accessToken,
996 playlistId: playlistServer1Id,
997 playlistElementId: playlistElementNSFW
998 })
999
1000 await waitJobs(servers)
1001
1002 for (const server of servers) {
1003 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1004
1005 expect(res.body.total).to.equal(4)
1006
1007 const elements: VideoPlaylistElement[] = res.body.data
1008 expect(elements).to.have.lengthOf(4)
1009
1010 expect(elements[ 0 ].video.name).to.equal('video 0 server 1')
1011 expect(elements[ 0 ].position).to.equal(1)
1012
1013 expect(elements[ 1 ].video.name).to.equal('video 2 server 3')
1014 expect(elements[ 1 ].position).to.equal(2)
1015
1016 expect(elements[ 2 ].video.name).to.equal('video 1 server 3')
1017 expect(elements[ 2 ].position).to.equal(3)
1018
1019 expect(elements[ 3 ].video.name).to.equal('video 4 server 1')
1020 expect(elements[ 3 ].position).to.equal(4)
1021 }
1022 })
1023
1024 it('Should be able to create a public playlist, and set it to private', async function () {
1025 this.timeout(30000)
1026
1027 const res = await createVideoPlaylist({
1028 url: servers[ 0 ].url,
1029 token: servers[ 0 ].accessToken,
1030 playlistAttrs: {
1031 displayName: 'my super public playlist',
1032 privacy: VideoPlaylistPrivacy.PUBLIC,
1033 videoChannelId: servers[ 0 ].videoChannel.id
1034 }
1035 })
1036 const videoPlaylistIds = res.body.videoPlaylist
1037
1038 await waitJobs(servers)
1039
1040 for (const server of servers) {
1041 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
1042 }
1043
1044 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1045 await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1046
1047 await waitJobs(servers)
1048
1049 for (const server of [ servers[ 1 ], servers[ 2 ] ]) {
1050 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
1051 }
1052 await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401)
1053
1054 await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200)
1055 })
1056 })
1057
1058 describe('Playlist deletion', function () {
1059
1060 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1061 this.timeout(30000)
1062
1063 await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id)
1064
1065 await waitJobs(servers)
1066
1067 for (const server of servers) {
1068 await getVideoPlaylist(server.url, playlistServer1UUID, 404)
1069 }
1070 })
1071
1072 it('Should have deleted the thumbnail on server 1, 2 and 3', async function () {
1073 this.timeout(30000)
1074
1075 for (const server of servers) {
1076 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
1077 }
1078 })
1079
1080 it('Should unfollow servers 1 and 2 and hide their playlists', async function () {
1081 this.timeout(30000)
1082
1083 const finder = data => data.find(p => p.displayName === 'my super playlist')
1084
1085 {
1086 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
1087 expect(res.body.total).to.equal(3)
1088 expect(finder(res.body.data)).to.not.be.undefined
1089 }
1090
1091 await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ])
1092
1093 {
1094 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
1095 expect(res.body.total).to.equal(1)
1096
1097 expect(finder(res.body.data)).to.be.undefined
1098 }
1099 })
1100
1101 it('Should delete a channel and put the associated playlist in private mode', async function () {
1102 this.timeout(30000)
1103
1104 const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' })
1105 const videoChannelId = res.body.videoChannel.id
1106
1107 const res2 = await createVideoPlaylist({
1108 url: servers[ 0 ].url,
1109 token: servers[ 0 ].accessToken,
1110 playlistAttrs: {
1111 displayName: 'channel playlist',
1112 privacy: VideoPlaylistPrivacy.PUBLIC,
1113 videoChannelId
1114 }
1115 })
1116 const videoPlaylistUUID = res2.body.videoPlaylist.uuid
1117
1118 await waitJobs(servers)
1119
1120 await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel')
1121
1122 await waitJobs(servers)
1123
1124 const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID)
1125 expect(res3.body.displayName).to.equal('channel playlist')
1126 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
1127
1128 await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404)
1129 })
1130
1131 it('Should delete an account and delete its playlists', async function () {
1132 this.timeout(30000)
1133
1134 const user = { username: 'user_1', password: 'password' }
1135 const res = await createUser({
1136 url: servers[ 0 ].url,
1137 accessToken: servers[ 0 ].accessToken,
1138 username: user.username,
1139 password: user.password
1140 })
1141
1142 const userId = res.body.user.id
1143 const userAccessToken = await userLogin(servers[ 0 ], user)
1144
1145 const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken)
1146 const userChannel = (resChannel.body as User).videoChannels[ 0 ]
1147
1148 await createVideoPlaylist({
1149 url: servers[ 0 ].url,
1150 token: userAccessToken,
1151 playlistAttrs: {
1152 displayName: 'playlist to be deleted',
1153 privacy: VideoPlaylistPrivacy.PUBLIC,
1154 videoChannelId: userChannel.id
1155 }
1156 })
1157
1158 await waitJobs(servers)
1159
1160 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
1161
1162 {
1163 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
1164 const res = await getVideoPlaylistsList(server.url, 0, 15)
1165 expect(finder(res.body.data)).to.not.be.undefined
1166 }
1167 }
1168
1169 await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken)
1170 await waitJobs(servers)
1171
1172 {
1173 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
1174 const res = await getVideoPlaylistsList(server.url, 0, 15)
1175 expect(finder(res.body.data)).to.be.undefined
1176 }
1177 }
1178 })
1179 })
1180
1181 after(async function () {
1182 await cleanupTests(servers)
1183 })
1184})