diff options
Diffstat (limited to 'client/src/app/+videos')
17 files changed, 342 insertions, 551 deletions
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html index 9e6fde2e0..0e00c9c0e 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html | |||
@@ -27,13 +27,7 @@ | |||
27 | 27 | ||
28 | <div *ngIf="totalNotDeletedComments === 0 && comments.length === 0" i18n>No comments.</div> | 28 | <div *ngIf="totalNotDeletedComments === 0 && comments.length === 0" i18n>No comments.</div> |
29 | 29 | ||
30 | <div | 30 | <div class="comment-threads" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()"> |
31 | class="comment-threads" | ||
32 | myInfiniteScroller | ||
33 | [autoInit]="true" | ||
34 | (nearOfBottom)="onNearOfBottom()" | ||
35 | [dataObservable]="onDataSubject.asObservable()" | ||
36 | > | ||
37 | <div> | 31 | <div> |
38 | <div class="anchor" #commentHighlightBlock id="highlighted-comment"></div> | 32 | <div class="anchor" #commentHighlightBlock id="highlighted-comment"></div> |
39 | <my-video-comment | 33 | <my-video-comment |
diff --git a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html index c270142a3..da81d76d1 100644 --- a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html +++ b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div | 1 | <div |
2 | *ngIf="playlist && currentPlaylistPosition" class="playlist" | 2 | *ngIf="playlist && currentPlaylistPosition" class="playlist" |
3 | myInfiniteScroller [autoInit]="true" [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()" | 3 | myInfiniteScroller [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()" |
4 | > | 4 | > |
5 | <div class="playlist-info"> | 5 | <div class="playlist-info"> |
6 | <div class="playlist-display-name"> | 6 | <div class="playlist-display-name"> |
diff --git a/client/src/app/+videos/video-list/index.ts b/client/src/app/+videos/video-list/index.ts index dc27e29e2..3492f43f4 100644 --- a/client/src/app/+videos/video-list/index.ts +++ b/client/src/app/+videos/video-list/index.ts | |||
@@ -1,4 +1,2 @@ | |||
1 | export * from './overview' | 1 | export * from './overview' |
2 | export * from './trending' | 2 | export * from './videos-list-common-page.component' |
3 | export * from './video-local.component' | ||
4 | export * from './video-recently-added.component' | ||
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.html b/client/src/app/+videos/video-list/overview/video-overview.component.html index d3c602aa5..1a715560c 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.html +++ b/client/src/app/+videos/video-list/overview/video-overview.component.html | |||
@@ -4,7 +4,7 @@ | |||
4 | <div class="no-results" i18n *ngIf="notResults">No results.</div> | 4 | <div class="no-results" i18n *ngIf="notResults">No results.</div> |
5 | 5 | ||
6 | <div | 6 | <div |
7 | myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()" | 7 | myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()" |
8 | > | 8 | > |
9 | <ng-container *ngFor="let overview of overviews"> | 9 | <ng-container *ngFor="let overview of overviews"> |
10 | 10 | ||
diff --git a/client/src/app/+videos/video-list/trending/index.ts b/client/src/app/+videos/video-list/trending/index.ts deleted file mode 100644 index 70835885a..000000000 --- a/client/src/app/+videos/video-list/trending/index.ts +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | export * from './video-trending-header.component' | ||
2 | export * from './video-trending.component' | ||
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 deleted file mode 100644 index db81ce6a1..000000000 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.html +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" [(ngModel)]="data.model" (ngModelChange)="setSort()"> | ||
2 | <ng-container *ngFor="let button of buttons"> | ||
3 | <label *ngIf="!button.hidden" ngbButtonLabel class="btn-light" placement="bottom right-bottom left-bottom" [ngbTooltip]="button.tooltip" container="body"> | ||
4 | <my-global-icon [iconName]="button.iconName"></my-global-icon> | ||
5 | <input ngbButton type="radio" [value]="button.value"> {{ button.label }} | ||
6 | </label> | ||
7 | </ng-container> | ||
8 | </div> | ||
diff --git a/client/src/app/+videos/video-list/trending/video-trending-header.component.scss b/client/src/app/+videos/video-list/trending/video-trending-header.component.scss deleted file mode 100644 index 54b072314..000000000 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.scss +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | @use '_mixins' as *; | ||
2 | |||
3 | .btn-group label { | ||
4 | border: 1px solid transparent; | ||
5 | border-radius: 9999px !important; | ||
6 | padding: 5px 16px; | ||
7 | opacity: .8; | ||
8 | |||
9 | &:not(:first-child) { | ||
10 | @include margin-left(.5rem); | ||
11 | } | ||
12 | |||
13 | my-global-icon { | ||
14 | @include margin-right(.1rem); | ||
15 | |||
16 | position: relative; | ||
17 | top: -2px; | ||
18 | height: 1rem; | ||
19 | } | ||
20 | } | ||
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 deleted file mode 100644 index c94655c74..000000000 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.ts +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | import { Subscription } from 'rxjs' | ||
2 | import { Component, HostBinding, Inject, OnDestroy, OnInit } from '@angular/core' | ||
3 | import { ActivatedRoute, Router } from '@angular/router' | ||
4 | import { AuthService, RedirectService } from '@app/core' | ||
5 | import { ServerService } from '@app/core/server/server.service' | ||
6 | import { GlobalIconName } from '@app/shared/shared-icons' | ||
7 | import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature' | ||
8 | |||
9 | interface VideoTrendingHeaderItem { | ||
10 | label: string | ||
11 | iconName: GlobalIconName | ||
12 | value: string | ||
13 | tooltip?: string | ||
14 | hidden?: boolean | ||
15 | } | ||
16 | |||
17 | @Component({ | ||
18 | selector: 'my-video-trending-title-page', | ||
19 | styleUrls: [ './video-trending-header.component.scss' ], | ||
20 | templateUrl: './video-trending-header.component.html' | ||
21 | }) | ||
22 | export class VideoTrendingHeaderComponent extends VideoListHeaderComponent implements OnInit, OnDestroy { | ||
23 | @HostBinding('class') class = 'title-page title-page-single' | ||
24 | |||
25 | buttons: VideoTrendingHeaderItem[] | ||
26 | |||
27 | private algorithmChangeSub: Subscription | ||
28 | |||
29 | constructor ( | ||
30 | @Inject('data') public data: any, | ||
31 | private route: ActivatedRoute, | ||
32 | private router: Router, | ||
33 | private auth: AuthService, | ||
34 | private serverService: ServerService, | ||
35 | private redirectService: RedirectService | ||
36 | ) { | ||
37 | super(data) | ||
38 | |||
39 | this.buttons = [ | ||
40 | { | ||
41 | label: $localize`:A variant of Trending videos based on the number of recent interactions, minus user history:Best`, | ||
42 | iconName: 'award', | ||
43 | value: 'best', | ||
44 | tooltip: $localize`Videos with the most interactions for recent videos, minus user history`, | ||
45 | hidden: true | ||
46 | }, | ||
47 | { | ||
48 | label: $localize`:A variant of Trending videos based on the number of recent interactions:Hot`, | ||
49 | iconName: 'flame', | ||
50 | value: 'hot', | ||
51 | tooltip: $localize`Videos with the most interactions for recent videos`, | ||
52 | hidden: true | ||
53 | }, | ||
54 | { | ||
55 | label: $localize`:Main variant of Trending videos based on number of recent views:Views`, | ||
56 | iconName: 'trending', | ||
57 | value: 'most-viewed', | ||
58 | tooltip: $localize`Videos with the most views during the last 24 hours` | ||
59 | }, | ||
60 | { | ||
61 | label: $localize`:A variant of Trending videos based on the number of likes:Likes`, | ||
62 | iconName: 'like', | ||
63 | value: 'most-liked', | ||
64 | tooltip: $localize`Videos that have the most likes` | ||
65 | } | ||
66 | ] | ||
67 | } | ||
68 | |||
69 | ngOnInit () { | ||
70 | const serverConfig = this.serverService.getHTMLConfig() | ||
71 | const algEnabled = serverConfig.trending.videos.algorithms.enabled | ||
72 | |||
73 | this.buttons = this.buttons.map(b => { | ||
74 | b.hidden = !algEnabled.includes(b.value) | ||
75 | |||
76 | // Best is adapted by the user history so | ||
77 | if (b.value === 'best' && !this.auth.isLoggedIn()) { | ||
78 | b.hidden = true | ||
79 | } | ||
80 | |||
81 | return b | ||
82 | }) | ||
83 | |||
84 | this.algorithmChangeSub = this.route.queryParams.subscribe( | ||
85 | queryParams => { | ||
86 | this.data.model = queryParams['alg'] || this.redirectService.getDefaultTrendingAlgorithm() | ||
87 | } | ||
88 | ) | ||
89 | } | ||
90 | |||
91 | ngOnDestroy () { | ||
92 | if (this.algorithmChangeSub) this.algorithmChangeSub.unsubscribe() | ||
93 | } | ||
94 | |||
95 | setSort () { | ||
96 | const alg = this.data.model !== this.redirectService.getDefaultTrendingAlgorithm() | ||
97 | ? this.data.model | ||
98 | : undefined | ||
99 | |||
100 | this.router.navigate( | ||
101 | [], | ||
102 | { | ||
103 | relativeTo: this.route, | ||
104 | queryParams: { alg }, | ||
105 | queryParamsHandling: 'merge' | ||
106 | } | ||
107 | ) | ||
108 | } | ||
109 | } | ||
diff --git a/client/src/app/+videos/video-list/trending/video-trending.component.ts b/client/src/app/+videos/video-list/trending/video-trending.component.ts deleted file mode 100644 index 085f29a8b..000000000 --- a/client/src/app/+videos/video-list/trending/video-trending.component.ts +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | import { Subscription } from 'rxjs' | ||
2 | import { first, switchMap } from 'rxjs/operators' | ||
3 | import { Component, ComponentFactoryResolver, Injector, OnDestroy, OnInit } from '@angular/core' | ||
4 | import { ActivatedRoute, Params, Router } from '@angular/router' | ||
5 | import { AuthService, LocalStorageService, Notifier, RedirectService, ScreenService, ServerService, UserService } from '@app/core' | ||
6 | import { HooksService } from '@app/core/plugins/hooks.service' | ||
7 | import { immutableAssign } from '@app/helpers' | ||
8 | import { VideoService } from '@app/shared/shared-main' | ||
9 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | ||
10 | import { VideoSortField } from '@shared/models' | ||
11 | import { VideoTrendingHeaderComponent } from './video-trending-header.component' | ||
12 | |||
13 | @Component({ | ||
14 | selector: 'my-videos-hot', | ||
15 | styleUrls: [ '../../../shared/shared-video-miniature/abstract-video-list.scss' ], | ||
16 | templateUrl: '../../../shared/shared-video-miniature/abstract-video-list.html' | ||
17 | }) | ||
18 | export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy { | ||
19 | HeaderComponent = VideoTrendingHeaderComponent | ||
20 | titlePage: string | ||
21 | defaultSort: VideoSortField = '-trending' | ||
22 | |||
23 | loadUserVideoPreferences = true | ||
24 | |||
25 | private algorithmChangeSub: Subscription | ||
26 | |||
27 | constructor ( | ||
28 | protected router: Router, | ||
29 | protected serverService: ServerService, | ||
30 | protected route: ActivatedRoute, | ||
31 | protected notifier: Notifier, | ||
32 | protected authService: AuthService, | ||
33 | protected userService: UserService, | ||
34 | protected screenService: ScreenService, | ||
35 | protected storageService: LocalStorageService, | ||
36 | protected cfr: ComponentFactoryResolver, | ||
37 | private videoService: VideoService, | ||
38 | private redirectService: RedirectService, | ||
39 | private hooks: HooksService | ||
40 | ) { | ||
41 | super() | ||
42 | |||
43 | this.defaultSort = this.parseAlgorithm(this.redirectService.getDefaultTrendingAlgorithm()) | ||
44 | |||
45 | this.headerComponentInjector = this.getInjector() | ||
46 | } | ||
47 | |||
48 | ngOnInit () { | ||
49 | super.ngOnInit() | ||
50 | |||
51 | this.generateSyndicationList() | ||
52 | |||
53 | // Subscribe to alg change after we loaded the data | ||
54 | // The initial alg load is handled by the parent class | ||
55 | this.algorithmChangeSub = this.onDataSubject | ||
56 | .pipe( | ||
57 | first(), | ||
58 | switchMap(() => this.route.queryParams) | ||
59 | ).subscribe(queryParams => { | ||
60 | const oldSort = this.sort | ||
61 | |||
62 | this.loadPageRouteParams(queryParams) | ||
63 | |||
64 | if (oldSort !== this.sort) this.reloadVideos() | ||
65 | } | ||
66 | ) | ||
67 | } | ||
68 | |||
69 | ngOnDestroy () { | ||
70 | super.ngOnDestroy() | ||
71 | if (this.algorithmChangeSub) this.algorithmChangeSub.unsubscribe() | ||
72 | } | ||
73 | |||
74 | getVideosObservable (page: number) { | ||
75 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
76 | const params = { | ||
77 | videoPagination: newPagination, | ||
78 | sort: this.sort, | ||
79 | categoryOneOf: this.categoryOneOf, | ||
80 | languageOneOf: this.languageOneOf, | ||
81 | nsfwPolicy: this.nsfwPolicy, | ||
82 | skipCount: true | ||
83 | } | ||
84 | |||
85 | return this.hooks.wrapObsFun( | ||
86 | this.videoService.getVideos.bind(this.videoService), | ||
87 | params, | ||
88 | 'common', | ||
89 | 'filter:api.trending-videos.videos.list.params', | ||
90 | 'filter:api.trending-videos.videos.list.result' | ||
91 | ) | ||
92 | } | ||
93 | |||
94 | generateSyndicationList () { | ||
95 | this.syndicationItems = this.videoService.getVideoFeedUrls(this.sort, undefined, this.categoryOneOf) | ||
96 | } | ||
97 | |||
98 | getInjector () { | ||
99 | return Injector.create({ | ||
100 | providers: [ { | ||
101 | provide: 'data', | ||
102 | useValue: { | ||
103 | model: this.defaultSort | ||
104 | } | ||
105 | } ] | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | protected loadPageRouteParams (queryParams: Params) { | ||
110 | const algorithm = queryParams['alg'] || this.redirectService.getDefaultTrendingAlgorithm() | ||
111 | |||
112 | this.sort = this.parseAlgorithm(algorithm) | ||
113 | } | ||
114 | |||
115 | private parseAlgorithm (algorithm: string): VideoSortField { | ||
116 | switch (algorithm) { | ||
117 | case 'most-viewed': | ||
118 | return '-trending' | ||
119 | |||
120 | case 'most-liked': | ||
121 | return '-likes' | ||
122 | |||
123 | default: | ||
124 | return '-' + algorithm as VideoSortField | ||
125 | } | ||
126 | } | ||
127 | } | ||
diff --git a/client/src/app/+videos/video-list/video-local.component.ts b/client/src/app/+videos/video-list/video-local.component.ts deleted file mode 100644 index b576883d1..000000000 --- a/client/src/app/+videos/video-list/video-local.component.ts +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | import { Component, ComponentFactoryResolver, 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 { VideoFilter, VideoSortField } from '@shared/models' | ||
9 | |||
10 | @Component({ | ||
11 | selector: 'my-videos-local', | ||
12 | styleUrls: [ '../../shared/shared-video-miniature/abstract-video-list.scss' ], | ||
13 | templateUrl: '../../shared/shared-video-miniature/abstract-video-list.html' | ||
14 | }) | ||
15 | export class VideoLocalComponent extends AbstractVideoList implements OnInit, OnDestroy { | ||
16 | titlePage: string | ||
17 | sort = '-publishedAt' as VideoSortField | ||
18 | filter: VideoFilter = 'local' | ||
19 | |||
20 | loadUserVideoPreferences = true | ||
21 | |||
22 | constructor ( | ||
23 | protected router: Router, | ||
24 | protected serverService: ServerService, | ||
25 | protected route: ActivatedRoute, | ||
26 | protected notifier: Notifier, | ||
27 | protected authService: AuthService, | ||
28 | protected userService: UserService, | ||
29 | protected screenService: ScreenService, | ||
30 | protected storageService: LocalStorageService, | ||
31 | protected cfr: ComponentFactoryResolver, | ||
32 | private videoService: VideoService, | ||
33 | private hooks: HooksService | ||
34 | ) { | ||
35 | super() | ||
36 | |||
37 | this.titlePage = $localize`Local videos` | ||
38 | } | ||
39 | |||
40 | ngOnInit () { | ||
41 | super.ngOnInit() | ||
42 | |||
43 | this.enableAllFilterIfPossible() | ||
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 | filter: this.filter, | ||
57 | categoryOneOf: this.categoryOneOf, | ||
58 | languageOneOf: this.languageOneOf, | ||
59 | nsfwPolicy: this.nsfwPolicy, | ||
60 | skipCount: true | ||
61 | } | ||
62 | |||
63 | return this.hooks.wrapObsFun( | ||
64 | this.videoService.getVideos.bind(this.videoService), | ||
65 | params, | ||
66 | 'common', | ||
67 | 'filter:api.local-videos.videos.list.params', | ||
68 | 'filter:api.local-videos.videos.list.result' | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | generateSyndicationList () { | ||
73 | this.syndicationItems = this.videoService.getVideoFeedUrls(this.sort, this.filter, this.categoryOneOf) | ||
74 | } | ||
75 | |||
76 | toggleModerationDisplay () { | ||
77 | this.filter = this.buildLocalFilter(this.filter, 'local') | ||
78 | |||
79 | this.reloadVideos() | ||
80 | } | ||
81 | } | ||
diff --git a/client/src/app/+videos/video-list/video-recently-added.component.ts b/client/src/app/+videos/video-list/video-recently-added.component.ts deleted file mode 100644 index 506f92d25..000000000 --- a/client/src/app/+videos/video-list/video-recently-added.component.ts +++ /dev/null | |||
@@ -1,73 +0,0 @@ | |||
1 | import { Component, ComponentFactoryResolver, 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 | |||
10 | @Component({ | ||
11 | selector: 'my-videos-recently-added', | ||
12 | styleUrls: [ '../../shared/shared-video-miniature/abstract-video-list.scss' ], | ||
13 | templateUrl: '../../shared/shared-video-miniature/abstract-video-list.html' | ||
14 | }) | ||
15 | export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { | ||
16 | titlePage: string | ||
17 | sort: VideoSortField = '-publishedAt' | ||
18 | groupByDate = true | ||
19 | |||
20 | loadUserVideoPreferences = true | ||
21 | |||
22 | constructor ( | ||
23 | protected route: ActivatedRoute, | ||
24 | protected serverService: ServerService, | ||
25 | protected router: Router, | ||
26 | protected notifier: Notifier, | ||
27 | protected authService: AuthService, | ||
28 | protected userService: UserService, | ||
29 | protected screenService: ScreenService, | ||
30 | protected storageService: LocalStorageService, | ||
31 | protected cfr: ComponentFactoryResolver, | ||
32 | private videoService: VideoService, | ||
33 | private hooks: HooksService | ||
34 | ) { | ||
35 | super() | ||
36 | |||
37 | this.titlePage = $localize`Recently added` | ||
38 | } | ||
39 | |||
40 | ngOnInit () { | ||
41 | super.ngOnInit() | ||
42 | |||
43 | this.generateSyndicationList() | ||
44 | } | ||
45 | |||
46 | ngOnDestroy () { | ||
47 | super.ngOnDestroy() | ||
48 | } | ||
49 | |||
50 | getVideosObservable (page: number) { | ||
51 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
52 | const params = { | ||
53 | videoPagination: newPagination, | ||
54 | sort: this.sort, | ||
55 | categoryOneOf: this.categoryOneOf, | ||
56 | languageOneOf: this.languageOneOf, | ||
57 | nsfwPolicy: this.nsfwPolicy, | ||
58 | skipCount: true | ||
59 | } | ||
60 | |||
61 | return this.hooks.wrapObsFun( | ||
62 | this.videoService.getVideos.bind(this.videoService), | ||
63 | params, | ||
64 | 'common', | ||
65 | 'filter:api.recently-added-videos.videos.list.params', | ||
66 | 'filter:api.recently-added-videos.videos.list.result' | ||
67 | ) | ||
68 | } | ||
69 | |||
70 | generateSyndicationList () { | ||
71 | this.syndicationItems = this.videoService.getVideoFeedUrls(this.sort, undefined, this.categoryOneOf) | ||
72 | } | ||
73 | } | ||
diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.html b/client/src/app/+videos/video-list/video-user-subscriptions.component.html new file mode 100644 index 000000000..2675b58bf --- /dev/null +++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.html | |||
@@ -0,0 +1,17 @@ | |||
1 | <my-videos-list | ||
2 | [getVideosObservableFunction]="getVideosObservableFunction" | ||
3 | [getSyndicationItemsFunction]="getSyndicationItemsFunction" | ||
4 | |||
5 | [title]="titlePage" | ||
6 | |||
7 | [defaultSort]="defaultSort" | ||
8 | |||
9 | [displayFilters]="false" | ||
10 | [displayModerationBlock]="false" | ||
11 | |||
12 | [loadUserVideoPreferences]="false" | ||
13 | [groupByDate]="true" | ||
14 | |||
15 | [disabled]="disabled" | ||
16 | > | ||
17 | </my-videos-list> | ||
diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts index a1498e797..43cbab9f6 100644 --- a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts +++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts | |||
@@ -1,94 +1,53 @@ | |||
1 | 1 | ||
2 | import { switchMap } from 'rxjs/operators' | 2 | import { firstValueFrom } from 'rxjs' |
3 | import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core' | 3 | import { switchMap, tap } from 'rxjs/operators' |
4 | import { ActivatedRoute, Router } from '@angular/router' | 4 | import { Component } from '@angular/core' |
5 | import { AuthService, LocalStorageService, Notifier, ScopedTokensService, ScreenService, ServerService, UserService } from '@app/core' | 5 | import { AuthService, ComponentPaginationLight, DisableForReuseHook, ScopedTokensService } from '@app/core' |
6 | import { HooksService } from '@app/core/plugins/hooks.service' | 6 | import { HooksService } from '@app/core/plugins/hooks.service' |
7 | import { immutableAssign } from '@app/helpers' | ||
8 | import { VideoService } from '@app/shared/shared-main' | 7 | import { VideoService } from '@app/shared/shared-main' |
9 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' | 8 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' |
10 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | 9 | import { VideoFilters } from '@app/shared/shared-video-miniature' |
11 | import { FeedFormat, VideoSortField } from '@shared/models' | 10 | import { VideoSortField } from '@shared/models' |
12 | import { environment } from '../../../environments/environment' | ||
13 | import { copyToClipboard } from '../../../root-helpers/utils' | ||
14 | 11 | ||
15 | @Component({ | 12 | @Component({ |
16 | selector: 'my-videos-user-subscriptions', | 13 | selector: 'my-videos-user-subscriptions', |
17 | styleUrls: [ '../../shared/shared-video-miniature/abstract-video-list.scss' ], | 14 | templateUrl: './video-user-subscriptions.component.html' |
18 | templateUrl: '../../shared/shared-video-miniature/abstract-video-list.html' | ||
19 | }) | 15 | }) |
20 | export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy { | 16 | export class VideoUserSubscriptionsComponent implements DisableForReuseHook { |
21 | titlePage: string | 17 | getVideosObservableFunction = this.getVideosObservable.bind(this) |
22 | sort = '-publishedAt' as VideoSortField | 18 | getSyndicationItemsFunction = this.getSyndicationItems.bind(this) |
23 | groupByDate = true | 19 | |
20 | defaultSort = '-publishedAt' as VideoSortField | ||
21 | |||
22 | actions = [ | ||
23 | { | ||
24 | routerLink: '/my-library/subscriptions', | ||
25 | label: $localize`Subscriptions`, | ||
26 | iconName: 'cog' | ||
27 | } | ||
28 | ] | ||
29 | |||
30 | titlePage = $localize`Videos from your subscriptions` | ||
31 | |||
32 | disabled = false | ||
33 | |||
34 | private feedToken: string | ||
24 | 35 | ||
25 | constructor ( | 36 | constructor ( |
26 | protected router: Router, | 37 | private authService: AuthService, |
27 | protected serverService: ServerService, | ||
28 | protected route: ActivatedRoute, | ||
29 | protected notifier: Notifier, | ||
30 | protected authService: AuthService, | ||
31 | protected userService: UserService, | ||
32 | protected screenService: ScreenService, | ||
33 | protected storageService: LocalStorageService, | ||
34 | private userSubscription: UserSubscriptionService, | 38 | private userSubscription: UserSubscriptionService, |
35 | protected cfr: ComponentFactoryResolver, | ||
36 | private hooks: HooksService, | 39 | private hooks: HooksService, |
37 | private videoService: VideoService, | 40 | private videoService: VideoService, |
38 | private scopedTokensService: ScopedTokensService | 41 | private scopedTokensService: ScopedTokensService |
39 | ) { | 42 | ) { |
40 | super() | ||
41 | 43 | ||
42 | this.titlePage = $localize`Videos from your subscriptions` | ||
43 | |||
44 | this.actions.push({ | ||
45 | routerLink: '/my-library/subscriptions', | ||
46 | label: $localize`Subscriptions`, | ||
47 | iconName: 'cog' | ||
48 | }) | ||
49 | } | 44 | } |
50 | 45 | ||
51 | ngOnInit () { | 46 | getVideosObservable (pagination: ComponentPaginationLight, filters: VideoFilters) { |
52 | super.ngOnInit() | ||
53 | |||
54 | const user = this.authService.getUser() | ||
55 | let feedUrl = environment.originServerUrl | ||
56 | |||
57 | this.authService.userInformationLoaded | ||
58 | .pipe(switchMap(() => this.scopedTokensService.getScopedTokens())) | ||
59 | .subscribe({ | ||
60 | next: tokens => { | ||
61 | const feeds = this.videoService.getVideoSubscriptionFeedUrls(user.account.id, tokens.feedToken) | ||
62 | feedUrl = feedUrl + feeds.find(f => f.format === FeedFormat.RSS).url | ||
63 | |||
64 | this.actions.unshift({ | ||
65 | label: $localize`Copy feed URL`, | ||
66 | iconName: 'syndication', | ||
67 | justIcon: true, | ||
68 | href: feedUrl, | ||
69 | click: e => { | ||
70 | e.preventDefault() | ||
71 | copyToClipboard(feedUrl) | ||
72 | this.activateCopiedMessage() | ||
73 | } | ||
74 | }) | ||
75 | }, | ||
76 | |||
77 | error: err => { | ||
78 | this.notifier.error(err.message) | ||
79 | } | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | ngOnDestroy () { | ||
84 | super.ngOnDestroy() | ||
85 | } | ||
86 | |||
87 | getVideosObservable (page: number) { | ||
88 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
89 | const params = { | 47 | const params = { |
90 | videoPagination: newPagination, | 48 | ...filters.toVideosAPIObject(), |
91 | sort: this.sort, | 49 | |
50 | videoPagination: pagination, | ||
92 | skipCount: true | 51 | skipCount: true |
93 | } | 52 | } |
94 | 53 | ||
@@ -101,12 +60,32 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement | |||
101 | ) | 60 | ) |
102 | } | 61 | } |
103 | 62 | ||
104 | generateSyndicationList () { | 63 | getSyndicationItems () { |
105 | /* method disabled: the view provides its own */ | 64 | return this.loadFeedToken() |
106 | throw new Error('Method not implemented.') | 65 | .then(() => { |
66 | const user = this.authService.getUser() | ||
67 | |||
68 | return this.videoService.getVideoSubscriptionFeedUrls(user.account.id, this.feedToken) | ||
69 | }) | ||
107 | } | 70 | } |
108 | 71 | ||
109 | activateCopiedMessage () { | 72 | disableForReuse () { |
110 | this.notifier.success($localize`Feed URL copied`) | 73 | this.disabled = true |
74 | } | ||
75 | |||
76 | enabledForReuse () { | ||
77 | this.disabled = false | ||
78 | } | ||
79 | |||
80 | private loadFeedToken () { | ||
81 | if (this.feedToken) return Promise.resolve(this.feedToken) | ||
82 | |||
83 | const obs = this.authService.userInformationLoaded | ||
84 | .pipe( | ||
85 | switchMap(() => this.scopedTokensService.getScopedTokens()), | ||
86 | tap(tokens => this.feedToken = tokens.feedToken) | ||
87 | ) | ||
88 | |||
89 | return firstValueFrom(obs) | ||
111 | } | 90 | } |
112 | } | 91 | } |
diff --git a/client/src/app/+videos/video-list/videos-list-common-page.component.html b/client/src/app/+videos/video-list/videos-list-common-page.component.html new file mode 100644 index 000000000..2831f996f --- /dev/null +++ b/client/src/app/+videos/video-list/videos-list-common-page.component.html | |||
@@ -0,0 +1,22 @@ | |||
1 | <my-videos-list | ||
2 | [getVideosObservableFunction]="getVideosObservableFunction" | ||
3 | [getSyndicationItemsFunction]="getSyndicationItemsFunction" | ||
4 | [baseRouteBuilderFunction]="baseRouteBuilderFunction" | ||
5 | |||
6 | [title]="title" | ||
7 | [titleTooltip]="titleTooltip" | ||
8 | |||
9 | [defaultSort]="defaultSort" | ||
10 | [defaultScope]="defaultScope" | ||
11 | |||
12 | [displayFilters]="true" | ||
13 | [displayModerationBlock]="true" | ||
14 | |||
15 | [loadUserVideoPreferences]="true" | ||
16 | [groupByDate]="groupByDate" | ||
17 | |||
18 | [disabled]="disabled" | ||
19 | |||
20 | (filtersChanged)="onFiltersChanged($event)" | ||
21 | > | ||
22 | </my-videos-list> | ||
diff --git a/client/src/app/+videos/video-list/videos-list-common-page.component.ts b/client/src/app/+videos/video-list/videos-list-common-page.component.ts new file mode 100644 index 000000000..ba64d4fec --- /dev/null +++ b/client/src/app/+videos/video-list/videos-list-common-page.component.ts | |||
@@ -0,0 +1,219 @@ | |||
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 | |||
88 | return this.videoService.getVideoFeedUrls(result.sort, result.filter) | ||
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 | |||
176 | default: | ||
177 | return '-' + algorithm as VideoSortField | ||
178 | } | ||
179 | } | ||
180 | |||
181 | private updateGroupByDate (sort: VideoSortField) { | ||
182 | this.groupByDate = sort === '-publishedAt' || sort === 'publishedAt' | ||
183 | } | ||
184 | |||
185 | private buildTitle (scope: VideoFilterScope = this.defaultScope, sort: VideoSortField = this.defaultSort) { | ||
186 | const sanitizedSort = this.getSanitizedSort(sort) | ||
187 | |||
188 | if (scope === 'local') { | ||
189 | this.title = $localize`Local videos` | ||
190 | this.titleTooltip = $localize`Only videos uploaded on this instance are displayed` | ||
191 | return | ||
192 | } | ||
193 | |||
194 | if (sanitizedSort === 'publishedAt') { | ||
195 | this.title = $localize`Recently added` | ||
196 | this.titleTooltip = undefined | ||
197 | return | ||
198 | } | ||
199 | |||
200 | if ([ 'best', 'hot', 'trending', 'likes' ].includes(sanitizedSort)) { | ||
201 | this.title = $localize`Trending` | ||
202 | |||
203 | if (sanitizedSort === 'best') this.titleTooltip = $localize`Videos with the most interactions for recent videos, minus user history` | ||
204 | if (sanitizedSort === 'hot') this.titleTooltip = $localize`Videos with the most interactions for recent videos` | ||
205 | if (sanitizedSort === 'likes') this.titleTooltip = $localize`Videos that have the most likes` | ||
206 | |||
207 | if (sanitizedSort === 'trending') { | ||
208 | if (this.trendingDays === 1) this.titleTooltip = $localize`Videos with the most views during the last 24 hours` | ||
209 | else this.titleTooltip = $localize`Videos with the most views during the last ${this.trendingDays} days` | ||
210 | } | ||
211 | |||
212 | return | ||
213 | } | ||
214 | } | ||
215 | |||
216 | private getSanitizedSort (sort: VideoSortField) { | ||
217 | return sort.replace(/^-/, '') as VideoSortField | ||
218 | } | ||
219 | } | ||
diff --git a/client/src/app/+videos/videos-routing.module.ts b/client/src/app/+videos/videos-routing.module.ts index 926dfaab0..7db519615 100644 --- a/client/src/app/+videos/videos-routing.module.ts +++ b/client/src/app/+videos/videos-routing.module.ts | |||
@@ -1,10 +1,8 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes, UrlSegment } from '@angular/router' |
3 | import { LoginGuard } from '@app/core' | 3 | import { LoginGuard } from '@app/core' |
4 | import { VideoTrendingComponent } from './video-list' | 4 | import { VideosListCommonPageComponent } from './video-list' |
5 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' | 5 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' |
6 | import { VideoLocalComponent } from './video-list/video-local.component' | ||
7 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | ||
8 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' | 6 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' |
9 | import { VideosComponent } from './videos.component' | 7 | import { VideosComponent } from './videos.component' |
10 | 8 | ||
@@ -22,32 +20,35 @@ const videosRoutes: Routes = [ | |||
22 | } | 20 | } |
23 | } | 21 | } |
24 | }, | 22 | }, |
23 | |||
25 | { | 24 | { |
26 | path: 'trending', | 25 | // Old URL redirection |
27 | component: VideoTrendingComponent, | ||
28 | data: { | ||
29 | meta: { | ||
30 | title: $localize`Trending videos` | ||
31 | } | ||
32 | } | ||
33 | }, | ||
34 | { | ||
35 | path: 'most-liked', | 26 | path: 'most-liked', |
36 | redirectTo: 'trending?alg=most-liked' | 27 | redirectTo: 'trending?sort=most-liked' |
37 | }, | 28 | }, |
38 | { | 29 | { |
39 | path: 'recently-added', | 30 | matcher: (url: UrlSegment[]) => { |
40 | component: VideoRecentlyAddedComponent, | 31 | if (url.length === 1 && [ 'recently-added', 'trending', 'local' ].includes(url[0].path)) { |
32 | return { | ||
33 | consumed: url, | ||
34 | posParams: { | ||
35 | page: new UrlSegment(url[0].path, {}) | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return null | ||
41 | }, | ||
42 | |||
43 | component: VideosListCommonPageComponent, | ||
41 | data: { | 44 | data: { |
42 | meta: { | ||
43 | title: $localize`Recently added videos` | ||
44 | }, | ||
45 | reuse: { | 45 | reuse: { |
46 | enabled: true, | 46 | enabled: true, |
47 | key: 'recently-added-videos-list' | 47 | key: 'videos-list' |
48 | } | 48 | } |
49 | } | 49 | } |
50 | }, | 50 | }, |
51 | |||
51 | { | 52 | { |
52 | path: 'subscriptions', | 53 | path: 'subscriptions', |
53 | canActivate: [ LoginGuard ], | 54 | canActivate: [ LoginGuard ], |
@@ -61,19 +62,6 @@ const videosRoutes: Routes = [ | |||
61 | key: 'subscription-videos-list' | 62 | key: 'subscription-videos-list' |
62 | } | 63 | } |
63 | } | 64 | } |
64 | }, | ||
65 | { | ||
66 | path: 'local', | ||
67 | component: VideoLocalComponent, | ||
68 | data: { | ||
69 | meta: { | ||
70 | title: $localize`Local videos` | ||
71 | }, | ||
72 | reuse: { | ||
73 | enabled: true, | ||
74 | key: 'local-videos-list' | ||
75 | } | ||
76 | } | ||
77 | } | 65 | } |
78 | ] | 66 | ] |
79 | } | 67 | } |
diff --git a/client/src/app/+videos/videos.module.ts b/client/src/app/+videos/videos.module.ts index 8a35015d6..523533c11 100644 --- a/client/src/app/+videos/videos.module.ts +++ b/client/src/app/+videos/videos.module.ts | |||
@@ -5,11 +5,8 @@ import { SharedGlobalIconModule } from '@app/shared/shared-icons' | |||
5 | import { SharedMainModule } from '@app/shared/shared-main' | 5 | import { SharedMainModule } from '@app/shared/shared-main' |
6 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' | 6 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' |
7 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' | 7 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' |
8 | import { OverviewService, VideoTrendingComponent } from './video-list' | 8 | import { OverviewService, VideosListCommonPageComponent } from './video-list' |
9 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' | 9 | import { VideoOverviewComponent } from './video-list/overview/video-overview.component' |
10 | import { VideoTrendingHeaderComponent } from './video-list/trending/video-trending-header.component' | ||
11 | import { VideoLocalComponent } from './video-list/video-local.component' | ||
12 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | ||
13 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' | 10 | import { VideoUserSubscriptionsComponent } from './video-list/video-user-subscriptions.component' |
14 | import { VideosRoutingModule } from './videos-routing.module' | 11 | import { VideosRoutingModule } from './videos-routing.module' |
15 | import { VideosComponent } from './videos.component' | 12 | import { VideosComponent } from './videos.component' |
@@ -29,12 +26,9 @@ import { VideosComponent } from './videos.component' | |||
29 | declarations: [ | 26 | declarations: [ |
30 | VideosComponent, | 27 | VideosComponent, |
31 | 28 | ||
32 | VideoTrendingHeaderComponent, | ||
33 | VideoTrendingComponent, | ||
34 | VideoRecentlyAddedComponent, | ||
35 | VideoLocalComponent, | ||
36 | VideoUserSubscriptionsComponent, | 29 | VideoUserSubscriptionsComponent, |
37 | VideoOverviewComponent | 30 | VideoOverviewComponent, |
31 | VideosListCommonPageComponent | ||
38 | ], | 32 | ], |
39 | 33 | ||
40 | exports: [ | 34 | exports: [ |