]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/shared/shared-video-miniature/video-filters.model.ts
More robust webtorrent redundancy download
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / shared-video-miniature / video-filters.model.ts
1 import { intoArray, toBoolean } from '@app/helpers'
2 import { AttributesOnly } from '@shared/core-utils'
3 import { BooleanBothQuery, NSFWPolicyType, VideoFilter, VideoSortField } from '@shared/models'
4
5 type VideoFiltersKeys = {
6 [ id in keyof AttributesOnly<VideoFilters> ]: any
7 }
8
9 export type VideoFilterScope = 'local' | 'federated'
10
11 export class VideoFilters {
12 sort: VideoSortField
13 nsfw: BooleanBothQuery
14
15 languageOneOf: string[]
16 categoryOneOf: number[]
17
18 scope: VideoFilterScope
19 allVideos: boolean
20
21 live: BooleanBothQuery
22
23 search: string
24
25 private defaultValues = new Map<keyof VideoFilters, any>([
26 [ 'sort', '-publishedAt' ],
27 [ 'nsfw', 'false' ],
28 [ 'languageOneOf', undefined ],
29 [ 'categoryOneOf', undefined ],
30 [ 'scope', 'federated' ],
31 [ 'allVideos', false ],
32 [ 'live', 'both' ]
33 ])
34
35 private activeFilters: { key: string, canRemove: boolean, label: string, value?: string }[] = []
36 private defaultNSFWPolicy: NSFWPolicyType
37
38 private onChangeCallbacks: Array<() => void> = []
39 private oldFormObjectString: string
40
41 private readonly hiddenFields: string[] = []
42
43 constructor (defaultSort: string, defaultScope: VideoFilterScope, hiddenFields: string[] = []) {
44 this.setDefaultSort(defaultSort)
45 this.setDefaultScope(defaultScope)
46
47 this.hiddenFields = hiddenFields
48
49 this.reset()
50 }
51
52 onChange (cb: () => void) {
53 this.onChangeCallbacks.push(cb)
54 }
55
56 triggerChange () {
57 // Don't run on change if the values did not change
58 const currentFormObjectString = JSON.stringify(this.toFormObject())
59 if (this.oldFormObjectString && currentFormObjectString === this.oldFormObjectString) return
60
61 this.oldFormObjectString = currentFormObjectString
62
63 for (const cb of this.onChangeCallbacks) {
64 cb()
65 }
66 }
67
68 setDefaultScope (scope: VideoFilterScope) {
69 this.defaultValues.set('scope', scope)
70 }
71
72 setDefaultSort (sort: string) {
73 this.defaultValues.set('sort', sort)
74 }
75
76 setNSFWPolicy (nsfwPolicy: NSFWPolicyType) {
77 this.updateDefaultNSFW(nsfwPolicy)
78 }
79
80 reset (specificKey?: string) {
81 for (const [ key, value ] of this.defaultValues) {
82 if (specificKey && specificKey !== key) continue
83
84 // FIXME: typings
85 this[key as any] = value
86 }
87
88 this.buildActiveFilters()
89 }
90
91 load (obj: Partial<AttributesOnly<VideoFilters>>) {
92 if (obj.sort !== undefined) this.sort = obj.sort
93
94 if (obj.nsfw !== undefined) this.nsfw = obj.nsfw
95
96 if (obj.languageOneOf !== undefined) this.languageOneOf = intoArray(obj.languageOneOf)
97 if (obj.categoryOneOf !== undefined) this.categoryOneOf = intoArray(obj.categoryOneOf)
98
99 if (obj.scope !== undefined) this.scope = obj.scope
100 if (obj.allVideos !== undefined) this.allVideos = toBoolean(obj.allVideos)
101
102 if (obj.live !== undefined) this.live = obj.live
103
104 if (obj.search !== undefined) this.search = obj.search
105
106 this.buildActiveFilters()
107 }
108
109 buildActiveFilters () {
110 this.activeFilters = []
111
112 this.activeFilters.push({
113 key: 'nsfw',
114 canRemove: false,
115 label: $localize`Sensitive content`,
116 value: this.getNSFWValue()
117 })
118
119 this.activeFilters.push({
120 key: 'scope',
121 canRemove: false,
122 label: $localize`Scope`,
123 value: this.scope === 'federated'
124 ? $localize`Federated`
125 : $localize`Local`
126 })
127
128 if (this.languageOneOf && this.languageOneOf.length !== 0) {
129 this.activeFilters.push({
130 key: 'languageOneOf',
131 canRemove: true,
132 label: $localize`Languages`,
133 value: this.languageOneOf.map(l => l.toUpperCase()).join(', ')
134 })
135 }
136
137 if (this.categoryOneOf && this.categoryOneOf.length !== 0) {
138 this.activeFilters.push({
139 key: 'categoryOneOf',
140 canRemove: true,
141 label: $localize`Categories`,
142 value: this.categoryOneOf.join(', ')
143 })
144 }
145
146 if (this.allVideos) {
147 this.activeFilters.push({
148 key: 'allVideos',
149 canRemove: true,
150 label: $localize`All videos`
151 })
152 }
153
154 if (this.live === 'true') {
155 this.activeFilters.push({
156 key: 'live',
157 canRemove: true,
158 label: $localize`Live videos`
159 })
160 } else if (this.live === 'false') {
161 this.activeFilters.push({
162 key: 'live',
163 canRemove: true,
164 label: $localize`VOD videos`
165 })
166 }
167
168 this.activeFilters = this.activeFilters
169 .filter(a => this.hiddenFields.includes(a.key) === false)
170 }
171
172 getActiveFilters () {
173 return this.activeFilters
174 }
175
176 toFormObject (): VideoFiltersKeys {
177 const result: Partial<VideoFiltersKeys> = {}
178
179 for (const [ key ] of this.defaultValues) {
180 result[key] = this[key]
181 }
182
183 return result as VideoFiltersKeys
184 }
185
186 toUrlObject () {
187 const result: { [ id: string ]: any } = {}
188
189 for (const [ key, defaultValue ] of this.defaultValues) {
190 if (this[key] !== defaultValue) {
191 result[key] = this[key]
192 }
193 }
194
195 return result
196 }
197
198 toVideosAPIObject () {
199 let filter: VideoFilter
200
201 if (this.scope === 'local' && this.allVideos) {
202 filter = 'all-local'
203 } else if (this.scope === 'federated' && this.allVideos) {
204 filter = 'all'
205 } else if (this.scope === 'local') {
206 filter = 'local'
207 }
208
209 let isLive: boolean
210 if (this.live === 'true') isLive = true
211 else if (this.live === 'false') isLive = false
212
213 return {
214 sort: this.sort,
215 nsfw: this.nsfw,
216 languageOneOf: this.languageOneOf,
217 categoryOneOf: this.categoryOneOf,
218 search: this.search,
219 filter,
220 isLive
221 }
222 }
223
224 getNSFWDisplayLabel () {
225 if (this.defaultNSFWPolicy === 'blur') return $localize`Blurred`
226
227 return $localize`Displayed`
228 }
229
230 private getNSFWValue () {
231 if (this.nsfw === 'false') return $localize`hidden`
232 if (this.defaultNSFWPolicy === 'blur') return $localize`blurred`
233
234 return $localize`displayed`
235 }
236
237 private updateDefaultNSFW (nsfwPolicy: NSFWPolicyType) {
238 const nsfw = nsfwPolicy === 'do_not_list'
239 ? 'false'
240 : 'both'
241
242 this.defaultValues.set('nsfw', nsfw)
243 this.defaultNSFWPolicy = nsfwPolicy
244
245 this.reset('nsfw')
246 }
247 }