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