1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import { expect } from 'chai'
5 import { pick } from '@shared/core-utils'
12 setAccessTokensToServers,
13 setDefaultVideoChannel,
15 } from '@shared/extra-utils'
16 import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models'
18 describe('Test videos filter', function () {
19 let servers: PeerTubeServer[]
21 let remotePaths: string[]
23 // ---------------------------------------------------------------
25 before(async function () {
28 servers = await createMultipleServers(2)
30 await setAccessTokensToServers(servers)
31 await setDefaultVideoChannel(servers)
33 for (const server of servers) {
34 const moderator = { username: 'moderator', password: 'my super password' }
35 await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR })
36 server['moderatorAccessToken'] = await server.login.getAccessToken(moderator)
38 await server.videos.upload({ attributes: { name: 'public ' + server.serverNumber } })
41 const attributes = { name: 'unlisted ' + server.serverNumber, privacy: VideoPrivacy.UNLISTED }
42 await server.videos.upload({ attributes })
46 const attributes = { name: 'private ' + server.serverNumber, privacy: VideoPrivacy.PRIVATE }
47 await server.videos.upload({ attributes })
51 await doubleFollow(servers[0], servers[1])
54 `/api/v1/video-channels/root_channel/videos`,
55 `/api/v1/accounts/root/videos`,
57 '/api/v1/search/videos'
61 `/api/v1/video-channels/root_channel@${servers[1].host}/videos`,
62 `/api/v1/accounts/root@${servers[1].host}/videos`,
64 '/api/v1/search/videos'
68 describe('Check deprecated videos filter', function () {
70 async function getVideosNames (server: PeerTubeServer, token: string, filter: string, expectedStatus = HttpStatusCode.OK_200) {
71 const videosResults: Video[][] = []
73 for (const path of paths) {
74 const res = await makeGetRequest({
85 videosResults.push(res.body.data.map(v => v.name))
91 it('Should display local videos', async function () {
92 for (const server of servers) {
93 const namesResults = await getVideosNames(server, server.accessToken, 'local')
94 for (const names of namesResults) {
95 expect(names).to.have.lengthOf(1)
96 expect(names[0]).to.equal('public ' + server.serverNumber)
101 it('Should display all local videos by the admin or the moderator', async function () {
102 for (const server of servers) {
103 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
105 const namesResults = await getVideosNames(server, token, 'all-local')
106 for (const names of namesResults) {
107 expect(names).to.have.lengthOf(3)
109 expect(names[0]).to.equal('public ' + server.serverNumber)
110 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
111 expect(names[2]).to.equal('private ' + server.serverNumber)
117 it('Should display all videos by the admin or the moderator', async function () {
118 for (const server of servers) {
119 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
121 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames(server, token, 'all')
122 expect(channelVideos).to.have.lengthOf(3)
123 expect(accountVideos).to.have.lengthOf(3)
125 expect(videos).to.have.lengthOf(5)
126 expect(searchVideos).to.have.lengthOf(5)
132 describe('Check videos filters', function () {
134 async function listVideos (options: {
135 server: PeerTubeServer
138 include?: VideoInclude
142 expectedStatus?: HttpStatusCode
144 const res = await makeGetRequest({
145 url: options.server.url,
147 token: options.token ?? options.server.accessToken,
149 ...pick(options, [ 'isLocal', 'include', 'category', 'tagsAllOf' ]),
153 expectedStatus: options.expectedStatus ?? HttpStatusCode.OK_200
156 return res.body.data as Video[]
159 async function getVideosNames (options: {
160 server: PeerTubeServer
162 include?: VideoInclude
164 expectedStatus?: HttpStatusCode
166 const videosResults: string[][] = []
168 for (const path of paths) {
169 const videos = await listVideos({ ...options, path })
171 videosResults.push(videos.map(v => v.name))
177 it('Should display local videos', async function () {
178 for (const server of servers) {
179 const namesResults = await getVideosNames({ server, isLocal: true })
181 for (const names of namesResults) {
182 expect(names).to.have.lengthOf(1)
183 expect(names[0]).to.equal('public ' + server.serverNumber)
188 it('Should display local videos with hidden privacy by the admin or the moderator', async function () {
189 for (const server of servers) {
190 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
192 const namesResults = await getVideosNames({
196 include: VideoInclude.HIDDEN_PRIVACY
199 for (const names of namesResults) {
200 expect(names).to.have.lengthOf(3)
202 expect(names[0]).to.equal('public ' + server.serverNumber)
203 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
204 expect(names[2]).to.equal('private ' + server.serverNumber)
210 it('Should display all videos by the admin or the moderator', async function () {
211 for (const server of servers) {
212 for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
214 const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames({
217 include: VideoInclude.HIDDEN_PRIVACY
220 expect(channelVideos).to.have.lengthOf(3)
221 expect(accountVideos).to.have.lengthOf(3)
223 expect(videos).to.have.lengthOf(5)
224 expect(searchVideos).to.have.lengthOf(5)
229 it('Should display only remote videos', async function () {
232 await servers[1].videos.upload({ attributes: { name: 'remote video' } })
234 await waitJobs(servers)
236 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
238 for (const path of remotePaths) {
240 const videos = await listVideos({ server: servers[0], path })
241 const video = finder(videos)
242 expect(video).to.exist
246 const videos = await listVideos({ server: servers[0], path, isLocal: false })
247 const video = finder(videos)
248 expect(video).to.exist
252 const videos = await listVideos({ server: servers[0], path, isLocal: true })
253 const video = finder(videos)
254 expect(video).to.not.exist
259 it('Should include not published videos', async function () {
260 await servers[0].config.enableLive({ allowReplay: false, transcoding: false })
261 await servers[0].live.create({ fields: { name: 'live video', channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC } })
263 const finder = (videos: Video[]) => videos.find(v => v.name === 'live video')
265 for (const path of paths) {
267 const videos = await listVideos({ server: servers[0], path })
268 const video = finder(videos)
269 expect(video).to.not.exist
270 expect(videos[0].state).to.not.exist
271 expect(videos[0].waitTranscoding).to.not.exist
275 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.NOT_PUBLISHED_STATE })
276 const video = finder(videos)
277 expect(video).to.exist
278 expect(video.state).to.exist
283 it('Should include blacklisted videos', async function () {
284 const { id } = await servers[0].videos.upload({ attributes: { name: 'blacklisted' } })
286 await servers[0].blacklist.add({ videoId: id })
288 const finder = (videos: Video[]) => videos.find(v => v.name === 'blacklisted')
290 for (const path of paths) {
292 const videos = await listVideos({ server: servers[0], path })
293 const video = finder(videos)
294 expect(video).to.not.exist
295 expect(videos[0].blacklisted).to.not.exist
299 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLACKLISTED })
300 const video = finder(videos)
301 expect(video).to.exist
302 expect(video.blacklisted).to.be.true
307 it('Should include videos from muted account', async function () {
308 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
310 await servers[0].blocklist.addToServerBlocklist({ account: 'root@' + servers[1].host })
312 for (const path of remotePaths) {
314 const videos = await listVideos({ server: servers[0], path })
315 const video = finder(videos)
316 expect(video).to.not.exist
318 // Some paths won't have videos
320 expect(videos[0].blockedOwner).to.not.exist
321 expect(videos[0].blockedServer).to.not.exist
326 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER })
328 const video = finder(videos)
329 expect(video).to.exist
330 expect(video.blockedServer).to.be.false
331 expect(video.blockedOwner).to.be.true
335 await servers[0].blocklist.removeFromServerBlocklist({ account: 'root@' + servers[1].host })
338 it('Should include videos from muted server', async function () {
339 const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video')
341 await servers[0].blocklist.addToServerBlocklist({ server: servers[1].host })
343 for (const path of remotePaths) {
345 const videos = await listVideos({ server: servers[0], path })
346 const video = finder(videos)
347 expect(video).to.not.exist
349 // Some paths won't have videos
351 expect(videos[0].blockedOwner).to.not.exist
352 expect(videos[0].blockedServer).to.not.exist
357 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER })
358 const video = finder(videos)
359 expect(video).to.exist
360 expect(video.blockedServer).to.be.true
361 expect(video.blockedOwner).to.be.false
365 await servers[0].blocklist.removeFromServerBlocklist({ server: servers[1].host })
368 it('Should include video files', async function () {
369 for (const path of paths) {
371 const videos = await listVideos({ server: servers[0], path })
373 for (const video of videos) {
374 const videoWithFiles = video as VideoDetails
376 expect(videoWithFiles.files).to.not.exist
377 expect(videoWithFiles.streamingPlaylists).to.not.exist
382 const videos = await listVideos({ server: servers[0], path, include: VideoInclude.FILES })
384 for (const video of videos) {
385 const videoWithFiles = video as VideoDetails
387 expect(videoWithFiles.files).to.exist
388 expect(videoWithFiles.files).to.have.length.at.least(1)
394 it('Should filter by tags and category', async function () {
395 await servers[0].videos.upload({ attributes: { name: 'tag filter', tags: [ 'tag1', 'tag2' ] } })
396 await servers[0].videos.upload({ attributes: { name: 'tag filter with category', tags: [ 'tag3' ], category: 4 } })
398 for (const path of paths) {
401 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] })
402 expect(videos).to.have.lengthOf(1)
403 expect(videos[0].name).to.equal('tag filter')
408 const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag3' ] })
409 expect(videos).to.have.lengthOf(0)
413 const { data, total } = await servers[0].videos.list({ tagsAllOf: [ 'tag3' ], categoryOneOf: [ 4 ] })
414 expect(total).to.equal(1)
415 expect(data[0].name).to.equal('tag filter with category')
419 const { total } = await servers[0].videos.list({ tagsAllOf: [ 'tag4' ], categoryOneOf: [ 4 ] })
420 expect(total).to.equal(0)
426 after(async function () {
427 await cleanupTests(servers)