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