]>
Commit | Line | Data |
---|---|---|
dd24f1bb C |
1 | import { Component, OnDestroy, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router' | |
3 | import { ComponentPaginationLight, DisableForReuseHook, MetaService, RedirectService, ServerService } from '@app/core' | |
4 | import { HooksService } from '@app/core/plugins/hooks.service' | |
5 | import { VideoService } from '@app/shared/shared-main' | |
6 | import { VideoFilters, VideoFilterScope } from '@app/shared/shared-video-miniature/video-filters.model' | |
7 | import { ClientFilterHookName, VideoSortField } from '@shared/models' | |
8 | import { Subscription } from 'rxjs' | |
9 | ||
10 | export type VideosListCommonPageRouteData = { | |
11 | sort: VideoSortField | |
12 | ||
13 | scope: VideoFilterScope | |
14 | hookParams: ClientFilterHookName | |
15 | hookResult: ClientFilterHookName | |
16 | } | |
17 | ||
18 | @Component({ | |
19 | templateUrl: './videos-list-common-page.component.html' | |
20 | }) | |
21 | export class VideosListCommonPageComponent implements OnInit, OnDestroy, DisableForReuseHook { | |
22 | getVideosObservableFunction = this.getVideosObservable.bind(this) | |
23 | getSyndicationItemsFunction = this.getSyndicationItems.bind(this) | |
24 | baseRouteBuilderFunction = this.baseRouteBuilder.bind(this) | |
25 | ||
26 | title: string | |
27 | titleTooltip: string | |
28 | ||
29 | groupByDate: boolean | |
30 | ||
31 | defaultSort: VideoSortField | |
32 | defaultScope: VideoFilterScope | |
33 | ||
34 | hookParams: ClientFilterHookName | |
35 | hookResult: ClientFilterHookName | |
36 | ||
37 | loadUserVideoPreferences = true | |
38 | ||
39 | displayFilters = true | |
40 | ||
41 | disabled = false | |
42 | ||
43 | private trendingDays: number | |
44 | private routeSub: Subscription | |
45 | ||
46 | constructor ( | |
47 | private server: ServerService, | |
48 | private route: ActivatedRoute, | |
49 | private videoService: VideoService, | |
50 | private hooks: HooksService, | |
51 | private meta: MetaService, | |
52 | private redirectService: RedirectService | |
53 | ) { | |
54 | } | |
55 | ||
56 | ngOnInit () { | |
57 | this.trendingDays = this.server.getHTMLConfig().trending.videos.intervalDays | |
58 | ||
59 | this.routeSub = this.route.params.subscribe(params => { | |
60 | this.update(params['page']) | |
61 | }) | |
62 | } | |
63 | ||
64 | ngOnDestroy () { | |
65 | if (this.routeSub) this.routeSub.unsubscribe() | |
66 | } | |
67 | ||
68 | getVideosObservable (pagination: ComponentPaginationLight, filters: VideoFilters) { | |
69 | const params = { | |
70 | ...filters.toVideosAPIObject(), | |
71 | ||
72 | videoPagination: pagination, | |
73 | skipCount: true | |
74 | } | |
75 | ||
76 | return this.hooks.wrapObsFun( | |
77 | this.videoService.getVideos.bind(this.videoService), | |
78 | params, | |
79 | 'common', | |
80 | this.hookParams, | |
81 | this.hookResult | |
82 | ) | |
83 | } | |
84 | ||
85 | getSyndicationItems (filters: VideoFilters) { | |
86 | const result = filters.toVideosAPIObject() | |
87 | ||
2760b454 | 88 | return this.videoService.getVideoFeedUrls(result.sort, result.isLocal) |
dd24f1bb C |
89 | } |
90 | ||
91 | onFiltersChanged (filters: VideoFilters) { | |
92 | this.buildTitle(filters.scope, filters.sort) | |
93 | this.updateGroupByDate(filters.sort) | |
94 | } | |
95 | ||
96 | baseRouteBuilder (filters: VideoFilters) { | |
97 | const sanitizedSort = this.getSanitizedSort(filters.sort) | |
98 | ||
99 | let suffix: string | |
100 | ||
101 | if (filters.scope === 'local') suffix = 'local' | |
102 | else if (sanitizedSort === 'publishedAt') suffix = 'recently-added' | |
103 | else suffix = 'trending' | |
104 | ||
105 | return [ '/videos', suffix ] | |
106 | } | |
107 | ||
108 | disableForReuse () { | |
109 | this.disabled = true | |
110 | } | |
111 | ||
112 | enabledForReuse () { | |
113 | this.disabled = false | |
114 | } | |
115 | ||
116 | update (page: string) { | |
117 | const data = this.getData(page) | |
118 | ||
119 | this.hookParams = data.hookParams | |
120 | this.hookResult = data.hookResult | |
121 | ||
122 | this.defaultSort = data.sort | |
123 | this.defaultScope = data.scope | |
124 | ||
125 | this.buildTitle() | |
126 | this.updateGroupByDate(this.defaultSort) | |
127 | ||
128 | this.meta.setTitle(this.title) | |
129 | } | |
130 | ||
131 | private getData (page: string) { | |
132 | if (page === 'trending') return this.generateTrendingData(this.route.snapshot) | |
133 | ||
134 | if (page === 'local') return this.generateLocalData() | |
135 | ||
136 | return this.generateRecentlyAddedData() | |
137 | } | |
138 | ||
139 | private generateRecentlyAddedData (): VideosListCommonPageRouteData { | |
140 | return { | |
141 | sort: '-publishedAt', | |
142 | scope: 'federated', | |
143 | hookParams: 'filter:api.recently-added-videos.videos.list.params', | |
144 | hookResult: 'filter:api.recently-added-videos.videos.list.result' | |
145 | } | |
146 | } | |
147 | ||
148 | private generateLocalData (): VideosListCommonPageRouteData { | |
149 | return { | |
150 | sort: '-publishedAt' as VideoSortField, | |
151 | scope: 'local', | |
152 | hookParams: 'filter:api.local-videos.videos.list.params', | |
153 | hookResult: 'filter:api.local-videos.videos.list.result' | |
154 | } | |
155 | } | |
156 | ||
157 | private generateTrendingData (route: ActivatedRouteSnapshot): VideosListCommonPageRouteData { | |
158 | const sort = route.queryParams['sort'] ?? this.parseTrendingAlgorithm(this.redirectService.getDefaultTrendingAlgorithm()) | |
159 | ||
160 | return { | |
161 | sort, | |
162 | scope: 'federated', | |
163 | hookParams: 'filter:api.trending-videos.videos.list.params', | |
164 | hookResult: 'filter:api.trending-videos.videos.list.result' | |
165 | } | |
166 | } | |
167 | ||
168 | private parseTrendingAlgorithm (algorithm: string): VideoSortField { | |
169 | switch (algorithm) { | |
170 | case 'most-viewed': | |
171 | return '-trending' | |
172 | ||
173 | case 'most-liked': | |
174 | return '-likes' | |
175 | ||
010382b6 C |
176 | // We'll automatically apply "best" sort if using "hot" sort with a logged user |
177 | case 'best': | |
178 | return '-hot' | |
179 | ||
dd24f1bb C |
180 | default: |
181 | return '-' + algorithm as VideoSortField | |
182 | } | |
183 | } | |
184 | ||
185 | private updateGroupByDate (sort: VideoSortField) { | |
186 | this.groupByDate = sort === '-publishedAt' || sort === 'publishedAt' | |
187 | } | |
188 | ||
189 | private buildTitle (scope: VideoFilterScope = this.defaultScope, sort: VideoSortField = this.defaultSort) { | |
190 | const sanitizedSort = this.getSanitizedSort(sort) | |
191 | ||
192 | if (scope === 'local') { | |
193 | this.title = $localize`Local videos` | |
194 | this.titleTooltip = $localize`Only videos uploaded on this instance are displayed` | |
195 | return | |
196 | } | |
197 | ||
198 | if (sanitizedSort === 'publishedAt') { | |
199 | this.title = $localize`Recently added` | |
200 | this.titleTooltip = undefined | |
201 | return | |
202 | } | |
203 | ||
db19581f | 204 | if ([ 'hot', 'trending', 'likes', 'views' ].includes(sanitizedSort)) { |
dd24f1bb C |
205 | this.title = $localize`Trending` |
206 | ||
eaa52952 C |
207 | if (sanitizedSort === 'hot') { |
208 | this.titleTooltip = $localize`Videos with the most interactions for recent videos` | |
209 | return | |
210 | } | |
211 | ||
212 | if (sanitizedSort === 'likes') { | |
213 | this.titleTooltip = $localize`Videos that have the most likes` | |
214 | return | |
215 | } | |
216 | ||
217 | if (sanitizedSort === 'views') { | |
218 | this.titleTooltip = undefined | |
219 | return | |
220 | } | |
dd24f1bb C |
221 | |
222 | if (sanitizedSort === 'trending') { | |
eaa52952 C |
223 | if (this.trendingDays === 1) { |
224 | this.titleTooltip = $localize`Videos with the most views during the last 24 hours` | |
225 | return | |
226 | } | |
227 | ||
228 | this.titleTooltip = $localize`Videos with the most views during the last ${this.trendingDays} days` | |
dd24f1bb C |
229 | } |
230 | ||
231 | return | |
232 | } | |
233 | } | |
234 | ||
235 | private getSanitizedSort (sort: VideoSortField) { | |
236 | return sort.replace(/^-/, '') as VideoSortField | |
237 | } | |
238 | } |