1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import * as chai from 'chai'
9 checkPlaylistFilesWereRemoved,
16 doVideosExistInMyPlaylist,
17 flushAndRunMultipleServers,
18 generateUserAccessToken,
20 getAccountPlaylistsList,
21 getAccountPlaylistsListWithToken,
24 getVideoChannelPlaylistsList,
26 getVideoPlaylistPrivacies,
27 getVideoPlaylistsList,
28 getVideoPlaylistWithToken,
30 removeVideoFromBlacklist,
31 removeVideoFromPlaylist,
32 reorderVideosPlaylist,
34 setAccessTokensToServers,
35 setDefaultVideoChannel,
40 updateVideoPlaylistElement,
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'
54 addAccountToAccountBlocklist,
55 addAccountToServerBlocklist,
56 addServerToAccountBlocklist,
57 addServerToServerBlocklist,
58 removeAccountFromAccountBlocklist,
59 removeAccountFromServerBlocklist,
60 removeServerFromAccountBlocklist,
61 removeServerFromServerBlocklist
62 } from '../../../../shared/extra-utils/users/blocklist'
64 const expect = chai.expect
66 async function checkPlaylistElementType (
67 servers: ServerInfo[],
69 type: VideoPlaylistElementType,
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)
78 const videoElement: VideoPlaylistElement = res.body.data.find((e: VideoPlaylistElement) => e.position === position)
79 expect(videoElement.type).to.equal(type, 'On server ' + server.url)
81 if (type === VideoPlaylistElementType.REGULAR) {
82 expect(videoElement.video).to.not.be.null
83 expect(videoElement.video.name).to.equal(name)
85 expect(videoElement.video).to.be.null
90 describe('Test video playlists', function () {
91 let servers: ServerInfo[] = []
93 let playlistServer2Id1: number
94 let playlistServer2Id2: number
95 let playlistServer2UUID2: number
97 let playlistServer1Id: number
98 let playlistServer1UUID: string
99 let playlistServer1UUID2: string
101 let playlistElementServer1Video4: number
102 let playlistElementServer1Video5: number
103 let playlistElementNSFW: number
105 let nsfwVideoServer1: number
107 let userAccessTokenServer1: string
109 before(async function () {
112 servers = await flushAndRunMultipleServers(3, { transcoding: { enabled: false } })
114 // Get the access tokens
115 await setAccessTokensToServers(servers)
116 await setDefaultVideoChannel(servers)
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])
124 const serverPromises: Promise<any>[][] = []
126 for (const server of servers) {
127 const videoPromises: Promise<any>[] = []
129 for (let i = 0; i < 7; i++) {
131 uploadVideo(server.url, server.accessToken, { name: `video ${i} server ${server.serverNumber}`, nsfw: false })
132 .then(res => res.body.video)
136 serverPromises.push(videoPromises)
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])
144 nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id
149 accessToken: servers[0].accessToken,
153 userAccessTokenServer1 = await getAccessToken(servers[0].url, 'user1', 'password')
156 await waitJobs(servers)
159 describe('Get default playlists', function () {
160 it('Should list video playlist privacies', async function () {
161 const res = await getVideoPlaylistPrivacies(servers[0].url)
163 const privacies = res.body
164 expect(Object.keys(privacies)).to.have.length.at.least(3)
166 expect(privacies[3]).to.equal('Private')
169 it('Should list watch later playlist', async function () {
170 const url = servers[0].url
171 const accessToken = servers[0].accessToken
174 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
176 expect(res.body.total).to.equal(1)
177 expect(res.body.data).to.have.lengthOf(1)
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')
186 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.REGULAR)
188 expect(res.body.total).to.equal(0)
189 expect(res.body.data).to.have.lengthOf(0)
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)
199 it('Should get private playlist for a classic user', async function () {
200 const token = await generateUserAccessToken(servers[0], 'toto')
202 const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5)
204 expect(res.body.total).to.equal(1)
205 expect(res.body.data).to.have.lengthOf(1)
207 const playlistId = res.body.data[0].id
208 await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5)
212 describe('Create and federate playlists', function () {
214 it('Should create a playlist on server 1 and have the playlist on server 2 and 3', async function () {
217 await createVideoPlaylist({
219 token: servers[0].accessToken,
221 displayName: 'my super playlist',
222 privacy: VideoPlaylistPrivacy.PUBLIC,
223 description: 'my super description',
224 thumbnailfile: 'thumbnail.jpg',
225 videoChannelId: servers[0].videoChannel.id
229 await waitJobs(servers)
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)
236 const playlistFromList = res.body.data[0] as VideoPlaylist
238 const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid)
239 const playlistFromGet = res2.body as VideoPlaylist
241 for (const playlist of [ playlistFromGet, playlistFromList ]) {
242 expect(playlist.id).to.be.a('number')
243 expect(playlist.uuid).to.be.a('string')
245 expect(playlist.isLocal).to.equal(server.serverNumber === 1)
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 expect(playlist.embedPath).to.equal('/video-playlists/embed/' + playlist.uuid)
255 expect(playlist.videosLength).to.equal(0)
257 expect(playlist.ownerAccount.name).to.equal('root')
258 expect(playlist.ownerAccount.displayName).to.equal('root')
259 expect(playlist.videoChannel.name).to.equal('root_channel')
260 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
265 it('Should create a playlist on server 2 and have the playlist on server 1 but not on server 3', async function () {
269 const res = await createVideoPlaylist({
271 token: servers[1].accessToken,
273 displayName: 'playlist 2',
274 privacy: VideoPlaylistPrivacy.PUBLIC,
275 videoChannelId: servers[1].videoChannel.id
278 playlistServer2Id1 = res.body.videoPlaylist.id
282 const res = await createVideoPlaylist({
284 token: servers[1].accessToken,
286 displayName: 'playlist 3',
287 privacy: VideoPlaylistPrivacy.PUBLIC,
288 thumbnailfile: 'thumbnail.jpg',
289 videoChannelId: servers[1].videoChannel.id
293 playlistServer2Id2 = res.body.videoPlaylist.id
294 playlistServer2UUID2 = res.body.videoPlaylist.uuid
297 for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) {
298 await addVideoInPlaylist({
300 token: servers[1].accessToken,
302 elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 }
304 await addVideoInPlaylist({
306 token: servers[1].accessToken,
308 elementAttrs: { videoId: servers[1].videos[1].id }
312 await waitJobs(servers)
314 for (const server of [ servers[0], servers[1] ]) {
315 const res = await getVideoPlaylistsList(server.url, 0, 5)
317 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
318 expect(playlist2).to.not.be.undefined
319 await testImage(server.url, 'thumbnail-playlist', playlist2.thumbnailPath)
321 const playlist3 = res.body.data.find(p => p.displayName === 'playlist 3')
322 expect(playlist3).to.not.be.undefined
323 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath)
326 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
327 expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined
328 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined
331 it('Should have the playlist on server 3 after a new follow', async function () {
334 // Server 2 and server 3 follow each other
335 await doubleFollow(servers[1], servers[2])
337 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
339 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
340 expect(playlist2).to.not.be.undefined
341 await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath)
343 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
347 describe('List playlists', function () {
349 it('Should correctly list the playlists', async function () {
353 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt')
355 expect(res.body.total).to.equal(3)
357 const data: VideoPlaylist[] = res.body.data
358 expect(data).to.have.lengthOf(2)
359 expect(data[0].displayName).to.equal('playlist 2')
360 expect(data[1].displayName).to.equal('playlist 3')
364 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt')
366 expect(res.body.total).to.equal(3)
368 const data: VideoPlaylist[] = res.body.data
369 expect(data).to.have.lengthOf(2)
370 expect(data[0].displayName).to.equal('playlist 2')
371 expect(data[1].displayName).to.equal('my super playlist')
375 it('Should list video channel playlists', async function () {
379 const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt')
381 expect(res.body.total).to.equal(1)
383 const data: VideoPlaylist[] = res.body.data
384 expect(data).to.have.lengthOf(1)
385 expect(data[0].displayName).to.equal('my super playlist')
389 it('Should list account playlists', async function () {
393 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt')
395 expect(res.body.total).to.equal(2)
397 const data: VideoPlaylist[] = res.body.data
398 expect(data).to.have.lengthOf(1)
399 expect(data[0].displayName).to.equal('playlist 2')
403 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt')
405 expect(res.body.total).to.equal(2)
407 const data: VideoPlaylist[] = res.body.data
408 expect(data).to.have.lengthOf(1)
409 expect(data[0].displayName).to.equal('playlist 3')
413 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3')
415 expect(res.body.total).to.equal(1)
417 const data: VideoPlaylist[] = res.body.data
418 expect(data).to.have.lengthOf(1)
419 expect(data[0].displayName).to.equal('playlist 3')
423 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4')
425 expect(res.body.total).to.equal(0)
427 const data: VideoPlaylist[] = res.body.data
428 expect(data).to.have.lengthOf(0)
432 it('Should not list unlisted or private playlists', async function () {
435 await createVideoPlaylist({
437 token: servers[1].accessToken,
439 displayName: 'playlist unlisted',
440 privacy: VideoPlaylistPrivacy.UNLISTED
444 await createVideoPlaylist({
446 token: servers[1].accessToken,
448 displayName: 'playlist private',
449 privacy: VideoPlaylistPrivacy.PRIVATE
453 await waitJobs(servers)
455 for (const server of servers) {
457 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
458 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
461 expect(results[0].body.total).to.equal(2)
462 expect(results[1].body.total).to.equal(3)
464 for (const res of results) {
465 const data: VideoPlaylist[] = res.body.data
466 expect(data).to.have.lengthOf(2)
467 expect(data[0].displayName).to.equal('playlist 3')
468 expect(data[1].displayName).to.equal('playlist 2')
474 describe('Update playlists', function () {
476 it('Should update a playlist', async function () {
479 await updateVideoPlaylist({
481 token: servers[1].accessToken,
483 displayName: 'playlist 3 updated',
484 description: 'description updated',
485 privacy: VideoPlaylistPrivacy.UNLISTED,
486 thumbnailfile: 'thumbnail.jpg',
487 videoChannelId: servers[1].videoChannel.id
489 playlistId: playlistServer2Id2
492 await waitJobs(servers)
494 for (const server of servers) {
495 const res = await getVideoPlaylist(server.url, playlistServer2UUID2)
496 const playlist: VideoPlaylist = res.body
498 expect(playlist.displayName).to.equal('playlist 3 updated')
499 expect(playlist.description).to.equal('description updated')
501 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED)
502 expect(playlist.privacy.label).to.equal('Unlisted')
504 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
505 expect(playlist.type.label).to.equal('Regular')
507 expect(playlist.videosLength).to.equal(2)
509 expect(playlist.ownerAccount.name).to.equal('root')
510 expect(playlist.ownerAccount.displayName).to.equal('root')
511 expect(playlist.videoChannel.name).to.equal('root_channel')
512 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
517 describe('Element timestamps', function () {
519 it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () {
522 const addVideo = (elementAttrs: any) => {
523 return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs })
526 const res = await createVideoPlaylist({
528 token: servers[0].accessToken,
530 displayName: 'playlist 4',
531 privacy: VideoPlaylistPrivacy.PUBLIC,
532 videoChannelId: servers[0].videoChannel.id
536 playlistServer1Id = res.body.videoPlaylist.id
537 playlistServer1UUID = res.body.videoPlaylist.uuid
539 await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
540 await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 })
541 await addVideo({ videoId: servers[2].videos[2].uuid })
543 const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 })
544 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
548 const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 })
549 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
553 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
554 playlistElementNSFW = res.body.videoPlaylistElement.id
556 await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 4 })
557 await addVideo({ videoId: nsfwVideoServer1 })
560 await waitJobs(servers)
563 it('Should correctly list playlist videos', async function () {
566 for (const server of servers) {
567 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
569 expect(res.body.total).to.equal(8)
571 const videoElements: VideoPlaylistElement[] = res.body.data
572 expect(videoElements).to.have.lengthOf(8)
574 expect(videoElements[0].video.name).to.equal('video 0 server 1')
575 expect(videoElements[0].position).to.equal(1)
576 expect(videoElements[0].startTimestamp).to.equal(15)
577 expect(videoElements[0].stopTimestamp).to.equal(28)
579 expect(videoElements[1].video.name).to.equal('video 1 server 3')
580 expect(videoElements[1].position).to.equal(2)
581 expect(videoElements[1].startTimestamp).to.equal(35)
582 expect(videoElements[1].stopTimestamp).to.be.null
584 expect(videoElements[2].video.name).to.equal('video 2 server 3')
585 expect(videoElements[2].position).to.equal(3)
586 expect(videoElements[2].startTimestamp).to.be.null
587 expect(videoElements[2].stopTimestamp).to.be.null
589 expect(videoElements[3].video.name).to.equal('video 3 server 1')
590 expect(videoElements[3].position).to.equal(4)
591 expect(videoElements[3].startTimestamp).to.be.null
592 expect(videoElements[3].stopTimestamp).to.equal(35)
594 expect(videoElements[4].video.name).to.equal('video 4 server 1')
595 expect(videoElements[4].position).to.equal(5)
596 expect(videoElements[4].startTimestamp).to.equal(45)
597 expect(videoElements[4].stopTimestamp).to.equal(60)
599 expect(videoElements[5].video.name).to.equal('NSFW video')
600 expect(videoElements[5].position).to.equal(6)
601 expect(videoElements[5].startTimestamp).to.equal(5)
602 expect(videoElements[5].stopTimestamp).to.be.null
604 expect(videoElements[6].video.name).to.equal('NSFW video')
605 expect(videoElements[6].position).to.equal(7)
606 expect(videoElements[6].startTimestamp).to.equal(4)
607 expect(videoElements[6].stopTimestamp).to.be.null
609 expect(videoElements[7].video.name).to.equal('NSFW video')
610 expect(videoElements[7].position).to.equal(8)
611 expect(videoElements[7].startTimestamp).to.be.null
612 expect(videoElements[7].stopTimestamp).to.be.null
614 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
615 expect(res3.body.data).to.have.lengthOf(2)
620 describe('Element type', function () {
621 let groupUser1: ServerInfo[]
622 let groupWithoutToken1: ServerInfo[]
623 let group1: ServerInfo[]
624 let group2: ServerInfo[]
630 before(async function () {
633 groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ]
634 groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ]
635 group1 = [ servers[0] ]
636 group2 = [ servers[1], servers[2] ]
638 const res = await createVideoPlaylist({
640 token: userAccessTokenServer1,
642 displayName: 'playlist 56',
643 privacy: VideoPlaylistPrivacy.PUBLIC,
644 videoChannelId: servers[0].videoChannel.id
648 const playlistServer1Id2 = res.body.videoPlaylist.id
649 playlistServer1UUID2 = res.body.videoPlaylist.uuid
651 const addVideo = (elementAttrs: any) => {
652 return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
655 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
656 video2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 90' })).uuid
657 video3 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 91', nsfw: true })).uuid
659 await waitJobs(servers)
661 await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 })
662 await addVideo({ videoId: video2, startTimestamp: 35 })
663 await addVideo({ videoId: video3 })
665 await waitJobs(servers)
668 it('Should update the element type if the video is private', async function () {
671 const name = 'video 89'
675 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
676 await waitJobs(servers)
678 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
679 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
680 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
681 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
685 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
686 await waitJobs(servers)
688 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
689 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
690 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
691 // We deleted the video, so even if we recreated it, the old entry is still deleted
692 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
696 it('Should update the element type if the video is blacklisted', async function () {
699 const name = 'video 89'
703 await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true)
704 await waitJobs(servers)
706 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
707 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
708 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
709 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
713 await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1)
714 await waitJobs(servers)
716 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
717 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
718 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
719 // We deleted the video (because unfederated), so even if we recreated it, the old entry is still deleted
720 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
724 it('Should update the element type if the account or server of the video is blocked', async function () {
727 const name = 'video 90'
731 await addAccountToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
732 await waitJobs(servers)
734 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
735 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
737 await removeAccountFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
738 await waitJobs(servers)
740 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
744 await addServerToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
745 await waitJobs(servers)
747 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
748 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
750 await removeServerFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
751 await waitJobs(servers)
753 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
757 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
758 await waitJobs(servers)
760 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
761 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
763 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
764 await waitJobs(servers)
766 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
770 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
771 await waitJobs(servers)
773 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
774 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
776 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
777 await waitJobs(servers)
779 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
783 it('Should hide the video if it is NSFW', async function () {
784 const res = await getPlaylistVideos(servers[0].url, userAccessTokenServer1, playlistServer1UUID2, 0, 10, { nsfw: false })
785 expect(res.body.total).to.equal(3)
787 const elements: VideoPlaylistElement[] = res.body.data
788 const element = elements.find(e => e.position === 3)
790 expect(element).to.exist
791 expect(element.video).to.be.null
792 expect(element.type).to.equal(VideoPlaylistElementType.UNAVAILABLE)
797 describe('Managing playlist elements', function () {
799 it('Should reorder the playlist', async function () {
803 await reorderVideosPlaylist({
805 token: servers[0].accessToken,
806 playlistId: playlistServer1Id,
809 insertAfterPosition: 3
813 await waitJobs(servers)
815 for (const server of servers) {
816 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
817 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
819 expect(names).to.deep.equal([
833 await reorderVideosPlaylist({
835 token: servers[0].accessToken,
836 playlistId: playlistServer1Id,
840 insertAfterPosition: 4
844 await waitJobs(servers)
846 for (const server of servers) {
847 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
848 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
850 expect(names).to.deep.equal([
864 await reorderVideosPlaylist({
866 token: servers[0].accessToken,
867 playlistId: playlistServer1Id,
870 insertAfterPosition: 3
874 await waitJobs(servers)
876 for (const server of servers) {
877 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
878 const elements: VideoPlaylistElement[] = res.body.data
879 const names = elements.map(v => v.video.name)
881 expect(names).to.deep.equal([
892 for (let i = 1; i <= elements.length; i++) {
893 expect(elements[i - 1].position).to.equal(i)
899 it('Should update startTimestamp/endTimestamp of some elements', async function () {
902 await updateVideoPlaylistElement({
904 token: servers[0].accessToken,
905 playlistId: playlistServer1Id,
906 playlistElementId: playlistElementServer1Video4,
912 await updateVideoPlaylistElement({
914 token: servers[0].accessToken,
915 playlistId: playlistServer1Id,
916 playlistElementId: playlistElementServer1Video5,
922 await waitJobs(servers)
924 for (const server of servers) {
925 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
926 const elements: VideoPlaylistElement[] = res.body.data
928 expect(elements[0].video.name).to.equal('video 3 server 1')
929 expect(elements[0].position).to.equal(1)
930 expect(elements[0].startTimestamp).to.equal(1)
931 expect(elements[0].stopTimestamp).to.equal(35)
933 expect(elements[5].video.name).to.equal('video 4 server 1')
934 expect(elements[5].position).to.equal(6)
935 expect(elements[5].startTimestamp).to.equal(45)
936 expect(elements[5].stopTimestamp).to.be.null
940 it('Should check videos existence in my playlist', async function () {
942 servers[0].videos[0].id,
944 servers[0].videos[3].id,
946 servers[0].videos[4].id
948 const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds)
949 const obj = res.body as VideoExistInPlaylist
952 const elem = obj[servers[0].videos[0].id]
953 expect(elem).to.have.lengthOf(1)
954 expect(elem[0].playlistElementId).to.exist
955 expect(elem[0].playlistId).to.equal(playlistServer1Id)
956 expect(elem[0].startTimestamp).to.equal(15)
957 expect(elem[0].stopTimestamp).to.equal(28)
961 const elem = obj[servers[0].videos[3].id]
962 expect(elem).to.have.lengthOf(1)
963 expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
964 expect(elem[0].playlistId).to.equal(playlistServer1Id)
965 expect(elem[0].startTimestamp).to.equal(1)
966 expect(elem[0].stopTimestamp).to.equal(35)
970 const elem = obj[servers[0].videos[4].id]
971 expect(elem).to.have.lengthOf(1)
972 expect(elem[0].playlistId).to.equal(playlistServer1Id)
973 expect(elem[0].startTimestamp).to.equal(45)
974 expect(elem[0].stopTimestamp).to.equal(null)
977 expect(obj[42000]).to.have.lengthOf(0)
978 expect(obj[43000]).to.have.lengthOf(0)
981 it('Should automatically update updatedAt field of playlists', async function () {
982 const server = servers[1]
983 const videoId = servers[1].videos[5].id
985 async function getPlaylistNames () {
986 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
988 return (res.body.data as VideoPlaylist[]).map(p => p.displayName)
991 const elementAttrs = { videoId }
992 const res1 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id1, elementAttrs })
993 const res2 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id2, elementAttrs })
995 const element1 = res1.body.videoPlaylistElement.id
996 const element2 = res2.body.videoPlaylistElement.id
998 const names1 = await getPlaylistNames()
999 expect(names1[0]).to.equal('playlist 3 updated')
1000 expect(names1[1]).to.equal('playlist 2')
1002 await removeVideoFromPlaylist({
1004 token: server.accessToken,
1005 playlistId: playlistServer2Id1,
1006 playlistElementId: element1
1009 const names2 = await getPlaylistNames()
1010 expect(names2[0]).to.equal('playlist 2')
1011 expect(names2[1]).to.equal('playlist 3 updated')
1013 await removeVideoFromPlaylist({
1015 token: server.accessToken,
1016 playlistId: playlistServer2Id2,
1017 playlistElementId: element2
1020 const names3 = await getPlaylistNames()
1021 expect(names3[0]).to.equal('playlist 3 updated')
1022 expect(names3[1]).to.equal('playlist 2')
1025 it('Should delete some elements', async function () {
1028 await removeVideoFromPlaylist({
1029 url: servers[0].url,
1030 token: servers[0].accessToken,
1031 playlistId: playlistServer1Id,
1032 playlistElementId: playlistElementServer1Video4
1035 await removeVideoFromPlaylist({
1036 url: servers[0].url,
1037 token: servers[0].accessToken,
1038 playlistId: playlistServer1Id,
1039 playlistElementId: playlistElementNSFW
1042 await waitJobs(servers)
1044 for (const server of servers) {
1045 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1047 expect(res.body.total).to.equal(6)
1049 const elements: VideoPlaylistElement[] = res.body.data
1050 expect(elements).to.have.lengthOf(6)
1052 expect(elements[0].video.name).to.equal('video 0 server 1')
1053 expect(elements[0].position).to.equal(1)
1055 expect(elements[1].video.name).to.equal('video 2 server 3')
1056 expect(elements[1].position).to.equal(2)
1058 expect(elements[2].video.name).to.equal('video 1 server 3')
1059 expect(elements[2].position).to.equal(3)
1061 expect(elements[3].video.name).to.equal('video 4 server 1')
1062 expect(elements[3].position).to.equal(4)
1064 expect(elements[4].video.name).to.equal('NSFW video')
1065 expect(elements[4].position).to.equal(5)
1067 expect(elements[5].video.name).to.equal('NSFW video')
1068 expect(elements[5].position).to.equal(6)
1072 it('Should be able to create a public playlist, and set it to private', async function () {
1075 const res = await createVideoPlaylist({
1076 url: servers[0].url,
1077 token: servers[0].accessToken,
1079 displayName: 'my super public playlist',
1080 privacy: VideoPlaylistPrivacy.PUBLIC,
1081 videoChannelId: servers[0].videoChannel.id
1084 const videoPlaylistIds = res.body.videoPlaylist
1086 await waitJobs(servers)
1088 for (const server of servers) {
1089 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
1092 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1093 await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1095 await waitJobs(servers)
1097 for (const server of [ servers[1], servers[2] ]) {
1098 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
1100 await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401)
1102 await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200)
1106 describe('Playlist deletion', function () {
1108 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1111 await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id)
1113 await waitJobs(servers)
1115 for (const server of servers) {
1116 await getVideoPlaylist(server.url, playlistServer1UUID, 404)
1120 it('Should have deleted the thumbnail on server 1, 2 and 3', async function () {
1123 for (const server of servers) {
1124 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
1128 it('Should unfollow servers 1 and 2 and hide their playlists', async function () {
1131 const finder = data => data.find(p => p.displayName === 'my super playlist')
1134 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1135 expect(res.body.total).to.equal(3)
1136 expect(finder(res.body.data)).to.not.be.undefined
1139 await unfollow(servers[2].url, servers[2].accessToken, servers[0])
1142 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1143 expect(res.body.total).to.equal(1)
1145 expect(finder(res.body.data)).to.be.undefined
1149 it('Should delete a channel and put the associated playlist in private mode', async function () {
1152 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' })
1153 const videoChannelId = res.body.videoChannel.id
1155 const res2 = await createVideoPlaylist({
1156 url: servers[0].url,
1157 token: servers[0].accessToken,
1159 displayName: 'channel playlist',
1160 privacy: VideoPlaylistPrivacy.PUBLIC,
1164 const videoPlaylistUUID = res2.body.videoPlaylist.uuid
1166 await waitJobs(servers)
1168 await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel')
1170 await waitJobs(servers)
1172 const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID)
1173 expect(res3.body.displayName).to.equal('channel playlist')
1174 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
1176 await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404)
1179 it('Should delete an account and delete its playlists', async function () {
1182 const user = { username: 'user_1', password: 'password' }
1183 const res = await createUser({
1184 url: servers[0].url,
1185 accessToken: servers[0].accessToken,
1186 username: user.username,
1187 password: user.password
1190 const userId = res.body.user.id
1191 const userAccessToken = await userLogin(servers[0], user)
1193 const resChannel = await getMyUserInformation(servers[0].url, userAccessToken)
1194 const userChannel = (resChannel.body as User).videoChannels[0]
1196 await createVideoPlaylist({
1197 url: servers[0].url,
1198 token: userAccessToken,
1200 displayName: 'playlist to be deleted',
1201 privacy: VideoPlaylistPrivacy.PUBLIC,
1202 videoChannelId: userChannel.id
1206 await waitJobs(servers)
1208 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
1211 for (const server of [ servers[0], servers[1] ]) {
1212 const res = await getVideoPlaylistsList(server.url, 0, 15)
1213 expect(finder(res.body.data)).to.not.be.undefined
1217 await removeUser(servers[0].url, userId, servers[0].accessToken)
1218 await waitJobs(servers)
1221 for (const server of [ servers[0], servers[1] ]) {
1222 const res = await getVideoPlaylistsList(server.url, 0, 15)
1223 expect(finder(res.body.data)).to.be.undefined
1229 after(async function () {
1230 await cleanupTests(servers)