1 /* tslint:disable:no-unused-expression */
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
148 url: servers[ 0 ].url,
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({
218 url: servers[ 0 ].url,
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
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')
254 expect(playlist.videosLength).to.equal(0)
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')
264 it('Should create a playlist on server 2 and have the playlist on server 1 but not on server 3', async function () {
268 const res = await createVideoPlaylist({
269 url: servers[ 1 ].url,
270 token: servers[ 1 ].accessToken,
272 displayName: 'playlist 2',
273 privacy: VideoPlaylistPrivacy.PUBLIC,
274 videoChannelId: servers[ 1 ].videoChannel.id
277 playlistServer2Id1 = res.body.videoPlaylist.id
281 const res = await createVideoPlaylist({
282 url: servers[ 1 ].url,
283 token: servers[ 1 ].accessToken,
285 displayName: 'playlist 3',
286 privacy: VideoPlaylistPrivacy.PUBLIC,
287 thumbnailfile: 'thumbnail.jpg',
288 videoChannelId: servers[ 1 ].videoChannel.id
292 playlistServer2Id2 = res.body.videoPlaylist.id
293 playlistServer2UUID2 = res.body.videoPlaylist.uuid
296 for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) {
297 await addVideoInPlaylist({
298 url: servers[ 1 ].url,
299 token: servers[ 1 ].accessToken,
301 elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 }
303 await addVideoInPlaylist({
304 url: servers[ 1 ].url,
305 token: servers[ 1 ].accessToken,
307 elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id }
311 await waitJobs(servers)
313 for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
314 const res = await getVideoPlaylistsList(server.url, 0, 5)
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)
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)
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
330 it('Should have the playlist on server 3 after a new follow', async function () {
333 // Server 2 and server 3 follow each other
334 await doubleFollow(servers[ 1 ], servers[ 2 ])
336 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
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)
342 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
346 describe('List playlists', function () {
348 it('Should correctly list the playlists', async function () {
352 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt')
354 expect(res.body.total).to.equal(3)
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')
363 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt')
365 expect(res.body.total).to.equal(3)
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')
374 it('Should list video channel playlists', async function () {
378 const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt')
380 expect(res.body.total).to.equal(1)
382 const data: VideoPlaylist[] = res.body.data
383 expect(data).to.have.lengthOf(1)
384 expect(data[ 0 ].displayName).to.equal('my super playlist')
388 it('Should list account playlists', async function () {
392 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt')
394 expect(res.body.total).to.equal(2)
396 const data: VideoPlaylist[] = res.body.data
397 expect(data).to.have.lengthOf(1)
398 expect(data[ 0 ].displayName).to.equal('playlist 2')
402 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt')
404 expect(res.body.total).to.equal(2)
406 const data: VideoPlaylist[] = res.body.data
407 expect(data).to.have.lengthOf(1)
408 expect(data[ 0 ].displayName).to.equal('playlist 3')
412 it('Should not list unlisted or private playlists', async function () {
415 await createVideoPlaylist({
416 url: servers[ 1 ].url,
417 token: servers[ 1 ].accessToken,
419 displayName: 'playlist unlisted',
420 privacy: VideoPlaylistPrivacy.UNLISTED
424 await createVideoPlaylist({
425 url: servers[ 1 ].url,
426 token: servers[ 1 ].accessToken,
428 displayName: 'playlist private',
429 privacy: VideoPlaylistPrivacy.PRIVATE
433 await waitJobs(servers)
435 for (const server of servers) {
437 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'),
438 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
441 expect(results[ 0 ].body.total).to.equal(2)
442 expect(results[ 1 ].body.total).to.equal(3)
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')
454 describe('Update playlists', function () {
456 it('Should update a playlist', async function () {
459 await updateVideoPlaylist({
461 token: servers[1].accessToken,
463 displayName: 'playlist 3 updated',
464 description: 'description updated',
465 privacy: VideoPlaylistPrivacy.UNLISTED,
466 thumbnailfile: 'thumbnail.jpg',
467 videoChannelId: servers[1].videoChannel.id
469 playlistId: playlistServer2Id2
472 await waitJobs(servers)
474 for (const server of servers) {
475 const res = await getVideoPlaylist(server.url, playlistServer2UUID2)
476 const playlist: VideoPlaylist = res.body
478 expect(playlist.displayName).to.equal('playlist 3 updated')
479 expect(playlist.description).to.equal('description updated')
481 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED)
482 expect(playlist.privacy.label).to.equal('Unlisted')
484 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
485 expect(playlist.type.label).to.equal('Regular')
487 expect(playlist.videosLength).to.equal(2)
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')
497 describe('Element timestamps', function () {
499 it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () {
502 const addVideo = (elementAttrs: any) => {
503 return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs })
506 const res = await createVideoPlaylist({
507 url: servers[ 0 ].url,
508 token: servers[ 0 ].accessToken,
510 displayName: 'playlist 4',
511 privacy: VideoPlaylistPrivacy.PUBLIC,
512 videoChannelId: servers[ 0 ].videoChannel.id
516 playlistServer1Id = res.body.videoPlaylist.id
517 playlistServer1UUID = res.body.videoPlaylist.uuid
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 })
523 const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 })
524 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
528 const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 })
529 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
533 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
534 playlistElementNSFW = res.body.videoPlaylistElement.id
537 await waitJobs(servers)
540 it('Should correctly list playlist videos', async function () {
543 for (const server of servers) {
544 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
546 expect(res.body.total).to.equal(6)
548 const videoElements: VideoPlaylistElement[] = res.body.data
549 expect(videoElements).to.have.lengthOf(6)
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)
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
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
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)
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)
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
581 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
582 expect(res3.body.data).to.have.lengthOf(2)
587 describe('Element type', function () {
588 let groupUser1: ServerInfo[]
589 let groupWithoutToken1: ServerInfo[]
590 let group1: ServerInfo[]
591 let group2: ServerInfo[]
597 before(async function () {
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 ] ]
605 const res = await createVideoPlaylist({
606 url: servers[ 0 ].url,
607 token: userAccessTokenServer1,
609 displayName: 'playlist 56',
610 privacy: VideoPlaylistPrivacy.PUBLIC,
611 videoChannelId: servers[ 0 ].videoChannel.id
615 const playlistServer1Id2 = res.body.videoPlaylist.id
616 playlistServer1UUID2 = res.body.videoPlaylist.uuid
618 const addVideo = (elementAttrs: any) => {
619 return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
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
626 await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 })
627 await addVideo({ videoId: video2, startTimestamp: 35 })
628 await addVideo({ videoId: video3 })
630 await waitJobs(servers)
633 it('Should update the element type if the video is private', async function () {
636 const name = 'video 89'
640 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
641 await waitJobs(servers)
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)
650 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
651 await waitJobs(servers)
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)
661 it('Should update the element type if the video is blacklisted', async function () {
664 const name = 'video 89'
668 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true)
669 await waitJobs(servers)
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)
678 await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1)
679 await waitJobs(servers)
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)
689 it('Should update the element type if the account or server of the video is blocked', async function () {
692 const name = 'video 90'
696 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
697 await waitJobs(servers)
699 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
700 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
702 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
703 await waitJobs(servers)
705 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
709 await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
710 await waitJobs(servers)
712 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
713 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
715 await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
716 await waitJobs(servers)
718 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
722 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
723 await waitJobs(servers)
725 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
726 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
728 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
729 await waitJobs(servers)
731 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
735 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
736 await waitJobs(servers)
738 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
739 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
741 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
742 await waitJobs(servers)
744 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
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)
752 const elements: VideoPlaylistElement[] = res.body.data
753 const element = elements.find(e => e.position === 3)
755 expect(element).to.exist
756 expect(element.video).to.be.null
757 expect(element.type).to.equal(VideoPlaylistElementType.UNAVAILABLE)
762 describe('Managing playlist elements', function () {
764 it('Should reorder the playlist', async function () {
768 await reorderVideosPlaylist({
769 url: servers[ 0 ].url,
770 token: servers[ 0 ].accessToken,
771 playlistId: playlistServer1Id,
774 insertAfterPosition: 3
778 await waitJobs(servers)
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)
784 expect(names).to.deep.equal([
796 await reorderVideosPlaylist({
797 url: servers[ 0 ].url,
798 token: servers[ 0 ].accessToken,
799 playlistId: playlistServer1Id,
803 insertAfterPosition: 4
807 await waitJobs(servers)
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)
813 expect(names).to.deep.equal([
825 await reorderVideosPlaylist({
826 url: servers[ 0 ].url,
827 token: servers[ 0 ].accessToken,
828 playlistId: playlistServer1Id,
831 insertAfterPosition: 3
835 await waitJobs(servers)
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)
842 expect(names).to.deep.equal([
851 for (let i = 1; i <= elements.length; i++) {
852 expect(elements[ i - 1 ].position).to.equal(i)
858 it('Should update startTimestamp/endTimestamp of some elements', async function () {
861 await updateVideoPlaylistElement({
862 url: servers[ 0 ].url,
863 token: servers[ 0 ].accessToken,
864 playlistId: playlistServer1Id,
865 playlistElementId: playlistElementServer1Video4,
871 await updateVideoPlaylistElement({
872 url: servers[ 0 ].url,
873 token: servers[ 0 ].accessToken,
874 playlistId: playlistServer1Id,
875 playlistElementId: playlistElementServer1Video5,
881 await waitJobs(servers)
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
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)
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
899 it('Should check videos existence in my playlist', async function () {
901 servers[ 0 ].videos[ 0 ].id,
903 servers[ 0 ].videos[ 3 ].id,
905 servers[ 0 ].videos[ 4 ].id
907 const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds)
908 const obj = res.body as VideoExistInPlaylist
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)
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)
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)
936 expect(obj[ 42000 ]).to.have.lengthOf(0)
937 expect(obj[ 43000 ]).to.have.lengthOf(0)
940 it('Should automatically update updatedAt field of playlists', async function () {
941 const server = servers[ 1 ]
942 const videoId = servers[ 1 ].videos[ 5 ].id
944 async function getPlaylistNames () {
945 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
947 return (res.body.data as VideoPlaylist[]).map(p => p.displayName)
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 })
954 const element1 = res1.body.videoPlaylistElement.id
955 const element2 = res2.body.videoPlaylistElement.id
957 const names1 = await getPlaylistNames()
958 expect(names1[ 0 ]).to.equal('playlist 3 updated')
959 expect(names1[ 1 ]).to.equal('playlist 2')
961 await removeVideoFromPlaylist({
963 token: server.accessToken,
964 playlistId: playlistServer2Id1,
965 playlistElementId: element1
968 const names2 = await getPlaylistNames()
969 expect(names2[ 0 ]).to.equal('playlist 2')
970 expect(names2[ 1 ]).to.equal('playlist 3 updated')
972 await removeVideoFromPlaylist({
974 token: server.accessToken,
975 playlistId: playlistServer2Id2,
976 playlistElementId: element2
979 const names3 = await getPlaylistNames()
980 expect(names3[ 0 ]).to.equal('playlist 3 updated')
981 expect(names3[ 1 ]).to.equal('playlist 2')
984 it('Should delete some elements', async function () {
987 await removeVideoFromPlaylist({
988 url: servers[ 0 ].url,
989 token: servers[ 0 ].accessToken,
990 playlistId: playlistServer1Id,
991 playlistElementId: playlistElementServer1Video4
994 await removeVideoFromPlaylist({
995 url: servers[ 0 ].url,
996 token: servers[ 0 ].accessToken,
997 playlistId: playlistServer1Id,
998 playlistElementId: playlistElementNSFW
1001 await waitJobs(servers)
1003 for (const server of servers) {
1004 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1006 expect(res.body.total).to.equal(4)
1008 const elements: VideoPlaylistElement[] = res.body.data
1009 expect(elements).to.have.lengthOf(4)
1011 expect(elements[ 0 ].video.name).to.equal('video 0 server 1')
1012 expect(elements[ 0 ].position).to.equal(1)
1014 expect(elements[ 1 ].video.name).to.equal('video 2 server 3')
1015 expect(elements[ 1 ].position).to.equal(2)
1017 expect(elements[ 2 ].video.name).to.equal('video 1 server 3')
1018 expect(elements[ 2 ].position).to.equal(3)
1020 expect(elements[ 3 ].video.name).to.equal('video 4 server 1')
1021 expect(elements[ 3 ].position).to.equal(4)
1025 it('Should be able to create a public playlist, and set it to private', async function () {
1028 const res = await createVideoPlaylist({
1029 url: servers[ 0 ].url,
1030 token: servers[ 0 ].accessToken,
1032 displayName: 'my super public playlist',
1033 privacy: VideoPlaylistPrivacy.PUBLIC,
1034 videoChannelId: servers[ 0 ].videoChannel.id
1037 const videoPlaylistIds = res.body.videoPlaylist
1039 await waitJobs(servers)
1041 for (const server of servers) {
1042 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
1045 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1046 await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1048 await waitJobs(servers)
1050 for (const server of [ servers[ 1 ], servers[ 2 ] ]) {
1051 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
1053 await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401)
1055 await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200)
1059 describe('Playlist deletion', function () {
1061 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1064 await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id)
1066 await waitJobs(servers)
1068 for (const server of servers) {
1069 await getVideoPlaylist(server.url, playlistServer1UUID, 404)
1073 it('Should have deleted the thumbnail on server 1, 2 and 3', async function () {
1076 for (const server of servers) {
1077 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
1081 it('Should unfollow servers 1 and 2 and hide their playlists', async function () {
1084 const finder = data => data.find(p => p.displayName === 'my super playlist')
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
1092 await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ])
1095 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
1096 expect(res.body.total).to.equal(1)
1098 expect(finder(res.body.data)).to.be.undefined
1102 it('Should delete a channel and put the associated playlist in private mode', async function () {
1105 const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' })
1106 const videoChannelId = res.body.videoChannel.id
1108 const res2 = await createVideoPlaylist({
1109 url: servers[ 0 ].url,
1110 token: servers[ 0 ].accessToken,
1112 displayName: 'channel playlist',
1113 privacy: VideoPlaylistPrivacy.PUBLIC,
1117 const videoPlaylistUUID = res2.body.videoPlaylist.uuid
1119 await waitJobs(servers)
1121 await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel')
1123 await waitJobs(servers)
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)
1129 await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404)
1132 it('Should delete an account and delete its playlists', async function () {
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
1143 const userId = res.body.user.id
1144 const userAccessToken = await userLogin(servers[ 0 ], user)
1146 const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken)
1147 const userChannel = (resChannel.body as User).videoChannels[ 0 ]
1149 await createVideoPlaylist({
1150 url: servers[ 0 ].url,
1151 token: userAccessToken,
1153 displayName: 'playlist to be deleted',
1154 privacy: VideoPlaylistPrivacy.PUBLIC,
1155 videoChannelId: userChannel.id
1159 await waitJobs(servers)
1161 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
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
1170 await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken)
1171 await waitJobs(servers)
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
1182 after(async function () {
1183 await cleanupTests(servers)