]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/videos/video-playlists.ts
Hide video abuses from muted accounts
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / video-playlists.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import 'mocha'
5 import {
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'
46 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
47 import { VideoPlaylist } from '../../../../shared/models/videos/playlist/video-playlist.model'
48 import { VideoPrivacy } from '../../../../shared/models/videos'
49 import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
50 import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
51 import { User } from '../../../../shared/models/users'
52 import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
53 import {
54 addAccountToAccountBlocklist,
55 addAccountToServerBlocklist,
56 addServerToAccountBlocklist,
57 addServerToServerBlocklist,
58 removeAccountFromAccountBlocklist,
59 removeAccountFromServerBlocklist,
60 removeServerFromAccountBlocklist,
61 removeServerFromServerBlocklist
62 } from '../../../../shared/extra-utils/users/blocklist'
63
64 const expect = chai.expect
65
66 async 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
90 describe('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
348 it('Should correctly list the playlists', async function () {
349 this.timeout(30000)
350
351 {
352 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt')
353
354 expect(res.body.total).to.equal(3)
355
356 const data: VideoPlaylist[] = res.body.data
357 expect(data).to.have.lengthOf(2)
358 expect(data[ 0 ].displayName).to.equal('playlist 2')
359 expect(data[ 1 ].displayName).to.equal('playlist 3')
360 }
361
362 {
363 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt')
364
365 expect(res.body.total).to.equal(3)
366
367 const data: VideoPlaylist[] = res.body.data
368 expect(data).to.have.lengthOf(2)
369 expect(data[ 0 ].displayName).to.equal('playlist 2')
370 expect(data[ 1 ].displayName).to.equal('my super playlist')
371 }
372 })
373
374 it('Should list video channel playlists', async function () {
375 this.timeout(30000)
376
377 {
378 const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt')
379
380 expect(res.body.total).to.equal(1)
381
382 const data: VideoPlaylist[] = res.body.data
383 expect(data).to.have.lengthOf(1)
384 expect(data[ 0 ].displayName).to.equal('my super playlist')
385 }
386 })
387
388 it('Should list account playlists', async function () {
389 this.timeout(30000)
390
391 {
392 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt')
393
394 expect(res.body.total).to.equal(2)
395
396 const data: VideoPlaylist[] = res.body.data
397 expect(data).to.have.lengthOf(1)
398 expect(data[ 0 ].displayName).to.equal('playlist 2')
399 }
400
401 {
402 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt')
403
404 expect(res.body.total).to.equal(2)
405
406 const data: VideoPlaylist[] = res.body.data
407 expect(data).to.have.lengthOf(1)
408 expect(data[ 0 ].displayName).to.equal('playlist 3')
409 }
410 })
411
412 it('Should not list unlisted or private playlists', async function () {
413 this.timeout(30000)
414
415 await createVideoPlaylist({
416 url: servers[ 1 ].url,
417 token: servers[ 1 ].accessToken,
418 playlistAttrs: {
419 displayName: 'playlist unlisted',
420 privacy: VideoPlaylistPrivacy.UNLISTED
421 }
422 })
423
424 await createVideoPlaylist({
425 url: servers[ 1 ].url,
426 token: servers[ 1 ].accessToken,
427 playlistAttrs: {
428 displayName: 'playlist private',
429 privacy: VideoPlaylistPrivacy.PRIVATE
430 }
431 })
432
433 await waitJobs(servers)
434
435 for (const server of servers) {
436 const results = [
437 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'),
438 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
439 ]
440
441 expect(results[ 0 ].body.total).to.equal(2)
442 expect(results[ 1 ].body.total).to.equal(3)
443
444 for (const res of results) {
445 const data: VideoPlaylist[] = res.body.data
446 expect(data).to.have.lengthOf(2)
447 expect(data[ 0 ].displayName).to.equal('playlist 3')
448 expect(data[ 1 ].displayName).to.equal('playlist 2')
449 }
450 }
451 })
452 })
453
454 describe('Update playlists', function () {
455
456 it('Should update a playlist', async function () {
457 this.timeout(30000)
458
459 await updateVideoPlaylist({
460 url: servers[1].url,
461 token: servers[1].accessToken,
462 playlistAttrs: {
463 displayName: 'playlist 3 updated',
464 description: 'description updated',
465 privacy: VideoPlaylistPrivacy.UNLISTED,
466 thumbnailfile: 'thumbnail.jpg',
467 videoChannelId: servers[1].videoChannel.id
468 },
469 playlistId: playlistServer2Id2
470 })
471
472 await waitJobs(servers)
473
474 for (const server of servers) {
475 const res = await getVideoPlaylist(server.url, playlistServer2UUID2)
476 const playlist: VideoPlaylist = res.body
477
478 expect(playlist.displayName).to.equal('playlist 3 updated')
479 expect(playlist.description).to.equal('description updated')
480
481 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED)
482 expect(playlist.privacy.label).to.equal('Unlisted')
483
484 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
485 expect(playlist.type.label).to.equal('Regular')
486
487 expect(playlist.videosLength).to.equal(2)
488
489 expect(playlist.ownerAccount.name).to.equal('root')
490 expect(playlist.ownerAccount.displayName).to.equal('root')
491 expect(playlist.videoChannel.name).to.equal('root_channel')
492 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
493 }
494 })
495 })
496
497 describe('Element timestamps', function () {
498
499 it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () {
500 this.timeout(30000)
501
502 const addVideo = (elementAttrs: any) => {
503 return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs })
504 }
505
506 const res = await createVideoPlaylist({
507 url: servers[ 0 ].url,
508 token: servers[ 0 ].accessToken,
509 playlistAttrs: {
510 displayName: 'playlist 4',
511 privacy: VideoPlaylistPrivacy.PUBLIC,
512 videoChannelId: servers[ 0 ].videoChannel.id
513 }
514 })
515
516 playlistServer1Id = res.body.videoPlaylist.id
517 playlistServer1UUID = res.body.videoPlaylist.uuid
518
519 await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 })
520 await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 })
521 await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid })
522 {
523 const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 })
524 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
525 }
526
527 {
528 const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 })
529 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
530 }
531
532 {
533 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
534 playlistElementNSFW = res.body.videoPlaylistElement.id
535 }
536
537 await waitJobs(servers)
538 })
539
540 it('Should correctly list playlist videos', async function () {
541 this.timeout(30000)
542
543 for (const server of servers) {
544 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
545
546 expect(res.body.total).to.equal(6)
547
548 const videoElements: VideoPlaylistElement[] = res.body.data
549 expect(videoElements).to.have.lengthOf(6)
550
551 expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1')
552 expect(videoElements[ 0 ].position).to.equal(1)
553 expect(videoElements[ 0 ].startTimestamp).to.equal(15)
554 expect(videoElements[ 0 ].stopTimestamp).to.equal(28)
555
556 expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3')
557 expect(videoElements[ 1 ].position).to.equal(2)
558 expect(videoElements[ 1 ].startTimestamp).to.equal(35)
559 expect(videoElements[ 1 ].stopTimestamp).to.be.null
560
561 expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3')
562 expect(videoElements[ 2 ].position).to.equal(3)
563 expect(videoElements[ 2 ].startTimestamp).to.be.null
564 expect(videoElements[ 2 ].stopTimestamp).to.be.null
565
566 expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1')
567 expect(videoElements[ 3 ].position).to.equal(4)
568 expect(videoElements[ 3 ].startTimestamp).to.be.null
569 expect(videoElements[ 3 ].stopTimestamp).to.equal(35)
570
571 expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1')
572 expect(videoElements[ 4 ].position).to.equal(5)
573 expect(videoElements[ 4 ].startTimestamp).to.equal(45)
574 expect(videoElements[ 4 ].stopTimestamp).to.equal(60)
575
576 expect(videoElements[ 5 ].video.name).to.equal('NSFW video')
577 expect(videoElements[ 5 ].position).to.equal(6)
578 expect(videoElements[ 5 ].startTimestamp).to.equal(5)
579 expect(videoElements[ 5 ].stopTimestamp).to.be.null
580
581 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
582 expect(res3.body.data).to.have.lengthOf(2)
583 }
584 })
585 })
586
587 describe('Element type', function () {
588 let groupUser1: ServerInfo[]
589 let groupWithoutToken1: ServerInfo[]
590 let group1: ServerInfo[]
591 let group2: ServerInfo[]
592
593 let video1: string
594 let video2: string
595 let video3: string
596
597 before(async function () {
598 this.timeout(30000)
599
600 groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ]
601 groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ]
602 group1 = [ servers[ 0 ] ]
603 group2 = [ servers[ 1 ], servers[ 2 ] ]
604
605 const res = await createVideoPlaylist({
606 url: servers[ 0 ].url,
607 token: userAccessTokenServer1,
608 playlistAttrs: {
609 displayName: 'playlist 56',
610 privacy: VideoPlaylistPrivacy.PUBLIC,
611 videoChannelId: servers[ 0 ].videoChannel.id
612 }
613 })
614
615 const playlistServer1Id2 = res.body.videoPlaylist.id
616 playlistServer1UUID2 = res.body.videoPlaylist.uuid
617
618 const addVideo = (elementAttrs: any) => {
619 return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
620 }
621
622 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
623 video2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 90' })).uuid
624 video3 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 91', nsfw: true })).uuid
625
626 await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 })
627 await addVideo({ videoId: video2, startTimestamp: 35 })
628 await addVideo({ videoId: video3 })
629
630 await waitJobs(servers)
631 })
632
633 it('Should update the element type if the video is private', async function () {
634 this.timeout(20000)
635
636 const name = 'video 89'
637 const position = 1
638
639 {
640 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
641 await waitJobs(servers)
642
643 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
644 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
645 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
646 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
647 }
648
649 {
650 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
651 await waitJobs(servers)
652
653 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
654 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
655 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
656 // We deleted the video, so even if we recreated it, the old entry is still deleted
657 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
658 }
659 })
660
661 it('Should update the element type if the video is blacklisted', async function () {
662 this.timeout(20000)
663
664 const name = 'video 89'
665 const position = 1
666
667 {
668 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true)
669 await waitJobs(servers)
670
671 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
672 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
673 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
674 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
675 }
676
677 {
678 await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1)
679 await waitJobs(servers)
680
681 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
682 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
683 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
684 // We deleted the video (because unfederated), so even if we recreated it, the old entry is still deleted
685 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
686 }
687 })
688
689 it('Should update the element type if the account or server of the video is blocked', async function () {
690 this.timeout(90000)
691
692 const name = 'video 90'
693 const position = 2
694
695 {
696 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
697 await waitJobs(servers)
698
699 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
700 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
701
702 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
703 await waitJobs(servers)
704
705 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
706 }
707
708 {
709 await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
710 await waitJobs(servers)
711
712 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
713 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
714
715 await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
716 await waitJobs(servers)
717
718 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
719 }
720
721 {
722 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
723 await waitJobs(servers)
724
725 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
726 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
727
728 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
729 await waitJobs(servers)
730
731 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
732 }
733
734 {
735 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
736 await waitJobs(servers)
737
738 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
739 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
740
741 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
742 await waitJobs(servers)
743
744 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
745 }
746 })
747
748 it('Should hide the video if it is NSFW', async function () {
749 const res = await getPlaylistVideos(servers[0].url, userAccessTokenServer1, playlistServer1UUID2, 0, 10, { nsfw: false })
750 expect(res.body.total).to.equal(3)
751
752 const elements: VideoPlaylistElement[] = res.body.data
753 const element = elements.find(e => e.position === 3)
754
755 expect(element).to.exist
756 expect(element.video).to.be.null
757 expect(element.type).to.equal(VideoPlaylistElementType.UNAVAILABLE)
758 })
759
760 })
761
762 describe('Managing playlist elements', function () {
763
764 it('Should reorder the playlist', async function () {
765 this.timeout(30000)
766
767 {
768 await reorderVideosPlaylist({
769 url: servers[ 0 ].url,
770 token: servers[ 0 ].accessToken,
771 playlistId: playlistServer1Id,
772 elementAttrs: {
773 startPosition: 2,
774 insertAfterPosition: 3
775 }
776 })
777
778 await waitJobs(servers)
779
780 for (const server of servers) {
781 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
782 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
783
784 expect(names).to.deep.equal([
785 'video 0 server 1',
786 'video 2 server 3',
787 'video 1 server 3',
788 'video 3 server 1',
789 'video 4 server 1',
790 'NSFW video'
791 ])
792 }
793 }
794
795 {
796 await reorderVideosPlaylist({
797 url: servers[ 0 ].url,
798 token: servers[ 0 ].accessToken,
799 playlistId: playlistServer1Id,
800 elementAttrs: {
801 startPosition: 1,
802 reorderLength: 3,
803 insertAfterPosition: 4
804 }
805 })
806
807 await waitJobs(servers)
808
809 for (const server of servers) {
810 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
811 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
812
813 expect(names).to.deep.equal([
814 'video 3 server 1',
815 'video 0 server 1',
816 'video 2 server 3',
817 'video 1 server 3',
818 'video 4 server 1',
819 'NSFW video'
820 ])
821 }
822 }
823
824 {
825 await reorderVideosPlaylist({
826 url: servers[ 0 ].url,
827 token: servers[ 0 ].accessToken,
828 playlistId: playlistServer1Id,
829 elementAttrs: {
830 startPosition: 6,
831 insertAfterPosition: 3
832 }
833 })
834
835 await waitJobs(servers)
836
837 for (const server of servers) {
838 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
839 const elements: VideoPlaylistElement[] = res.body.data
840 const names = elements.map(v => v.video.name)
841
842 expect(names).to.deep.equal([
843 'video 3 server 1',
844 'video 0 server 1',
845 'video 2 server 3',
846 'NSFW video',
847 'video 1 server 3',
848 'video 4 server 1'
849 ])
850
851 for (let i = 1; i <= elements.length; i++) {
852 expect(elements[ i - 1 ].position).to.equal(i)
853 }
854 }
855 }
856 })
857
858 it('Should update startTimestamp/endTimestamp of some elements', async function () {
859 this.timeout(30000)
860
861 await updateVideoPlaylistElement({
862 url: servers[ 0 ].url,
863 token: servers[ 0 ].accessToken,
864 playlistId: playlistServer1Id,
865 playlistElementId: playlistElementServer1Video4,
866 elementAttrs: {
867 startTimestamp: 1
868 }
869 })
870
871 await updateVideoPlaylistElement({
872 url: servers[ 0 ].url,
873 token: servers[ 0 ].accessToken,
874 playlistId: playlistServer1Id,
875 playlistElementId: playlistElementServer1Video5,
876 elementAttrs: {
877 stopTimestamp: null
878 }
879 })
880
881 await waitJobs(servers)
882
883 for (const server of servers) {
884 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
885 const elements: VideoPlaylistElement[] = res.body.data
886
887 expect(elements[ 0 ].video.name).to.equal('video 3 server 1')
888 expect(elements[ 0 ].position).to.equal(1)
889 expect(elements[ 0 ].startTimestamp).to.equal(1)
890 expect(elements[ 0 ].stopTimestamp).to.equal(35)
891
892 expect(elements[ 5 ].video.name).to.equal('video 4 server 1')
893 expect(elements[ 5 ].position).to.equal(6)
894 expect(elements[ 5 ].startTimestamp).to.equal(45)
895 expect(elements[ 5 ].stopTimestamp).to.be.null
896 }
897 })
898
899 it('Should check videos existence in my playlist', async function () {
900 const videoIds = [
901 servers[ 0 ].videos[ 0 ].id,
902 42000,
903 servers[ 0 ].videos[ 3 ].id,
904 43000,
905 servers[ 0 ].videos[ 4 ].id
906 ]
907 const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds)
908 const obj = res.body as VideoExistInPlaylist
909
910 {
911 const elem = obj[ servers[ 0 ].videos[ 0 ].id ]
912 expect(elem).to.have.lengthOf(1)
913 expect(elem[ 0 ].playlistElementId).to.exist
914 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
915 expect(elem[ 0 ].startTimestamp).to.equal(15)
916 expect(elem[ 0 ].stopTimestamp).to.equal(28)
917 }
918
919 {
920 const elem = obj[ servers[ 0 ].videos[ 3 ].id ]
921 expect(elem).to.have.lengthOf(1)
922 expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4)
923 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
924 expect(elem[ 0 ].startTimestamp).to.equal(1)
925 expect(elem[ 0 ].stopTimestamp).to.equal(35)
926 }
927
928 {
929 const elem = obj[ servers[ 0 ].videos[ 4 ].id ]
930 expect(elem).to.have.lengthOf(1)
931 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
932 expect(elem[ 0 ].startTimestamp).to.equal(45)
933 expect(elem[ 0 ].stopTimestamp).to.equal(null)
934 }
935
936 expect(obj[ 42000 ]).to.have.lengthOf(0)
937 expect(obj[ 43000 ]).to.have.lengthOf(0)
938 })
939
940 it('Should automatically update updatedAt field of playlists', async function () {
941 const server = servers[ 1 ]
942 const videoId = servers[ 1 ].videos[ 5 ].id
943
944 async function getPlaylistNames () {
945 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
946
947 return (res.body.data as VideoPlaylist[]).map(p => p.displayName)
948 }
949
950 const elementAttrs = { videoId }
951 const res1 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id1, elementAttrs })
952 const res2 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id2, elementAttrs })
953
954 const element1 = res1.body.videoPlaylistElement.id
955 const element2 = res2.body.videoPlaylistElement.id
956
957 const names1 = await getPlaylistNames()
958 expect(names1[ 0 ]).to.equal('playlist 3 updated')
959 expect(names1[ 1 ]).to.equal('playlist 2')
960
961 await removeVideoFromPlaylist({
962 url: server.url,
963 token: server.accessToken,
964 playlistId: playlistServer2Id1,
965 playlistElementId: element1
966 })
967
968 const names2 = await getPlaylistNames()
969 expect(names2[ 0 ]).to.equal('playlist 2')
970 expect(names2[ 1 ]).to.equal('playlist 3 updated')
971
972 await removeVideoFromPlaylist({
973 url: server.url,
974 token: server.accessToken,
975 playlistId: playlistServer2Id2,
976 playlistElementId: element2
977 })
978
979 const names3 = await getPlaylistNames()
980 expect(names3[ 0 ]).to.equal('playlist 3 updated')
981 expect(names3[ 1 ]).to.equal('playlist 2')
982 })
983
984 it('Should delete some elements', async function () {
985 this.timeout(30000)
986
987 await removeVideoFromPlaylist({
988 url: servers[ 0 ].url,
989 token: servers[ 0 ].accessToken,
990 playlistId: playlistServer1Id,
991 playlistElementId: playlistElementServer1Video4
992 })
993
994 await removeVideoFromPlaylist({
995 url: servers[ 0 ].url,
996 token: servers[ 0 ].accessToken,
997 playlistId: playlistServer1Id,
998 playlistElementId: playlistElementNSFW
999 })
1000
1001 await waitJobs(servers)
1002
1003 for (const server of servers) {
1004 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1005
1006 expect(res.body.total).to.equal(4)
1007
1008 const elements: VideoPlaylistElement[] = res.body.data
1009 expect(elements).to.have.lengthOf(4)
1010
1011 expect(elements[ 0 ].video.name).to.equal('video 0 server 1')
1012 expect(elements[ 0 ].position).to.equal(1)
1013
1014 expect(elements[ 1 ].video.name).to.equal('video 2 server 3')
1015 expect(elements[ 1 ].position).to.equal(2)
1016
1017 expect(elements[ 2 ].video.name).to.equal('video 1 server 3')
1018 expect(elements[ 2 ].position).to.equal(3)
1019
1020 expect(elements[ 3 ].video.name).to.equal('video 4 server 1')
1021 expect(elements[ 3 ].position).to.equal(4)
1022 }
1023 })
1024
1025 it('Should be able to create a public playlist, and set it to private', async function () {
1026 this.timeout(30000)
1027
1028 const res = await createVideoPlaylist({
1029 url: servers[ 0 ].url,
1030 token: servers[ 0 ].accessToken,
1031 playlistAttrs: {
1032 displayName: 'my super public playlist',
1033 privacy: VideoPlaylistPrivacy.PUBLIC,
1034 videoChannelId: servers[ 0 ].videoChannel.id
1035 }
1036 })
1037 const videoPlaylistIds = res.body.videoPlaylist
1038
1039 await waitJobs(servers)
1040
1041 for (const server of servers) {
1042 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
1043 }
1044
1045 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1046 await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1047
1048 await waitJobs(servers)
1049
1050 for (const server of [ servers[ 1 ], servers[ 2 ] ]) {
1051 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
1052 }
1053 await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401)
1054
1055 await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200)
1056 })
1057 })
1058
1059 describe('Playlist deletion', function () {
1060
1061 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1062 this.timeout(30000)
1063
1064 await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id)
1065
1066 await waitJobs(servers)
1067
1068 for (const server of servers) {
1069 await getVideoPlaylist(server.url, playlistServer1UUID, 404)
1070 }
1071 })
1072
1073 it('Should have deleted the thumbnail on server 1, 2 and 3', async function () {
1074 this.timeout(30000)
1075
1076 for (const server of servers) {
1077 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
1078 }
1079 })
1080
1081 it('Should unfollow servers 1 and 2 and hide their playlists', async function () {
1082 this.timeout(30000)
1083
1084 const finder = data => data.find(p => p.displayName === 'my super playlist')
1085
1086 {
1087 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
1088 expect(res.body.total).to.equal(3)
1089 expect(finder(res.body.data)).to.not.be.undefined
1090 }
1091
1092 await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ])
1093
1094 {
1095 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
1096 expect(res.body.total).to.equal(1)
1097
1098 expect(finder(res.body.data)).to.be.undefined
1099 }
1100 })
1101
1102 it('Should delete a channel and put the associated playlist in private mode', async function () {
1103 this.timeout(30000)
1104
1105 const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' })
1106 const videoChannelId = res.body.videoChannel.id
1107
1108 const res2 = await createVideoPlaylist({
1109 url: servers[ 0 ].url,
1110 token: servers[ 0 ].accessToken,
1111 playlistAttrs: {
1112 displayName: 'channel playlist',
1113 privacy: VideoPlaylistPrivacy.PUBLIC,
1114 videoChannelId
1115 }
1116 })
1117 const videoPlaylistUUID = res2.body.videoPlaylist.uuid
1118
1119 await waitJobs(servers)
1120
1121 await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel')
1122
1123 await waitJobs(servers)
1124
1125 const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID)
1126 expect(res3.body.displayName).to.equal('channel playlist')
1127 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
1128
1129 await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404)
1130 })
1131
1132 it('Should delete an account and delete its playlists', async function () {
1133 this.timeout(30000)
1134
1135 const user = { username: 'user_1', password: 'password' }
1136 const res = await createUser({
1137 url: servers[ 0 ].url,
1138 accessToken: servers[ 0 ].accessToken,
1139 username: user.username,
1140 password: user.password
1141 })
1142
1143 const userId = res.body.user.id
1144 const userAccessToken = await userLogin(servers[ 0 ], user)
1145
1146 const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken)
1147 const userChannel = (resChannel.body as User).videoChannels[ 0 ]
1148
1149 await createVideoPlaylist({
1150 url: servers[ 0 ].url,
1151 token: userAccessToken,
1152 playlistAttrs: {
1153 displayName: 'playlist to be deleted',
1154 privacy: VideoPlaylistPrivacy.PUBLIC,
1155 videoChannelId: userChannel.id
1156 }
1157 })
1158
1159 await waitJobs(servers)
1160
1161 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
1162
1163 {
1164 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
1165 const res = await getVideoPlaylistsList(server.url, 0, 15)
1166 expect(finder(res.body.data)).to.not.be.undefined
1167 }
1168 }
1169
1170 await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken)
1171 await waitJobs(servers)
1172
1173 {
1174 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
1175 const res = await getVideoPlaylistsList(server.url, 0, 15)
1176 expect(finder(res.body.data)).to.be.undefined
1177 }
1178 }
1179 })
1180 })
1181
1182 after(async function () {
1183 await cleanupTests(servers)
1184 })
1185 })