1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import * as chai from 'chai'
5 import { wait } from '@shared/core-utils'
6 import { VideoPrivacy } from '@shared/models'
13 setAccessTokensToServers,
14 setDefaultAccountAvatar,
15 setDefaultChannelAvatar,
16 setDefaultVideoChannel,
18 } from '@shared/server-commands'
20 const expect = chai.expect
22 describe('Test videos search', function () {
23 let server: PeerTubeServer
24 let remoteServer: PeerTubeServer
27 let videoShortUUID: string
29 let command: SearchCommand
31 before(async function () {
34 const servers = await Promise.all([
35 createSingleServer(1),
39 remoteServer = servers[1]
41 await setAccessTokensToServers([ server, remoteServer ])
42 await setDefaultVideoChannel([ server, remoteServer ])
43 await setDefaultChannelAvatar(server)
44 await setDefaultAccountAvatar(servers)
48 name: '1111 2222 3333',
49 fixture: '60fps_720p_small.mp4', // 2 seconds
55 await server.videos.upload({ attributes: attributes1 })
57 const attributes2 = { ...attributes1, name: attributes1.name + ' - 2', fixture: 'video_short.mp4' }
58 await server.videos.upload({ attributes: attributes2 })
61 const attributes3 = { ...attributes1, name: attributes1.name + ' - 3', language: undefined }
62 const { id, uuid, shortUUID } = await server.videos.upload({ attributes: attributes3 })
64 videoShortUUID = shortUUID
66 await server.captions.add({
69 fixture: 'subtitle-good2.vtt',
70 mimeType: 'application/octet-stream'
73 await server.captions.add({
76 fixture: 'subtitle-good2.vtt',
77 mimeType: 'application/octet-stream'
81 const attributes4 = { ...attributes1, name: attributes1.name + ' - 4', language: 'pl', nsfw: true }
82 await server.videos.upload({ attributes: attributes4 })
86 startDate = new Date().toISOString()
88 const attributes5 = { ...attributes1, name: attributes1.name + ' - 5', licence: 2, language: undefined }
89 await server.videos.upload({ attributes: attributes5 })
91 const attributes6 = { ...attributes1, name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] }
92 await server.videos.upload({ attributes: attributes6 })
94 const attributes7 = { ...attributes1, name: attributes1.name + ' - 7', originallyPublishedAt: '2019-02-12T09:58:08.286Z' }
95 await server.videos.upload({ attributes: attributes7 })
97 const attributes8 = { ...attributes1, name: attributes1.name + ' - 8', licence: 4 }
98 await server.videos.upload({ attributes: attributes8 })
103 name: '3333 4444 5555',
104 fixture: 'video_short.mp4',
109 await server.videos.upload({ attributes: attributes })
111 await server.videos.upload({ attributes: { ...attributes, name: attributes.name + ' duplicate' } })
116 name: '6666 7777 8888',
117 fixture: 'video_short.mp4',
122 await server.videos.upload({ attributes: attributes })
126 const attributes1 = {
128 tags: [ 'aaaa', 'bbbb', 'cccc' ],
131 await server.videos.upload({ attributes: attributes1 })
132 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
134 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'cccc', 'dddd' ] } })
135 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'eeee', 'ffff' ] } })
139 const attributes1 = {
143 await server.videos.upload({ attributes: attributes1 })
144 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
148 await remoteServer.videos.upload({ attributes: { name: 'remote video 1' } })
149 await remoteServer.videos.upload({ attributes: { name: 'remote video 2' } })
152 await doubleFollow(server, remoteServer)
154 command = server.search
157 it('Should make a simple search and not have results', async function () {
158 const body = await command.searchVideos({ search: 'abc' })
160 expect(body.total).to.equal(0)
161 expect(body.data).to.have.lengthOf(0)
164 it('Should make a simple search and have results', async function () {
165 const body = await command.searchVideos({ search: '4444 5555 duplicate' })
167 expect(body.total).to.equal(2)
169 const videos = body.data
170 expect(videos).to.have.lengthOf(2)
173 expect(videos[0].name).to.equal('3333 4444 5555 duplicate')
174 expect(videos[1].name).to.equal('3333 4444 5555')
177 it('Should make a search on tags too, and have results', async function () {
182 const body = await command.advancedVideoSearch({ search })
184 expect(body.total).to.equal(2)
186 const videos = body.data
187 expect(videos).to.have.lengthOf(2)
190 expect(videos[0].name).to.equal('aaaa 2')
191 expect(videos[1].name).to.equal('9999')
194 it('Should filter on tags without a search', async function () {
196 tagsAllOf: [ 'bbbb' ]
198 const body = await command.advancedVideoSearch({ search })
200 expect(body.total).to.equal(2)
202 const videos = body.data
203 expect(videos).to.have.lengthOf(2)
205 expect(videos[0].name).to.equal('9999')
206 expect(videos[1].name).to.equal('9999')
209 it('Should filter on category without a search', async function () {
213 const body = await command.advancedVideoSearch({ search: search })
215 expect(body.total).to.equal(1)
217 const videos = body.data
218 expect(videos).to.have.lengthOf(1)
220 expect(videos[0].name).to.equal('6666 7777 8888')
223 it('Should search by tags (one of)', async function () {
226 categoryOneOf: [ 1 ],
227 tagsOneOf: [ 'aAaa', 'ffff' ]
231 const body = await command.advancedVideoSearch({ search: query })
232 expect(body.total).to.equal(2)
236 const body = await command.advancedVideoSearch({ search: { ...query, tagsOneOf: [ 'blabla' ] } })
237 expect(body.total).to.equal(0)
241 it('Should search by tags (all of)', async function () {
244 categoryOneOf: [ 1 ],
245 tagsAllOf: [ 'CCcc' ]
249 const body = await command.advancedVideoSearch({ search: query })
250 expect(body.total).to.equal(2)
254 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'blAbla' ] } })
255 expect(body.total).to.equal(0)
259 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'bbbb', 'CCCC' ] } })
260 expect(body.total).to.equal(1)
264 it('Should search by category', async function () {
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')
277 const body = await command.advancedVideoSearch({ search: { ...query, categoryOneOf: [ 2 ] } })
278 expect(body.total).to.equal(0)
282 it('Should search by licence', async function () {
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')
296 const body = await command.advancedVideoSearch({ search: { ...query, licenceOneOf: [ 3 ] } })
297 expect(body.total).to.equal(0)
301 it('Should search by languages', async function () {
303 search: '1111 2222 3333',
304 languageOneOf: [ 'pl', 'en' ]
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')
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')
323 const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'eo' ] } })
324 expect(body.total).to.equal(0)
328 it('Should search by start date', async function () {
330 search: '1111 2222 3333',
334 const body = await command.advancedVideoSearch({ search: query })
335 expect(body.total).to.equal(4)
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')
344 it('Should make an advanced search', async function () {
346 search: '1111 2222 3333',
347 languageOneOf: [ 'pl', 'fr' ],
349 nsfw: 'false' as 'false',
350 licenceOneOf: [ 1, 4 ]
353 const body = await command.advancedVideoSearch({ search: query })
354 expect(body.total).to.equal(4)
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')
363 it('Should make an advanced search and sort results', async function () {
365 search: '1111 2222 3333',
366 languageOneOf: [ 'pl', 'fr' ],
368 nsfw: 'false' as 'false',
369 licenceOneOf: [ 1, 4 ],
373 const body = await command.advancedVideoSearch({ search: query })
374 expect(body.total).to.equal(4)
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')
383 it('Should make an advanced search and only show the first result', async function () {
385 search: '1111 2222 3333',
386 languageOneOf: [ 'pl', 'fr' ],
388 nsfw: 'false' as 'false',
389 licenceOneOf: [ 1, 4 ],
395 const body = await command.advancedVideoSearch({ search: query })
396 expect(body.total).to.equal(4)
398 const videos = body.data
399 expect(videos[0].name).to.equal('1111 2222 3333 - 8')
402 it('Should make an advanced search and only show the last result', async function () {
404 search: '1111 2222 3333',
405 languageOneOf: [ 'pl', 'fr' ],
407 nsfw: 'false' as 'false',
408 licenceOneOf: [ 1, 4 ],
414 const body = await command.advancedVideoSearch({ search: query })
415 expect(body.total).to.equal(4)
417 const videos = body.data
418 expect(videos[0].name).to.equal('1111 2222 3333')
421 it('Should search on originally published date', async function () {
423 search: '1111 2222 3333',
424 languageOneOf: [ 'pl', 'fr' ],
426 nsfw: 'false' as 'false',
427 licenceOneOf: [ 1, 4 ]
431 const query = { ...baseQuery, originallyPublishedStartDate: '2019-02-11T09:58:08.286Z' }
432 const body = await command.advancedVideoSearch({ search: query })
434 expect(body.total).to.equal(1)
435 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
439 const query = { ...baseQuery, originallyPublishedEndDate: '2019-03-11T09:58:08.286Z' }
440 const body = await command.advancedVideoSearch({ search: query })
442 expect(body.total).to.equal(1)
443 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
447 const query = { ...baseQuery, originallyPublishedEndDate: '2019-01-11T09:58:08.286Z' }
448 const body = await command.advancedVideoSearch({ search: query })
450 expect(body.total).to.equal(0)
454 const query = { ...baseQuery, originallyPublishedStartDate: '2019-03-11T09:58:08.286Z' }
455 const body = await command.advancedVideoSearch({ search: query })
457 expect(body.total).to.equal(0)
463 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
464 originallyPublishedEndDate: '2019-01-10T09:58:08.286Z'
466 const body = await command.advancedVideoSearch({ search: query })
468 expect(body.total).to.equal(0)
474 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
475 originallyPublishedEndDate: '2019-04-11T09:58:08.286Z'
477 const body = await command.advancedVideoSearch({ search: query })
479 expect(body.total).to.equal(1)
480 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
484 it('Should search by UUID', async function () {
485 const search = videoUUID
486 const body = await command.advancedVideoSearch({ search: { search } })
488 expect(body.total).to.equal(1)
489 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
492 it('Should filter by UUIDs', async function () {
493 for (const uuid of [ videoUUID, videoShortUUID ]) {
494 const body = await command.advancedVideoSearch({ search: { uuids: [ uuid ] } })
496 expect(body.total).to.equal(1)
497 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
501 const body = await command.advancedVideoSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
503 expect(body.total).to.equal(0)
504 expect(body.data).to.have.lengthOf(0)
508 it('Should search by host', async function () {
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')
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)
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')
530 it('Should search by live', async function () {
536 searchIndex: { enabled: false }
538 live: { enabled: true }
540 await server.config.updateCustomSubConfig({ newConfig })
544 const body = await command.advancedVideoSearch({ search: { isLive: true } })
546 expect(body.total).to.equal(0)
547 expect(body.data).to.have.lengthOf(0)
551 const liveCommand = server.live
553 const liveAttributes = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.store.channel.id }
554 const live = await liveCommand.create({ fields: liveAttributes })
556 const ffmpegCommand = await liveCommand.sendRTMPStreamInVideo({ videoId: live.id })
557 await liveCommand.waitUntilPublished({ videoId: live.id })
559 const body = await command.advancedVideoSearch({ search: { isLive: true } })
561 expect(body.total).to.equal(1)
562 expect(body.data[0].name).to.equal('live')
564 await stopFfmpeg(ffmpegCommand)
568 after(async function () {
569 await cleanupTests([ server ])