diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-29 17:18:30 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-29 17:18:39 +0200 |
commit | 911186dae411d78788ccede093c251303187589a (patch) | |
tree | 967a07cd985ae4e2ea5249855726455fe929471d /client/src/app/+videos/+video-watch/recommendations | |
parent | b0c43e36dbdc2c964f6828a78b146faebfb75b21 (diff) | |
download | PeerTube-911186dae411d78788ccede093c251303187589a.tar.gz PeerTube-911186dae411d78788ccede093c251303187589a.tar.zst PeerTube-911186dae411d78788ccede093c251303187589a.zip |
Reorganize watch components
Diffstat (limited to 'client/src/app/+videos/+video-watch/recommendations')
8 files changed, 0 insertions, 351 deletions
diff --git a/client/src/app/+videos/+video-watch/recommendations/recent-videos-recommendation.service.ts b/client/src/app/+videos/+video-watch/recommendations/recent-videos-recommendation.service.ts deleted file mode 100644 index 4654da847..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recent-videos-recommendation.service.ts +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | import { Observable, of } from 'rxjs' | ||
2 | import { map, switchMap } from 'rxjs/operators' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { ServerService, UserService } from '@app/core' | ||
5 | import { Video, VideoService } from '@app/shared/shared-main' | ||
6 | import { AdvancedSearch, SearchService } from '@app/shared/shared-search' | ||
7 | import { HTMLServerConfig } from '@shared/models' | ||
8 | import { RecommendationInfo } from './recommendation-info.model' | ||
9 | import { RecommendationService } from './recommendations.service' | ||
10 | |||
11 | /** | ||
12 | * Provides "recommendations" by providing the most recently uploaded videos. | ||
13 | */ | ||
14 | @Injectable() | ||
15 | export class RecentVideosRecommendationService implements RecommendationService { | ||
16 | readonly pageSize = 5 | ||
17 | |||
18 | private config: HTMLServerConfig | ||
19 | |||
20 | constructor ( | ||
21 | private videos: VideoService, | ||
22 | private searchService: SearchService, | ||
23 | private userService: UserService, | ||
24 | private serverService: ServerService | ||
25 | ) { | ||
26 | this.config = this.serverService.getHTMLConfig() | ||
27 | } | ||
28 | |||
29 | getRecommendations (recommendation: RecommendationInfo): Observable<Video[]> { | ||
30 | |||
31 | return this.fetchPage(1, recommendation) | ||
32 | .pipe( | ||
33 | map(videos => { | ||
34 | const otherVideos = videos.filter(v => v.uuid !== recommendation.uuid) | ||
35 | return otherVideos.slice(0, this.pageSize) | ||
36 | }) | ||
37 | ) | ||
38 | } | ||
39 | |||
40 | private fetchPage (page: number, recommendation: RecommendationInfo): Observable<Video[]> { | ||
41 | const pagination = { currentPage: page, itemsPerPage: this.pageSize + 1 } | ||
42 | const defaultSubscription = this.videos.getVideos({ videoPagination: pagination, sort: '-createdAt' }) | ||
43 | .pipe(map(v => v.data)) | ||
44 | |||
45 | const tags = recommendation.tags | ||
46 | const searchIndexConfig = this.config.search.searchIndex | ||
47 | if ( | ||
48 | !tags || tags.length === 0 || | ||
49 | (searchIndexConfig.enabled === true && searchIndexConfig.disableLocalSearch === true) | ||
50 | ) { | ||
51 | return defaultSubscription | ||
52 | } | ||
53 | |||
54 | return this.userService.getAnonymousOrLoggedUser() | ||
55 | .pipe( | ||
56 | map(user => { | ||
57 | return { | ||
58 | search: '', | ||
59 | componentPagination: pagination, | ||
60 | advancedSearch: new AdvancedSearch({ | ||
61 | tagsOneOf: recommendation.tags.join(','), | ||
62 | sort: '-publishedAt', | ||
63 | searchTarget: 'local', | ||
64 | nsfw: user.nsfwPolicy | ||
65 | ? this.videos.nsfwPolicyToParam(user.nsfwPolicy) | ||
66 | : undefined | ||
67 | }) | ||
68 | } | ||
69 | }), | ||
70 | switchMap(params => this.searchService.searchVideos(params)), | ||
71 | map(v => v.data), | ||
72 | switchMap(videos => { | ||
73 | if (videos.length <= 1) return defaultSubscription | ||
74 | |||
75 | return of(videos) | ||
76 | }) | ||
77 | ) | ||
78 | } | ||
79 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommendation-info.model.ts b/client/src/app/+videos/+video-watch/recommendations/recommendation-info.model.ts deleted file mode 100644 index 0233563bb..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommendation-info.model.ts +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | export interface RecommendationInfo { | ||
2 | uuid: string | ||
3 | tags?: string[] | ||
4 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts b/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts deleted file mode 100644 index 1417f3e2a..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | |||
2 | import { CommonModule } from '@angular/common' | ||
3 | import { NgModule } from '@angular/core' | ||
4 | import { SharedFormModule } from '@app/shared/shared-forms' | ||
5 | import { SharedMainModule } from '@app/shared/shared-main' | ||
6 | import { SharedSearchModule } from '@app/shared/shared-search' | ||
7 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' | ||
8 | import { SharedVideoPlaylistModule } from '@app/shared/shared-video-playlist' | ||
9 | import { RecentVideosRecommendationService } from './recent-videos-recommendation.service' | ||
10 | import { RecommendedVideosComponent } from './recommended-videos.component' | ||
11 | import { RecommendedVideosStore } from './recommended-videos.store' | ||
12 | |||
13 | @NgModule({ | ||
14 | imports: [ | ||
15 | CommonModule, | ||
16 | |||
17 | SharedMainModule, | ||
18 | SharedSearchModule, | ||
19 | SharedVideoPlaylistModule, | ||
20 | SharedVideoMiniatureModule, | ||
21 | SharedFormModule | ||
22 | ], | ||
23 | declarations: [ | ||
24 | RecommendedVideosComponent | ||
25 | ], | ||
26 | exports: [ | ||
27 | RecommendedVideosComponent | ||
28 | ], | ||
29 | providers: [ | ||
30 | RecommendedVideosStore, | ||
31 | RecentVideosRecommendationService | ||
32 | ] | ||
33 | }) | ||
34 | export class RecommendationsModule { | ||
35 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommendations.service.ts b/client/src/app/+videos/+video-watch/recommendations/recommendations.service.ts deleted file mode 100644 index 1d79d35f6..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommendations.service.ts +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | import { Observable } from 'rxjs' | ||
2 | import { Video } from '@app/shared/shared-main' | ||
3 | import { RecommendationInfo } from './recommendation-info.model' | ||
4 | |||
5 | export interface RecommendationService { | ||
6 | getRecommendations (recommendation: RecommendationInfo): Observable<Video[]> | ||
7 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html deleted file mode 100644 index e1040fead..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | <div class="other-videos" [ngClass]="{ 'display-as-row': displayAsRow }"> | ||
2 | <ng-container *ngIf="hasVideos$ | async"> | ||
3 | <div class="title-page-container"> | ||
4 | <h2 i18n class="title-page title-page-single"> | ||
5 | Other videos | ||
6 | </h2> | ||
7 | <div *ngIf="!playlist" class="title-page-autoplay" | ||
8 | [ngbTooltip]="autoPlayNextVideoTooltip" placement="bottom-right auto" | ||
9 | > | ||
10 | <span i18n>AUTOPLAY</span> | ||
11 | <my-input-switch class="small" [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></my-input-switch> | ||
12 | </div> | ||
13 | </div> | ||
14 | |||
15 | <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> | ||
16 | <my-video-miniature | ||
17 | [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" [displayAsRow]="displayAsRow" | ||
18 | (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()" | ||
19 | actorImageSize="32" | ||
20 | > | ||
21 | </my-video-miniature> | ||
22 | |||
23 | <hr *ngIf="!playlist && i == 0 && length > 1" /> | ||
24 | </ng-container> | ||
25 | </ng-container> | ||
26 | </div> | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss deleted file mode 100644 index 84ed25ae8..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | @use '_variables' as *; | ||
2 | @use '_mixins' as *; | ||
3 | |||
4 | .title-page-container { | ||
5 | display: flex; | ||
6 | justify-content: space-between; | ||
7 | align-items: baseline; | ||
8 | margin-bottom: 25px; | ||
9 | flex-wrap: wrap-reverse; | ||
10 | |||
11 | .title-page.active, | ||
12 | .title-page.title-page-single { | ||
13 | @include margin-right(.5rem !important); | ||
14 | |||
15 | margin-bottom: unset; | ||
16 | } | ||
17 | } | ||
18 | |||
19 | .title-page { | ||
20 | margin-top: 0; | ||
21 | } | ||
22 | |||
23 | .title-page-autoplay { | ||
24 | @include margin-left(auto); | ||
25 | |||
26 | display: flex; | ||
27 | width: max-content; | ||
28 | height: max-content; | ||
29 | align-items: center; | ||
30 | |||
31 | span { | ||
32 | @include margin-right(0.3rem); | ||
33 | |||
34 | text-transform: uppercase; | ||
35 | font-size: 85%; | ||
36 | font-weight: 600; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | hr { | ||
41 | margin-top: 0; | ||
42 | } | ||
43 | |||
44 | my-video-miniature { | ||
45 | display: block; | ||
46 | } | ||
47 | |||
48 | .other-videos:not(.display-as-row) my-video-miniature { | ||
49 | min-width: $video-thumbnail-medium-width; | ||
50 | max-width: $video-thumbnail-medium-width; | ||
51 | } | ||
52 | |||
53 | .display-as-row { | ||
54 | my-video-miniature { | ||
55 | margin-bottom: 20px; | ||
56 | } | ||
57 | |||
58 | hr { | ||
59 | display: none; | ||
60 | } | ||
61 | |||
62 | @media screen and (max-width: $mobile-view) { | ||
63 | my-video-miniature { | ||
64 | margin-bottom: 10px; | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts deleted file mode 100644 index 89b9c01b6..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | import { Observable } from 'rxjs' | ||
2 | import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core' | ||
3 | import { AuthService, Notifier, SessionStorageService, User, UserService } from '@app/core' | ||
4 | import { Video } from '@app/shared/shared-main' | ||
5 | import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature' | ||
6 | import { VideoPlaylist } from '@app/shared/shared-video-playlist' | ||
7 | import { UserLocalStorageKeys } from '@root-helpers/users' | ||
8 | import { RecommendationInfo } from './recommendation-info.model' | ||
9 | import { RecommendedVideosStore } from './recommended-videos.store' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-recommended-videos', | ||
13 | templateUrl: './recommended-videos.component.html', | ||
14 | styleUrls: [ './recommended-videos.component.scss' ] | ||
15 | }) | ||
16 | export class RecommendedVideosComponent implements OnInit, OnChanges { | ||
17 | @Input() inputRecommendation: RecommendationInfo | ||
18 | @Input() playlist: VideoPlaylist | ||
19 | @Input() displayAsRow: boolean | ||
20 | |||
21 | @Output() gotRecommendations = new EventEmitter<Video[]>() | ||
22 | |||
23 | autoPlayNextVideo: boolean | ||
24 | autoPlayNextVideoTooltip: string | ||
25 | |||
26 | displayOptions: MiniatureDisplayOptions = { | ||
27 | date: true, | ||
28 | views: true, | ||
29 | by: true, | ||
30 | avatar: true | ||
31 | } | ||
32 | |||
33 | userMiniature: User | ||
34 | |||
35 | readonly hasVideos$: Observable<boolean> | ||
36 | readonly videos$: Observable<Video[]> | ||
37 | |||
38 | constructor ( | ||
39 | private userService: UserService, | ||
40 | private authService: AuthService, | ||
41 | private notifier: Notifier, | ||
42 | private store: RecommendedVideosStore, | ||
43 | private sessionStorageService: SessionStorageService | ||
44 | ) { | ||
45 | this.videos$ = this.store.recommendations$ | ||
46 | this.hasVideos$ = this.store.hasRecommendations$ | ||
47 | this.videos$.subscribe(videos => this.gotRecommendations.emit(videos)) | ||
48 | |||
49 | if (this.authService.isLoggedIn()) { | ||
50 | this.autoPlayNextVideo = this.authService.getUser().autoPlayNextVideo | ||
51 | } else { | ||
52 | this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' | ||
53 | |||
54 | this.sessionStorageService.watch([UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO]).subscribe( | ||
55 | () => { | ||
56 | this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' | ||
57 | } | ||
58 | ) | ||
59 | } | ||
60 | |||
61 | this.autoPlayNextVideoTooltip = $localize`When active, the next video is automatically played after the current one.` | ||
62 | } | ||
63 | |||
64 | ngOnInit () { | ||
65 | this.userService.getAnonymousOrLoggedUser() | ||
66 | .subscribe(user => this.userMiniature = user) | ||
67 | } | ||
68 | |||
69 | ngOnChanges () { | ||
70 | if (this.inputRecommendation) { | ||
71 | this.store.requestNewRecommendations(this.inputRecommendation) | ||
72 | } | ||
73 | } | ||
74 | |||
75 | onVideoRemoved () { | ||
76 | this.store.requestNewRecommendations(this.inputRecommendation) | ||
77 | } | ||
78 | |||
79 | switchAutoPlayNextVideo () { | ||
80 | this.sessionStorageService.setItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO, this.autoPlayNextVideo.toString()) | ||
81 | |||
82 | if (this.authService.isLoggedIn()) { | ||
83 | const details = { | ||
84 | autoPlayNextVideo: this.autoPlayNextVideo | ||
85 | } | ||
86 | |||
87 | this.userService.updateMyProfile(details).subscribe( | ||
88 | () => { | ||
89 | this.authService.refreshUserInformation() | ||
90 | }, | ||
91 | err => this.notifier.error(err.message) | ||
92 | ) | ||
93 | } | ||
94 | } | ||
95 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.store.ts b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.store.ts deleted file mode 100644 index 8c3fb6480..000000000 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.store.ts +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | import { Observable, ReplaySubject } from 'rxjs' | ||
2 | import { map, shareReplay, switchMap, take } from 'rxjs/operators' | ||
3 | import { Inject, Injectable } from '@angular/core' | ||
4 | import { Video } from '@app/shared/shared-main' | ||
5 | import { RecentVideosRecommendationService } from './recent-videos-recommendation.service' | ||
6 | import { RecommendationInfo } from './recommendation-info.model' | ||
7 | import { RecommendationService } from './recommendations.service' | ||
8 | |||
9 | /** | ||
10 | * This store is intended to provide data for the RecommendedVideosComponent. | ||
11 | */ | ||
12 | @Injectable() | ||
13 | export class RecommendedVideosStore { | ||
14 | public readonly recommendations$: Observable<Video[]> | ||
15 | public readonly hasRecommendations$: Observable<boolean> | ||
16 | private readonly requestsForLoad$$ = new ReplaySubject<RecommendationInfo>(1) | ||
17 | |||
18 | constructor ( | ||
19 | @Inject(RecentVideosRecommendationService) private recommendations: RecommendationService | ||
20 | ) { | ||
21 | this.recommendations$ = this.requestsForLoad$$.pipe( | ||
22 | switchMap(requestedRecommendation => { | ||
23 | return this.recommendations.getRecommendations(requestedRecommendation) | ||
24 | .pipe(take(1)) | ||
25 | }), | ||
26 | shareReplay() | ||
27 | ) | ||
28 | |||
29 | this.hasRecommendations$ = this.recommendations$.pipe( | ||
30 | map(otherVideos => otherVideos.length > 0) | ||
31 | ) | ||
32 | } | ||
33 | |||
34 | requestNewRecommendations (recommend: RecommendationInfo) { | ||
35 | this.requestsForLoad$$.next(recommend) | ||
36 | } | ||
37 | } | ||