1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import * as chai from 'chai'
5 import { HttpStatusCode } from '@shared/core-utils'
10 checkPlaylistFilesWereRemoved,
17 doVideosExistInMyPlaylist,
18 flushAndRunMultipleServers,
19 generateUserAccessToken,
21 getAccountPlaylistsList,
22 getAccountPlaylistsListWithToken,
25 getVideoChannelPlaylistsList,
27 getVideoPlaylistPrivacies,
28 getVideoPlaylistsList,
29 getVideoPlaylistWithToken,
31 removeVideoFromBlacklist,
32 removeVideoFromPlaylist,
33 reorderVideosPlaylist,
35 setAccessTokensToServers,
36 setDefaultVideoChannel,
40 updateVideoPlaylistElement,
46 } from '@shared/extra-utils'
51 VideoPlaylistCreateResult,
53 VideoPlaylistElementType,
57 } from '@shared/models'
59 const expect = chai.expect
61 async function checkPlaylistElementType (
62 servers: ServerInfo[],
64 type: VideoPlaylistElementType,
69 for (const server of servers) {
70 const res = await getPlaylistVideos(server.url, server.accessToken, playlistId, 0, 10)
71 expect(res.body.total).to.equal(total)
73 const videoElement: VideoPlaylistElement = res.body.data.find((e: VideoPlaylistElement) => e.position === position)
74 expect(videoElement.type).to.equal(type, 'On server ' + server.url)
76 if (type === VideoPlaylistElementType.REGULAR) {
77 expect(videoElement.video).to.not.be.null
78 expect(videoElement.video.name).to.equal(name)
80 expect(videoElement.video).to.be.null
85 describe('Test video playlists', function () {
86 let servers: ServerInfo[] = []
88 let playlistServer2Id1: number
89 let playlistServer2Id2: number
90 let playlistServer2UUID2: number
92 let playlistServer1Id: number
93 let playlistServer1UUID: string
94 let playlistServer1UUID2: string
96 let playlistElementServer1Video4: number
97 let playlistElementServer1Video5: number
98 let playlistElementNSFW: number
100 let nsfwVideoServer1: number
102 let userAccessTokenServer1: string
104 before(async function () {
107 servers = await flushAndRunMultipleServers(3, { transcoding: { enabled: false } })
109 // Get the access tokens
110 await setAccessTokensToServers(servers)
111 await setDefaultVideoChannel(servers)
113 // Server 1 and server 2 follow each other
114 await doubleFollow(servers[0], servers[1])
115 // Server 1 and server 3 follow each other
116 await doubleFollow(servers[0], servers[2])
119 servers[0].videos = []
120 servers[1].videos = []
121 servers[2].videos = []
123 for (const server of servers) {
124 for (let i = 0; i < 7; i++) {
125 const name = `video ${i} server ${server.serverNumber}`
126 const resVideo = await uploadVideo(server.url, server.accessToken, { name, nsfw: false })
128 server.videos.push(resVideo.body.video)
133 nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id
138 accessToken: servers[0].accessToken,
142 userAccessTokenServer1 = await getAccessToken(servers[0].url, 'user1', 'password')
145 await waitJobs(servers)
148 describe('Get default playlists', function () {
149 it('Should list video playlist privacies', async function () {
150 const res = await getVideoPlaylistPrivacies(servers[0].url)
152 const privacies = res.body
153 expect(Object.keys(privacies)).to.have.length.at.least(3)
155 expect(privacies[3]).to.equal('Private')
158 it('Should list watch later playlist', async function () {
159 const url = servers[0].url
160 const accessToken = servers[0].accessToken
163 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
165 expect(res.body.total).to.equal(1)
166 expect(res.body.data).to.have.lengthOf(1)
168 const playlist: VideoPlaylist = res.body.data[0]
169 expect(playlist.displayName).to.equal('Watch later')
170 expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER)
171 expect(playlist.type.label).to.equal('Watch later')
175 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.REGULAR)
177 expect(res.body.total).to.equal(0)
178 expect(res.body.data).to.have.lengthOf(0)
182 const res = await getAccountPlaylistsList(url, 'root', 0, 5)
183 expect(res.body.total).to.equal(0)
184 expect(res.body.data).to.have.lengthOf(0)
188 it('Should get private playlist for a classic user', async function () {
189 const token = await generateUserAccessToken(servers[0], 'toto')
191 const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5)
193 expect(res.body.total).to.equal(1)
194 expect(res.body.data).to.have.lengthOf(1)
196 const playlistId = res.body.data[0].id
197 await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5)
201 describe('Create and federate playlists', function () {
203 it('Should create a playlist on server 1 and have the playlist on server 2 and 3', async function () {
206 await createVideoPlaylist({
208 token: servers[0].accessToken,
210 displayName: 'my super playlist',
211 privacy: VideoPlaylistPrivacy.PUBLIC,
212 description: 'my super description',
213 thumbnailfile: 'thumbnail.jpg',
214 videoChannelId: servers[0].videoChannel.id
218 await waitJobs(servers)
219 // Processing a playlist by the receiver could be long
222 for (const server of servers) {
223 const res = await getVideoPlaylistsList(server.url, 0, 5)
224 expect(res.body.total).to.equal(1)
225 expect(res.body.data).to.have.lengthOf(1)
227 const playlistFromList = res.body.data[0] as VideoPlaylist
229 const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid)
230 const playlistFromGet = res2.body as VideoPlaylist
232 for (const playlist of [ playlistFromGet, playlistFromList ]) {
233 expect(playlist.id).to.be.a('number')
234 expect(playlist.uuid).to.be.a('string')
236 expect(playlist.isLocal).to.equal(server.serverNumber === 1)
238 expect(playlist.displayName).to.equal('my super playlist')
239 expect(playlist.description).to.equal('my super description')
240 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC)
241 expect(playlist.privacy.label).to.equal('Public')
242 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
243 expect(playlist.type.label).to.equal('Regular')
244 expect(playlist.embedPath).to.equal('/video-playlists/embed/' + playlist.uuid)
246 expect(playlist.videosLength).to.equal(0)
248 expect(playlist.ownerAccount.name).to.equal('root')
249 expect(playlist.ownerAccount.displayName).to.equal('root')
250 expect(playlist.videoChannel.name).to.equal('root_channel')
251 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
256 it('Should create a playlist on server 2 and have the playlist on server 1 but not on server 3', async function () {
260 const res = await createVideoPlaylist({
262 token: servers[1].accessToken,
264 displayName: 'playlist 2',
265 privacy: VideoPlaylistPrivacy.PUBLIC,
266 videoChannelId: servers[1].videoChannel.id
269 playlistServer2Id1 = res.body.videoPlaylist.id
273 const res = await createVideoPlaylist({
275 token: servers[1].accessToken,
277 displayName: 'playlist 3',
278 privacy: VideoPlaylistPrivacy.PUBLIC,
279 thumbnailfile: 'thumbnail.jpg',
280 videoChannelId: servers[1].videoChannel.id
284 playlistServer2Id2 = res.body.videoPlaylist.id
285 playlistServer2UUID2 = res.body.videoPlaylist.uuid
288 for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) {
289 await addVideoInPlaylist({
291 token: servers[1].accessToken,
293 elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 }
295 await addVideoInPlaylist({
297 token: servers[1].accessToken,
299 elementAttrs: { videoId: servers[1].videos[1].id }
303 await waitJobs(servers)
306 for (const server of [ servers[0], servers[1] ]) {
307 const res = await getVideoPlaylistsList(server.url, 0, 5)
309 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
310 expect(playlist2).to.not.be.undefined
311 await testImage(server.url, 'thumbnail-playlist', playlist2.thumbnailPath)
313 const playlist3 = res.body.data.find(p => p.displayName === 'playlist 3')
314 expect(playlist3).to.not.be.undefined
315 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath)
318 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
319 expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined
320 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined
323 it('Should have the playlist on server 3 after a new follow', async function () {
326 // Server 2 and server 3 follow each other
327 await doubleFollow(servers[1], servers[2])
329 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
331 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
332 expect(playlist2).to.not.be.undefined
333 await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath)
335 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
339 describe('List playlists', function () {
341 it('Should correctly list the playlists', async function () {
345 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt')
347 expect(res.body.total).to.equal(3)
349 const data: VideoPlaylist[] = res.body.data
350 expect(data).to.have.lengthOf(2)
351 expect(data[0].displayName).to.equal('playlist 2')
352 expect(data[1].displayName).to.equal('playlist 3')
356 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt')
358 expect(res.body.total).to.equal(3)
360 const data: VideoPlaylist[] = res.body.data
361 expect(data).to.have.lengthOf(2)
362 expect(data[0].displayName).to.equal('playlist 2')
363 expect(data[1].displayName).to.equal('my super playlist')
367 it('Should list video channel playlists', async function () {
371 const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt')
373 expect(res.body.total).to.equal(1)
375 const data: VideoPlaylist[] = res.body.data
376 expect(data).to.have.lengthOf(1)
377 expect(data[0].displayName).to.equal('my super playlist')
381 it('Should list account playlists', async function () {
385 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt')
387 expect(res.body.total).to.equal(2)
389 const data: VideoPlaylist[] = res.body.data
390 expect(data).to.have.lengthOf(1)
391 expect(data[0].displayName).to.equal('playlist 2')
395 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt')
397 expect(res.body.total).to.equal(2)
399 const data: VideoPlaylist[] = res.body.data
400 expect(data).to.have.lengthOf(1)
401 expect(data[0].displayName).to.equal('playlist 3')
405 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3')
407 expect(res.body.total).to.equal(1)
409 const data: VideoPlaylist[] = res.body.data
410 expect(data).to.have.lengthOf(1)
411 expect(data[0].displayName).to.equal('playlist 3')
415 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4')
417 expect(res.body.total).to.equal(0)
419 const data: VideoPlaylist[] = res.body.data
420 expect(data).to.have.lengthOf(0)
425 describe('Playlist rights', function () {
426 let unlistedPlaylist: VideoPlaylistCreateResult
427 let privatePlaylist: VideoPlaylistCreateResult
429 before(async function () {
433 const res = await createVideoPlaylist({
435 token: servers[1].accessToken,
437 displayName: 'playlist unlisted',
438 privacy: VideoPlaylistPrivacy.UNLISTED,
439 videoChannelId: servers[1].videoChannel.id
442 unlistedPlaylist = res.body.videoPlaylist
446 const res = await createVideoPlaylist({
448 token: servers[1].accessToken,
450 displayName: 'playlist private',
451 privacy: VideoPlaylistPrivacy.PRIVATE
454 privatePlaylist = res.body.videoPlaylist
457 await waitJobs(servers)
461 it('Should not list unlisted or private playlists', async function () {
462 for (const server of servers) {
464 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
465 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
468 expect(results[0].body.total).to.equal(2)
469 expect(results[1].body.total).to.equal(3)
471 for (const res of results) {
472 const data: VideoPlaylist[] = res.body.data
473 expect(data).to.have.lengthOf(2)
474 expect(data[0].displayName).to.equal('playlist 3')
475 expect(data[1].displayName).to.equal('playlist 2')
480 it('Should not get unlisted playlist using only the id', async function () {
481 await getVideoPlaylist(servers[1].url, unlistedPlaylist.id, 404)
484 it('Should get unlisted plyaylist using uuid or shortUUID', async function () {
485 await getVideoPlaylist(servers[1].url, unlistedPlaylist.uuid)
486 await getVideoPlaylist(servers[1].url, unlistedPlaylist.shortUUID)
489 it('Should not get private playlist without token', async function () {
490 for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
491 await getVideoPlaylist(servers[1].url, id, 401)
495 it('Should get private playlist with a token', async function () {
496 for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
497 await getVideoPlaylistWithToken(servers[1].url, servers[1].accessToken, id)
502 describe('Update playlists', function () {
504 it('Should update a playlist', async function () {
507 await updateVideoPlaylist({
509 token: servers[1].accessToken,
511 displayName: 'playlist 3 updated',
512 description: 'description updated',
513 privacy: VideoPlaylistPrivacy.UNLISTED,
514 thumbnailfile: 'thumbnail.jpg',
515 videoChannelId: servers[1].videoChannel.id
517 playlistId: playlistServer2Id2
520 await waitJobs(servers)
522 for (const server of servers) {
523 const res = await getVideoPlaylist(server.url, playlistServer2UUID2)
524 const playlist: VideoPlaylist = res.body
526 expect(playlist.displayName).to.equal('playlist 3 updated')
527 expect(playlist.description).to.equal('description updated')
529 expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED)
530 expect(playlist.privacy.label).to.equal('Unlisted')
532 expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR)
533 expect(playlist.type.label).to.equal('Regular')
535 expect(playlist.videosLength).to.equal(2)
537 expect(playlist.ownerAccount.name).to.equal('root')
538 expect(playlist.ownerAccount.displayName).to.equal('root')
539 expect(playlist.videoChannel.name).to.equal('root_channel')
540 expect(playlist.videoChannel.displayName).to.equal('Main root channel')
545 describe('Element timestamps', function () {
547 it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () {
550 const addVideo = (elementAttrs: any) => {
551 return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs })
554 const res = await createVideoPlaylist({
556 token: servers[0].accessToken,
558 displayName: 'playlist 4',
559 privacy: VideoPlaylistPrivacy.PUBLIC,
560 videoChannelId: servers[0].videoChannel.id
564 playlistServer1Id = res.body.videoPlaylist.id
565 playlistServer1UUID = res.body.videoPlaylist.uuid
567 await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
568 await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 })
569 await addVideo({ videoId: servers[2].videos[2].uuid })
571 const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 })
572 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
576 const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 })
577 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
581 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
582 playlistElementNSFW = res.body.videoPlaylistElement.id
584 await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 4 })
585 await addVideo({ videoId: nsfwVideoServer1 })
588 await waitJobs(servers)
591 it('Should correctly list playlist videos', async function () {
594 for (const server of servers) {
595 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
597 expect(res.body.total).to.equal(8)
599 const videoElements: VideoPlaylistElement[] = res.body.data
600 expect(videoElements).to.have.lengthOf(8)
602 expect(videoElements[0].video.name).to.equal('video 0 server 1')
603 expect(videoElements[0].position).to.equal(1)
604 expect(videoElements[0].startTimestamp).to.equal(15)
605 expect(videoElements[0].stopTimestamp).to.equal(28)
607 expect(videoElements[1].video.name).to.equal('video 1 server 3')
608 expect(videoElements[1].position).to.equal(2)
609 expect(videoElements[1].startTimestamp).to.equal(35)
610 expect(videoElements[1].stopTimestamp).to.be.null
612 expect(videoElements[2].video.name).to.equal('video 2 server 3')
613 expect(videoElements[2].position).to.equal(3)
614 expect(videoElements[2].startTimestamp).to.be.null
615 expect(videoElements[2].stopTimestamp).to.be.null
617 expect(videoElements[3].video.name).to.equal('video 3 server 1')
618 expect(videoElements[3].position).to.equal(4)
619 expect(videoElements[3].startTimestamp).to.be.null
620 expect(videoElements[3].stopTimestamp).to.equal(35)
622 expect(videoElements[4].video.name).to.equal('video 4 server 1')
623 expect(videoElements[4].position).to.equal(5)
624 expect(videoElements[4].startTimestamp).to.equal(45)
625 expect(videoElements[4].stopTimestamp).to.equal(60)
627 expect(videoElements[5].video.name).to.equal('NSFW video')
628 expect(videoElements[5].position).to.equal(6)
629 expect(videoElements[5].startTimestamp).to.equal(5)
630 expect(videoElements[5].stopTimestamp).to.be.null
632 expect(videoElements[6].video.name).to.equal('NSFW video')
633 expect(videoElements[6].position).to.equal(7)
634 expect(videoElements[6].startTimestamp).to.equal(4)
635 expect(videoElements[6].stopTimestamp).to.be.null
637 expect(videoElements[7].video.name).to.equal('NSFW video')
638 expect(videoElements[7].position).to.equal(8)
639 expect(videoElements[7].startTimestamp).to.be.null
640 expect(videoElements[7].stopTimestamp).to.be.null
642 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
643 expect(res3.body.data).to.have.lengthOf(2)
648 describe('Element type', function () {
649 let groupUser1: ServerInfo[]
650 let groupWithoutToken1: ServerInfo[]
651 let group1: ServerInfo[]
652 let group2: ServerInfo[]
658 before(async function () {
661 groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ]
662 groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ]
663 group1 = [ servers[0] ]
664 group2 = [ servers[1], servers[2] ]
666 const res = await createVideoPlaylist({
668 token: userAccessTokenServer1,
670 displayName: 'playlist 56',
671 privacy: VideoPlaylistPrivacy.PUBLIC,
672 videoChannelId: servers[0].videoChannel.id
676 const playlistServer1Id2 = res.body.videoPlaylist.id
677 playlistServer1UUID2 = res.body.videoPlaylist.uuid
679 const addVideo = (elementAttrs: any) => {
680 return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
683 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
684 video2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 90' })).uuid
685 video3 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 91', nsfw: true })).uuid
687 await waitJobs(servers)
689 await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 })
690 await addVideo({ videoId: video2, startTimestamp: 35 })
691 await addVideo({ videoId: video3 })
693 await waitJobs(servers)
696 it('Should update the element type if the video is private', async function () {
699 const name = 'video 89'
703 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
704 await waitJobs(servers)
706 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
707 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
708 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3)
709 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
713 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
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, 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 video is blacklisted', async function () {
727 const name = 'video 89'
731 await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true)
732 await waitJobs(servers)
734 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
735 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
736 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
737 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
741 await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1)
742 await waitJobs(servers)
744 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
745 await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
746 await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
747 // We deleted the video (because unfederated), so even if we recreated it, the old entry is still deleted
748 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3)
752 it('Should update the element type if the account or server of the video is blocked', async function () {
755 const command = servers[0].blocklistCommand
757 const name = 'video 90'
761 await command.addToMyBlocklist({ token: userAccessTokenServer1, account: 'root@localhost:' + servers[1].port })
762 await waitJobs(servers)
764 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
765 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
767 await command.removeFromMyBlocklist({ token: userAccessTokenServer1, account: 'root@localhost:' + servers[1].port })
768 await waitJobs(servers)
770 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
774 await command.addToMyBlocklist({ token: userAccessTokenServer1, server: 'localhost:' + servers[1].port })
775 await waitJobs(servers)
777 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
778 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
780 await command.removeFromMyBlocklist({ token: userAccessTokenServer1, server: 'localhost:' + servers[1].port })
781 await waitJobs(servers)
783 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
787 await command.addToServerBlocklist({ account: 'root@localhost:' + servers[1].port })
788 await waitJobs(servers)
790 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
791 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
793 await command.removeFromServerBlocklist({ account: 'root@localhost:' + servers[1].port })
794 await waitJobs(servers)
796 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
800 await command.addToServerBlocklist({ server: 'localhost:' + servers[1].port })
801 await waitJobs(servers)
803 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
804 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
806 await command.removeFromServerBlocklist({ server: 'localhost:' + servers[1].port })
807 await waitJobs(servers)
809 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
813 it('Should hide the video if it is NSFW', async function () {
814 const res = await getPlaylistVideos(servers[0].url, userAccessTokenServer1, playlistServer1UUID2, 0, 10, { nsfw: false })
815 expect(res.body.total).to.equal(3)
817 const elements: VideoPlaylistElement[] = res.body.data
818 const element = elements.find(e => e.position === 3)
820 expect(element).to.exist
821 expect(element.video).to.be.null
822 expect(element.type).to.equal(VideoPlaylistElementType.UNAVAILABLE)
827 describe('Managing playlist elements', function () {
829 it('Should reorder the playlist', async function () {
833 await reorderVideosPlaylist({
835 token: servers[0].accessToken,
836 playlistId: playlistServer1Id,
839 insertAfterPosition: 3
843 await waitJobs(servers)
845 for (const server of servers) {
846 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
847 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
849 expect(names).to.deep.equal([
863 await reorderVideosPlaylist({
865 token: servers[0].accessToken,
866 playlistId: playlistServer1Id,
870 insertAfterPosition: 4
874 await waitJobs(servers)
876 for (const server of servers) {
877 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
878 const names = (res.body.data as VideoPlaylistElement[]).map(v => v.video.name)
880 expect(names).to.deep.equal([
894 await reorderVideosPlaylist({
896 token: servers[0].accessToken,
897 playlistId: playlistServer1Id,
900 insertAfterPosition: 3
904 await waitJobs(servers)
906 for (const server of servers) {
907 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
908 const elements: VideoPlaylistElement[] = res.body.data
909 const names = elements.map(v => v.video.name)
911 expect(names).to.deep.equal([
922 for (let i = 1; i <= elements.length; i++) {
923 expect(elements[i - 1].position).to.equal(i)
929 it('Should update startTimestamp/endTimestamp of some elements', async function () {
932 await updateVideoPlaylistElement({
934 token: servers[0].accessToken,
935 playlistId: playlistServer1Id,
936 playlistElementId: playlistElementServer1Video4,
942 await updateVideoPlaylistElement({
944 token: servers[0].accessToken,
945 playlistId: playlistServer1Id,
946 playlistElementId: playlistElementServer1Video5,
952 await waitJobs(servers)
954 for (const server of servers) {
955 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
956 const elements: VideoPlaylistElement[] = res.body.data
958 expect(elements[0].video.name).to.equal('video 3 server 1')
959 expect(elements[0].position).to.equal(1)
960 expect(elements[0].startTimestamp).to.equal(1)
961 expect(elements[0].stopTimestamp).to.equal(35)
963 expect(elements[5].video.name).to.equal('video 4 server 1')
964 expect(elements[5].position).to.equal(6)
965 expect(elements[5].startTimestamp).to.equal(45)
966 expect(elements[5].stopTimestamp).to.be.null
970 it('Should check videos existence in my playlist', async function () {
972 servers[0].videos[0].id,
974 servers[0].videos[3].id,
976 servers[0].videos[4].id
978 const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds)
979 const obj = res.body as VideoExistInPlaylist
982 const elem = obj[servers[0].videos[0].id]
983 expect(elem).to.have.lengthOf(1)
984 expect(elem[0].playlistElementId).to.exist
985 expect(elem[0].playlistId).to.equal(playlistServer1Id)
986 expect(elem[0].startTimestamp).to.equal(15)
987 expect(elem[0].stopTimestamp).to.equal(28)
991 const elem = obj[servers[0].videos[3].id]
992 expect(elem).to.have.lengthOf(1)
993 expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
994 expect(elem[0].playlistId).to.equal(playlistServer1Id)
995 expect(elem[0].startTimestamp).to.equal(1)
996 expect(elem[0].stopTimestamp).to.equal(35)
1000 const elem = obj[servers[0].videos[4].id]
1001 expect(elem).to.have.lengthOf(1)
1002 expect(elem[0].playlistId).to.equal(playlistServer1Id)
1003 expect(elem[0].startTimestamp).to.equal(45)
1004 expect(elem[0].stopTimestamp).to.equal(null)
1007 expect(obj[42000]).to.have.lengthOf(0)
1008 expect(obj[43000]).to.have.lengthOf(0)
1011 it('Should automatically update updatedAt field of playlists', async function () {
1012 const server = servers[1]
1013 const videoId = servers[1].videos[5].id
1015 async function getPlaylistNames () {
1016 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
1018 return (res.body.data as VideoPlaylist[]).map(p => p.displayName)
1021 const elementAttrs = { videoId }
1022 const res1 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id1, elementAttrs })
1023 const res2 = await addVideoInPlaylist({ url: server.url, token: server.accessToken, playlistId: playlistServer2Id2, elementAttrs })
1025 const element1 = res1.body.videoPlaylistElement.id
1026 const element2 = res2.body.videoPlaylistElement.id
1028 const names1 = await getPlaylistNames()
1029 expect(names1[0]).to.equal('playlist 3 updated')
1030 expect(names1[1]).to.equal('playlist 2')
1032 await removeVideoFromPlaylist({
1034 token: server.accessToken,
1035 playlistId: playlistServer2Id1,
1036 playlistElementId: element1
1039 const names2 = await getPlaylistNames()
1040 expect(names2[0]).to.equal('playlist 2')
1041 expect(names2[1]).to.equal('playlist 3 updated')
1043 await removeVideoFromPlaylist({
1045 token: server.accessToken,
1046 playlistId: playlistServer2Id2,
1047 playlistElementId: element2
1050 const names3 = await getPlaylistNames()
1051 expect(names3[0]).to.equal('playlist 3 updated')
1052 expect(names3[1]).to.equal('playlist 2')
1055 it('Should delete some elements', async function () {
1058 await removeVideoFromPlaylist({
1059 url: servers[0].url,
1060 token: servers[0].accessToken,
1061 playlistId: playlistServer1Id,
1062 playlistElementId: playlistElementServer1Video4
1065 await removeVideoFromPlaylist({
1066 url: servers[0].url,
1067 token: servers[0].accessToken,
1068 playlistId: playlistServer1Id,
1069 playlistElementId: playlistElementNSFW
1072 await waitJobs(servers)
1074 for (const server of servers) {
1075 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1077 expect(res.body.total).to.equal(6)
1079 const elements: VideoPlaylistElement[] = res.body.data
1080 expect(elements).to.have.lengthOf(6)
1082 expect(elements[0].video.name).to.equal('video 0 server 1')
1083 expect(elements[0].position).to.equal(1)
1085 expect(elements[1].video.name).to.equal('video 2 server 3')
1086 expect(elements[1].position).to.equal(2)
1088 expect(elements[2].video.name).to.equal('video 1 server 3')
1089 expect(elements[2].position).to.equal(3)
1091 expect(elements[3].video.name).to.equal('video 4 server 1')
1092 expect(elements[3].position).to.equal(4)
1094 expect(elements[4].video.name).to.equal('NSFW video')
1095 expect(elements[4].position).to.equal(5)
1097 expect(elements[5].video.name).to.equal('NSFW video')
1098 expect(elements[5].position).to.equal(6)
1102 it('Should be able to create a public playlist, and set it to private', async function () {
1105 const res = await createVideoPlaylist({
1106 url: servers[0].url,
1107 token: servers[0].accessToken,
1109 displayName: 'my super public playlist',
1110 privacy: VideoPlaylistPrivacy.PUBLIC,
1111 videoChannelId: servers[0].videoChannel.id
1114 const videoPlaylistIds = res.body.videoPlaylist
1116 await waitJobs(servers)
1118 for (const server of servers) {
1119 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, HttpStatusCode.OK_200)
1122 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1123 await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1125 await waitJobs(servers)
1127 for (const server of [ servers[1], servers[2] ]) {
1128 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, HttpStatusCode.NOT_FOUND_404)
1130 await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, HttpStatusCode.UNAUTHORIZED_401)
1132 await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, HttpStatusCode.OK_200)
1136 describe('Playlist deletion', function () {
1138 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1141 await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id)
1143 await waitJobs(servers)
1145 for (const server of servers) {
1146 await getVideoPlaylist(server.url, playlistServer1UUID, HttpStatusCode.NOT_FOUND_404)
1150 it('Should have deleted the thumbnail on server 1, 2 and 3', async function () {
1153 for (const server of servers) {
1154 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
1158 it('Should unfollow servers 1 and 2 and hide their playlists', async function () {
1161 const finder = data => data.find(p => p.displayName === 'my super playlist')
1164 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1165 expect(res.body.total).to.equal(3)
1166 expect(finder(res.body.data)).to.not.be.undefined
1169 await servers[2].followsCommand.unfollow({ target: servers[0] })
1172 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1173 expect(res.body.total).to.equal(1)
1175 expect(finder(res.body.data)).to.be.undefined
1179 it('Should delete a channel and put the associated playlist in private mode', async function () {
1182 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' })
1183 const videoChannelId = res.body.videoChannel.id
1185 const res2 = await createVideoPlaylist({
1186 url: servers[0].url,
1187 token: servers[0].accessToken,
1189 displayName: 'channel playlist',
1190 privacy: VideoPlaylistPrivacy.PUBLIC,
1194 const videoPlaylistUUID = res2.body.videoPlaylist.uuid
1196 await waitJobs(servers)
1198 await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel')
1200 await waitJobs(servers)
1202 const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID)
1203 expect(res3.body.displayName).to.equal('channel playlist')
1204 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
1206 await getVideoPlaylist(servers[1].url, videoPlaylistUUID, HttpStatusCode.NOT_FOUND_404)
1209 it('Should delete an account and delete its playlists', async function () {
1212 const user = { username: 'user_1', password: 'password' }
1213 const res = await createUser({
1214 url: servers[0].url,
1215 accessToken: servers[0].accessToken,
1216 username: user.username,
1217 password: user.password
1220 const userId = res.body.user.id
1221 const userAccessToken = await userLogin(servers[0], user)
1223 const resChannel = await getMyUserInformation(servers[0].url, userAccessToken)
1224 const userChannel = (resChannel.body as User).videoChannels[0]
1226 await createVideoPlaylist({
1227 url: servers[0].url,
1228 token: userAccessToken,
1230 displayName: 'playlist to be deleted',
1231 privacy: VideoPlaylistPrivacy.PUBLIC,
1232 videoChannelId: userChannel.id
1236 await waitJobs(servers)
1238 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
1241 for (const server of [ servers[0], servers[1] ]) {
1242 const res = await getVideoPlaylistsList(server.url, 0, 15)
1243 expect(finder(res.body.data)).to.not.be.undefined
1247 await removeUser(servers[0].url, userId, servers[0].accessToken)
1248 await waitJobs(servers)
1251 for (const server of [ servers[0], servers[1] ]) {
1252 const res = await getVideoPlaylistsList(server.url, 0, 15)
1253 expect(finder(res.body.data)).to.be.undefined
1259 after(async function () {
1260 await cleanupTests(servers)