diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2021-01-27 17:15:21 +0100 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2021-01-28 15:55:34 +0100 |
commit | ba5d4a849c7d7ba05f093480ae12286c4af61556 (patch) | |
tree | 704a80b96d3b437ad12feacaaaf58a96b97282a1 | |
parent | 3da68f0a781ebd893521e2e6fa200280c92ae815 (diff) | |
download | PeerTube-ba5d4a849c7d7ba05f093480ae12286c4af61556.tar.gz PeerTube-ba5d4a849c7d7ba05f093480ae12286c4af61556.tar.zst PeerTube-ba5d4a849c7d7ba05f093480ae12286c4af61556.zip |
move from trending routes to alg param
30 files changed, 211 insertions, 396 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 83b1c6a31..dd62a4aab 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -271,10 +271,9 @@ | |||
271 | <option i18n value="/videos/overview">Discover videos</option> | 271 | <option i18n value="/videos/overview">Discover videos</option> |
272 | <optgroup i18n-label label="Trending pages"> | 272 | <optgroup i18n-label label="Trending pages"> |
273 | <option i18n value="/videos/trending">Default trending page</option> | 273 | <option i18n value="/videos/trending">Default trending page</option> |
274 | <option i18n value="/videos/hot" *ngIf="isTrendingHotEnabled()">Hot videos</option> | 274 | <option i18n value="/videos/trending?alg=hot" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('hot')">Hot videos</option> |
275 | <option i18n value="/videos/hot" *ngIf="!isTrendingHotEnabled()" disabled>Hot videos</option> | 275 | <option i18n value="/videos/trending?alg=most-viewed" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('most-viewed')">Most viewed videos</option> |
276 | <option i18n value="/videos/most-viewed">Most viewed videos</option> | 276 | <option i18n value="/videos/trending?alg=most-liked" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('most-liked')">Most liked videos</option> |
277 | <option i18n value="/videos/most-liked">Most liked videos</option> | ||
278 | </optgroup> | 277 | </optgroup> |
279 | <option i18n value="/videos/recently-added">Recently added videos</option> | 278 | <option i18n value="/videos/recently-added">Recently added videos</option> |
280 | <option i18n value="/videos/local">Local videos</option> | 279 | <option i18n value="/videos/local">Local videos</option> |
@@ -283,17 +282,20 @@ | |||
283 | <div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div> | 282 | <div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div> |
284 | </div> | 283 | </div> |
285 | 284 | ||
286 | <div class="form-group" formGroupName="instance"> | 285 | <div class="form-group" formGroupName="trending"> |
287 | <label i18n for="instanceDefaultTrendingRoute">Default trending page</label> | 286 | <ng-container formGroupName="videos"> |
288 | <div class="peertube-select-container"> | 287 | <ng-container formGroupName="algorithms"> |
289 | <select id="instanceDefaultTrendingRoute" formControlName="defaultTrendingRoute" class="form-control"> | 288 | <label i18n for="trendingVideosAlgorithmsDefault">Default trending page</label> |
290 | <option i18n value="/videos/hot" *ngIf="isTrendingHotEnabled()">Hot videos</option> | 289 | <div class="peertube-select-container"> |
291 | <option i18n value="/videos/hot" *ngIf="!isTrendingHotEnabled()" disabled>Hot videos</option> | 290 | <select id="trendingVideosAlgorithmsDefault" formControlName="default" class="form-control"> |
292 | <option i18n value="/videos/trending">Most viewed videos</option> | 291 | <option i18n value="hot">Hot videos</option> |
293 | <option i18n value="/videos/most-liked">Most liked videos</option> | 292 | <option i18n value="most-viewed">Most viewed videos</option> |
294 | </select> | 293 | <option i18n value="most-liked">Most liked videos</option> |
295 | </div> | 294 | </select> |
296 | <div *ngIf="formErrors.instance.defaultTrendingRoute" class="form-error">{{ formErrors.instance.defaultTrendingRoute }}</div> | 295 | </div> |
296 | <div *ngIf="formErrors.trending.videos.algorithms.default" class="form-error">{{ formErrors.trending.videos.algorithms.default }}</div> | ||
297 | </ng-container> | ||
298 | </ng-container> | ||
297 | </div> | 299 | </div> |
298 | 300 | ||
299 | </div> | 301 | </div> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index e6fc4582b..9a46a2e59 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -186,12 +186,6 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
186 | languages: null, | 186 | languages: null, |
187 | 187 | ||
188 | defaultClientRoute: null, | 188 | defaultClientRoute: null, |
189 | defaultTrendingRoute: null, | ||
190 | pages: { | ||
191 | hot: { | ||
192 | enabled: null | ||
193 | } | ||
194 | }, | ||
195 | 189 | ||
196 | customizations: { | 190 | customizations: { |
197 | javascript: null, | 191 | javascript: null, |
@@ -230,6 +224,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
230 | } | 224 | } |
231 | } | 225 | } |
232 | }, | 226 | }, |
227 | trending: { | ||
228 | videos: { | ||
229 | algorithms: { | ||
230 | enabled: null, | ||
231 | default: null | ||
232 | } | ||
233 | } | ||
234 | }, | ||
233 | admin: { | 235 | admin: { |
234 | email: ADMIN_EMAIL_VALIDATOR | 236 | email: ADMIN_EMAIL_VALIDATOR |
235 | }, | 237 | }, |
@@ -370,8 +372,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
370 | return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true | 372 | return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true |
371 | } | 373 | } |
372 | 374 | ||
373 | isTrendingHotEnabled () { | 375 | trendingVideosAlgorithmsEnabledIncludes (algorithm: string) { |
374 | return this.form.value['instance']['pages']['hot']['enabled'] === true | 376 | return this.form.value['trending']['videos']['algorithms']['enabled'].find((e: string) => e === algorithm) |
375 | } | 377 | } |
376 | 378 | ||
377 | async formValidated () { | 379 | async formValidated () { |
diff --git a/client/src/app/+videos/video-list/trending/index.ts b/client/src/app/+videos/video-list/trending/index.ts index 93f4b1df6..70835885a 100644 --- a/client/src/app/+videos/video-list/trending/index.ts +++ b/client/src/app/+videos/video-list/trending/index.ts | |||
@@ -1,4 +1,2 @@ | |||
1 | export * from './video-trending-header.component' | 1 | export * from './video-trending-header.component' |
2 | export * from './video-hot.component' | 2 | export * from './video-trending.component' |
3 | export * from './video-most-viewed.component' | ||
4 | export * from './video-most-liked.component' | ||
diff --git a/client/src/app/+videos/video-list/trending/video-hot.component.ts b/client/src/app/+videos/video-list/trending/video-hot.component.ts deleted file mode 100644 index 1617eb21e..000000000 --- a/client/src/app/+videos/video-list/trending/video-hot.component.ts +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | import { Component, ComponentFactoryResolver, Injector, OnDestroy, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | ||
3 | import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' | ||
4 | import { HooksService } from '@app/core/plugins/hooks.service' | ||
5 | import { immutableAssign } from '@app/helpers' | ||
6 | import { VideoService } from '@app/shared/shared-main' | ||
7 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | ||
8 | import { VideoSortField } from '@shared/models' | ||
9 | import { VideoTrendingHeaderComponent } from './video-trending-header.component' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-videos-hot', | ||
13 | styleUrls: [ '../../../shared/shared-video-miniature/abstract-video-list.scss' ], | ||
14 | templateUrl: '../../../shared/shared-video-miniature/abstract-video-list.html' | ||
15 | }) | ||
16 | export class VideoHotComponent extends AbstractVideoList implements OnInit, OnDestroy { | ||
17 | HeaderComponent = VideoTrendingHeaderComponent | ||
18 | titlePage: string | ||
19 | defaultSort: VideoSortField = '-hot' | ||
20 | |||
21 | useUserVideoPreferences = true | ||
22 | |||
23 | constructor ( | ||
24 | protected router: Router, | ||
25 | protected serverService: ServerService, | ||
26 | protected route: ActivatedRoute, | ||
27 | protected notifier: Notifier, | ||
28 | protected authService: AuthService, | ||
29 | protected userService: UserService, | ||
30 | protected screenService: ScreenService, | ||
31 | protected storageService: LocalStorageService, | ||
32 | protected cfr: ComponentFactoryResolver, | ||
33 | private videoService: VideoService, | ||
34 | private hooks: HooksService | ||
35 | ) { | ||
36 | super() | ||
37 | |||
38 | this.headerComponentInjector = this.getInjector() | ||
39 | } | ||
40 | |||
41 | ngOnInit () { | ||
42 | super.ngOnInit() | ||
43 | |||
44 | this.generateSyndicationList() | ||
45 | } | ||
46 | |||
47 | ngOnDestroy () { | ||
48 | super.ngOnDestroy() | ||
49 | } | ||
50 | |||
51 | getVideosObservable (page: number) { | ||
52 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
53 | const params = { | ||
54 | videoPagination: newPagination, | ||
55 | sort: this.sort, | ||
56 | categoryOneOf: this.categoryOneOf, | ||
57 | languageOneOf: this.languageOneOf, | ||
58 | nsfwPolicy: this.nsfwPolicy, | ||
59 | skipCount: true | ||
60 | } | ||
61 | |||
62 | return this.hooks.wrapObsFun( | ||
63 | this.videoService.getVideos.bind(this.videoService), | ||
64 | params, | ||
65 | 'common', | ||
66 | 'filter:api.trending-videos.videos.list.params', | ||
67 | 'filter:api.trending-videos.videos.list.result' | ||
68 | ) | ||
69 | } | ||
70 | |||
71 | generateSyndicationList () { | ||
72 | this.syndicationItems = this.videoService.getVideoFeedUrls(this.sort, undefined, this.categoryOneOf) | ||
73 | } | ||
74 | |||
75 | getInjector () { | ||
76 | return Injector.create({ | ||
77 | providers: [{ | ||
78 | provide: 'data', | ||
79 | useValue: { | ||
80 | model: this.defaultSort | ||
81 | } | ||
82 | }] | ||
83 | }) | ||
84 | } | ||
85 | } | ||
diff --git a/client/src/app/+videos/video-list/trending/video-most-liked.component.ts b/client/src/app/+videos/video-list/trending/video-most-liked.component.ts deleted file mode 100644 index 1781cc6aa..000000000 --- a/client/src/app/+videos/video-list/trending/video-most-liked.component.ts +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | import { Component, ComponentFactoryResolver, Injector, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | ||
3 | import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' | ||
4 | import { HooksService } from '@app/core/plugins/hooks.service' | ||
5 | import { immutableAssign } from '@app/helpers' | ||
6 | import { VideoService } from '@app/shared/shared-main' | ||
7 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | ||
8 | import { VideoSortField } from '@shared/models' | ||
9 | import { VideoTrendingHeaderComponent } from './video-trending-header.component' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-videos-most-liked', | ||
13 | styleUrls: [ '../../../shared/shared-video-miniature/abstract-video-list.scss' ], | ||
14 | templateUrl: '../../../shared/shared-video-miniature/abstract-video-list.html' | ||
15 | }) | ||
16 | export class VideoMostLikedComponent extends AbstractVideoList implements OnInit { | ||
17 | HeaderComponent = VideoTrendingHeaderComponent | ||
18 | titlePage: string | ||
19 | defaultSort: VideoSortField = '-likes' | ||
20 | |||
21 | useUserVideoPreferences = true | ||
22 | |||
23 | constructor ( | ||
24 | protected router: Router, | ||
25 | protected serverService: ServerService, | ||
26 | protected route: ActivatedRoute, | ||
27 | protected notifier: Notifier, | ||
28 | protected authService: AuthService, | ||
29 | protected userService: UserService, | ||
30 | protected screenService: ScreenService, | ||
31 | protected storageService: LocalStorageService, | ||
32 | protected cfr: ComponentFactoryResolver, | ||
33 | private videoService: VideoService, | ||
34 | private hooks: HooksService | ||
35 | ) { | ||
36 | super() | ||
37 | |||
38 | this.headerComponentInjector = this.getInjector() | ||
39 | } | ||
40 | |||
41 | ngOnInit () { | ||
42 | super.ngOnInit() | ||
43 | |||
44 | this.generateSyndicationList() | ||
45 | } | ||
46 | |||
47 | getVideosObservable (page: number) { | ||
48 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
49 | const params = { | ||
50 | videoPagination: newPagination, | ||
51 | sort: this.sort, | ||
52 | categoryOneOf: this.categoryOneOf, | ||
53 | languageOneOf: this.languageOneOf, | ||
54 | nsfwPolicy: this.nsfwPolicy, | ||
55 | skipCount: true | ||
56 | } | ||
57 | |||
58 | return this.hooks.wrapObsFun( | ||
59 | this.videoService.getVideos.bind(this.videoService), | ||
60 | params, | ||
61 | 'common', | ||
62 | 'filter:api.most-liked-videos.videos.list.params', | ||
63 | 'filter:api.most-liked-videos.videos.list.result' | ||
64 | ) | ||
65 | } | ||
66 | |||
67 | generateSyndicationList () { | ||
68 | this.syndicationItems = this.videoService.getVideoFeedUrls(this.sort, undefined, this.categoryOneOf) | ||
69 | } | ||
70 | |||
71 | getInjector () { | ||
72 | return Injector.create({ | ||
73 | providers: [{ | ||
74 | provide: 'data', | ||
75 | useValue: { | ||
76 | model: this.defaultSort | ||
77 | } | ||
78 | }] | ||
79 | }) | ||
80 | } | ||
81 | } | ||
diff --git a/client/src/app/+videos/video-list/trending/video-trending-header.component.html b/client/src/app/+videos/video-list/trending/video-trending-header.component.html index a025bf1a2..7eb1e4f95 100644 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.html +++ b/client/src/app/+videos/video-list/trending/video-trending-header.component.html | |||
@@ -1,6 +1,8 @@ | |||
1 | <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" [(ngModel)]="data.model" (ngModelChange)="setSort()"> | 1 | <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" [(ngModel)]="data.model" (ngModelChange)="setSort()"> |
2 | <label *ngFor="let button of visibleButtons" ngbButtonLabel class="btn-light" placement="bottom" [ngbTooltip]="button.tooltip" container="body"> | 2 | <ng-container *ngFor="let button of buttons"> |
3 | <my-global-icon [iconName]="button.iconName"></my-global-icon> | 3 | <label *ngIf="!button.hidden" ngbButtonLabel class="btn-light" placement="bottom" [ngbTooltip]="button.tooltip" container="body"> |
4 | <input ngbButton type="radio" [value]="button.value"> {{ button.label }} | 4 | <my-global-icon [iconName]="button.iconName"></my-global-icon> |
5 | </label> | 5 | <input ngbButton type="radio" [value]="button.value"> {{ button.label }} |
6 | </label> | ||
7 | </ng-container> | ||
6 | </div> \ No newline at end of file | 8 | </div> \ No newline at end of file |
diff --git a/client/src/app/+videos/video-list/trending/video-trending-header.component.ts b/client/src/app/+videos/video-list/trending/video-trending-header.component.ts index e49b61c68..33eaa2c1e 100644 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.ts +++ b/client/src/app/+videos/video-list/trending/video-trending-header.component.ts | |||
@@ -1,30 +1,34 @@ | |||
1 | import { Component, Inject, OnInit } from '@angular/core' | 1 | import { Component, HostBinding, Inject, OnDestroy, OnInit } from '@angular/core' |
2 | import { Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature' | 3 | import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature' |
4 | import { GlobalIconName } from '@app/shared/shared-icons' | 4 | import { GlobalIconName } from '@app/shared/shared-icons' |
5 | import { VideoSortField } from '@shared/models' | ||
6 | import { ServerService } from '@app/core/server/server.service' | 5 | import { ServerService } from '@app/core/server/server.service' |
6 | import { Subscription } from 'rxjs' | ||
7 | import { RedirectService } from '@app/core' | ||
7 | 8 | ||
8 | interface VideoTrendingHeaderItem { | 9 | interface VideoTrendingHeaderItem { |
9 | label: string | 10 | label: string |
10 | iconName: GlobalIconName | 11 | iconName: GlobalIconName |
11 | value: VideoSortField | 12 | value: string |
12 | path: string | ||
13 | tooltip?: string | 13 | tooltip?: string |
14 | hidden?: boolean | 14 | hidden?: boolean |
15 | } | 15 | } |
16 | 16 | ||
17 | @Component({ | 17 | @Component({ |
18 | selector: 'video-trending-title-page', | 18 | selector: 'video-trending-title-page', |
19 | host: { 'class': 'title-page title-page-single' }, | ||
20 | styleUrls: [ './video-trending-header.component.scss' ], | 19 | styleUrls: [ './video-trending-header.component.scss' ], |
21 | templateUrl: './video-trending-header.component.html' | 20 | templateUrl: './video-trending-header.component.html' |
22 | }) | 21 | }) |
23 | export class VideoTrendingHeaderComponent extends VideoListHeaderComponent implements OnInit { | 22 | export class VideoTrendingHeaderComponent extends VideoListHeaderComponent implements OnInit, OnDestroy { |
23 | @HostBinding('class') class = 'title-page title-page-single' | ||
24 | |||
24 | buttons: VideoTrendingHeaderItem[] | 25 | buttons: VideoTrendingHeaderItem[] |
25 | 26 | ||
27 | private algorithmChangeSub: Subscription | ||
28 | |||
26 | constructor ( | 29 | constructor ( |
27 | @Inject('data') public data: any, | 30 | @Inject('data') public data: any, |
31 | private route: ActivatedRoute, | ||
28 | private router: Router, | 32 | private router: Router, |
29 | private serverService: ServerService | 33 | private serverService: ServerService |
30 | ) { | 34 | ) { |
@@ -34,23 +38,20 @@ export class VideoTrendingHeaderComponent extends VideoListHeaderComponent imple | |||
34 | { | 38 | { |
35 | label: $localize`:A variant of Trending videos based on the number of recent interactions:Hot`, | 39 | label: $localize`:A variant of Trending videos based on the number of recent interactions:Hot`, |
36 | iconName: 'flame', | 40 | iconName: 'flame', |
37 | value: '-hot', | 41 | value: 'hot', |
38 | path: 'hot', | ||
39 | tooltip: $localize`Videos totalizing the most interactions for recent videos`, | 42 | tooltip: $localize`Videos totalizing the most interactions for recent videos`, |
40 | hidden: true | 43 | hidden: true |
41 | }, | 44 | }, |
42 | { | 45 | { |
43 | label: $localize`:Main variant of Trending videos based on number of recent views:Views`, | 46 | label: $localize`:Main variant of Trending videos based on number of recent views:Views`, |
44 | iconName: 'trending', | 47 | iconName: 'trending', |
45 | value: '-trending', | 48 | value: 'most-viewed', |
46 | path: 'most-viewed', | 49 | tooltip: $localize`Videos totalizing the most views during the last 24 hours` |
47 | tooltip: $localize`Videos totalizing the most views during the last 24 hours`, | ||
48 | }, | 50 | }, |
49 | { | 51 | { |
50 | label: $localize`:A variant of Trending videos based on the number of likes:Likes`, | 52 | label: $localize`:A variant of Trending videos based on the number of likes:Likes`, |
51 | iconName: 'like', | 53 | iconName: 'like', |
52 | value: '-likes', | 54 | value: 'most-liked', |
53 | path: 'most-liked', | ||
54 | tooltip: $localize`Videos that have the most likes` | 55 | tooltip: $localize`Videos that have the most likes` |
55 | } | 56 | } |
56 | ] | 57 | ] |
@@ -59,20 +60,40 @@ export class VideoTrendingHeaderComponent extends VideoListHeaderComponent imple | |||
59 | ngOnInit () { | 60 | ngOnInit () { |
60 | this.serverService.getConfig() | 61 | this.serverService.getConfig() |
61 | .subscribe(config => { | 62 | .subscribe(config => { |
62 | // don't filter if auto-blacklist is not enabled as this will be the only list | 63 | this.buttons = this.buttons.map(b => { |
63 | if (config.instance.pages.hot.enabled) { | 64 | b.hidden = !config.trending.videos.algorithms.enabled.includes(b.value) |
64 | const index = this.buttons.findIndex(b => b.path === 'hot') | 65 | return b |
65 | this.buttons[index].hidden = false | 66 | }) |
66 | } | ||
67 | }) | 67 | }) |
68 | |||
69 | this.algorithmChangeSub = this.route.queryParams.subscribe( | ||
70 | queryParams => { | ||
71 | const algorithm = queryParams['alg'] | ||
72 | if (algorithm) { | ||
73 | this.data.model = algorithm | ||
74 | } else { | ||
75 | this.data.model = RedirectService.DEFAULT_TRENDING_ALGORITHM | ||
76 | } | ||
77 | } | ||
78 | ) | ||
68 | } | 79 | } |
69 | 80 | ||
70 | get visibleButtons () { | 81 | ngOnDestroy () { |
71 | return this.buttons.filter(b => !b.hidden) | 82 | if (this.algorithmChangeSub) this.algorithmChangeSub.unsubscribe() |
72 | } | 83 | } |
73 | 84 | ||
74 | setSort () { | 85 | setSort () { |
75 | const path = this.buttons.find(b => b.value === this.data.model).path | 86 | const alg = this.data.model !== RedirectService.DEFAULT_TRENDING_ALGORITHM |
76 | this.router.navigate([ `/videos/${path}` ]) | 87 | ? this.data.model |
88 | : undefined | ||
89 | |||
90 | this.router.navigate( | ||
91 | [], | ||
92 | { | ||
93 | relativeTo: this.route, | ||
94 | queryParams: { alg }, | ||
95 | queryParamsHandling: 'merge' | ||
96 | } | ||
97 | ) | ||
77 | } | 98 | } |
78 | } | 99 | } |
diff --git a/client/src/app/+videos/video-list/trending/video-most-viewed.component.ts b/client/src/app/+videos/video-list/trending/video-trending.component.ts index 98ced42d6..6128c4acd 100644 --- a/client/src/app/+videos/video-list/trending/video-most-viewed.component.ts +++ b/client/src/app/+videos/video-list/trending/video-trending.component.ts | |||
@@ -1,25 +1,28 @@ | |||
1 | import { Component, ComponentFactoryResolver, Injector, OnDestroy, OnInit } from '@angular/core' | 1 | import { Component, ComponentFactoryResolver, Injector, OnDestroy, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' | 3 | import { AuthService, LocalStorageService, Notifier, RedirectService, ScreenService, ServerService, UserService } from '@app/core' |
4 | import { HooksService } from '@app/core/plugins/hooks.service' | 4 | import { HooksService } from '@app/core/plugins/hooks.service' |
5 | import { immutableAssign } from '@app/helpers' | 5 | import { immutableAssign } from '@app/helpers' |
6 | import { VideoService } from '@app/shared/shared-main' | 6 | import { VideoService } from '@app/shared/shared-main' |
7 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | 7 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' |
8 | import { VideoSortField } from '@shared/models' | 8 | import { VideoSortField } from '@shared/models' |
9 | import { Subscription } from 'rxjs' | ||
9 | import { VideoTrendingHeaderComponent } from './video-trending-header.component' | 10 | import { VideoTrendingHeaderComponent } from './video-trending-header.component' |
10 | 11 | ||
11 | @Component({ | 12 | @Component({ |
12 | selector: 'my-videos-most-viewed', | 13 | selector: 'my-videos-hot', |
13 | styleUrls: [ '../../../shared/shared-video-miniature/abstract-video-list.scss' ], | 14 | styleUrls: [ '../../../shared/shared-video-miniature/abstract-video-list.scss' ], |
14 | templateUrl: '../../../shared/shared-video-miniature/abstract-video-list.html' | 15 | templateUrl: '../../../shared/shared-video-miniature/abstract-video-list.html' |
15 | }) | 16 | }) |
16 | export class VideoMostViewedComponent extends AbstractVideoList implements OnInit, OnDestroy { | 17 | export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy { |
17 | HeaderComponent = VideoTrendingHeaderComponent | 18 | HeaderComponent = VideoTrendingHeaderComponent |
18 | titlePage: string | 19 | titlePage: string |
19 | defaultSort: VideoSortField = '-trending' | 20 | defaultSort: VideoSortField = '-trending' |
20 | 21 | ||
21 | useUserVideoPreferences = true | 22 | useUserVideoPreferences = true |
22 | 23 | ||
24 | private algorithmChangeSub: Subscription | ||
25 | |||
23 | constructor ( | 26 | constructor ( |
24 | protected router: Router, | 27 | protected router: Router, |
25 | protected serverService: ServerService, | 28 | protected serverService: ServerService, |
@@ -35,6 +38,8 @@ export class VideoMostViewedComponent extends AbstractVideoList implements OnIni | |||
35 | ) { | 38 | ) { |
36 | super() | 39 | super() |
37 | 40 | ||
41 | this.defaultSort = this.parseAlgorithm(RedirectService.DEFAULT_TRENDING_ALGORITHM) | ||
42 | |||
38 | this.headerComponentInjector = this.getInjector() | 43 | this.headerComponentInjector = this.getInjector() |
39 | } | 44 | } |
40 | 45 | ||
@@ -43,23 +48,19 @@ export class VideoMostViewedComponent extends AbstractVideoList implements OnIni | |||
43 | 48 | ||
44 | this.generateSyndicationList() | 49 | this.generateSyndicationList() |
45 | 50 | ||
46 | this.serverService.getConfig().subscribe( | 51 | this.algorithmChangeSub = this.route.queryParams.subscribe( |
47 | config => { | 52 | queryParams => { |
48 | const trendingDays = config.trending.videos.intervalDays | 53 | const algorithm = queryParams['alg'] || RedirectService.DEFAULT_TRENDING_ALGORITHM |
49 | |||
50 | if (trendingDays === 1) { | ||
51 | this.titleTooltip = $localize`Trending videos are those totalizing the greatest number of views during the last 24 hours` | ||
52 | } else { | ||
53 | this.titleTooltip = $localize`Trending videos are those totalizing the greatest number of views during the last ${trendingDays} days` | ||
54 | } | ||
55 | 54 | ||
56 | this.headerComponentInjector = this.getInjector() | 55 | this.sort = this.parseAlgorithm(algorithm) |
57 | this.setHeader() | 56 | this.reloadVideos() |
58 | }) | 57 | } |
58 | ) | ||
59 | } | 59 | } |
60 | 60 | ||
61 | ngOnDestroy () { | 61 | ngOnDestroy () { |
62 | super.ngOnDestroy() | 62 | super.ngOnDestroy() |
63 | if (this.algorithmChangeSub) this.algorithmChangeSub.unsubscribe() | ||
63 | } | 64 | } |
64 | 65 | ||
65 | getVideosObservable (page: number) { | 66 | getVideosObservable (page: number) { |
@@ -96,4 +97,15 @@ export class VideoMostViewedComponent extends AbstractVideoList implements OnIni | |||
96 | }] | 97 | }] |
97 | }) | 98 | }) |
98 | } | 99 | } |
100 | |||
101 | private parseAlgorithm (algorithm: string): VideoSortField { | ||
102 | switch (algorithm) { | ||
103 | case 'most-viewed': | ||
104 | return '-trending' | ||
105 | case 'most-liked': | ||
106 | return '-likes' | ||
107 | default: | ||
108 | return '-' + algorithm as VideoSortField | ||
109 | } | ||
110 | } | ||
99 | } | 111 | } |
diff --git a/client/src/app/+videos/videos-routing.module.ts b/client/src/app/+videos/videos-routing.module.ts index 973935af8..16e3b9bb2 100644 --- a/client/src/app/+videos/videos-routing.module.ts +++ b/client/src/app/+videos/videos-routing.module.ts | |||
@@ -1,11 +1,9 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | import { LoginGuard, TrendingGuard } from '@app/core' | 3 | import { LoginGuard } from '@app/core' |
4 | import { MetaGuard } from '@ngx-meta/core' | 4 | import { MetaGuard } from '@ngx-meta/core' |
5 | import { VideoTrendingComponent } from './video-list' | ||
5 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' | 6 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' |
6 | import { VideoHotComponent } from './video-list/trending/video-hot.component' | ||
7 | import { VideoMostLikedComponent } from './video-list/trending/video-most-liked.component' | ||
8 | import { VideoMostViewedComponent } from './video-list/trending/video-most-viewed.component' | ||
9 | import { VideoLocalComponent } from './video-list/video-local.component' | 7 | import { VideoLocalComponent } from './video-list/video-local.component' |
10 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | 8 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' |
11 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' | 9 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' |
@@ -28,46 +26,16 @@ const videosRoutes: Routes = [ | |||
28 | }, | 26 | }, |
29 | { | 27 | { |
30 | path: 'trending', | 28 | path: 'trending', |
31 | canActivate: [ TrendingGuard ] | 29 | component: VideoTrendingComponent, |
32 | }, | ||
33 | { | ||
34 | path: 'hot', | ||
35 | component: VideoHotComponent, | ||
36 | data: { | 30 | data: { |
37 | meta: { | 31 | meta: { |
38 | title: $localize`Hot videos` | 32 | title: $localize`Trending videos` |
39 | }, | ||
40 | reuse: { | ||
41 | enabled: true, | ||
42 | key: 'hot-videos-list' | ||
43 | } | ||
44 | } | ||
45 | }, | ||
46 | { | ||
47 | path: 'most-viewed', | ||
48 | component: VideoMostViewedComponent, | ||
49 | data: { | ||
50 | meta: { | ||
51 | title: $localize`Most viewed videos` | ||
52 | }, | ||
53 | reuse: { | ||
54 | enabled: true, | ||
55 | key: 'most-viewed-videos-list' | ||
56 | } | 33 | } |
57 | } | 34 | } |
58 | }, | 35 | }, |
59 | { | 36 | { |
60 | path: 'most-liked', | 37 | path: 'most-liked', |
61 | component: VideoMostLikedComponent, | 38 | redirectTo: 'trending?alg=most-liked' |
62 | data: { | ||
63 | meta: { | ||
64 | title: $localize`Most liked videos` | ||
65 | }, | ||
66 | reuse: { | ||
67 | enabled: true, | ||
68 | key: 'most-liked-videos-list' | ||
69 | } | ||
70 | } | ||
71 | }, | 39 | }, |
72 | { | 40 | { |
73 | path: 'recently-added', | 41 | path: 'recently-added', |
diff --git a/client/src/app/+videos/videos.module.ts b/client/src/app/+videos/videos.module.ts index ae9c680eb..61d012d63 100644 --- a/client/src/app/+videos/videos.module.ts +++ b/client/src/app/+videos/videos.module.ts | |||
@@ -1,16 +1,12 @@ | |||
1 | import { CommonModule } from '@angular/common' | ||
2 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
3 | import { SharedFormModule } from '@app/shared/shared-forms' | 2 | import { SharedFormModule } from '@app/shared/shared-forms' |
4 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 3 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
5 | import { SharedMainModule } from '@app/shared/shared-main' | 4 | import { SharedMainModule } from '@app/shared/shared-main' |
6 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' | 5 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' |
7 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' | 6 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' |
8 | import { OverviewService } from './video-list' | 7 | import { OverviewService, VideoTrendingComponent } from './video-list' |
9 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' | 8 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' |
10 | import { VideoTrendingHeaderComponent } from './video-list/trending/video-trending-header.component' | 9 | import { VideoTrendingHeaderComponent } from './video-list/trending/video-trending-header.component' |
11 | import { VideoHotComponent } from './video-list/trending/video-hot.component' | ||
12 | import { VideoMostViewedComponent } from './video-list/trending/video-most-viewed.component' | ||
13 | import { VideoMostLikedComponent } from './video-list/trending/video-most-liked.component' | ||
14 | import { VideoLocalComponent } from './video-list/video-local.component' | 10 | import { VideoLocalComponent } from './video-list/video-local.component' |
15 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | 11 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' |
16 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' | 12 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' |
@@ -32,9 +28,7 @@ import { VideosComponent } from './videos.component' | |||
32 | VideosComponent, | 28 | VideosComponent, |
33 | 29 | ||
34 | VideoTrendingHeaderComponent, | 30 | VideoTrendingHeaderComponent, |
35 | VideoMostViewedComponent, | 31 | VideoTrendingComponent, |
36 | VideoHotComponent, | ||
37 | VideoMostLikedComponent, | ||
38 | VideoRecentlyAddedComponent, | 32 | VideoRecentlyAddedComponent, |
39 | VideoLocalComponent, | 33 | VideoLocalComponent, |
40 | VideoUserSubscriptionsComponent, | 34 | VideoUserSubscriptionsComponent, |
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 77d876f8e..108b127be 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html | |||
@@ -8,7 +8,7 @@ | |||
8 | <div class="top-left-block"> | 8 | <div class="top-left-block"> |
9 | <span class="icon icon-menu" role="button" [title]="getToggleTitle()" (click)="menu.toggleMenu()"></span> | 9 | <span class="icon icon-menu" role="button" [title]="getToggleTitle()" (click)="menu.toggleMenu()"></span> |
10 | 10 | ||
11 | <a class="peertube-title" [routerLink]="defaultRoute"> | 11 | <a class="peertube-title c-hand" (click)="goToDefaultRoute()"> |
12 | <span class="icon icon-logo"></span> | 12 | <span class="icon icon-logo"></span> |
13 | <span class="instance-name">{{ instanceName }}</span> | 13 | <span class="instance-name">{{ instanceName }}</span> |
14 | </a> | 14 | </a> |
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index ca4b69899..66d871b4a 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts | |||
@@ -66,8 +66,8 @@ export class AppComponent implements OnInit, AfterViewInit { | |||
66 | return this.serverConfig.instance.name | 66 | return this.serverConfig.instance.name |
67 | } | 67 | } |
68 | 68 | ||
69 | get defaultRoute () { | 69 | goToDefaultRoute () { |
70 | return RedirectService.DEFAULT_ROUTE | 70 | return this.router.navigateByUrl(RedirectService.DEFAULT_ROUTE) |
71 | } | 71 | } |
72 | 72 | ||
73 | ngOnInit () { | 73 | ngOnInit () { |
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 32dfc8f36..2392a234c 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts | |||
@@ -15,7 +15,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard' | |||
15 | import { Notifier } from './notification' | 15 | import { Notifier } from './notification' |
16 | import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer' | 16 | import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer' |
17 | import { RestExtractor, RestService } from './rest' | 17 | import { RestExtractor, RestService } from './rest' |
18 | import { LoginGuard, RedirectService, UserRightGuard, UnloggedGuard, TrendingGuard } from './routing' | 18 | import { LoginGuard, RedirectService, UserRightGuard, UnloggedGuard } from './routing' |
19 | import { CanDeactivateGuard } from './routing/can-deactivate-guard.service' | 19 | import { CanDeactivateGuard } from './routing/can-deactivate-guard.service' |
20 | import { ServerConfigResolver } from './routing/server-config-resolver.service' | 20 | import { ServerConfigResolver } from './routing/server-config-resolver.service' |
21 | import { ScopedTokensService } from './scoped-tokens' | 21 | import { ScopedTokensService } from './scoped-tokens' |
@@ -56,7 +56,6 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra | |||
56 | LoginGuard, | 56 | LoginGuard, |
57 | UserRightGuard, | 57 | UserRightGuard, |
58 | UnloggedGuard, | 58 | UnloggedGuard, |
59 | TrendingGuard, | ||
60 | 59 | ||
61 | PluginService, | 60 | PluginService, |
62 | HooksService, | 61 | HooksService, |
diff --git a/client/src/app/core/routing/index.ts b/client/src/app/core/routing/index.ts index b3985d870..239c27caf 100644 --- a/client/src/app/core/routing/index.ts +++ b/client/src/app/core/routing/index.ts | |||
@@ -8,4 +8,3 @@ export * from './redirect.service' | |||
8 | export * from './server-config-resolver.service' | 8 | export * from './server-config-resolver.service' |
9 | export * from './unlogged-guard.service' | 9 | export * from './unlogged-guard.service' |
10 | export * from './user-right-guard.service' | 10 | export * from './user-right-guard.service' |
11 | export * from './trending-guard.service' | ||
diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts index 76e28e461..6d26fb504 100644 --- a/client/src/app/core/routing/redirect.service.ts +++ b/client/src/app/core/routing/redirect.service.ts | |||
@@ -7,14 +7,13 @@ export class RedirectService { | |||
7 | // Default route could change according to the instance configuration | 7 | // Default route could change according to the instance configuration |
8 | static INIT_DEFAULT_ROUTE = '/videos/trending' | 8 | static INIT_DEFAULT_ROUTE = '/videos/trending' |
9 | static DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE | 9 | static DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE |
10 | static INIT_DEFAULT_TRENDING_ROUTE = '/videos/most-viewed' | 10 | static INIT_DEFAULT_TRENDING_ALGORITHM = 'most-viewed' |
11 | static DEFAULT_TRENDING_ROUTE = RedirectService.INIT_DEFAULT_TRENDING_ROUTE | 11 | static DEFAULT_TRENDING_ALGORITHM = RedirectService.INIT_DEFAULT_TRENDING_ALGORITHM |
12 | 12 | ||
13 | private previousUrl: string | 13 | private previousUrl: string |
14 | private currentUrl: string | 14 | private currentUrl: string |
15 | 15 | ||
16 | private redirectingToHomepage = false | 16 | private redirectingToHomepage = false |
17 | private redirectingToTrending = false | ||
18 | 17 | ||
19 | constructor ( | 18 | constructor ( |
20 | private router: Router, | 19 | private router: Router, |
@@ -22,27 +21,25 @@ export class RedirectService { | |||
22 | ) { | 21 | ) { |
23 | // The config is first loaded from the cache so try to get the default route | 22 | // The config is first loaded from the cache so try to get the default route |
24 | const tmpConfig = this.serverService.getTmpConfig() | 23 | const tmpConfig = this.serverService.getTmpConfig() |
25 | if (tmpConfig && tmpConfig.instance) { | 24 | if (tmpConfig?.instance?.defaultClientRoute) { |
26 | if (tmpConfig.instance.defaultClientRoute) { | 25 | RedirectService.DEFAULT_ROUTE = tmpConfig.instance.defaultClientRoute |
27 | RedirectService.DEFAULT_ROUTE = tmpConfig.instance.defaultClientRoute | 26 | } |
28 | } | 27 | if (tmpConfig?.trending?.videos?.algorithms?.default) { |
29 | if (tmpConfig.instance.defaultTrendingRoute) { | 28 | RedirectService.DEFAULT_TRENDING_ALGORITHM = tmpConfig.trending.videos.algorithms.default |
30 | RedirectService.DEFAULT_TRENDING_ROUTE = tmpConfig.instance.defaultTrendingRoute | ||
31 | } | ||
32 | } | 29 | } |
33 | 30 | ||
34 | // Load default route | 31 | // Load default route |
35 | this.serverService.getConfig() | 32 | this.serverService.getConfig() |
36 | .subscribe(config => { | 33 | .subscribe(config => { |
37 | const defaultRouteConfig = config.instance.defaultClientRoute | 34 | const defaultRouteConfig = config.instance.defaultClientRoute |
38 | const defaultTrendingConfig = config.instance.defaultTrendingRoute | 35 | const defaultTrendingConfig = config.trending.videos.algorithms.default |
39 | 36 | ||
40 | if (defaultRouteConfig) { | 37 | if (defaultRouteConfig) { |
41 | RedirectService.DEFAULT_ROUTE = defaultRouteConfig | 38 | RedirectService.DEFAULT_ROUTE = defaultRouteConfig |
42 | } | 39 | } |
43 | 40 | ||
44 | if (defaultTrendingConfig) { | 41 | if (defaultTrendingConfig) { |
45 | RedirectService.DEFAULT_TRENDING_ROUTE = defaultTrendingConfig | 42 | RedirectService.DEFAULT_TRENDING_ALGORITHM = defaultTrendingConfig |
46 | } | 43 | } |
47 | }) | 44 | }) |
48 | 45 | ||
@@ -70,15 +67,6 @@ export class RedirectService { | |||
70 | return this.redirectToHomepage() | 67 | return this.redirectToHomepage() |
71 | } | 68 | } |
72 | 69 | ||
73 | redirectToTrending () { | ||
74 | if (this.redirectingToTrending) return | ||
75 | |||
76 | this.redirectingToTrending = true | ||
77 | |||
78 | this.router.navigate([ RedirectService.DEFAULT_TRENDING_ROUTE ]) | ||
79 | .then(() => this.redirectingToTrending = false) | ||
80 | } | ||
81 | |||
82 | redirectToHomepage (skipLocationChange = false) { | 70 | redirectToHomepage (skipLocationChange = false) { |
83 | if (this.redirectingToHomepage) return | 71 | if (this.redirectingToHomepage) return |
84 | 72 | ||
@@ -86,7 +74,7 @@ export class RedirectService { | |||
86 | 74 | ||
87 | console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE) | 75 | console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE) |
88 | 76 | ||
89 | this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { skipLocationChange }) | 77 | this.router.navigateByUrl(RedirectService.DEFAULT_ROUTE, { skipLocationChange }) |
90 | .then(() => this.redirectingToHomepage = false) | 78 | .then(() => this.redirectingToHomepage = false) |
91 | .catch(() => { | 79 | .catch(() => { |
92 | this.redirectingToHomepage = false | 80 | this.redirectingToHomepage = false |
@@ -98,7 +86,7 @@ export class RedirectService { | |||
98 | ) | 86 | ) |
99 | 87 | ||
100 | RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE | 88 | RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE |
101 | return this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { skipLocationChange }) | 89 | return this.router.navigateByUrl(RedirectService.DEFAULT_ROUTE, { skipLocationChange }) |
102 | }) | 90 | }) |
103 | 91 | ||
104 | } | 92 | } |
diff --git a/client/src/app/core/routing/trending-guard.service.ts b/client/src/app/core/routing/trending-guard.service.ts deleted file mode 100644 index 7db7fe994..000000000 --- a/client/src/app/core/routing/trending-guard.service.ts +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router' | ||
3 | import { RedirectService } from './redirect.service' | ||
4 | |||
5 | @Injectable() | ||
6 | export class TrendingGuard implements CanActivate { | ||
7 | |||
8 | constructor (private redirectService: RedirectService) {} | ||
9 | |||
10 | canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { | ||
11 | this.redirectService.redirectToTrending() | ||
12 | return false | ||
13 | } | ||
14 | } | ||
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 5f13190b4..a38883eee 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -39,12 +39,6 @@ export class ServerService { | |||
39 | isNSFW: false, | 39 | isNSFW: false, |
40 | defaultNSFWPolicy: 'do_not_list' as 'do_not_list', | 40 | defaultNSFWPolicy: 'do_not_list' as 'do_not_list', |
41 | defaultClientRoute: '', | 41 | defaultClientRoute: '', |
42 | defaultTrendingRoute: '', | ||
43 | pages: { | ||
44 | hot: { | ||
45 | enabled: true | ||
46 | } | ||
47 | }, | ||
48 | customizations: { | 42 | customizations: { |
49 | javascript: '', | 43 | javascript: '', |
50 | css: '' | 44 | css: '' |
@@ -131,7 +125,11 @@ export class ServerService { | |||
131 | }, | 125 | }, |
132 | trending: { | 126 | trending: { |
133 | videos: { | 127 | videos: { |
134 | intervalDays: 0 | 128 | intervalDays: 0, |
129 | algorithms: { | ||
130 | enabled: [ 'hot', 'most-viewed', 'most-liked' ], | ||
131 | default: 'most-viewed' | ||
132 | } | ||
135 | } | 133 | } |
136 | }, | 134 | }, |
137 | autoBlacklist: { | 135 | autoBlacklist: { |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index fc57b970b..9aa397edd 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -127,14 +127,10 @@ | |||
127 | <ng-container i18n>Discover</ng-container> | 127 | <ng-container i18n>Discover</ng-container> |
128 | </a> | 128 | </a> |
129 | 129 | ||
130 | <a routerLink="/videos/trending" routerLinkActive="active" [ngClass]="{ 'active': hot.isActive || mostViewed.isActive || mostLiked.isActive }"> | 130 | <a routerLink="/videos/trending" routerLinkActive="active"> |
131 | <my-global-icon iconName="trending" aria-hidden="true"></my-global-icon> | 131 | <my-global-icon iconName="trending" aria-hidden="true"></my-global-icon> |
132 | <ng-container i18n>Trending</ng-container> | 132 | <ng-container i18n>Trending</ng-container> |
133 | </a> | 133 | </a> |
134 | <a routerLink="/videos/hot" routerLinkActive #hot="routerLinkActive" hidden></a> | ||
135 | <a routerLink="/videos/most-viewed" routerLinkActive #mostViewed="routerLinkActive" hidden></a> | ||
136 | <a routerLink="/videos/most-liked" routerLinkActive #mostLiked="routerLinkActive" hidden></a> | ||
137 | |||
138 | 134 | ||
139 | <a routerLink="/videos/recently-added" routerLinkActive="active"> | 135 | <a routerLink="/videos/recently-added" routerLinkActive="active"> |
140 | <my-global-icon iconName="recently-added" aria-hidden="true"></my-global-icon> | 136 | <my-global-icon iconName="recently-added" aria-hidden="true"></my-global-icon> |
diff --git a/client/src/app/shared/shared-video-miniature/video-list-header.component.ts b/client/src/app/shared/shared-video-miniature/video-list-header.component.ts index 67bbf7d7a..08a961be1 100644 --- a/client/src/app/shared/shared-video-miniature/video-list-header.component.ts +++ b/client/src/app/shared/shared-video-miniature/video-list-header.component.ts | |||
@@ -1,16 +1,22 @@ | |||
1 | import { Component, Inject, ViewEncapsulation } from '@angular/core' | 1 | import { Component, Inject, ViewEncapsulation } from '@angular/core' |
2 | 2 | ||
3 | export interface GenericHeaderData { | ||
4 | titlePage: string | ||
5 | titleTooltip?: string | ||
6 | } | ||
7 | |||
3 | export abstract class GenericHeaderComponent { | 8 | export abstract class GenericHeaderComponent { |
4 | constructor (@Inject('data') public data: any) {} | 9 | constructor (@Inject('data') public data: GenericHeaderData) {} |
5 | } | 10 | } |
6 | 11 | ||
7 | @Component({ | 12 | @Component({ |
8 | selector: 'my-video-list-header', | 13 | selector: 'my-video-list-header', |
14 | // tslint:disable-next-line:use-component-view-encapsulation | ||
9 | encapsulation: ViewEncapsulation.None, | 15 | encapsulation: ViewEncapsulation.None, |
10 | templateUrl: './video-list-header.component.html' | 16 | templateUrl: './video-list-header.component.html' |
11 | }) | 17 | }) |
12 | export class VideoListHeaderComponent extends GenericHeaderComponent { | 18 | export class VideoListHeaderComponent extends GenericHeaderComponent { |
13 | constructor (@Inject('data') public data: any) { | 19 | constructor (@Inject('data') public data: GenericHeaderData) { |
14 | super(data) | 20 | super(data) |
15 | } | 21 | } |
16 | } | 22 | } |
diff --git a/config/default.yaml b/config/default.yaml index 43c7f4a53..b9e382fa7 100644 --- a/config/default.yaml +++ b/config/default.yaml | |||
@@ -106,6 +106,12 @@ log: | |||
106 | trending: | 106 | trending: |
107 | videos: | 107 | videos: |
108 | interval_days: 7 # Compute trending videos for the last x days | 108 | interval_days: 7 # Compute trending videos for the last x days |
109 | algorithms: | ||
110 | enabled: | ||
111 | - 'hot' # adaptation of the Reddit 'Hot' algorithm | ||
112 | - 'most-viewed' # default, used initially by PeerTube as the trending page | ||
113 | - 'most-liked' | ||
114 | default: 'most-viewed' | ||
109 | 115 | ||
110 | # Cache remote videos on your server, to help other instances to broadcast the video | 116 | # Cache remote videos on your server, to help other instances to broadcast the video |
111 | # You can define multiple caches using different sizes/strategies | 117 | # You can define multiple caches using different sizes/strategies |
@@ -366,10 +372,6 @@ instance: | |||
366 | # - 18 # Food | 372 | # - 18 # Food |
367 | 373 | ||
368 | default_client_route: '/videos/trending' | 374 | default_client_route: '/videos/trending' |
369 | default_trending_route: '/videos/most-viewed' | ||
370 | pages: | ||
371 | hot: | ||
372 | enabled: true | ||
373 | 375 | ||
374 | # Whether or not the instance is dedicated to NSFW content | 376 | # Whether or not the instance is dedicated to NSFW content |
375 | # Enabling it will allow other administrators to know that you are mainly federating sensitive content | 377 | # Enabling it will allow other administrators to know that you are mainly federating sensitive content |
diff --git a/config/production.yaml.example b/config/production.yaml.example index f9f3abc18..b616c6ced 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -106,6 +106,12 @@ log: | |||
106 | trending: | 106 | trending: |
107 | videos: | 107 | videos: |
108 | interval_days: 7 # Compute trending videos for the last x days | 108 | interval_days: 7 # Compute trending videos for the last x days |
109 | algorithms: | ||
110 | enabled: | ||
111 | - 'hot' # adaptation of the Reddit 'Hot' algorithm | ||
112 | - 'most-viewed' # default, used initially by PeerTube as the trending page | ||
113 | - 'most-liked' | ||
114 | default: 'most-viewed' | ||
109 | 115 | ||
110 | # Cache remote videos on your server, to help other instances to broadcast the video | 116 | # Cache remote videos on your server, to help other instances to broadcast the video |
111 | # You can define multiple caches using different sizes/strategies | 117 | # You can define multiple caches using different sizes/strategies |
@@ -380,10 +386,6 @@ instance: | |||
380 | # - 18 # Food | 386 | # - 18 # Food |
381 | 387 | ||
382 | default_client_route: '/videos/trending' | 388 | default_client_route: '/videos/trending' |
383 | default_trending_route: '/videos/most-viewed' | ||
384 | pages: | ||
385 | hot: | ||
386 | enabled: true | ||
387 | 389 | ||
388 | # Whether or not the instance is dedicated to NSFW content | 390 | # Whether or not the instance is dedicated to NSFW content |
389 | # Enabling it will allow other administrators to know that you are mainly federating sensitive content | 391 | # Enabling it will allow other administrators to know that you are mainly federating sensitive content |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 24e7601ec..45c03be24 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -68,12 +68,6 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
68 | isNSFW: CONFIG.INSTANCE.IS_NSFW, | 68 | isNSFW: CONFIG.INSTANCE.IS_NSFW, |
69 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 69 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
70 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | 70 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, |
71 | defaultTrendingRoute: CONFIG.INSTANCE.DEFAULT_TRENDING_ROUTE, | ||
72 | pages: { | ||
73 | hot: { | ||
74 | enabled: CONFIG.INSTANCE.PAGES.HOT.ENABLED | ||
75 | } | ||
76 | }, | ||
77 | customizations: { | 71 | customizations: { |
78 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, | 72 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, |
79 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS | 73 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS |
@@ -189,7 +183,11 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
189 | }, | 183 | }, |
190 | trending: { | 184 | trending: { |
191 | videos: { | 185 | videos: { |
192 | intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS | 186 | intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS, |
187 | algorithms: { | ||
188 | enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED, | ||
189 | default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT | ||
190 | } | ||
193 | } | 191 | } |
194 | }, | 192 | }, |
195 | tracker: { | 193 | tracker: { |
@@ -371,12 +369,6 @@ function customConfig (): CustomConfig { | |||
371 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 369 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
372 | 370 | ||
373 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | 371 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, |
374 | defaultTrendingRoute: CONFIG.INSTANCE.DEFAULT_TRENDING_ROUTE, | ||
375 | pages: { | ||
376 | hot: { | ||
377 | enabled: CONFIG.INSTANCE.PAGES.HOT.ENABLED | ||
378 | } | ||
379 | }, | ||
380 | 372 | ||
381 | customizations: { | 373 | customizations: { |
382 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, | 374 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, |
@@ -467,6 +459,14 @@ function customConfig (): CustomConfig { | |||
467 | } | 459 | } |
468 | } | 460 | } |
469 | }, | 461 | }, |
462 | trending: { | ||
463 | videos: { | ||
464 | algorithms: { | ||
465 | enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED, | ||
466 | default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT | ||
467 | } | ||
468 | } | ||
469 | }, | ||
470 | autoBlacklist: { | 470 | autoBlacklist: { |
471 | videos: { | 471 | videos: { |
472 | ofUsers: { | 472 | ofUsers: { |
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index e474959b2..6aae5e821 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -230,7 +230,6 @@ const customConfigKeysToKeep = [ | |||
230 | 'instance-description', | 230 | 'instance-description', |
231 | 'instance-terms', | 231 | 'instance-terms', |
232 | 'instance-defaultClientRoute', | 232 | 'instance-defaultClientRoute', |
233 | 'instance-defaultTrendingRoute', | ||
234 | 'instance-defaultNSFWPolicy', | 233 | 'instance-defaultNSFWPolicy', |
235 | 'instance-customizations-javascript', | 234 | 'instance-customizations-javascript', |
236 | 'instance-customizations-css', | 235 | 'instance-customizations-css', |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index e1f807752..fc4a8b709 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -110,7 +110,11 @@ const CONFIG = { | |||
110 | }, | 110 | }, |
111 | TRENDING: { | 111 | TRENDING: { |
112 | VIDEOS: { | 112 | VIDEOS: { |
113 | INTERVAL_DAYS: config.get<number>('trending.videos.interval_days') | 113 | INTERVAL_DAYS: config.get<number>('trending.videos.interval_days'), |
114 | ALGORITHMS: { | ||
115 | get ENABLED () { return config.get<string[]>('trending.videos.algorithms.enabled') }, | ||
116 | get DEFAULT () { return config.get<string>('trending.videos.algorithms.default') } | ||
117 | } | ||
114 | } | 118 | } |
115 | }, | 119 | }, |
116 | REDUNDANCY: { | 120 | REDUNDANCY: { |
@@ -281,12 +285,6 @@ const CONFIG = { | |||
281 | get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') }, | 285 | get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') }, |
282 | 286 | ||
283 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, | 287 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, |
284 | get DEFAULT_TRENDING_ROUTE () { return config.get<string>('instance.default_trending_route') }, | ||
285 | PAGES: { | ||
286 | HOT: { | ||
287 | get ENABLED () { return config.get<boolean>('instance.pages.hot.enabled') } | ||
288 | } | ||
289 | }, | ||
290 | 288 | ||
291 | CUSTOMIZATIONS: { | 289 | CUSTOMIZATIONS: { |
292 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, | 290 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 0efe1157f..52c28799f 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -17,7 +17,6 @@ const customConfigUpdateValidator = [ | |||
17 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), | 17 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), |
18 | body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), | 18 | body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), |
19 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), | 19 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), |
20 | body('instance.defaultTrendingRoute').exists().withMessage('Should have a valid instance default trending route'), | ||
21 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), | 20 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), |
22 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), | 21 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), |
23 | 22 | ||
@@ -55,6 +54,9 @@ const customConfigUpdateValidator = [ | |||
55 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), | 54 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), |
56 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), | 55 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), |
57 | 56 | ||
57 | body('trending.videos.algorithms.default').exists().withMessage('Should have a valid default trending algorithm'), | ||
58 | body('trending.videos.algorithms.enabled').exists().withMessage('Should have a valid array of enabled trending algorithms'), | ||
59 | |||
58 | body('followers.instance.enabled').isBoolean().withMessage('Should have a valid followers of instance boolean'), | 60 | body('followers.instance.enabled').isBoolean().withMessage('Should have a valid followers of instance boolean'), |
59 | body('followers.instance.manualApproval').isBoolean().withMessage('Should have a valid manual approval boolean'), | 61 | body('followers.instance.manualApproval').isBoolean().withMessage('Should have a valid manual approval boolean'), |
60 | 62 | ||
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index e58e0cd9f..d3ae5fe0a 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -44,12 +44,6 @@ describe('Test config API validators', function () { | |||
44 | defaultNSFWPolicy: 'blur', | 44 | defaultNSFWPolicy: 'blur', |
45 | 45 | ||
46 | defaultClientRoute: '/videos/recently-added', | 46 | defaultClientRoute: '/videos/recently-added', |
47 | defaultTrendingRoute: '/videos/trending', | ||
48 | pages: { | ||
49 | hot: { | ||
50 | enabled: true | ||
51 | } | ||
52 | }, | ||
53 | 47 | ||
54 | customizations: { | 48 | customizations: { |
55 | javascript: 'alert("coucou")', | 49 | javascript: 'alert("coucou")', |
@@ -142,6 +136,14 @@ describe('Test config API validators', function () { | |||
142 | } | 136 | } |
143 | } | 137 | } |
144 | }, | 138 | }, |
139 | trending: { | ||
140 | videos: { | ||
141 | algorithms: { | ||
142 | enabled: [ 'hot', 'most-viewed', 'most-liked' ], | ||
143 | default: 'most-viewed' | ||
144 | } | ||
145 | } | ||
146 | }, | ||
145 | autoBlacklist: { | 147 | autoBlacklist: { |
146 | videos: { | 148 | videos: { |
147 | ofUsers: { | 149 | ofUsers: { |
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index 328f4852a..e0575bdfd 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -276,12 +276,6 @@ describe('Test config', function () { | |||
276 | defaultNSFWPolicy: 'blur' as 'blur', | 276 | defaultNSFWPolicy: 'blur' as 'blur', |
277 | 277 | ||
278 | defaultClientRoute: '/videos/recently-added', | 278 | defaultClientRoute: '/videos/recently-added', |
279 | defaultTrendingRoute: '/videos/trending', | ||
280 | pages: { | ||
281 | hot: { | ||
282 | enabled: true | ||
283 | } | ||
284 | }, | ||
285 | 279 | ||
286 | customizations: { | 280 | customizations: { |
287 | javascript: 'alert("coucou")', | 281 | javascript: 'alert("coucou")', |
@@ -372,6 +366,14 @@ describe('Test config', function () { | |||
372 | } | 366 | } |
373 | } | 367 | } |
374 | }, | 368 | }, |
369 | trending: { | ||
370 | videos: { | ||
371 | algorithms: { | ||
372 | enabled: [ 'hot', 'most-viewed', 'most-liked' ], | ||
373 | default: 'hot' | ||
374 | } | ||
375 | } | ||
376 | }, | ||
375 | autoBlacklist: { | 377 | autoBlacklist: { |
376 | videos: { | 378 | videos: { |
377 | ofUsers: { | 379 | ofUsers: { |
diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts index 5152ec693..4e09e0412 100644 --- a/shared/extra-utils/server/config.ts +++ b/shared/extra-utils/server/config.ts | |||
@@ -69,12 +69,6 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
69 | defaultNSFWPolicy: 'blur', | 69 | defaultNSFWPolicy: 'blur', |
70 | 70 | ||
71 | defaultClientRoute: '/videos/recently-added', | 71 | defaultClientRoute: '/videos/recently-added', |
72 | defaultTrendingRoute: '/videos/trending', | ||
73 | pages: { | ||
74 | hot: { | ||
75 | enabled: true | ||
76 | } | ||
77 | }, | ||
78 | 72 | ||
79 | customizations: { | 73 | customizations: { |
80 | javascript: 'alert("coucou")', | 74 | javascript: 'alert("coucou")', |
@@ -165,6 +159,14 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
165 | } | 159 | } |
166 | } | 160 | } |
167 | }, | 161 | }, |
162 | trending: { | ||
163 | videos: { | ||
164 | algorithms: { | ||
165 | enabled: [ 'hot', 'most-viewed', 'most-liked' ], | ||
166 | default: 'hot' | ||
167 | } | ||
168 | } | ||
169 | }, | ||
168 | autoBlacklist: { | 170 | autoBlacklist: { |
169 | videos: { | 171 | videos: { |
170 | ofUsers: { | 172 | ofUsers: { |
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index fcc29e5d7..a57237414 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -33,12 +33,6 @@ export interface CustomConfig { | |||
33 | defaultNSFWPolicy: NSFWPolicyType | 33 | defaultNSFWPolicy: NSFWPolicyType |
34 | 34 | ||
35 | defaultClientRoute: string | 35 | defaultClientRoute: string |
36 | defaultTrendingRoute: string | ||
37 | pages: { | ||
38 | hot: { | ||
39 | enabled: boolean | ||
40 | } | ||
41 | } | ||
42 | 36 | ||
43 | customizations: { | 37 | customizations: { |
44 | javascript?: string | 38 | javascript?: string |
@@ -131,6 +125,15 @@ export interface CustomConfig { | |||
131 | } | 125 | } |
132 | } | 126 | } |
133 | 127 | ||
128 | trending: { | ||
129 | videos: { | ||
130 | algorithms: { | ||
131 | enabled: string[] | ||
132 | default: string | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
134 | autoBlacklist: { | 137 | autoBlacklist: { |
135 | videos: { | 138 | videos: { |
136 | ofUsers: { | 139 | ofUsers: { |
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts index a2d93ce73..47d0e623b 100644 --- a/shared/models/server/server-config.model.ts +++ b/shared/models/server/server-config.model.ts | |||
@@ -39,12 +39,6 @@ export interface ServerConfig { | |||
39 | isNSFW: boolean | 39 | isNSFW: boolean |
40 | defaultNSFWPolicy: NSFWPolicyType | 40 | defaultNSFWPolicy: NSFWPolicyType |
41 | defaultClientRoute: string | 41 | defaultClientRoute: string |
42 | defaultTrendingRoute: string | ||
43 | pages: { | ||
44 | hot: { | ||
45 | enabled: boolean | ||
46 | } | ||
47 | } | ||
48 | customizations: { | 42 | customizations: { |
49 | javascript: string | 43 | javascript: string |
50 | css: string | 44 | css: string |
@@ -180,6 +174,10 @@ export interface ServerConfig { | |||
180 | trending: { | 174 | trending: { |
181 | videos: { | 175 | videos: { |
182 | intervalDays: number | 176 | intervalDays: number |
177 | algorithms: { | ||
178 | enabled: string[] | ||
179 | default: string | ||
180 | } | ||
183 | } | 181 | } |
184 | } | 182 | } |
185 | 183 | ||