]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/videos-common-filters.ts
Add ability to filter by file type
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / videos-common-filters.ts
CommitLineData
2760b454
C
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import { expect } from 'chai'
5import { pick } from '@shared/core-utils'
6import {
7 cleanupTests,
8 createMultipleServers,
9 doubleFollow,
10 makeGetRequest,
11 PeerTubeServer,
12 setAccessTokensToServers,
13 setDefaultVideoChannel,
14 waitJobs
15} from '@shared/extra-utils'
3c10840f 16import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models'
2760b454
C
17
18describe('Test videos filter', function () {
19 let servers: PeerTubeServer[]
20 let paths: string[]
21 let remotePaths: string[]
22
23 // ---------------------------------------------------------------
24
25 before(async function () {
26 this.timeout(160000)
27
28 servers = await createMultipleServers(2)
29
30 await setAccessTokensToServers(servers)
31 await setDefaultVideoChannel(servers)
32
33 for (const server of servers) {
34 const moderator = { username: 'moderator', password: 'my super password' }
35 await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR })
36 server['moderatorAccessToken'] = await server.login.getAccessToken(moderator)
37
38 await server.videos.upload({ attributes: { name: 'public ' + server.serverNumber } })
39
40 {
41 const attributes = { name: 'unlisted ' + server.serverNumber, privacy: VideoPrivacy.UNLISTED }
42 await server.videos.upload({ attributes })
43 }
44
45 {
46 const attributes = { name: 'private ' + server.serverNumber, privacy: VideoPrivacy.PRIVATE }
47 await server.videos.upload({ attributes })
48 }
49 }
50
51 await doubleFollow(servers[0], servers[1])
52
53 paths = [
54 `/api/v1/video-channels/root_channel/videos`,
55 `/api/v1/accounts/root/videos`,
56 '/api/v1/videos',
57 '/api/v1/search/videos'
58 ]
59
60 remotePaths = [
61 `/api/v1/video-channels/root_channel@${servers[1].host}/videos`,
62 `/api/v1/accounts/root@${servers[1].host}/videos`,
63 '/api/v1/videos',
64 '/api/v1/search/videos'
65 ]
66 })
67
68 describe('Check deprecated videos filter', function () {
69
70 async function getVideosNames (server: PeerTubeServer, token: string, filter: string, expectedStatus = HttpStatusCode.OK_200) {
71 const videosResults: Video[][] = []
72
73 for (const path of paths) {
74 const res = await makeGetRequest({
75 url: server.url,
76 path,
77 token,
78 query: {
79 sort: 'createdAt',
80 filter
81 },
82 expectedStatus
83 })
84
85 videosResults.push(res.body.data.map(v => v.name))
86 }
87
88 return videosResults
89 }
90
91 it('Should display local videos', async function () {
92 for (const server of servers) {
93 const namesResults = await getVideosNames(server, server.accessToken, 'local')
94 for (const names of namesResults) {
95 expect(names).to.have.lengthOf(1)
96 expect(names[0]).to.equal('public ' + server.serverNumber)
97 }
98 }
99 })
100
101 it('Should display all local videos by the admin or the moderator', async function () {
102 for (const server of servers) {
103 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
104
105 const namesResults = await getVideosNames(server, token, 'all-local')
106 for (const names of namesResults) {
107 expect(names).to.have.lengthOf(3)
108
109 expect(names[0]).to.equal('public ' + server.serverNumber)
110 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
111 expect(names[2]).to.equal('private ' + server.serverNumber)
112 }
113 }
114 }
115 })
116
117 it('Should display all videos by the admin or the moderator', async function () {
118 for (const server of servers) {
119 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
120
121 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames(server, token, 'all')
122 expect(channelVideos).to.have.lengthOf(3)
123 expect(accountVideos).to.have.lengthOf(3)
124
125 expect(videos).to.have.lengthOf(5)
126 expect(searchVideos).to.have.lengthOf(5)
127 }
128 }
129 })
130 })
131
132 describe('Check videos filters', function () {
133
134 async function listVideos (options: {
135 server: PeerTubeServer
136 path: string
137 isLocal?: boolean
d324756e
C
138 hasWebtorrentFiles?: boolean
139 hasHLSFiles?: boolean
2760b454
C
140 include?: VideoInclude
141 category?: number
142 tagsAllOf?: string[]
143 token?: string
144 expectedStatus?: HttpStatusCode
145 }) {
146 const res = await makeGetRequest({
147 url: options.server.url,
148 path: options.path,
149 token: options.token ?? options.server.accessToken,
150 query: {
d324756e 151 ...pick(options, [ 'isLocal', 'include', 'category', 'tagsAllOf', 'hasWebtorrentFiles', 'hasHLSFiles' ]),
2760b454
C
152
153 sort: 'createdAt'
154 },
155 expectedStatus: options.expectedStatus ?? HttpStatusCode.OK_200
156 })
157
158 return res.body.data as Video[]
159 }
160
161 async function getVideosNames (options: {
162 server: PeerTubeServer
163 isLocal?: boolean
164 include?: VideoInclude
165 token?: string
166 expectedStatus?: HttpStatusCode
167 }) {
168 const videosResults: string[][] = []
169
170 for (const path of paths) {
171 const videos = await listVideos({ ...options, path })
172
173 videosResults.push(videos.map(v => v.name))
174 }
175
176 return videosResults
177 }
178
179 it('Should display local videos', async function () {
180 for (const server of servers) {
181 const namesResults = await getVideosNames({ server, isLocal: true })
182
183 for (const names of namesResults) {
184 expect(names).to.have.lengthOf(1)
185 expect(names[0]).to.equal('public ' + server.serverNumber)
186 }
187 }
188 })
189
190 it('Should display local videos with hidden privacy by the admin or the moderator', async function () {
191 for (const server of servers) {
192 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
193
194 const namesResults = await getVideosNames({
195 server,
196 token,
197 isLocal: true,
198 include: VideoInclude.HIDDEN_PRIVACY
199 })
200
201 for (const names of namesResults) {
202 expect(names).to.have.lengthOf(3)
203
204 expect(names[0]).to.equal('public ' + server.serverNumber)
205 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
206 expect(names[2]).to.equal('private ' + server.serverNumber)
207 }
208 }
209 }
210 })
211
212 it('Should display all videos by the admin or the moderator', async function () {
213 for (const server of servers) {
214 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
215
216 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames({
217 server,
218 token,
219 include: VideoInclude.HIDDEN_PRIVACY
220 })
221
222 expect(channelVideos).to.have.lengthOf(3)
223 expect(accountVideos).to.have.lengthOf(3)
224
225 expect(videos).to.have.lengthOf(5)
226 expect(searchVideos).to.have.lengthOf(5)
227 }
228 }
229 })
230
231 it('Should display only remote videos', async function () {
232 this.timeout(40000)
233
234 await servers[1].videos.upload({ attributes: { name: 'remote video' } })
235
236 await waitJobs(servers)
237
238 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
239
240 for (const path of remotePaths) {
241 {
242 const videos = await listVideos({ server: servers[0], path })
243 const video = finder(videos)
244 expect(video).to.exist
245 }
246
247 {
248 const videos = await listVideos({ server: servers[0], path, isLocal: false })
249 const video = finder(videos)
250 expect(video).to.exist
251 }
252
253 {
254 const videos = await listVideos({ server: servers[0], path, isLocal: true })
255 const video = finder(videos)
256 expect(video).to.not.exist
257 }
258 }
259 })
260
261 it('Should include not published videos', async function () {
262 await servers[0].config.enableLive({ allowReplay: false, transcoding: false })
263 await servers[0].live.create({ fields: { name: 'live video', channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC } })
264
265 const finder = (videos: Video[]) => videos.find(v => v.name === 'live video')
266
267 for (const path of paths) {
268 {
269 const videos = await listVideos({ server: servers[0], path })
270 const video = finder(videos)
271 expect(video).to.not.exist
272 expect(videos[0].state).to.not.exist
273 expect(videos[0].waitTranscoding).to.not.exist
274 }
275
276 {
277 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.NOT_PUBLISHED_STATE })
278 const video = finder(videos)
279 expect(video).to.exist
280 expect(video.state).to.exist
281 }
282 }
283 })
284
285 it('Should include blacklisted videos', async function () {
286 const { id } = await servers[0].videos.upload({ attributes: { name: 'blacklisted' } })
287
288 await servers[0].blacklist.add({ videoId: id })
289
290 const finder = (videos: Video[]) => videos.find(v => v.name === 'blacklisted')
291
292 for (const path of paths) {
293 {
294 const videos = await listVideos({ server: servers[0], path })
295 const video = finder(videos)
296 expect(video).to.not.exist
297 expect(videos[0].blacklisted).to.not.exist
298 }
299
300 {
301 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLACKLISTED })
302 const video = finder(videos)
303 expect(video).to.exist
304 expect(video.blacklisted).to.be.true
305 }
306 }
307 })
308
309 it('Should include videos from muted account', async function () {
310 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
311
312 await servers[0].blocklist.addToServerBlocklist({ account: 'root@' + servers[1].host })
313
314 for (const path of remotePaths) {
315 {
316 const videos = await listVideos({ server: servers[0], path })
317 const video = finder(videos)
318 expect(video).to.not.exist
319
320 // Some paths won't have videos
321 if (videos[0]) {
322 expect(videos[0].blockedOwner).to.not.exist
323 expect(videos[0].blockedServer).to.not.exist
324 }
325 }
326
327 {
328 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER })
329
330 const video = finder(videos)
331 expect(video).to.exist
332 expect(video.blockedServer).to.be.false
333 expect(video.blockedOwner).to.be.true
334 }
335 }
336
337 await servers[0].blocklist.removeFromServerBlocklist({ account: 'root@' + servers[1].host })
338 })
339
340 it('Should include videos from muted server', async function () {
341 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
342
343 await servers[0].blocklist.addToServerBlocklist({ server: servers[1].host })
344
345 for (const path of remotePaths) {
346 {
347 const videos = await listVideos({ server: servers[0], path })
348 const video = finder(videos)
349 expect(video).to.not.exist
350
351 // Some paths won't have videos
352 if (videos[0]) {
353 expect(videos[0].blockedOwner).to.not.exist
354 expect(videos[0].blockedServer).to.not.exist
355 }
356 }
357
358 {
359 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER })
360 const video = finder(videos)
361 expect(video).to.exist
362 expect(video.blockedServer).to.be.true
363 expect(video.blockedOwner).to.be.false
364 }
365 }
366
367 await servers[0].blocklist.removeFromServerBlocklist({ server: servers[1].host })
368 })
369
3c10840f
C
370 it('Should include video files', async function () {
371 for (const path of paths) {
372 {
373 const videos = await listVideos({ server: servers[0], path })
374
375 for (const video of videos) {
376 const videoWithFiles = video as VideoDetails
377
378 expect(videoWithFiles.files).to.not.exist
379 expect(videoWithFiles.streamingPlaylists).to.not.exist
380 }
381 }
382
383 {
384 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.FILES })
385
386 for (const video of videos) {
387 const videoWithFiles = video as VideoDetails
388
389 expect(videoWithFiles.files).to.exist
390 expect(videoWithFiles.files).to.have.length.at.least(1)
391 }
392 }
393 }
394 })
395
2760b454
C
396 it('Should filter by tags and category', async function () {
397 await servers[0].videos.upload({ attributes: { name: 'tag filter', tags: [ 'tag1', 'tag2' ] } })
398 await servers[0].videos.upload({ attributes: { name: 'tag filter with category', tags: [ 'tag3' ], category: 4 } })
399
400 for (const path of paths) {
401 {
2760b454
C
402 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] })
403 expect(videos).to.have.lengthOf(1)
404 expect(videos[0].name).to.equal('tag filter')
2760b454
C
405 }
406
407 {
408 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag3' ] })
409 expect(videos).to.have.lengthOf(0)
410 }
411
412 {
413 const { data, total } = await servers[0].videos.list({ tagsAllOf: [ 'tag3' ], categoryOneOf: [ 4 ] })
414 expect(total).to.equal(1)
415 expect(data[0].name).to.equal('tag filter with category')
416 }
417
418 {
419 const { total } = await servers[0].videos.list({ tagsAllOf: [ 'tag4' ], categoryOneOf: [ 4 ] })
420 expect(total).to.equal(0)
421 }
422 }
423 })
d324756e
C
424
425 it('Should filter by HLS or WebTorrent files', async function () {
426 this.timeout(360000)
427
428 const finderFactory = (name: string) => (videos: Video[]) => videos.some(v => v.name === name)
429
430 await servers[0].config.enableTranscoding(true, false)
431 await servers[0].videos.upload({ attributes: { name: 'webtorrent video' } })
432 const hasWebtorrent = finderFactory('webtorrent video')
433
434 await waitJobs(servers)
435
436 await servers[0].config.enableTranscoding(false, true)
437 await servers[0].videos.upload({ attributes: { name: 'hls video' } })
438 const hasHLS = finderFactory('hls video')
439
440 await waitJobs(servers)
441
442 await servers[0].config.enableTranscoding(true, true)
443 await servers[0].videos.upload({ attributes: { name: 'hls and webtorrent video' } })
444 const hasBoth = finderFactory('hls and webtorrent video')
445
446 await waitJobs(servers)
447
448 for (const path of paths) {
449 {
450 const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: true })
451
452 expect(hasWebtorrent(videos)).to.be.true
453 expect(hasHLS(videos)).to.be.false
454 expect(hasBoth(videos)).to.be.true
455 }
456
457 {
458 const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: false })
459
460 expect(hasWebtorrent(videos)).to.be.false
461 expect(hasHLS(videos)).to.be.true
462 expect(hasBoth(videos)).to.be.false
463 }
464
465 {
466 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true })
467
468 expect(hasWebtorrent(videos)).to.be.false
469 expect(hasHLS(videos)).to.be.true
470 expect(hasBoth(videos)).to.be.true
471 }
472
473 {
474 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false })
475
476 expect(hasWebtorrent(videos)).to.be.true
477 expect(hasHLS(videos)).to.be.false
478 expect(hasBoth(videos)).to.be.false
479 }
480
481 {
482 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false, hasWebtorrentFiles: false })
483
484 expect(hasWebtorrent(videos)).to.be.false
485 expect(hasHLS(videos)).to.be.false
486 expect(hasBoth(videos)).to.be.false
487 }
488
489 {
490 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true, hasWebtorrentFiles: true })
491
492 expect(hasWebtorrent(videos)).to.be.false
493 expect(hasHLS(videos)).to.be.false
494 expect(hasBoth(videos)).to.be.true
495 }
496 }
497 })
2760b454
C
498 })
499
500 after(async function () {
501 await cleanupTests(servers)
502 })
503})