Add ability to filter by host
This commit is contained in:
parent
4543d255b6
commit
e5a2e7a442
2
PeerTube
2
PeerTube
|
@ -1 +1 @@
|
||||||
Subproject commit cffa06fd28bbfb03980bc7d151cfd93130c3daaf
|
Subproject commit 28be9d1d3ee92db7c9fd84c82e4ea20900eab0f5
|
|
@ -1,6 +1,7 @@
|
||||||
export interface SearchUrl {
|
export interface SearchUrl {
|
||||||
search?: string
|
search?: string
|
||||||
nsfw?: string
|
nsfw?: string
|
||||||
|
host?: string
|
||||||
publishedDateRange?: string
|
publishedDateRange?: string
|
||||||
durationRange?: string
|
durationRange?: string
|
||||||
categoryOneOf?: number[]
|
categoryOneOf?: number[]
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
@import "_variables";
|
@import "_variables";
|
||||||
@import "./progress";
|
@import "./progress";
|
||||||
|
|
||||||
|
$border-input-color: #C6C6C6;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +96,7 @@ body {
|
||||||
select {
|
select {
|
||||||
padding: 0 35px 0 12px;
|
padding: 0 35px 0 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 1px solid #C6C6C6;
|
border: 1px solid $border-input-color;
|
||||||
background: transparent none;
|
background: transparent none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -117,6 +119,15 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.classic-input-text {
|
||||||
|
display: block;
|
||||||
|
min-height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid $border-input-color;
|
||||||
|
padding: 0 35px 0 12px;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.results {
|
.results {
|
||||||
.root-result {
|
.root-result {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { VideoPlaylistsSearchQuery } from '../../../PeerTube/shared/models'
|
import { ResultList, VideoPlaylistsSearchQuery } from '../../../PeerTube/shared/models'
|
||||||
import { ResultList } from '../../../PeerTube/shared/models/result-list.model'
|
|
||||||
import { VideoChannelsSearchQuery } from '../../../PeerTube/shared/models/search/video-channels-search-query.model'
|
import { VideoChannelsSearchQuery } from '../../../PeerTube/shared/models/search/video-channels-search-query.model'
|
||||||
import { VideosSearchQuery } from '../../../PeerTube/shared/models/search/videos-search-query.model'
|
import { VideosSearchQuery } from '../../../PeerTube/shared/models/search/videos-search-query.model'
|
||||||
import { EnhancedVideoChannel } from '../../../server/types/channel.model'
|
import { EnhancedVideoChannel } from '../../../server/types/channel.model'
|
||||||
import { EnhancedVideo } from '../../../server/types/video.model'
|
|
||||||
import { EnhancedPlaylist } from '../../../server/types/playlist.model'
|
import { EnhancedPlaylist } from '../../../server/types/playlist.model'
|
||||||
|
import { EnhancedVideo } from '../../../server/types/video.model'
|
||||||
import { buildApiUrl } from './utils'
|
import { buildApiUrl } from './utils'
|
||||||
|
|
||||||
const baseVideosPath = '/api/v1/search/videos'
|
const baseVideosPath = '/api/v1/search/videos'
|
||||||
|
|
|
@ -160,6 +160,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label v-translate for="host">Host</label>
|
||||||
|
|
||||||
|
<input type="text" id="host" name="host" v-model="formHost" class="classic-input-text" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label v-translate for="tagsAllOf">All of these tags</label>
|
<label v-translate for="tagsAllOf">All of these tags</label>
|
||||||
<button v-translate class="reset-button" v-on:click="resetField('tagsAllOf')" v-if="formTagsAllOf.length !== 0">
|
<button v-translate class="reset-button" v-on:click="resetField('tagsAllOf')" v-if="formTagsAllOf.length !== 0">
|
||||||
|
@ -500,6 +506,7 @@
|
||||||
formSort: '-match',
|
formSort: '-match',
|
||||||
|
|
||||||
formNSFW: undefined,
|
formNSFW: undefined,
|
||||||
|
formHost: '',
|
||||||
formPublishedDateRange: undefined,
|
formPublishedDateRange: undefined,
|
||||||
formDurationRange: undefined,
|
formDurationRange: undefined,
|
||||||
formCategoryOneOf: undefined,
|
formCategoryOneOf: undefined,
|
||||||
|
@ -785,6 +792,7 @@
|
||||||
search: this.formSearch,
|
search: this.formSearch,
|
||||||
sort: this.formSort,
|
sort: this.formSort,
|
||||||
nsfw: this.formNSFW,
|
nsfw: this.formNSFW,
|
||||||
|
host: this.formHost,
|
||||||
isLive: this.formIsLive,
|
isLive: this.formIsLive,
|
||||||
publishedDateRange: this.formPublishedDateRange,
|
publishedDateRange: this.formPublishedDateRange,
|
||||||
durationRange: this.formDurationRange,
|
durationRange: this.formDurationRange,
|
||||||
|
@ -835,6 +843,9 @@
|
||||||
if (query.isLive) this.formIsLive = query.isLive
|
if (query.isLive) this.formIsLive = query.isLive
|
||||||
else this.formIsLive = undefined
|
else this.formIsLive = undefined
|
||||||
|
|
||||||
|
if (query.host) this.formHost = query.host
|
||||||
|
else this.formHost = ''
|
||||||
|
|
||||||
if (query.page && this.currentPage !== query.page) {
|
if (query.page && this.currentPage !== query.page) {
|
||||||
this.currentPage = parseInt(query.page + '')
|
this.currentPage = parseInt(query.page + '')
|
||||||
} else {
|
} else {
|
||||||
|
@ -871,6 +882,8 @@
|
||||||
|
|
||||||
isLive: this.formIsLive !== undefined ? this.formIsLive : undefined,
|
isLive: this.formIsLive !== undefined ? this.formIsLive : undefined,
|
||||||
|
|
||||||
|
host: this.formHost || undefined,
|
||||||
|
|
||||||
start,
|
start,
|
||||||
count,
|
count,
|
||||||
sort: this.formSort
|
sort: this.formSort
|
||||||
|
@ -887,6 +900,7 @@
|
||||||
|
|
||||||
return {
|
return {
|
||||||
search: this.formSearch,
|
search: this.formSearch,
|
||||||
|
host: this.formHost || undefined,
|
||||||
start,
|
start,
|
||||||
sort,
|
sort,
|
||||||
count
|
count
|
||||||
|
@ -903,6 +917,7 @@
|
||||||
|
|
||||||
return {
|
return {
|
||||||
search: this.formSearch,
|
search: this.formSearch,
|
||||||
|
host: this.formHost || undefined,
|
||||||
start,
|
start,
|
||||||
sort,
|
sort,
|
||||||
count
|
count
|
||||||
|
@ -1011,6 +1026,7 @@
|
||||||
else if (field === 'isLive') this.formIsLive = undefined
|
else if (field === 'isLive') this.formIsLive = undefined
|
||||||
else if (field === 'tagsAllOf') this.formTagsAllOf = []
|
else if (field === 'tagsAllOf') this.formTagsAllOf = []
|
||||||
else if (field === 'tagsOneOf') this.formTagsOneOf = []
|
else if (field === 'tagsOneOf') this.formTagsOneOf = []
|
||||||
|
else if (field === 'host') this.formHost = ''
|
||||||
},
|
},
|
||||||
|
|
||||||
simpleFormReset (searchDone = true) {
|
simpleFormReset (searchDone = true) {
|
||||||
|
@ -1022,6 +1038,7 @@
|
||||||
let count = 0
|
let count = 0
|
||||||
|
|
||||||
if (this.formNSFW) count++
|
if (this.formNSFW) count++
|
||||||
|
if (this.formHost) count++
|
||||||
if (this.formPublishedDateRange) count++
|
if (this.formPublishedDateRange) count++
|
||||||
if (this.formDurationRange) count++
|
if (this.formDurationRange) count++
|
||||||
if (this.formCategoryOneOf) count++
|
if (this.formCategoryOneOf) count++
|
||||||
|
@ -1035,6 +1052,9 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
isChannelOrPlaylistSearchDisabled () {
|
isChannelOrPlaylistSearchDisabled () {
|
||||||
|
// We can search against host for playlists and channels
|
||||||
|
if (this.formHost) return this.countActiveFilters() > 1
|
||||||
|
|
||||||
return this.countActiveFilters() > 0
|
return this.countActiveFilters() > 0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
import { ResultList } from '../../PeerTube/shared/models/result-list.model'
|
import { ResultList } from '../../PeerTube/shared/models/common/result-list.model'
|
||||||
|
|
||||||
function badRequest (req: express.Request, res: express.Response) {
|
function badRequest (req: express.Request, res: express.Response) {
|
||||||
return res.type('json').status(400).end()
|
return res.type('json').status(400).end()
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { formatAvatarForAPI, formatAvatarForDB } from './shared/elastic-search-a
|
||||||
async function queryChannels (search: ChannelsSearchQuery) {
|
async function queryChannels (search: ChannelsSearchQuery) {
|
||||||
const bool: any = {}
|
const bool: any = {}
|
||||||
const mustNot: any[] = []
|
const mustNot: any[] = []
|
||||||
|
const filter: any[] = []
|
||||||
|
|
||||||
if (search.search) {
|
if (search.search) {
|
||||||
Object.assign(bool, {
|
Object.assign(bool, {
|
||||||
|
@ -42,6 +43,18 @@ async function queryChannels (search: ChannelsSearchQuery) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (search.host) {
|
||||||
|
filter.push({
|
||||||
|
term: {
|
||||||
|
host: search.host
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.length !== 0) {
|
||||||
|
Object.assign(bool, { filter })
|
||||||
|
}
|
||||||
|
|
||||||
if (mustNot.length !== 0) {
|
if (mustNot.length !== 0) {
|
||||||
Object.assign(bool, { must_not: mustNot })
|
Object.assign(bool, { must_not: mustNot })
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { buildChannelOrAccountSummaryMapping, formatActorForDB, formatActorSumma
|
||||||
async function queryPlaylists (search: PlaylistsSearchQuery) {
|
async function queryPlaylists (search: PlaylistsSearchQuery) {
|
||||||
const bool: any = {}
|
const bool: any = {}
|
||||||
const mustNot: any[] = []
|
const mustNot: any[] = []
|
||||||
|
const filter: any[] = []
|
||||||
|
|
||||||
if (search.search) {
|
if (search.search) {
|
||||||
Object.assign(bool, {
|
Object.assign(bool, {
|
||||||
|
@ -41,6 +42,18 @@ async function queryPlaylists (search: PlaylistsSearchQuery) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (search.host) {
|
||||||
|
filter.push({
|
||||||
|
term: {
|
||||||
|
'ownerAccount.host': search.host
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.length !== 0) {
|
||||||
|
Object.assign(bool, { filter })
|
||||||
|
}
|
||||||
|
|
||||||
if (mustNot.length !== 0) {
|
if (mustNot.length !== 0) {
|
||||||
Object.assign(bool, { must_not: mustNot })
|
Object.assign(bool, { must_not: mustNot })
|
||||||
}
|
}
|
||||||
|
@ -66,6 +79,7 @@ function formatPlaylistForAPI (p: DBPlaylist, fromHost?: string): EnhancedPlayli
|
||||||
return {
|
return {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
uuid: p.uuid,
|
uuid: p.uuid,
|
||||||
|
shortUUID: p.shortUUID,
|
||||||
|
|
||||||
score: p.score,
|
score: p.score,
|
||||||
|
|
||||||
|
@ -106,6 +120,7 @@ function formatPlaylistForDB (p: IndexablePlaylist): DBPlaylist {
|
||||||
return {
|
return {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
uuid: p.uuid,
|
uuid: p.uuid,
|
||||||
|
shortUUID: p.shortUUID,
|
||||||
|
|
||||||
indexedAt: new Date(),
|
indexedAt: new Date(),
|
||||||
createdAt: p.createdAt,
|
createdAt: p.createdAt,
|
||||||
|
@ -145,6 +160,9 @@ function buildPlaylistsMapping () {
|
||||||
uuid: {
|
uuid: {
|
||||||
type: 'keyword'
|
type: 'keyword'
|
||||||
},
|
},
|
||||||
|
shortUUID: {
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
format: 'date_optional_time'
|
format: 'date_optional_time'
|
||||||
|
|
|
@ -162,6 +162,14 @@ async function queryVideos (search: VideosSearchQuery) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exists(search.host)) {
|
||||||
|
filter.push({
|
||||||
|
term: {
|
||||||
|
'account.host': search.host
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(bool, { filter })
|
Object.assign(bool, { filter })
|
||||||
|
|
||||||
if (mustNot.length !== 0) {
|
if (mustNot.length !== 0) {
|
||||||
|
@ -231,6 +239,9 @@ function buildVideosMapping () {
|
||||||
uuid: {
|
uuid: {
|
||||||
type: 'keyword'
|
type: 'keyword'
|
||||||
},
|
},
|
||||||
|
shortUUID: {
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
format: 'date_optional_time'
|
format: 'date_optional_time'
|
||||||
|
@ -366,6 +377,7 @@ function formatVideoForDB (v: IndexableVideo | IndexableVideoDetails): DBVideo |
|
||||||
return {
|
return {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
uuid: v.uuid,
|
uuid: v.uuid,
|
||||||
|
shortUUID: v.shortUUID,
|
||||||
|
|
||||||
indexedAt: new Date(),
|
indexedAt: new Date(),
|
||||||
createdAt: v.createdAt,
|
createdAt: v.createdAt,
|
||||||
|
@ -418,6 +430,7 @@ function formatVideoForAPI (v: DBVideoDetails, fromHost?: string): EnhancedVideo
|
||||||
return {
|
return {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
uuid: v.uuid,
|
uuid: v.uuid,
|
||||||
|
shortUUID: v.shortUUID,
|
||||||
|
|
||||||
score: v.score,
|
score: v.score,
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,8 @@ const commonVideosFiltersValidator = [
|
||||||
const videosSearchValidator = [
|
const videosSearchValidator = [
|
||||||
check('search').optional().not().isEmpty().withMessage('Should have a valid search'),
|
check('search').optional().not().isEmpty().withMessage('Should have a valid search'),
|
||||||
|
|
||||||
|
check('host').optional().not().isEmpty().withMessage('Should have a valid host'),
|
||||||
|
|
||||||
check('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'),
|
check('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'),
|
||||||
check('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'),
|
check('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'),
|
||||||
|
|
||||||
|
@ -87,6 +89,7 @@ const videosSearchValidator = [
|
||||||
|
|
||||||
const videoChannelsSearchValidator = [
|
const videoChannelsSearchValidator = [
|
||||||
check('search').not().isEmpty().withMessage('Should have a valid search'),
|
check('search').not().isEmpty().withMessage('Should have a valid search'),
|
||||||
|
check('host').optional().not().isEmpty().withMessage('Should have a valid host'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug({ query: req.query, body: req.body }, 'Checking video channels search query')
|
logger.debug({ query: req.query, body: req.body }, 'Checking video channels search query')
|
||||||
|
@ -99,6 +102,7 @@ const videoChannelsSearchValidator = [
|
||||||
|
|
||||||
const videoPlaylistsSearchValidator = [
|
const videoPlaylistsSearchValidator = [
|
||||||
check('search').not().isEmpty().withMessage('Should have a valid search'),
|
check('search').not().isEmpty().withMessage('Should have a valid search'),
|
||||||
|
check('host').optional().not().isEmpty().withMessage('Should have a valid host'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug({ query: req.query, body: req.body }, 'Checking video playlists search query')
|
logger.debug({ query: req.query, body: req.body }, 'Checking video playlists search query')
|
||||||
|
|
Loading…
Reference in New Issue