14a5d04846f495236e8b9b020acf2bcab58eefd4
[oweals/peertube.git] / client / src / app / search / search-filters.component.ts
1 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
2 import { ValidatorFn } from '@angular/forms'
3 import { ServerService } from '@app/core'
4 import { AdvancedSearch } from '@app/search/advanced-search.model'
5 import { VideoValidatorsService } from '@app/shared/shared-forms'
6 import { I18n } from '@ngx-translate/i18n-polyfill'
7 import { ServerConfig, VideoConstant } from '@shared/models'
8
9 @Component({
10   selector: 'my-search-filters',
11   styleUrls: [ './search-filters.component.scss' ],
12   templateUrl: './search-filters.component.html'
13 })
14 export class SearchFiltersComponent implements OnInit {
15   @Input() advancedSearch: AdvancedSearch = new AdvancedSearch()
16
17   @Output() filtered = new EventEmitter<AdvancedSearch>()
18
19   videoCategories: VideoConstant<number>[] = []
20   videoLicences: VideoConstant<number>[] = []
21   videoLanguages: VideoConstant<string>[] = []
22
23   tagValidators: ValidatorFn[]
24   tagValidatorsMessages: { [ name: string ]: string }
25
26   publishedDateRanges: { id: string, label: string }[] = []
27   sorts: { id: string, label: string }[] = []
28   durationRanges: { id: string, label: string }[] = []
29
30   publishedDateRange: string
31   durationRange: string
32
33   originallyPublishedStartYear: string
34   originallyPublishedEndYear: string
35
36   private serverConfig: ServerConfig
37
38   constructor (
39     private i18n: I18n,
40     private videoValidatorsService: VideoValidatorsService,
41     private serverService: ServerService
42   ) {
43     this.tagValidators = this.videoValidatorsService.VIDEO_TAGS.VALIDATORS
44     this.tagValidatorsMessages = this.videoValidatorsService.VIDEO_TAGS.MESSAGES
45     this.publishedDateRanges = [
46       {
47         id: 'any_published_date',
48         label: this.i18n('Any')
49       },
50       {
51         id: 'today',
52         label: this.i18n('Today')
53       },
54       {
55         id: 'last_7days',
56         label: this.i18n('Last 7 days')
57       },
58       {
59         id: 'last_30days',
60         label: this.i18n('Last 30 days')
61       },
62       {
63         id: 'last_365days',
64         label: this.i18n('Last 365 days')
65       }
66     ]
67
68     this.durationRanges = [
69       {
70         id: 'any_duration',
71         label: this.i18n('Any')
72       },
73       {
74         id: 'short',
75         label: this.i18n('Short (< 4 min)')
76       },
77       {
78         id: 'medium',
79         label: this.i18n('Medium (4-10 min)')
80       },
81       {
82         id: 'long',
83         label: this.i18n('Long (> 10 min)')
84       }
85     ]
86
87     this.sorts = [
88       {
89         id: '-match',
90         label: this.i18n('Relevance')
91       },
92       {
93         id: '-publishedAt',
94         label: this.i18n('Publish date')
95       },
96       {
97         id: '-views',
98         label: this.i18n('Views')
99       }
100     ]
101   }
102
103   ngOnInit () {
104     this.serverConfig = this.serverService.getTmpConfig()
105     this.serverService.getConfig()
106         .subscribe(config => this.serverConfig = config)
107
108     this.serverService.getVideoCategories().subscribe(categories => this.videoCategories = categories)
109     this.serverService.getVideoLicences().subscribe(licences => this.videoLicences = licences)
110     this.serverService.getVideoLanguages().subscribe(languages => this.videoLanguages = languages)
111
112     this.loadFromDurationRange()
113     this.loadFromPublishedRange()
114     this.loadOriginallyPublishedAtYears()
115   }
116
117   inputUpdated () {
118     this.updateModelFromDurationRange()
119     this.updateModelFromPublishedRange()
120     this.updateModelFromOriginallyPublishedAtYears()
121   }
122
123   formUpdated () {
124     this.inputUpdated()
125     this.filtered.emit(this.advancedSearch)
126   }
127
128   reset () {
129     this.advancedSearch.reset()
130     this.durationRange = undefined
131     this.publishedDateRange = undefined
132     this.originallyPublishedStartYear = undefined
133     this.originallyPublishedEndYear = undefined
134     this.inputUpdated()
135   }
136
137   resetField (fieldName: string, value?: any) {
138     this.advancedSearch[fieldName] = value
139   }
140
141   resetLocalField (fieldName: string, value?: any) {
142     this[fieldName] = value
143     this.inputUpdated()
144   }
145
146   resetOriginalPublicationYears () {
147     this.originallyPublishedStartYear = this.originallyPublishedEndYear = undefined
148   }
149
150   isSearchTargetEnabled () {
151     return this.serverConfig.search.searchIndex.enabled && this.serverConfig.search.searchIndex.disableLocalSearch !== true
152   }
153
154   private loadOriginallyPublishedAtYears () {
155     this.originallyPublishedStartYear = this.advancedSearch.originallyPublishedStartDate
156       ? new Date(this.advancedSearch.originallyPublishedStartDate).getFullYear().toString()
157       : null
158
159     this.originallyPublishedEndYear = this.advancedSearch.originallyPublishedEndDate
160       ? new Date(this.advancedSearch.originallyPublishedEndDate).getFullYear().toString()
161       : null
162   }
163
164   private loadFromDurationRange () {
165     if (this.advancedSearch.durationMin || this.advancedSearch.durationMax) {
166       const fourMinutes = 60 * 4
167       const tenMinutes = 60 * 10
168
169       if (this.advancedSearch.durationMin === fourMinutes && this.advancedSearch.durationMax === tenMinutes) {
170         this.durationRange = 'medium'
171       } else if (this.advancedSearch.durationMax === fourMinutes) {
172         this.durationRange = 'short'
173       } else if (this.advancedSearch.durationMin === tenMinutes) {
174         this.durationRange = 'long'
175       }
176     }
177   }
178
179   private loadFromPublishedRange () {
180     if (this.advancedSearch.startDate) {
181       const date = new Date(this.advancedSearch.startDate)
182       const now = new Date()
183
184       const diff = Math.abs(date.getTime() - now.getTime())
185
186       const dayMS = 1000 * 3600 * 24
187       const numberOfDays = diff / dayMS
188
189       if (numberOfDays >= 365) this.publishedDateRange = 'last_365days'
190       else if (numberOfDays >= 30) this.publishedDateRange = 'last_30days'
191       else if (numberOfDays >= 7) this.publishedDateRange = 'last_7days'
192       else if (numberOfDays >= 0) this.publishedDateRange = 'today'
193     }
194   }
195
196   private updateModelFromOriginallyPublishedAtYears () {
197     const baseDate = new Date()
198     baseDate.setHours(0, 0, 0, 0)
199     baseDate.setMonth(0, 1)
200
201     if (this.originallyPublishedStartYear) {
202       const year = parseInt(this.originallyPublishedStartYear, 10)
203       const start = new Date(baseDate)
204       start.setFullYear(year)
205
206       this.advancedSearch.originallyPublishedStartDate = start.toISOString()
207     } else {
208       this.advancedSearch.originallyPublishedStartDate = null
209     }
210
211     if (this.originallyPublishedEndYear) {
212       const year = parseInt(this.originallyPublishedEndYear, 10)
213       const end = new Date(baseDate)
214       end.setFullYear(year)
215
216       this.advancedSearch.originallyPublishedEndDate = end.toISOString()
217     } else {
218       this.advancedSearch.originallyPublishedEndDate = null
219     }
220   }
221
222   private updateModelFromDurationRange () {
223     if (!this.durationRange) return
224
225     const fourMinutes = 60 * 4
226     const tenMinutes = 60 * 10
227
228     switch (this.durationRange) {
229       case 'short':
230         this.advancedSearch.durationMin = undefined
231         this.advancedSearch.durationMax = fourMinutes
232         break
233
234       case 'medium':
235         this.advancedSearch.durationMin = fourMinutes
236         this.advancedSearch.durationMax = tenMinutes
237         break
238
239       case 'long':
240         this.advancedSearch.durationMin = tenMinutes
241         this.advancedSearch.durationMax = undefined
242         break
243     }
244   }
245
246   private updateModelFromPublishedRange () {
247     if (!this.publishedDateRange) return
248
249     // today
250     const date = new Date()
251     date.setHours(0, 0, 0, 0)
252
253     switch (this.publishedDateRange) {
254       case 'last_7days':
255         date.setDate(date.getDate() - 7)
256         break
257
258       case 'last_30days':
259         date.setDate(date.getDate() - 30)
260         break
261
262       case 'last_365days':
263         date.setDate(date.getDate() - 365)
264         break
265     }
266
267     this.advancedSearch.startDate = date.toISOString()
268   }
269 }