1 import { intoArray } from '@app/helpers'
6 VideoChannelsSearchQuery,
7 VideoPlaylistsSearchQuery,
9 } from '@shared/models'
11 export type AdvancedSearchResultType = 'videos' | 'playlists' | 'channels'
13 export class AdvancedSearch {
14 startDate: string // ISO 8601
15 endDate: string // ISO 8601
17 originallyPublishedStartDate: string // ISO 8601
18 originallyPublishedEndDate: string // ISO 8601
20 nsfw: BooleanBothQuery
31 durationMin: number // seconds
32 durationMax: number // seconds
40 searchTarget: SearchTargetType
41 resultType: AdvancedSearchResultType
43 // Filters we don't want to count, because they are mandatory
44 private silentFilters = new Set([ 'sort', 'searchTarget' ])
46 constructor (options?: {
49 originallyPublishedStartDate?: string
50 originallyPublishedEndDate?: string
51 nsfw?: BooleanBothQuery
52 categoryOneOf?: string
54 languageOneOf?: string
66 searchTarget?: SearchTargetType
67 resultType?: AdvancedSearchResultType
71 this.startDate = options.startDate || undefined
72 this.endDate = options.endDate || undefined
73 this.originallyPublishedStartDate = options.originallyPublishedStartDate || undefined
74 this.originallyPublishedEndDate = options.originallyPublishedEndDate || undefined
76 this.nsfw = options.nsfw || undefined
77 this.isLive = options.isLive || undefined
79 this.categoryOneOf = options.categoryOneOf || undefined
80 this.licenceOneOf = options.licenceOneOf || undefined
81 this.languageOneOf = options.languageOneOf || undefined
82 this.tagsOneOf = intoArray(options.tagsOneOf)
83 this.tagsAllOf = intoArray(options.tagsAllOf)
84 this.durationMin = options.durationMin ? parseInt(options.durationMin, 10) : undefined
85 this.durationMax = options.durationMax ? parseInt(options.durationMax, 10) : undefined
87 this.host = options.host || undefined
89 this.searchTarget = options.searchTarget || undefined
91 this.resultType = options.resultType || undefined
93 if (!this.resultType && this.hasVideoFilter()) {
94 this.resultType = 'videos'
97 if (isNaN(this.durationMin)) this.durationMin = undefined
98 if (isNaN(this.durationMax)) this.durationMax = undefined
100 this.sort = options.sort || '-match'
104 const obj = this.toUrlObject()
105 for (const k of Object.keys(obj)) {
106 if (this.silentFilters.has(k)) continue
108 if (this.isValidValue(obj[k])) return true
115 this.startDate = undefined
116 this.endDate = undefined
117 this.originallyPublishedStartDate = undefined
118 this.originallyPublishedEndDate = undefined
119 this.nsfw = undefined
120 this.categoryOneOf = undefined
121 this.licenceOneOf = undefined
122 this.languageOneOf = undefined
123 this.tagsOneOf = undefined
124 this.tagsAllOf = undefined
125 this.durationMin = undefined
126 this.durationMax = undefined
127 this.isLive = undefined
128 this.host = undefined
135 startDate: this.startDate,
136 endDate: this.endDate,
137 originallyPublishedStartDate: this.originallyPublishedStartDate,
138 originallyPublishedEndDate: this.originallyPublishedEndDate,
140 categoryOneOf: this.categoryOneOf,
141 licenceOneOf: this.licenceOneOf,
142 languageOneOf: this.languageOneOf,
143 tagsOneOf: this.tagsOneOf,
144 tagsAllOf: this.tagsAllOf,
145 durationMin: this.durationMin,
146 durationMax: this.durationMax,
150 searchTarget: this.searchTarget,
151 resultType: this.resultType
155 toVideosAPIObject (): VideosSearchQuery {
157 if (this.isLive) isLive = this.isLive === 'true'
160 startDate: this.startDate,
161 endDate: this.endDate,
162 originallyPublishedStartDate: this.originallyPublishedStartDate,
163 originallyPublishedEndDate: this.originallyPublishedEndDate,
165 categoryOneOf: intoArray(this.categoryOneOf),
166 licenceOneOf: intoArray(this.licenceOneOf),
167 languageOneOf: intoArray(this.languageOneOf),
168 tagsOneOf: this.tagsOneOf,
169 tagsAllOf: this.tagsAllOf,
170 durationMin: this.durationMin,
171 durationMax: this.durationMax,
175 searchTarget: this.searchTarget
179 toPlaylistAPIObject (): VideoPlaylistsSearchQuery {
182 searchTarget: this.searchTarget
186 toChannelAPIObject (): VideoChannelsSearchQuery {
189 searchTarget: this.searchTarget
196 const obj = this.toUrlObject()
197 for (const k of Object.keys(obj)) {
198 if (this.silentFilters.has(k)) continue
200 if (this.isValidValue(obj[k])) acc++
206 private isValidValue (val: any) {
207 if (val === undefined) return false
208 if (val === '') return false
209 if (Array.isArray(val) && val.length === 0) return false
214 private hasVideoFilter () {
215 return this.startDate !== undefined ||
216 this.endDate !== undefined ||
217 this.originallyPublishedStartDate !== undefined ||
218 this.originallyPublishedEndDate !== undefined ||
219 this.nsfw !== undefined ||
220 this.categoryOneOf !== undefined ||
221 this.licenceOneOf !== undefined ||
222 this.languageOneOf !== undefined ||
223 this.tagsOneOf !== undefined ||
224 this.tagsAllOf !== undefined ||
225 this.durationMin !== undefined ||
226 this.durationMax !== undefined ||
227 this.host !== undefined ||
228 this.isLive !== undefined