mirror of https://github.com/Chocobozzz/PeerTube
Add ability to search by uuids/actor names
parent
164c8d46cf
commit
fbd67e7f38
|
@ -46,7 +46,7 @@ export { searchChannelsRouter }
|
|||
|
||||
function searchVideoChannels (req: express.Request, res: express.Response) {
|
||||
const query: VideoChannelsSearchQuery = req.query
|
||||
const search = query.search
|
||||
let search = query.search || ''
|
||||
|
||||
const parts = search.split('@')
|
||||
|
||||
|
@ -57,7 +57,7 @@ function searchVideoChannels (req: express.Request, res: express.Response) {
|
|||
if (isURISearch(search) || isWebfingerSearch) return searchVideoChannelURI(search, isWebfingerSearch, res)
|
||||
|
||||
// @username -> username to search in DB
|
||||
if (query.search.startsWith('@')) query.search = query.search.replace(/^@/, '')
|
||||
if (search.startsWith('@')) search = search.replace(/^@/, '')
|
||||
|
||||
if (isSearchIndexSearch(query)) {
|
||||
return searchVideoChannelsIndex(query, res)
|
||||
|
@ -99,7 +99,8 @@ async function searchVideoChannelsDB (query: VideoChannelsSearchQuery, res: expr
|
|||
start: query.start,
|
||||
count: query.count,
|
||||
sort: query.sort,
|
||||
host: query.host
|
||||
host: query.host,
|
||||
names: query.names
|
||||
}, 'filter:api.search.video-channels.local.list.params')
|
||||
|
||||
const resultList = await Hooks.wrapPromiseFun(
|
||||
|
|
|
@ -89,7 +89,8 @@ async function searchVideoPlaylistsDB (query: VideoPlaylistsSearchQuery, res: ex
|
|||
start: query.start,
|
||||
count: query.count,
|
||||
sort: query.sort,
|
||||
host: query.host
|
||||
host: query.host,
|
||||
uuids: query.uuids
|
||||
}, 'filter:api.search.video-playlists.local.list.params')
|
||||
|
||||
const resultList = await Hooks.wrapPromiseFun(
|
||||
|
|
|
@ -39,6 +39,10 @@ function isUUIDValid (value: string) {
|
|||
return exists(value) && validator.isUUID('' + value, 4)
|
||||
}
|
||||
|
||||
function areUUIDsValid (values: string[]) {
|
||||
return isArray(values) && values.every(v => isUUIDValid(v))
|
||||
}
|
||||
|
||||
function isIdOrUUIDValid (value: string) {
|
||||
return isIdValid(value) || isUUIDValid(value)
|
||||
}
|
||||
|
@ -132,6 +136,10 @@ function toCompleteUUID (value: string) {
|
|||
return value
|
||||
}
|
||||
|
||||
function toCompleteUUIDs (values: string[]) {
|
||||
return values.map(v => toCompleteUUID(v))
|
||||
}
|
||||
|
||||
function toIntOrNull (value: string) {
|
||||
const v = toValueOrNull(value)
|
||||
|
||||
|
@ -180,6 +188,7 @@ export {
|
|||
isIdValid,
|
||||
isSafePath,
|
||||
isUUIDValid,
|
||||
toCompleteUUIDs,
|
||||
toCompleteUUID,
|
||||
isIdOrUUIDValid,
|
||||
isDateValid,
|
||||
|
@ -187,6 +196,7 @@ export {
|
|||
toBooleanOrNull,
|
||||
isBooleanValid,
|
||||
toIntOrNull,
|
||||
areUUIDsValid,
|
||||
toArray,
|
||||
toIntArray,
|
||||
isFileFieldValid,
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as express from 'express'
|
|||
import { query } from 'express-validator'
|
||||
import { isSearchTargetValid } from '@server/helpers/custom-validators/search'
|
||||
import { isHostValid } from '@server/helpers/custom-validators/servers'
|
||||
import { isDateValid } from '../../helpers/custom-validators/misc'
|
||||
import { areUUIDsValid, isDateValid, toCompleteUUIDs } from '../../helpers/custom-validators/misc'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { areValidationErrors } from './shared'
|
||||
|
||||
|
@ -27,8 +27,18 @@ const videosSearchValidator = [
|
|||
.optional()
|
||||
.custom(isDateValid).withMessage('Should have a published end date that conforms to ISO 8601'),
|
||||
|
||||
query('durationMin').optional().isInt().withMessage('Should have a valid min duration'),
|
||||
query('durationMax').optional().isInt().withMessage('Should have a valid max duration'),
|
||||
query('durationMin')
|
||||
.optional()
|
||||
.isInt().withMessage('Should have a valid min duration'),
|
||||
query('durationMax')
|
||||
.optional()
|
||||
.isInt().withMessage('Should have a valid max duration'),
|
||||
|
||||
query('uuids')
|
||||
.optional()
|
||||
.toArray()
|
||||
.customSanitizer(toCompleteUUIDs)
|
||||
.custom(areUUIDsValid).withMessage('Should have valid uuids'),
|
||||
|
||||
query('searchTarget').optional().custom(isSearchTargetValid).withMessage('Should have a valid search target'),
|
||||
|
||||
|
@ -42,7 +52,9 @@ const videosSearchValidator = [
|
|||
]
|
||||
|
||||
const videoChannelsListSearchValidator = [
|
||||
query('search').not().isEmpty().withMessage('Should have a valid search'),
|
||||
query('search')
|
||||
.optional()
|
||||
.not().isEmpty().withMessage('Should have a valid search'),
|
||||
|
||||
query('host')
|
||||
.optional()
|
||||
|
@ -52,6 +64,10 @@ const videoChannelsListSearchValidator = [
|
|||
.optional()
|
||||
.custom(isSearchTargetValid).withMessage('Should have a valid search target'),
|
||||
|
||||
query('names')
|
||||
.optional()
|
||||
.toArray(),
|
||||
|
||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
logger.debug('Checking video channels search query', { parameters: req.query })
|
||||
|
||||
|
@ -62,7 +78,9 @@ const videoChannelsListSearchValidator = [
|
|||
]
|
||||
|
||||
const videoPlaylistsListSearchValidator = [
|
||||
query('search').not().isEmpty().withMessage('Should have a valid search'),
|
||||
query('search')
|
||||
.optional()
|
||||
.not().isEmpty().withMessage('Should have a valid search'),
|
||||
|
||||
query('host')
|
||||
.optional()
|
||||
|
@ -72,6 +90,12 @@ const videoPlaylistsListSearchValidator = [
|
|||
.optional()
|
||||
.custom(isSearchTargetValid).withMessage('Should have a valid search target'),
|
||||
|
||||
query('uuids')
|
||||
.optional()
|
||||
.toArray()
|
||||
.customSanitizer(toCompleteUUIDs)
|
||||
.custom(areUUIDsValid).withMessage('Should have valid uuids'),
|
||||
|
||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
logger.debug('Checking video playlists search query', { parameters: req.query })
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ export type BuildVideosListQueryOptions = {
|
|||
tagsOneOf?: string[]
|
||||
tagsAllOf?: string[]
|
||||
|
||||
uuids?: string[]
|
||||
|
||||
withFiles?: boolean
|
||||
|
||||
accountId?: number
|
||||
|
@ -161,6 +163,10 @@ export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
|
|||
this.whereTagsAllOf(options.tagsAllOf)
|
||||
}
|
||||
|
||||
if (options.uuids) {
|
||||
this.whereUUIDs(options.uuids)
|
||||
}
|
||||
|
||||
if (options.nsfw === true) {
|
||||
this.whereNSFW()
|
||||
} else if (options.nsfw === false) {
|
||||
|
@ -386,6 +392,10 @@ export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
|
|||
)
|
||||
}
|
||||
|
||||
private whereUUIDs (uuids: string[]) {
|
||||
this.and.push('"video"."uuid" IN (' + createSafeIn(this.sequelize, uuids) + ')')
|
||||
}
|
||||
|
||||
private whereCategoryOneOf (categoryOneOf: number[]) {
|
||||
this.and.push('"video"."category" IN (:categoryOneOf)')
|
||||
this.replacements.categoryOneOf = categoryOneOf
|
||||
|
|
|
@ -59,6 +59,7 @@ type AvailableForListOptions = {
|
|||
actorId: number
|
||||
search?: string
|
||||
host?: string
|
||||
names?: string[]
|
||||
}
|
||||
|
||||
type AvailableWithStatsOptions = {
|
||||
|
@ -84,18 +85,20 @@ export type SummaryOptions = {
|
|||
// Only list local channels OR channels that are on an instance followed by actorId
|
||||
const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId)
|
||||
|
||||
const whereActor = {
|
||||
[Op.or]: [
|
||||
{
|
||||
serverId: null
|
||||
},
|
||||
{
|
||||
serverId: {
|
||||
[Op.in]: Sequelize.literal(inQueryInstanceFollow)
|
||||
const whereActorAnd: WhereOptions[] = [
|
||||
{
|
||||
[Op.or]: [
|
||||
{
|
||||
serverId: null
|
||||
},
|
||||
{
|
||||
serverId: {
|
||||
[Op.in]: Sequelize.literal(inQueryInstanceFollow)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
let serverRequired = false
|
||||
let whereServer: WhereOptions
|
||||
|
@ -106,8 +109,16 @@ export type SummaryOptions = {
|
|||
}
|
||||
|
||||
if (options.host === WEBSERVER.HOST) {
|
||||
Object.assign(whereActor, {
|
||||
[Op.and]: [ { serverId: null } ]
|
||||
whereActorAnd.push({
|
||||
serverId: null
|
||||
})
|
||||
}
|
||||
|
||||
if (options.names) {
|
||||
whereActorAnd.push({
|
||||
preferredUsername: {
|
||||
[Op.in]: options.names
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -118,7 +129,9 @@ export type SummaryOptions = {
|
|||
exclude: unusedActorAttributesForAPI
|
||||
},
|
||||
model: ActorModel,
|
||||
where: whereActor,
|
||||
where: {
|
||||
[Op.and]: whereActorAnd
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: ServerModel,
|
||||
|
@ -454,26 +467,23 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
|||
|
||||
static searchForApi (options: {
|
||||
actorId: number
|
||||
search: string
|
||||
search?: string
|
||||
start: number
|
||||
count: number
|
||||
sort: string
|
||||
|
||||
host?: string
|
||||
names?: string[]
|
||||
}) {
|
||||
const attributesInclude = []
|
||||
const escapedSearch = VideoChannelModel.sequelize.escape(options.search)
|
||||
const escapedLikeSearch = VideoChannelModel.sequelize.escape('%' + options.search + '%')
|
||||
attributesInclude.push(createSimilarityAttribute('VideoChannelModel.name', options.search))
|
||||
let attributesInclude: any[] = [ literal('0 as similarity') ]
|
||||
let where: WhereOptions
|
||||
|
||||
const query = {
|
||||
attributes: {
|
||||
include: attributesInclude
|
||||
},
|
||||
offset: options.start,
|
||||
limit: options.count,
|
||||
order: getSort(options.sort),
|
||||
where: {
|
||||
if (options.search) {
|
||||
const escapedSearch = VideoChannelModel.sequelize.escape(options.search)
|
||||
const escapedLikeSearch = VideoChannelModel.sequelize.escape('%' + options.search + '%')
|
||||
attributesInclude = [ createSimilarityAttribute('VideoChannelModel.name', options.search) ]
|
||||
|
||||
where = {
|
||||
[Op.or]: [
|
||||
Sequelize.literal(
|
||||
'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))'
|
||||
|
@ -485,9 +495,19 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
|||
}
|
||||
}
|
||||
|
||||
const query = {
|
||||
attributes: {
|
||||
include: attributesInclude
|
||||
},
|
||||
offset: options.start,
|
||||
limit: options.count,
|
||||
order: getSort(options.sort),
|
||||
where
|
||||
}
|
||||
|
||||
return VideoChannelModel
|
||||
.scope({
|
||||
method: [ ScopeNames.FOR_API, { actorId: options.actorId, host: options.host } as AvailableForListOptions ]
|
||||
method: [ ScopeNames.FOR_API, { actorId: options.actorId, host: options.host, names: options.names } as AvailableForListOptions ]
|
||||
})
|
||||
.findAndCountAll(query)
|
||||
.then(({ rows, count }) => {
|
||||
|
|
|
@ -83,6 +83,7 @@ type AvailableForListOptions = {
|
|||
listMyPlaylists?: boolean
|
||||
search?: string
|
||||
host?: string
|
||||
uuids?: string[]
|
||||
withVideos?: boolean
|
||||
}
|
||||
|
||||
|
@ -200,18 +201,26 @@ function getVideoLengthSelect () {
|
|||
})
|
||||
}
|
||||
|
||||
if (options.uuids) {
|
||||
whereAnd.push({
|
||||
uuid: {
|
||||
[Op.in]: options.uuids
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (options.withVideos === true) {
|
||||
whereAnd.push(
|
||||
literal(`(${getVideoLengthSelect()}) != 0`)
|
||||
)
|
||||
}
|
||||
|
||||
const attributesInclude = []
|
||||
let attributesInclude: any[] = [ literal('0 as similarity') ]
|
||||
|
||||
if (options.search) {
|
||||
const escapedSearch = VideoPlaylistModel.sequelize.escape(options.search)
|
||||
const escapedLikeSearch = VideoPlaylistModel.sequelize.escape('%' + options.search + '%')
|
||||
attributesInclude.push(createSimilarityAttribute('VideoPlaylistModel.name', options.search))
|
||||
attributesInclude = [ createSimilarityAttribute('VideoPlaylistModel.name', options.search) ]
|
||||
|
||||
whereAnd.push({
|
||||
[Op.or]: [
|
||||
|
@ -359,6 +368,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
|||
listMyPlaylists?: boolean
|
||||
search?: string
|
||||
host?: string
|
||||
uuids?: string[]
|
||||
withVideos?: boolean // false by default
|
||||
}) {
|
||||
const query = {
|
||||
|
@ -379,6 +389,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
|||
listMyPlaylists: options.listMyPlaylists,
|
||||
search: options.search,
|
||||
host: options.host,
|
||||
uuids: options.uuids,
|
||||
withVideos: options.withVideos || false
|
||||
} as AvailableForListOptions
|
||||
]
|
||||
|
@ -402,6 +413,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
|||
sort: string
|
||||
search?: string
|
||||
host?: string
|
||||
uuids?: string[]
|
||||
}) {
|
||||
return VideoPlaylistModel.listForApi({
|
||||
...options,
|
||||
|
|
|
@ -1132,6 +1132,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
durationMax?: number // seconds
|
||||
user?: MUserAccountId
|
||||
filter?: VideoFilter
|
||||
uuids?: string[]
|
||||
}) {
|
||||
const serverActor = await getServerActor()
|
||||
|
||||
|
@ -1167,6 +1168,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
durationMin: options.durationMin,
|
||||
durationMax: options.durationMax,
|
||||
|
||||
uuids: options.uuids,
|
||||
|
||||
search: options.search
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,16 @@ describe('Test videos API validator', function () {
|
|||
const customQuery = { ...query, host: 'example.com' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with valid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When searching video playlists', function () {
|
||||
|
@ -172,6 +182,11 @@ describe('Test videos API validator', function () {
|
|||
await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
|
|
@ -22,8 +22,12 @@ describe('Test channels search', function () {
|
|||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
remoteServer = await createSingleServer(2, { transcoding: { enabled: false } })
|
||||
const servers = await Promise.all([
|
||||
createSingleServer(1),
|
||||
createSingleServer(2, { transcoding: { enabled: false } })
|
||||
])
|
||||
server = servers[0]
|
||||
remoteServer = servers[1]
|
||||
|
||||
await setAccessTokensToServers([ server, remoteServer ])
|
||||
|
||||
|
@ -116,6 +120,22 @@ describe('Test channels search', function () {
|
|||
}
|
||||
})
|
||||
|
||||
it('Should filter by names', async function () {
|
||||
{
|
||||
const body = await command.advancedChannelSearch({ search: { names: [ 'squall_channel', 'zell_channel' ] } })
|
||||
expect(body.total).to.equal(2)
|
||||
expect(body.data).to.have.lengthOf(2)
|
||||
expect(body.data[0].displayName).to.equal('Squall channel')
|
||||
expect(body.data[1].displayName).to.equal('Zell channel')
|
||||
}
|
||||
|
||||
{
|
||||
const body = await command.advancedChannelSearch({ search: { names: [ 'chocobozzz_channel' ] } })
|
||||
expect(body.total).to.equal(0)
|
||||
expect(body.data).to.have.lengthOf(0)
|
||||
}
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
|
|
|
@ -19,12 +19,18 @@ describe('Test playlists search', function () {
|
|||
let server: PeerTubeServer
|
||||
let remoteServer: PeerTubeServer
|
||||
let command: SearchCommand
|
||||
let playlistUUID: string
|
||||
let playlistShortUUID: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
remoteServer = await createSingleServer(2, { transcoding: { enabled: false } })
|
||||
const servers = await Promise.all([
|
||||
createSingleServer(1),
|
||||
createSingleServer(2, { transcoding: { enabled: false } })
|
||||
])
|
||||
server = servers[0]
|
||||
remoteServer = servers[1]
|
||||
|
||||
await setAccessTokensToServers([ remoteServer, server ])
|
||||
await setDefaultVideoChannel([ remoteServer, server ])
|
||||
|
@ -38,6 +44,8 @@ describe('Test playlists search', function () {
|
|||
videoChannelId: server.store.channel.id
|
||||
}
|
||||
const created = await server.playlists.create({ attributes })
|
||||
playlistUUID = created.uuid
|
||||
playlistShortUUID = created.shortUUID
|
||||
|
||||
await server.playlists.addElement({ playlistId: created.id, attributes: { videoId } })
|
||||
}
|
||||
|
@ -136,6 +144,22 @@ describe('Test playlists search', function () {
|
|||
}
|
||||
})
|
||||
|
||||
it('Should filter by UUIDs', async function () {
|
||||
for (const uuid of [ playlistUUID, playlistShortUUID ]) {
|
||||
const body = await command.advancedPlaylistSearch({ search: { uuids: [ uuid ] } })
|
||||
|
||||
expect(body.total).to.equal(1)
|
||||
expect(body.data[0].displayName).to.equal('Dr. Kenzo Tenma hospital videos')
|
||||
}
|
||||
|
||||
{
|
||||
const body = await command.advancedPlaylistSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
|
||||
|
||||
expect(body.total).to.equal(0)
|
||||
expect(body.data).to.have.lengthOf(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should not display playlists without videos', async function () {
|
||||
const search = {
|
||||
search: 'Lunge',
|
||||
|
|
|
@ -22,14 +22,19 @@ describe('Test videos search', function () {
|
|||
let remoteServer: PeerTubeServer
|
||||
let startDate: string
|
||||
let videoUUID: string
|
||||
let videoShortUUID: string
|
||||
|
||||
let command: SearchCommand
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
remoteServer = await createSingleServer(2)
|
||||
const servers = await Promise.all([
|
||||
createSingleServer(1),
|
||||
createSingleServer(2)
|
||||
])
|
||||
server = servers[0]
|
||||
remoteServer = servers[1]
|
||||
|
||||
await setAccessTokensToServers([ server, remoteServer ])
|
||||
await setDefaultVideoChannel([ server, remoteServer ])
|
||||
|
@ -50,8 +55,9 @@ describe('Test videos search', function () {
|
|||
|
||||
{
|
||||
const attributes3 = { ...attributes1, name: attributes1.name + ' - 3', language: undefined }
|
||||
const { id, uuid } = await server.videos.upload({ attributes: attributes3 })
|
||||
const { id, uuid, shortUUID } = await server.videos.upload({ attributes: attributes3 })
|
||||
videoUUID = uuid
|
||||
videoShortUUID = shortUUID
|
||||
|
||||
await server.captions.add({
|
||||
language: 'en',
|
||||
|
@ -479,6 +485,22 @@ describe('Test videos search', function () {
|
|||
expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
|
||||
})
|
||||
|
||||
it('Should filter by UUIDs', async function () {
|
||||
for (const uuid of [ videoUUID, videoShortUUID ]) {
|
||||
const body = await command.advancedVideoSearch({ search: { uuids: [ uuid ] } })
|
||||
|
||||
expect(body.total).to.equal(1)
|
||||
expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
|
||||
}
|
||||
|
||||
{
|
||||
const body = await command.advancedVideoSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
|
||||
|
||||
expect(body.total).to.equal(0)
|
||||
expect(body.data).to.have.lengthOf(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should search by host', async function () {
|
||||
{
|
||||
const body = await command.advancedVideoSearch({ search: { search: '6666 7777 8888', host: server.host } })
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { SearchTargetQuery } from './search-target-query.model'
|
||||
|
||||
export interface VideoChannelsSearchQuery extends SearchTargetQuery {
|
||||
search: string
|
||||
search?: string
|
||||
|
||||
start?: number
|
||||
count?: number
|
||||
sort?: string
|
||||
|
||||
host?: string
|
||||
names?: string[]
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { SearchTargetQuery } from './search-target-query.model'
|
||||
|
||||
export interface VideoPlaylistsSearchQuery extends SearchTargetQuery {
|
||||
search: string
|
||||
search?: string
|
||||
|
||||
start?: number
|
||||
count?: number
|
||||
sort?: string
|
||||
|
||||
host?: string
|
||||
uuids?: string[]
|
||||
}
|
||||
|
|
|
@ -14,4 +14,7 @@ export interface VideosSearchQuery extends SearchTargetQuery, VideosCommonQuery
|
|||
|
||||
durationMin?: number // seconds
|
||||
durationMax?: number // seconds
|
||||
|
||||
// UUIDs or short
|
||||
uuids?: string[]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue