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