]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/search/search-videos.ts
ff4c3c161897699469134979f00aec247f058d95
[github/Chocobozzz/PeerTube.git] / server / tests / api / search / search-videos.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import 'mocha'
4 import * as chai from 'chai'
5 import { wait } from '@shared/core-utils'
6 import { VideoPrivacy } from '@shared/models'
7 import {
8 cleanupTests,
9 createSingleServer,
10 doubleFollow,
11 PeerTubeServer,
12 SearchCommand,
13 setAccessTokensToServers,
14 setDefaultAccountAvatar,
15 setDefaultChannelAvatar,
16 setDefaultVideoChannel,
17 stopFfmpeg
18 } from '@shared/server-commands'
19
20 const expect = chai.expect
21
22 describe('Test videos search', function () {
23 let server: PeerTubeServer
24 let remoteServer: PeerTubeServer
25 let startDate: string
26 let videoUUID: string
27 let videoShortUUID: string
28
29 let command: SearchCommand
30
31 before(async function () {
32 this.timeout(240000)
33
34 const servers = await Promise.all([
35 createSingleServer(1),
36 createSingleServer(2)
37 ])
38 server = servers[0]
39 remoteServer = servers[1]
40
41 await setAccessTokensToServers([ server, remoteServer ])
42 await setDefaultVideoChannel([ server, remoteServer ])
43 await setDefaultChannelAvatar(server)
44 await setDefaultAccountAvatar(servers)
45
46 {
47 const attributes1 = {
48 name: '1111 2222 3333',
49 fixture: '60fps_720p_small.mp4', // 2 seconds
50 category: 1,
51 licence: 1,
52 nsfw: false,
53 language: 'fr'
54 }
55 await server.videos.upload({ attributes: attributes1 })
56
57 const attributes2 = { ...attributes1, name: attributes1.name + ' - 2', fixture: 'video_short.mp4' }
58 await server.videos.upload({ attributes: attributes2 })
59
60 {
61 const attributes3 = { ...attributes1, name: attributes1.name + ' - 3', language: undefined }
62 const { id, uuid, shortUUID } = await server.videos.upload({ attributes: attributes3 })
63 videoUUID = uuid
64 videoShortUUID = shortUUID
65
66 await server.captions.add({
67 language: 'en',
68 videoId: id,
69 fixture: 'subtitle-good2.vtt',
70 mimeType: 'application/octet-stream'
71 })
72
73 await server.captions.add({
74 language: 'aa',
75 videoId: id,
76 fixture: 'subtitle-good2.vtt',
77 mimeType: 'application/octet-stream'
78 })
79 }
80
81 const attributes4 = { ...attributes1, name: attributes1.name + ' - 4', language: 'pl', nsfw: true }
82 await server.videos.upload({ attributes: attributes4 })
83
84 await wait(1000)
85
86 startDate = new Date().toISOString()
87
88 const attributes5 = { ...attributes1, name: attributes1.name + ' - 5', licence: 2, language: undefined }
89 await server.videos.upload({ attributes: attributes5 })
90
91 const attributes6 = { ...attributes1, name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] }
92 await server.videos.upload({ attributes: attributes6 })
93
94 const attributes7 = { ...attributes1, name: attributes1.name + ' - 7', originallyPublishedAt: '2019-02-12T09:58:08.286Z' }
95 await server.videos.upload({ attributes: attributes7 })
96
97 const attributes8 = { ...attributes1, name: attributes1.name + ' - 8', licence: 4 }
98 await server.videos.upload({ attributes: attributes8 })
99 }
100
101 {
102 const attributes = {
103 name: '3333 4444 5555',
104 fixture: 'video_short.mp4',
105 category: 2,
106 licence: 2,
107 language: 'en'
108 }
109 await server.videos.upload({ attributes: attributes })
110
111 await server.videos.upload({ attributes: { ...attributes, name: attributes.name + ' duplicate' } })
112 }
113
114 {
115 const attributes = {
116 name: '6666 7777 8888',
117 fixture: 'video_short.mp4',
118 category: 3,
119 licence: 3,
120 language: 'pl'
121 }
122 await server.videos.upload({ attributes: attributes })
123 }
124
125 {
126 const attributes1 = {
127 name: '9999',
128 tags: [ 'aaaa', 'bbbb', 'cccc' ],
129 category: 1
130 }
131 await server.videos.upload({ attributes: attributes1 })
132 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
133
134 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'cccc', 'dddd' ] } })
135 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'eeee', 'ffff' ] } })
136 }
137
138 {
139 const attributes1 = {
140 name: 'aaaa 2',
141 category: 1
142 }
143 await server.videos.upload({ attributes: attributes1 })
144 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
145 }
146
147 {
148 await remoteServer.videos.upload({ attributes: { name: 'remote video 1' } })
149 await remoteServer.videos.upload({ attributes: { name: 'remote video 2' } })
150 }
151
152 await doubleFollow(server, remoteServer)
153
154 command = server.search
155 })
156
157 it('Should make a simple search and not have results', async function () {
158 const body = await command.searchVideos({ search: 'abc' })
159
160 expect(body.total).to.equal(0)
161 expect(body.data).to.have.lengthOf(0)
162 })
163
164 it('Should make a simple search and have results', async function () {
165 const body = await command.searchVideos({ search: '4444 5555 duplicate' })
166
167 expect(body.total).to.equal(2)
168
169 const videos = body.data
170 expect(videos).to.have.lengthOf(2)
171
172 // bestmatch
173 expect(videos[0].name).to.equal('3333 4444 5555 duplicate')
174 expect(videos[1].name).to.equal('3333 4444 5555')
175 })
176
177 it('Should make a search on tags too, and have results', async function () {
178 const search = {
179 search: 'aaaa',
180 categoryOneOf: [ 1 ]
181 }
182 const body = await command.advancedVideoSearch({ search })
183
184 expect(body.total).to.equal(2)
185
186 const videos = body.data
187 expect(videos).to.have.lengthOf(2)
188
189 // bestmatch
190 expect(videos[0].name).to.equal('aaaa 2')
191 expect(videos[1].name).to.equal('9999')
192 })
193
194 it('Should filter on tags without a search', async function () {
195 const search = {
196 tagsAllOf: [ 'bbbb' ]
197 }
198 const body = await command.advancedVideoSearch({ search })
199
200 expect(body.total).to.equal(2)
201
202 const videos = body.data
203 expect(videos).to.have.lengthOf(2)
204
205 expect(videos[0].name).to.equal('9999')
206 expect(videos[1].name).to.equal('9999')
207 })
208
209 it('Should filter on category without a search', async function () {
210 const search = {
211 categoryOneOf: [ 3 ]
212 }
213 const body = await command.advancedVideoSearch({ search: search })
214
215 expect(body.total).to.equal(1)
216
217 const videos = body.data
218 expect(videos).to.have.lengthOf(1)
219
220 expect(videos[0].name).to.equal('6666 7777 8888')
221 })
222
223 it('Should search by tags (one of)', async function () {
224 const query = {
225 search: '9999',
226 categoryOneOf: [ 1 ],
227 tagsOneOf: [ 'aAaa', 'ffff' ]
228 }
229
230 {
231 const body = await command.advancedVideoSearch({ search: query })
232 expect(body.total).to.equal(2)
233 }
234
235 {
236 const body = await command.advancedVideoSearch({ search: { ...query, tagsOneOf: [ 'blabla' ] } })
237 expect(body.total).to.equal(0)
238 }
239 })
240
241 it('Should search by tags (all of)', async function () {
242 const query = {
243 search: '9999',
244 categoryOneOf: [ 1 ],
245 tagsAllOf: [ 'CCcc' ]
246 }
247
248 {
249 const body = await command.advancedVideoSearch({ search: query })
250 expect(body.total).to.equal(2)
251 }
252
253 {
254 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'blAbla' ] } })
255 expect(body.total).to.equal(0)
256 }
257
258 {
259 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'bbbb', 'CCCC' ] } })
260 expect(body.total).to.equal(1)
261 }
262 })
263
264 it('Should search by category', async function () {
265 const query = {
266 search: '6666',
267 categoryOneOf: [ 3 ]
268 }
269
270 {
271 const body = await command.advancedVideoSearch({ search: query })
272 expect(body.total).to.equal(1)
273 expect(body.data[0].name).to.equal('6666 7777 8888')
274 }
275
276 {
277 const body = await command.advancedVideoSearch({ search: { ...query, categoryOneOf: [ 2 ] } })
278 expect(body.total).to.equal(0)
279 }
280 })
281
282 it('Should search by licence', async function () {
283 const query = {
284 search: '4444 5555',
285 licenceOneOf: [ 2 ]
286 }
287
288 {
289 const body = await command.advancedVideoSearch({ search: query })
290 expect(body.total).to.equal(2)
291 expect(body.data[0].name).to.equal('3333 4444 5555')
292 expect(body.data[1].name).to.equal('3333 4444 5555 duplicate')
293 }
294
295 {
296 const body = await command.advancedVideoSearch({ search: { ...query, licenceOneOf: [ 3 ] } })
297 expect(body.total).to.equal(0)
298 }
299 })
300
301 it('Should search by languages', async function () {
302 const query = {
303 search: '1111 2222 3333',
304 languageOneOf: [ 'pl', 'en' ]
305 }
306
307 {
308 const body = await command.advancedVideoSearch({ search: query })
309 expect(body.total).to.equal(2)
310 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
311 expect(body.data[1].name).to.equal('1111 2222 3333 - 4')
312 }
313
314 {
315 const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'pl', 'en', '_unknown' ] } })
316 expect(body.total).to.equal(3)
317 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
318 expect(body.data[1].name).to.equal('1111 2222 3333 - 4')
319 expect(body.data[2].name).to.equal('1111 2222 3333 - 5')
320 }
321
322 {
323 const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'eo' ] } })
324 expect(body.total).to.equal(0)
325 }
326 })
327
328 it('Should search by start date', async function () {
329 const query = {
330 search: '1111 2222 3333',
331 startDate
332 }
333
334 const body = await command.advancedVideoSearch({ search: query })
335 expect(body.total).to.equal(4)
336
337 const videos = body.data
338 expect(videos[0].name).to.equal('1111 2222 3333 - 5')
339 expect(videos[1].name).to.equal('1111 2222 3333 - 6')
340 expect(videos[2].name).to.equal('1111 2222 3333 - 7')
341 expect(videos[3].name).to.equal('1111 2222 3333 - 8')
342 })
343
344 it('Should make an advanced search', async function () {
345 const query = {
346 search: '1111 2222 3333',
347 languageOneOf: [ 'pl', 'fr' ],
348 durationMax: 4,
349 nsfw: 'false' as 'false',
350 licenceOneOf: [ 1, 4 ]
351 }
352
353 const body = await command.advancedVideoSearch({ search: query })
354 expect(body.total).to.equal(4)
355
356 const videos = body.data
357 expect(videos[0].name).to.equal('1111 2222 3333')
358 expect(videos[1].name).to.equal('1111 2222 3333 - 6')
359 expect(videos[2].name).to.equal('1111 2222 3333 - 7')
360 expect(videos[3].name).to.equal('1111 2222 3333 - 8')
361 })
362
363 it('Should make an advanced search and sort results', async function () {
364 const query = {
365 search: '1111 2222 3333',
366 languageOneOf: [ 'pl', 'fr' ],
367 durationMax: 4,
368 nsfw: 'false' as 'false',
369 licenceOneOf: [ 1, 4 ],
370 sort: '-name'
371 }
372
373 const body = await command.advancedVideoSearch({ search: query })
374 expect(body.total).to.equal(4)
375
376 const videos = body.data
377 expect(videos[0].name).to.equal('1111 2222 3333 - 8')
378 expect(videos[1].name).to.equal('1111 2222 3333 - 7')
379 expect(videos[2].name).to.equal('1111 2222 3333 - 6')
380 expect(videos[3].name).to.equal('1111 2222 3333')
381 })
382
383 it('Should make an advanced search and only show the first result', async function () {
384 const query = {
385 search: '1111 2222 3333',
386 languageOneOf: [ 'pl', 'fr' ],
387 durationMax: 4,
388 nsfw: 'false' as 'false',
389 licenceOneOf: [ 1, 4 ],
390 sort: '-name',
391 start: 0,
392 count: 1
393 }
394
395 const body = await command.advancedVideoSearch({ search: query })
396 expect(body.total).to.equal(4)
397
398 const videos = body.data
399 expect(videos[0].name).to.equal('1111 2222 3333 - 8')
400 })
401
402 it('Should make an advanced search and only show the last result', async function () {
403 const query = {
404 search: '1111 2222 3333',
405 languageOneOf: [ 'pl', 'fr' ],
406 durationMax: 4,
407 nsfw: 'false' as 'false',
408 licenceOneOf: [ 1, 4 ],
409 sort: '-name',
410 start: 3,
411 count: 1
412 }
413
414 const body = await command.advancedVideoSearch({ search: query })
415 expect(body.total).to.equal(4)
416
417 const videos = body.data
418 expect(videos[0].name).to.equal('1111 2222 3333')
419 })
420
421 it('Should search on originally published date', async function () {
422 const baseQuery = {
423 search: '1111 2222 3333',
424 languageOneOf: [ 'pl', 'fr' ],
425 durationMax: 4,
426 nsfw: 'false' as 'false',
427 licenceOneOf: [ 1, 4 ]
428 }
429
430 {
431 const query = { ...baseQuery, originallyPublishedStartDate: '2019-02-11T09:58:08.286Z' }
432 const body = await command.advancedVideoSearch({ search: query })
433
434 expect(body.total).to.equal(1)
435 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
436 }
437
438 {
439 const query = { ...baseQuery, originallyPublishedEndDate: '2019-03-11T09:58:08.286Z' }
440 const body = await command.advancedVideoSearch({ search: query })
441
442 expect(body.total).to.equal(1)
443 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
444 }
445
446 {
447 const query = { ...baseQuery, originallyPublishedEndDate: '2019-01-11T09:58:08.286Z' }
448 const body = await command.advancedVideoSearch({ search: query })
449
450 expect(body.total).to.equal(0)
451 }
452
453 {
454 const query = { ...baseQuery, originallyPublishedStartDate: '2019-03-11T09:58:08.286Z' }
455 const body = await command.advancedVideoSearch({ search: query })
456
457 expect(body.total).to.equal(0)
458 }
459
460 {
461 const query = {
462 ...baseQuery,
463 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
464 originallyPublishedEndDate: '2019-01-10T09:58:08.286Z'
465 }
466 const body = await command.advancedVideoSearch({ search: query })
467
468 expect(body.total).to.equal(0)
469 }
470
471 {
472 const query = {
473 ...baseQuery,
474 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
475 originallyPublishedEndDate: '2019-04-11T09:58:08.286Z'
476 }
477 const body = await command.advancedVideoSearch({ search: query })
478
479 expect(body.total).to.equal(1)
480 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
481 }
482 })
483
484 it('Should search by UUID', async function () {
485 const search = videoUUID
486 const body = await command.advancedVideoSearch({ search: { search } })
487
488 expect(body.total).to.equal(1)
489 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
490 })
491
492 it('Should filter by UUIDs', async function () {
493 for (const uuid of [ videoUUID, videoShortUUID ]) {
494 const body = await command.advancedVideoSearch({ search: { uuids: [ uuid ] } })
495
496 expect(body.total).to.equal(1)
497 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
498 }
499
500 {
501 const body = await command.advancedVideoSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
502
503 expect(body.total).to.equal(0)
504 expect(body.data).to.have.lengthOf(0)
505 }
506 })
507
508 it('Should search by host', async function () {
509 {
510 const body = await command.advancedVideoSearch({ search: { search: '6666 7777 8888', host: server.host } })
511 expect(body.total).to.equal(1)
512 expect(body.data[0].name).to.equal('6666 7777 8888')
513 }
514
515 {
516 const body = await command.advancedVideoSearch({ search: { search: '1111', host: 'example.com' } })
517 expect(body.total).to.equal(0)
518 expect(body.data).to.have.lengthOf(0)
519 }
520
521 {
522 const body = await command.advancedVideoSearch({ search: { search: 'remote', host: remoteServer.host } })
523 expect(body.total).to.equal(2)
524 expect(body.data).to.have.lengthOf(2)
525 expect(body.data[0].name).to.equal('remote video 1')
526 expect(body.data[1].name).to.equal('remote video 2')
527 }
528 })
529
530 it('Should search by live', async function () {
531 this.timeout(60000)
532
533 {
534 const newConfig = {
535 search: {
536 searchIndex: { enabled: false }
537 },
538 live: { enabled: true }
539 }
540 await server.config.updateCustomSubConfig({ newConfig })
541 }
542
543 {
544 const body = await command.advancedVideoSearch({ search: { isLive: true } })
545
546 expect(body.total).to.equal(0)
547 expect(body.data).to.have.lengthOf(0)
548 }
549
550 {
551 const liveCommand = server.live
552
553 const liveAttributes = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.store.channel.id }
554 const live = await liveCommand.create({ fields: liveAttributes })
555
556 const ffmpegCommand = await liveCommand.sendRTMPStreamInVideo({ videoId: live.id })
557 await liveCommand.waitUntilPublished({ videoId: live.id })
558
559 const body = await command.advancedVideoSearch({ search: { isLive: true } })
560
561 expect(body.total).to.equal(1)
562 expect(body.data[0].name).to.equal('live')
563
564 await stopFfmpeg(ffmpegCommand)
565 }
566 })
567
568 after(async function () {
569 await cleanupTests([ server ])
570 })
571 })