1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { expect } from 'chai'
4 import { pick } from '@shared/core-utils'
5 import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models'
12 setAccessTokensToServers,
13 setDefaultAccountAvatar,
14 setDefaultVideoChannel,
16 } from '@shared/server-commands'
18 describe('Test videos filter', function () {
19 let servers: PeerTubeServer[]
21 let remotePaths: string[]
23 const subscriptionVideosPath = '/api/v1/users/me/subscriptions/videos'
25 // ---------------------------------------------------------------
27 before(async function () {
30 servers = await createMultipleServers(2)
32 await setAccessTokensToServers(servers)
33 await setDefaultVideoChannel(servers)
34 await setDefaultAccountAvatar(servers)
36 await servers[1].config.enableMinimumTranscoding()
38 for (const server of servers) {
39 const moderator = { username: 'moderator', password: 'my super password' }
40 await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR })
41 server['moderatorAccessToken'] = await server.login.getAccessToken(moderator)
43 await server.videos.upload({ attributes: { name: 'public ' + server.serverNumber } })
46 const attributes = { name: 'unlisted ' + server.serverNumber, privacy: VideoPrivacy.UNLISTED }
47 await server.videos.upload({ attributes })
51 const attributes = { name: 'private ' + server.serverNumber, privacy: VideoPrivacy.PRIVATE }
52 await server.videos.upload({ attributes })
55 // Subscribing to itself
56 await server.subscriptions.add({ targetUri: 'root_channel@' + server.host })
59 await doubleFollow(servers[0], servers[1])
62 `/api/v1/video-channels/root_channel/videos`,
63 `/api/v1/accounts/root/videos`,
65 '/api/v1/search/videos',
66 subscriptionVideosPath
70 `/api/v1/video-channels/root_channel@${servers[1].host}/videos`,
71 `/api/v1/accounts/root@${servers[1].host}/videos`,
73 '/api/v1/search/videos'
77 describe('Check deprecated videos filter', function () {
79 async function getVideosNames (options: {
80 server: PeerTubeServer
83 skipSubscription?: boolean
84 expectedStatus?: HttpStatusCode
86 const { server, token, filter, skipSubscription = false, expectedStatus = HttpStatusCode.OK_200 } = options
88 const videosResults: Video[][] = []
90 for (const path of paths) {
91 if (skipSubscription && path === subscriptionVideosPath) continue
93 const res = await makeGetRequest({
104 videosResults.push(res.body.data.map(v => v.name))
110 it('Should display local videos', async function () {
111 for (const server of servers) {
112 const namesResults = await getVideosNames({ server, token: server.accessToken, filter: 'local' })
113 for (const names of namesResults) {
114 expect(names).to.have.lengthOf(1)
115 expect(names[0]).to.equal('public ' + server.serverNumber)
120 it('Should display all local videos by the admin or the moderator', async function () {
121 for (const server of servers) {
122 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
124 const namesResults = await getVideosNames({ server, token, filter: 'all-local', skipSubscription: true })
125 for (const names of namesResults) {
126 expect(names).to.have.lengthOf(3)
128 expect(names[0]).to.equal('public ' + server.serverNumber)
129 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
130 expect(names[2]).to.equal('private ' + server.serverNumber)
136 it('Should display all videos by the admin or the moderator', async function () {
137 for (const server of servers) {
138 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
140 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames({ server, token, filter: 'all' })
141 expect(channelVideos).to.have.lengthOf(3)
142 expect(accountVideos).to.have.lengthOf(3)
144 expect(videos).to.have.lengthOf(5)
145 expect(searchVideos).to.have.lengthOf(5)
151 describe('Check videos filters', function () {
153 async function listVideos (options: {
154 server: PeerTubeServer
157 hasWebtorrentFiles?: boolean
158 hasHLSFiles?: boolean
159 include?: VideoInclude
160 privacyOneOf?: VideoPrivacy[]
164 expectedStatus?: HttpStatusCode
166 const res = await makeGetRequest({
167 url: options.server.url,
169 token: options.token ?? options.server.accessToken,
171 ...pick(options, [ 'isLocal', 'include', 'category', 'tagsAllOf', 'hasWebtorrentFiles', 'hasHLSFiles', 'privacyOneOf' ]),
175 expectedStatus: options.expectedStatus ?? HttpStatusCode.OK_200
178 return res.body.data as Video[]
181 async function getVideosNames (
183 server: PeerTubeServer
185 include?: VideoInclude
186 privacyOneOf?: VideoPrivacy[]
188 expectedStatus?: HttpStatusCode
189 skipSubscription?: boolean
192 const { skipSubscription = false } = options
193 const videosResults: string[][] = []
195 for (const path of paths) {
196 if (skipSubscription && path === subscriptionVideosPath) continue
198 const videos = await listVideos({ ...options, path })
200 videosResults.push(videos.map(v => v.name))
206 it('Should display local videos', async function () {
207 for (const server of servers) {
208 const namesResults = await getVideosNames({ server, isLocal: true })
210 for (const names of namesResults) {
211 expect(names).to.have.lengthOf(1)
212 expect(names[0]).to.equal('public ' + server.serverNumber)
217 it('Should display local videos with hidden privacy by the admin or the moderator', async function () {
218 for (const server of servers) {
219 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
221 const namesResults = await getVideosNames(
226 privacyOneOf: [ VideoPrivacy.UNLISTED, VideoPrivacy.PUBLIC, VideoPrivacy.PRIVATE ],
227 skipSubscription: true
231 for (const names of namesResults) {
232 expect(names).to.have.lengthOf(3)
234 expect(names[0]).to.equal('public ' + server.serverNumber)
235 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
236 expect(names[2]).to.equal('private ' + server.serverNumber)
242 it('Should display all videos by the admin or the moderator', async function () {
243 for (const server of servers) {
244 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
246 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames({
249 privacyOneOf: [ VideoPrivacy.UNLISTED, VideoPrivacy.PUBLIC, VideoPrivacy.PRIVATE ]
252 expect(channelVideos).to.have.lengthOf(3)
253 expect(accountVideos).to.have.lengthOf(3)
255 expect(videos).to.have.lengthOf(5)
256 expect(searchVideos).to.have.lengthOf(5)
261 it('Should display only remote videos', async function () {
264 await servers[1].videos.upload({ attributes: { name: 'remote video' } })
266 await waitJobs(servers)
268 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
270 for (const path of remotePaths) {
272 const videos = await listVideos({ server: servers[0], path })
273 const video = finder(videos)
274 expect(video).to.exist
278 const videos = await listVideos({ server: servers[0], path, isLocal: false })
279 const video = finder(videos)
280 expect(video).to.exist
284 const videos = await listVideos({ server: servers[0], path, isLocal: true })
285 const video = finder(videos)
286 expect(video).to.not.exist
291 it('Should include not published videos', async function () {
292 await servers[0].config.enableLive({ allowReplay: false, transcoding: false })
293 await servers[0].live.create({ fields: { name: 'live video', channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC } })
295 const finder = (videos: Video[]) => videos.find(v => v.name === 'live video')
297 for (const path of paths) {
299 const videos = await listVideos({ server: servers[0], path })
300 const video = finder(videos)
301 expect(video).to.not.exist
302 expect(videos[0].state).to.not.exist
303 expect(videos[0].waitTranscoding).to.not.exist
307 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.NOT_PUBLISHED_STATE })
308 const video = finder(videos)
309 expect(video).to.exist
310 expect(video.state).to.exist
315 it('Should include blacklisted videos', async function () {
316 const { id } = await servers[0].videos.upload({ attributes: { name: 'blacklisted' } })
318 await servers[0].blacklist.add({ videoId: id })
320 const finder = (videos: Video[]) => videos.find(v => v.name === 'blacklisted')
322 for (const path of paths) {
324 const videos = await listVideos({ server: servers[0], path })
325 const video = finder(videos)
326 expect(video).to.not.exist
327 expect(videos[0].blacklisted).to.not.exist
331 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLACKLISTED })
332 const video = finder(videos)
333 expect(video).to.exist
334 expect(video.blacklisted).to.be.true
339 it('Should include videos from muted account', async function () {
340 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
342 await servers[0].blocklist.addToServerBlocklist({ account: 'root@' + servers[1].host })
344 for (const path of remotePaths) {
346 const videos = await listVideos({ server: servers[0], path })
347 const video = finder(videos)
348 expect(video).to.not.exist
350 // Some paths won't have videos
352 expect(videos[0].blockedOwner).to.not.exist
353 expect(videos[0].blockedServer).to.not.exist
358 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.false
363 expect(video.blockedOwner).to.be.true
367 await servers[0].blocklist.removeFromServerBlocklist({ account: 'root@' + servers[1].host })
370 it('Should include videos from muted server', async function () {
371 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
373 await servers[0].blocklist.addToServerBlocklist({ server: servers[1].host })
375 for (const path of remotePaths) {
377 const videos = await listVideos({ server: servers[0], path })
378 const video = finder(videos)
379 expect(video).to.not.exist
381 // Some paths won't have videos
383 expect(videos[0].blockedOwner).to.not.exist
384 expect(videos[0].blockedServer).to.not.exist
389 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER })
390 const video = finder(videos)
391 expect(video).to.exist
392 expect(video.blockedServer).to.be.true
393 expect(video.blockedOwner).to.be.false
397 await servers[0].blocklist.removeFromServerBlocklist({ server: servers[1].host })
400 it('Should include video files', async function () {
401 for (const path of paths) {
403 const videos = await listVideos({ server: servers[0], path })
405 for (const video of videos) {
406 const videoWithFiles = video as VideoDetails
408 expect(videoWithFiles.files).to.not.exist
409 expect(videoWithFiles.streamingPlaylists).to.not.exist
414 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.FILES })
416 for (const video of videos) {
417 const videoWithFiles = video as VideoDetails
419 expect(videoWithFiles.files).to.exist
420 expect(videoWithFiles.files).to.have.length.at.least(1)
426 it('Should filter by tags and category', async function () {
427 await servers[0].videos.upload({ attributes: { name: 'tag filter', tags: [ 'tag1', 'tag2' ] } })
428 await servers[0].videos.upload({ attributes: { name: 'tag filter with category', tags: [ 'tag3' ], category: 4 } })
430 for (const path of paths) {
432 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] })
433 expect(videos).to.have.lengthOf(1)
434 expect(videos[0].name).to.equal('tag filter')
438 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag3' ] })
439 expect(videos).to.have.lengthOf(0)
443 const { data, total } = await servers[0].videos.list({ tagsAllOf: [ 'tag3' ], categoryOneOf: [ 4 ] })
444 expect(total).to.equal(1)
445 expect(data[0].name).to.equal('tag filter with category')
449 const { total } = await servers[0].videos.list({ tagsAllOf: [ 'tag4' ], categoryOneOf: [ 4 ] })
450 expect(total).to.equal(0)
455 it('Should filter by HLS or WebTorrent files', async function () {
458 const finderFactory = (name: string) => (videos: Video[]) => videos.some(v => v.name === name)
460 await servers[0].config.enableTranscoding(true, false)
461 await servers[0].videos.upload({ attributes: { name: 'webtorrent video' } })
462 const hasWebtorrent = finderFactory('webtorrent video')
464 await waitJobs(servers)
466 await servers[0].config.enableTranscoding(false, true)
467 await servers[0].videos.upload({ attributes: { name: 'hls video' } })
468 const hasHLS = finderFactory('hls video')
470 await waitJobs(servers)
472 await servers[0].config.enableTranscoding(true, true)
473 await servers[0].videos.upload({ attributes: { name: 'hls and webtorrent video' } })
474 const hasBoth = finderFactory('hls and webtorrent video')
476 await waitJobs(servers)
478 for (const path of paths) {
480 const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: true })
482 expect(hasWebtorrent(videos)).to.be.true
483 expect(hasHLS(videos)).to.be.false
484 expect(hasBoth(videos)).to.be.true
488 const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: false })
490 expect(hasWebtorrent(videos)).to.be.false
491 expect(hasHLS(videos)).to.be.true
492 expect(hasBoth(videos)).to.be.false
496 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true })
498 expect(hasWebtorrent(videos)).to.be.false
499 expect(hasHLS(videos)).to.be.true
500 expect(hasBoth(videos)).to.be.true
504 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false })
506 expect(hasWebtorrent(videos)).to.be.true
507 expect(hasHLS(videos)).to.be.false
508 expect(hasBoth(videos)).to.be.false
512 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false, hasWebtorrentFiles: false })
514 expect(hasWebtorrent(videos)).to.be.false
515 expect(hasHLS(videos)).to.be.false
516 expect(hasBoth(videos)).to.be.false
520 const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true, hasWebtorrentFiles: true })
522 expect(hasWebtorrent(videos)).to.be.false
523 expect(hasHLS(videos)).to.be.false
524 expect(hasBoth(videos)).to.be.true
530 after(async function () {
531 await cleanupTests(servers)