Add host to common video filters
This commit is contained in:
parent
e433a74bb6
commit
94a7879d7d
|
@ -210,6 +210,8 @@ export class CustomMarkupService {
|
||||||
accountHandle: data.accountHandle || undefined,
|
accountHandle: data.accountHandle || undefined,
|
||||||
channelHandle: data.channelHandle || undefined,
|
channelHandle: data.channelHandle || undefined,
|
||||||
|
|
||||||
|
host: data.host || undefined,
|
||||||
|
|
||||||
isLive: this.buildBoolean(data.isLive),
|
isLive: this.buildBoolean(data.isLive),
|
||||||
|
|
||||||
isLocal: this.buildBoolean(data.onlyLocal) ? true : undefined
|
isLocal: this.buildBoolean(data.onlyLocal) ? true : undefined
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { finalize, map } from 'rxjs/operators'
|
import { NgFor, NgStyle } from '@angular/common'
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
||||||
import { AuthService, Notifier } from '@app/core'
|
import { AuthService, Notifier } from '@app/core'
|
||||||
|
import { Video } from '@app/shared/shared-main/video/video.model'
|
||||||
|
import { CommonVideoParams, VideoService } from '@app/shared/shared-main/video/video.service'
|
||||||
import { objectKeysTyped } from '@peertube/peertube-core-utils'
|
import { objectKeysTyped } from '@peertube/peertube-core-utils'
|
||||||
import { ResultList, VideoSortField } from '@peertube/peertube-models'
|
import { ResultList, VideoSortField } from '@peertube/peertube-models'
|
||||||
import { CustomMarkupComponent } from './shared'
|
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
|
import { finalize, map } from 'rxjs/operators'
|
||||||
import { MiniatureDisplayOptions, VideoMiniatureComponent } from '../../shared-video-miniature/video-miniature.component'
|
import { MiniatureDisplayOptions, VideoMiniatureComponent } from '../../shared-video-miniature/video-miniature.component'
|
||||||
import { NgStyle, NgFor } from '@angular/common'
|
import { CustomMarkupComponent } from './shared'
|
||||||
import { Video } from '@app/shared/shared-main/video/video.model'
|
|
||||||
import { VideoService } from '@app/shared/shared-main/video/video.service'
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Markup component list videos depending on criteria
|
* Markup component list videos depending on criteria
|
||||||
|
@ -33,6 +33,7 @@ export class VideosListMarkupComponent implements CustomMarkupComponent, OnInit
|
||||||
@Input() maxRows: number
|
@Input() maxRows: number
|
||||||
@Input() channelHandle: string
|
@Input() channelHandle: string
|
||||||
@Input() accountHandle: string
|
@Input() accountHandle: string
|
||||||
|
@Input() host: string
|
||||||
|
|
||||||
@Output() loaded = new EventEmitter<boolean>()
|
@Output() loaded = new EventEmitter<boolean>()
|
||||||
|
|
||||||
|
@ -90,26 +91,37 @@ export class VideosListMarkupComponent implements CustomMarkupComponent, OnInit
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideosObservable () {
|
getVideosObservable () {
|
||||||
const options = {
|
const options: CommonVideoParams = {
|
||||||
videoPagination: {
|
videoPagination: {
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
itemsPerPage: this.count
|
itemsPerPage: this.count
|
||||||
},
|
},
|
||||||
categoryOneOf: this.categoryOneOf,
|
categoryOneOf: this.categoryOneOf,
|
||||||
languageOneOf: this.languageOneOf,
|
languageOneOf: this.languageOneOf,
|
||||||
|
host: this.host,
|
||||||
isLocal: this.isLocal,
|
isLocal: this.isLocal,
|
||||||
isLive: this.isLive,
|
isLive: this.isLive,
|
||||||
sort: this.sort as VideoSortField,
|
sort: this.sort as VideoSortField,
|
||||||
account: { nameWithHost: this.accountHandle },
|
|
||||||
videoChannel: { nameWithHost: this.channelHandle },
|
|
||||||
skipCount: true
|
skipCount: true
|
||||||
}
|
}
|
||||||
|
|
||||||
let obs: Observable<ResultList<Video>>
|
let obs: Observable<ResultList<Video>>
|
||||||
|
|
||||||
if (this.channelHandle) obs = this.videoService.getVideoChannelVideos(options)
|
if (this.channelHandle) {
|
||||||
else if (this.accountHandle) obs = this.videoService.getAccountVideos(options)
|
obs = this.videoService.getVideoChannelVideos({
|
||||||
else obs = this.videoService.getVideos(options)
|
...options,
|
||||||
|
|
||||||
|
videoChannel: { nameWithHost: this.channelHandle }
|
||||||
|
})
|
||||||
|
} else if (this.accountHandle) {
|
||||||
|
obs = this.videoService.getAccountVideos({
|
||||||
|
...options,
|
||||||
|
|
||||||
|
account: { nameWithHost: this.accountHandle }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
obs = this.videoService.getVideos(options)
|
||||||
|
}
|
||||||
|
|
||||||
return obs.pipe(map(({ data }) => data))
|
return obs.pipe(map(({ data }) => data))
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ export type CommonVideoParams = {
|
||||||
isLive?: boolean
|
isLive?: boolean
|
||||||
skipCount?: boolean
|
skipCount?: boolean
|
||||||
nsfw?: BooleanBothQuery
|
nsfw?: BooleanBothQuery
|
||||||
|
host?: string
|
||||||
search?: string
|
search?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,6 +549,7 @@ export class VideoService {
|
||||||
isLive,
|
isLive,
|
||||||
nsfw,
|
nsfw,
|
||||||
search,
|
search,
|
||||||
|
host,
|
||||||
|
|
||||||
...otherOptions
|
...otherOptions
|
||||||
} = options
|
} = options
|
||||||
|
@ -568,6 +570,7 @@ export class VideoService {
|
||||||
if (categoryOneOf !== undefined) newParams = this.restService.addArrayParams(newParams, 'categoryOneOf', categoryOneOf)
|
if (categoryOneOf !== undefined) newParams = this.restService.addArrayParams(newParams, 'categoryOneOf', categoryOneOf)
|
||||||
if (privacyOneOf !== undefined) newParams = this.restService.addArrayParams(newParams, 'privacyOneOf', privacyOneOf)
|
if (privacyOneOf !== undefined) newParams = this.restService.addArrayParams(newParams, 'privacyOneOf', privacyOneOf)
|
||||||
if (search) newParams = newParams.set('search', search)
|
if (search) newParams = newParams.set('search', search)
|
||||||
|
if (host) newParams = newParams.set('host', host)
|
||||||
|
|
||||||
newParams = this.restService.addObjectParams(newParams, otherOptions)
|
newParams = this.restService.addObjectParams(newParams, otherOptions)
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ export type VideosListMarkupData = {
|
||||||
channelHandle?: string
|
channelHandle?: string
|
||||||
accountHandle?: string
|
accountHandle?: string
|
||||||
|
|
||||||
|
host?: string
|
||||||
|
|
||||||
isLive?: string // number
|
isLive?: string // number
|
||||||
|
|
||||||
onlyLocal?: StringBoolean
|
onlyLocal?: StringBoolean
|
||||||
|
|
|
@ -34,6 +34,8 @@ export interface VideosCommonQuery {
|
||||||
|
|
||||||
excludeAlreadyWatched?: boolean
|
excludeAlreadyWatched?: boolean
|
||||||
|
|
||||||
|
host?: string
|
||||||
|
|
||||||
// Only available with special user right
|
// Only available with special user right
|
||||||
autoTagOneOf?: string[]
|
autoTagOneOf?: string[]
|
||||||
privacyOneOf?: VideoPrivacyType[]
|
privacyOneOf?: VideoPrivacyType[]
|
||||||
|
|
|
@ -615,13 +615,15 @@ export class VideosCommand extends AbstractCommand {
|
||||||
'categoryOneOf',
|
'categoryOneOf',
|
||||||
'licenceOneOf',
|
'licenceOneOf',
|
||||||
'languageOneOf',
|
'languageOneOf',
|
||||||
|
'host',
|
||||||
'privacyOneOf',
|
'privacyOneOf',
|
||||||
'tagsOneOf',
|
'tagsOneOf',
|
||||||
'tagsAllOf',
|
'tagsAllOf',
|
||||||
'isLocal',
|
'isLocal',
|
||||||
'include',
|
'include',
|
||||||
'skipCount',
|
'skipCount',
|
||||||
'autoTagOneOf'
|
'autoTagOneOf',
|
||||||
|
'search'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
import { expect } from 'chai'
|
|
||||||
import { pick } from '@peertube/peertube-core-utils'
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
import {
|
import {
|
||||||
HttpStatusCode,
|
HttpStatusCode,
|
||||||
|
@ -11,7 +10,8 @@ import {
|
||||||
VideoInclude,
|
VideoInclude,
|
||||||
VideoIncludeType,
|
VideoIncludeType,
|
||||||
VideoPrivacy,
|
VideoPrivacy,
|
||||||
VideoPrivacyType
|
VideoPrivacyType,
|
||||||
|
VideosCommonQuery
|
||||||
} from '@peertube/peertube-models'
|
} from '@peertube/peertube-models'
|
||||||
import {
|
import {
|
||||||
cleanupTests,
|
cleanupTests,
|
||||||
|
@ -24,6 +24,7 @@ import {
|
||||||
setDefaultVideoChannel,
|
setDefaultVideoChannel,
|
||||||
waitJobs
|
waitJobs
|
||||||
} from '@peertube/peertube-server-commands'
|
} from '@peertube/peertube-server-commands'
|
||||||
|
import { expect } from 'chai'
|
||||||
|
|
||||||
describe('Test videos filter', function () {
|
describe('Test videos filter', function () {
|
||||||
let servers: PeerTubeServer[]
|
let servers: PeerTubeServer[]
|
||||||
|
@ -89,17 +90,11 @@ describe('Test videos filter', function () {
|
||||||
async function listVideos (options: {
|
async function listVideos (options: {
|
||||||
server: PeerTubeServer
|
server: PeerTubeServer
|
||||||
path: string
|
path: string
|
||||||
isLocal?: boolean
|
|
||||||
hasWebVideoFiles?: boolean
|
|
||||||
hasHLSFiles?: boolean
|
|
||||||
include?: VideoIncludeType
|
|
||||||
privacyOneOf?: VideoPrivacyType[]
|
|
||||||
category?: number
|
|
||||||
tagsAllOf?: string[]
|
|
||||||
token?: string
|
token?: string
|
||||||
expectedStatus?: HttpStatusCodeType
|
expectedStatus?: HttpStatusCodeType
|
||||||
excludeAlreadyWatched?: boolean
|
excludeAlreadyWatched?: boolean
|
||||||
}) {
|
} & VideosCommonQuery) {
|
||||||
const res = await makeGetRequest({
|
const res = await makeGetRequest({
|
||||||
url: options.server.url,
|
url: options.server.url,
|
||||||
path: options.path,
|
path: options.path,
|
||||||
|
@ -108,12 +103,15 @@ describe('Test videos filter', function () {
|
||||||
...pick(options, [
|
...pick(options, [
|
||||||
'isLocal',
|
'isLocal',
|
||||||
'include',
|
'include',
|
||||||
'category',
|
|
||||||
'tagsAllOf',
|
|
||||||
'hasWebVideoFiles',
|
'hasWebVideoFiles',
|
||||||
'hasHLSFiles',
|
'hasHLSFiles',
|
||||||
|
'tagsAllOf',
|
||||||
|
'categoryOneOf',
|
||||||
|
'languageOneOf',
|
||||||
'privacyOneOf',
|
'privacyOneOf',
|
||||||
'excludeAlreadyWatched'
|
'excludeAlreadyWatched',
|
||||||
|
'host',
|
||||||
|
'search'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
sort: 'createdAt'
|
sort: 'createdAt'
|
||||||
|
@ -399,6 +397,51 @@ describe('Test videos filter', function () {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should filter by language', async function () {
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'english', language: 'en' } })
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'french', language: 'fr' } })
|
||||||
|
|
||||||
|
for (const path of paths) {
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, languageOneOf: [ 'fr', 'en' ] })
|
||||||
|
expect(videos).to.have.lengthOf(2)
|
||||||
|
expect(videos.map(v => v.name)).to.have.members([ 'english', 'french' ])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, languageOneOf: [ 'ca', 'es' ] })
|
||||||
|
expect(videos).to.have.lengthOf(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should filter by host', async function () {
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'filter host 1' } })
|
||||||
|
await servers[1].videos.upload({ attributes: { name: 'filter host 2' } })
|
||||||
|
|
||||||
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
const getVideos = (videos: Video[]) => videos.filter(v => v.name.includes('filter host'))
|
||||||
|
|
||||||
|
{
|
||||||
|
const { data } = await servers[0].videos.list({ search: 'filter host' })
|
||||||
|
expect(getVideos(data)).to.have.lengthOf(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const { data } = await servers[0].videos.list({ search: 'filter host', host: servers[0].host })
|
||||||
|
const videos = getVideos(data)
|
||||||
|
|
||||||
|
expect(videos).to.have.lengthOf(1)
|
||||||
|
expect(videos.map(v => v.name)).to.have.members([ 'filter host 1' ])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const { data } = await servers[0].videos.list({ host: 'example.com' })
|
||||||
|
expect(data).to.have.lengthOf(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('Should filter by HLS or Web Video files', async function () {
|
it('Should filter by HLS or Web Video files', async function () {
|
||||||
this.timeout(360000)
|
this.timeout(360000)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ function pickCommonVideoQuery (query: VideosCommonQueryAfterSanitize) {
|
||||||
'categoryOneOf',
|
'categoryOneOf',
|
||||||
'licenceOneOf',
|
'licenceOneOf',
|
||||||
'languageOneOf',
|
'languageOneOf',
|
||||||
|
'host',
|
||||||
'privacyOneOf',
|
'privacyOneOf',
|
||||||
'tagsOneOf',
|
'tagsOneOf',
|
||||||
'tagsAllOf',
|
'tagsAllOf',
|
||||||
|
|
|
@ -10,10 +10,6 @@ const videosSearchValidator = [
|
||||||
.optional()
|
.optional()
|
||||||
.not().isEmpty(),
|
.not().isEmpty(),
|
||||||
|
|
||||||
query('host')
|
|
||||||
.optional()
|
|
||||||
.custom(isHostValid),
|
|
||||||
|
|
||||||
query('startDate')
|
query('startDate')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isDateValid).withMessage('Should have a start date that conforms to ISO 8601'),
|
.custom(isDateValid).withMessage('Should have a start date that conforms to ISO 8601'),
|
||||||
|
|
|
@ -56,6 +56,7 @@ import {
|
||||||
} from '../shared/index.js'
|
} from '../shared/index.js'
|
||||||
import { addDurationToVideoFileIfNeeded, commonVideoFileChecks, isVideoFileAccepted } from './shared/index.js'
|
import { addDurationToVideoFileIfNeeded, commonVideoFileChecks, isVideoFileAccepted } from './shared/index.js'
|
||||||
import { VideoLoadType } from '@server/lib/model-loaders/video.js'
|
import { VideoLoadType } from '@server/lib/model-loaders/video.js'
|
||||||
|
import { isHostValid } from '@server/helpers/custom-validators/servers.js'
|
||||||
|
|
||||||
export const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
|
export const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
|
||||||
body('videofile')
|
body('videofile')
|
||||||
|
@ -491,6 +492,9 @@ export const commonVideosFiltersValidator = [
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(arrayify)
|
.customSanitizer(arrayify)
|
||||||
.custom(isStringArray).withMessage('Should have a valid autoTagOneOf array'),
|
.custom(isStringArray).withMessage('Should have a valid autoTagOneOf array'),
|
||||||
|
query('host')
|
||||||
|
.optional()
|
||||||
|
.custom(isHostValid),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
|
@ -1141,6 +1141,8 @@ export class VideoModel extends SequelizeModel<VideoModel> {
|
||||||
tagsAllOf?: string[]
|
tagsAllOf?: string[]
|
||||||
privacyOneOf?: VideoPrivacyType[]
|
privacyOneOf?: VideoPrivacyType[]
|
||||||
|
|
||||||
|
host?: string
|
||||||
|
|
||||||
accountId?: number
|
accountId?: number
|
||||||
videoChannelId?: number
|
videoChannelId?: number
|
||||||
|
|
||||||
|
@ -1184,6 +1186,7 @@ export class VideoModel extends SequelizeModel<VideoModel> {
|
||||||
'categoryOneOf',
|
'categoryOneOf',
|
||||||
'licenceOneOf',
|
'licenceOneOf',
|
||||||
'languageOneOf',
|
'languageOneOf',
|
||||||
|
'host',
|
||||||
'autoTagOneOf',
|
'autoTagOneOf',
|
||||||
'tagsOneOf',
|
'tagsOneOf',
|
||||||
'tagsAllOf',
|
'tagsAllOf',
|
||||||
|
|
|
@ -794,6 +794,7 @@ paths:
|
||||||
- $ref: '#/components/parameters/languageOneOf'
|
- $ref: '#/components/parameters/languageOneOf'
|
||||||
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
|
- $ref: '#/components/parameters/host'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
- $ref: '#/components/parameters/privacyOneOf'
|
- $ref: '#/components/parameters/privacyOneOf'
|
||||||
|
@ -2256,6 +2257,7 @@ paths:
|
||||||
- $ref: '#/components/parameters/tagsAllOf'
|
- $ref: '#/components/parameters/tagsAllOf'
|
||||||
- $ref: '#/components/parameters/licenceOneOf'
|
- $ref: '#/components/parameters/licenceOneOf'
|
||||||
- $ref: '#/components/parameters/languageOneOf'
|
- $ref: '#/components/parameters/languageOneOf'
|
||||||
|
- $ref: '#/components/parameters/host'
|
||||||
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
|
@ -2803,6 +2805,7 @@ paths:
|
||||||
- $ref: '#/components/parameters/tagsAllOf'
|
- $ref: '#/components/parameters/tagsAllOf'
|
||||||
- $ref: '#/components/parameters/licenceOneOf'
|
- $ref: '#/components/parameters/licenceOneOf'
|
||||||
- $ref: '#/components/parameters/languageOneOf'
|
- $ref: '#/components/parameters/languageOneOf'
|
||||||
|
- $ref: '#/components/parameters/host'
|
||||||
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
|
@ -4497,6 +4500,7 @@ paths:
|
||||||
- $ref: '#/components/parameters/tagsAllOf'
|
- $ref: '#/components/parameters/tagsAllOf'
|
||||||
- $ref: '#/components/parameters/licenceOneOf'
|
- $ref: '#/components/parameters/licenceOneOf'
|
||||||
- $ref: '#/components/parameters/languageOneOf'
|
- $ref: '#/components/parameters/languageOneOf'
|
||||||
|
- $ref: '#/components/parameters/host'
|
||||||
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
- $ref: '#/components/parameters/autoTagOneOfVideo'
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
|
|
Loading…
Reference in New Issue