diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2019-12-11 20:20:42 +0100 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2019-12-13 09:13:43 +0100 |
commit | bee29df8a9ba3090be3daa8ff806dd9a26d7a5cf (patch) | |
tree | 9e9f6d509ed24f799f82667109498b9561474a4d /client/src/app | |
parent | d816f3a063febac1cad09ab3a32e5f0d29353627 (diff) | |
download | PeerTube-bee29df8a9ba3090be3daa8ff806dd9a26d7a5cf.tar.gz PeerTube-bee29df8a9ba3090be3daa8ff806dd9a26d7a5cf.tar.zst PeerTube-bee29df8a9ba3090be3daa8ff806dd9a26d7a5cf.zip |
autoplay next video support for playlists
Diffstat (limited to 'client/src/app')
11 files changed, 100 insertions, 17 deletions
diff --git a/client/src/app/shared/images/global-icon.component.scss b/client/src/app/shared/images/global-icon.component.scss index 32fb9badb..6795d6628 100644 --- a/client/src/app/shared/images/global-icon.component.scss +++ b/client/src/app/shared/images/global-icon.component.scss | |||
@@ -1,4 +1,6 @@ | |||
1 | ::ng-deep svg { | 1 | ::ng-deep { |
2 | width: inherit; | 2 | svg { |
3 | height: inherit; | 3 | width: inherit; |
4 | height: inherit; | ||
5 | } | ||
4 | } | 6 | } |
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index e0b3f1faf..7707d7dda 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts | |||
@@ -17,6 +17,7 @@ export class User implements UserServerModel { | |||
17 | 17 | ||
18 | autoPlayVideo: boolean | 18 | autoPlayVideo: boolean |
19 | autoPlayNextVideo: boolean | 19 | autoPlayNextVideo: boolean |
20 | autoPlayNextVideoPlaylist: boolean | ||
20 | webTorrentEnabled: boolean | 21 | webTorrentEnabled: boolean |
21 | videosHistoryEnabled: boolean | 22 | videosHistoryEnabled: boolean |
22 | videoLanguages: string[] | 23 | videoLanguages: string[] |
diff --git a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss index b55ca0dea..4d9d249d9 100644 --- a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss +++ b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss | |||
@@ -72,10 +72,6 @@ my-video-thumbnail, | |||
72 | 72 | ||
73 | a { | 73 | a { |
74 | width: auto; | 74 | width: auto; |
75 | |||
76 | &:hover { | ||
77 | text-decoration: underline !important; | ||
78 | } | ||
79 | } | 75 | } |
80 | 76 | ||
81 | .video-info-account, .video-info-timestamp { | 77 | .video-info-account, .video-info-timestamp { |
diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.html b/client/src/app/videos/+video-watch/video-watch-playlist.component.html index c89936bd1..c07ba1ed6 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.html +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.html | |||
@@ -14,6 +14,17 @@ | |||
14 | <span>{{ currentPlaylistPosition }}</span><span>{{ playlistPagination.totalItems }}</span> | 14 | <span>{{ currentPlaylistPosition }}</span><span>{{ playlistPagination.totalItems }}</span> |
15 | </div> | 15 | </div> |
16 | </div> | 16 | </div> |
17 | |||
18 | <div class="playlist-controls"> | ||
19 | <my-global-icon | ||
20 | iconName="videos" | ||
21 | [class.active]="autoPlayNextVideoPlaylist" | ||
22 | (click)="switchAutoPlayNextVideoPlaylist()" | ||
23 | [ngbTooltip]="autoPlayNextVideoPlaylistSwitchText" | ||
24 | placement="bottom auto" | ||
25 | container="body" | ||
26 | ></my-global-icon> | ||
27 | </div> | ||
17 | </div> | 28 | </div> |
18 | 29 | ||
19 | <div *ngFor="let playlistElement of playlistElements"> | 30 | <div *ngFor="let playlistElement of playlistElements"> |
diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.scss b/client/src/app/videos/+video-watch/video-watch-playlist.component.scss index 4c24d6b05..ba8d1c3e1 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.scss +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.scss | |||
@@ -34,6 +34,21 @@ | |||
34 | margin: 0 3px; | 34 | margin: 0 3px; |
35 | } | 35 | } |
36 | } | 36 | } |
37 | |||
38 | .playlist-controls { | ||
39 | display: flex; | ||
40 | margin: 10px 0; | ||
41 | |||
42 | my-global-icon { | ||
43 | &:not(.active) { | ||
44 | opacity: .5 | ||
45 | } | ||
46 | |||
47 | ::ng-deep { | ||
48 | cursor: pointer; | ||
49 | } | ||
50 | } | ||
51 | } | ||
37 | } | 52 | } |
38 | 53 | ||
39 | my-video-playlist-element-miniature { | 54 | my-video-playlist-element-miniature { |
diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.ts b/client/src/app/videos/+video-watch/video-watch-playlist.component.ts index 524055ce2..ed2aeda6e 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.ts +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.ts | |||
@@ -3,9 +3,12 @@ import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | |||
3 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | 3 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' |
4 | import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' | 4 | import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' |
5 | import { Router } from '@angular/router' | 5 | import { Router } from '@angular/router' |
6 | import { AuthService } from '@app/core' | 6 | import { User, UserService } from '@app/shared' |
7 | import { AuthService, Notifier } from '@app/core' | ||
7 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 8 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
8 | import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' | 9 | import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' |
10 | import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' | ||
11 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
9 | 12 | ||
10 | @Component({ | 13 | @Component({ |
11 | selector: 'my-video-watch-playlist', | 14 | selector: 'my-video-watch-playlist', |
@@ -13,6 +16,8 @@ import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist- | |||
13 | styleUrls: [ './video-watch-playlist.component.scss' ] | 16 | styleUrls: [ './video-watch-playlist.component.scss' ] |
14 | }) | 17 | }) |
15 | export class VideoWatchPlaylistComponent { | 18 | export class VideoWatchPlaylistComponent { |
19 | static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist' | ||
20 | |||
16 | @Input() video: VideoDetails | 21 | @Input() video: VideoDetails |
17 | @Input() playlist: VideoPlaylist | 22 | @Input() playlist: VideoPlaylist |
18 | 23 | ||
@@ -23,14 +28,24 @@ export class VideoWatchPlaylistComponent { | |||
23 | totalItems: null | 28 | totalItems: null |
24 | } | 29 | } |
25 | 30 | ||
31 | autoPlayNextVideoPlaylist: boolean | ||
32 | autoPlayNextVideoPlaylistSwitchText = '' | ||
26 | noPlaylistVideos = false | 33 | noPlaylistVideos = false |
27 | currentPlaylistPosition = 1 | 34 | currentPlaylistPosition = 1 |
28 | 35 | ||
29 | constructor ( | 36 | constructor ( |
37 | private userService: UserService, | ||
30 | private auth: AuthService, | 38 | private auth: AuthService, |
39 | private notifier: Notifier, | ||
40 | private i18n: I18n, | ||
31 | private videoPlaylist: VideoPlaylistService, | 41 | private videoPlaylist: VideoPlaylistService, |
32 | private router: Router | 42 | private router: Router |
33 | ) {} | 43 | ) { |
44 | this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn() | ||
45 | ? this.auth.getUser().autoPlayNextVideoPlaylist | ||
46 | : peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false' | ||
47 | this.setAutoPlayNextVideoPlaylistSwitchText() | ||
48 | } | ||
34 | 49 | ||
35 | onPlaylistVideosNearOfBottom () { | 50 | onPlaylistVideosNearOfBottom () { |
36 | // Last page | 51 | // Last page |
@@ -121,4 +136,33 @@ export class VideoWatchPlaylistComponent { | |||
121 | this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } }) | 136 | this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } }) |
122 | } | 137 | } |
123 | } | 138 | } |
139 | |||
140 | switchAutoPlayNextVideoPlaylist () { | ||
141 | this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist | ||
142 | this.setAutoPlayNextVideoPlaylistSwitchText() | ||
143 | |||
144 | peertubeLocalStorage.setItem( | ||
145 | VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST, | ||
146 | this.autoPlayNextVideoPlaylist.toString() | ||
147 | ) | ||
148 | |||
149 | if (this.auth.isLoggedIn()) { | ||
150 | const details = { | ||
151 | autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist | ||
152 | } | ||
153 | |||
154 | this.userService.updateMyProfile(details).subscribe( | ||
155 | () => { | ||
156 | this.auth.refreshUserInformation() | ||
157 | }, | ||
158 | err => this.notifier.error(err.message) | ||
159 | ) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | private setAutoPlayNextVideoPlaylistSwitchText () { | ||
164 | this.autoPlayNextVideoPlaylistSwitchText = this.i18n('{{verb}} autoplay for playlists', { | ||
165 | verb: this.autoPlayNextVideoPlaylist ? this.i18n('Disable') : this.i18n('Enable') | ||
166 | }) | ||
167 | } | ||
124 | } | 168 | } |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index c57b00032..97f3a336e 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -217,6 +217,7 @@ | |||
217 | <my-recommended-videos | 217 | <my-recommended-videos |
218 | [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }" | 218 | [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }" |
219 | [user]="user" | 219 | [user]="user" |
220 | [playlist]="playlist" | ||
220 | (gotRecommendations)="onRecommendations($event)" | 221 | (gotRecommendations)="onRecommendations($event)" |
221 | ></my-recommended-videos> | 222 | ></my-recommended-videos> |
222 | </div> | 223 | </div> |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts index 156a3235a..f13acec40 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -37,6 +37,7 @@ import { PluginService } from '@app/core/plugins/plugin.service' | |||
37 | import { HooksService } from '@app/core/plugins/hooks.service' | 37 | import { HooksService } from '@app/core/plugins/hooks.service' |
38 | import { PlatformLocation } from '@angular/common' | 38 | import { PlatformLocation } from '@angular/common' |
39 | import { randomInt } from '@shared/core-utils/miscs/miscs' | 39 | import { randomInt } from '@shared/core-utils/miscs/miscs' |
40 | import { RecommendedVideosComponent } from '../recommendations/recommended-videos.component' | ||
40 | 41 | ||
41 | @Component({ | 42 | @Component({ |
42 | selector: 'my-video-watch', | 43 | selector: 'my-video-watch', |
@@ -436,10 +437,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
436 | 437 | ||
437 | this.player.one('ended', () => { | 438 | this.player.one('ended', () => { |
438 | if (this.playlist) { | 439 | if (this.playlist) { |
439 | this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) | 440 | if ( |
441 | this.user && this.user.autoPlayNextVideoPlaylist || | ||
442 | peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' | ||
443 | ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) | ||
440 | } else if ( | 444 | } else if ( |
441 | this.user && this.user.autoPlayNextVideo || | 445 | this.user && this.user.autoPlayNextVideo || |
442 | peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' | 446 | peertubeLocalStorage.getItem(RecommendedVideosComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' |
443 | ) { | 447 | ) { |
444 | this.zone.run(() => this.autoplayNext()) | 448 | this.zone.run(() => this.autoplayNext()) |
445 | } | 449 | } |
@@ -447,7 +451,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
447 | 451 | ||
448 | this.player.one('stopped', () => { | 452 | this.player.one('stopped', () => { |
449 | if (this.playlist) { | 453 | if (this.playlist) { |
450 | this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) | 454 | if ( |
455 | this.user && this.user.autoPlayNextVideoPlaylist || | ||
456 | peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' | ||
457 | ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) | ||
451 | } | 458 | } |
452 | }) | 459 | }) |
453 | 460 | ||
diff --git a/client/src/app/videos/+video-watch/video-watch.module.ts b/client/src/app/videos/+video-watch/video-watch.module.ts index f083aca4d..2e45e5674 100644 --- a/client/src/app/videos/+video-watch/video-watch.module.ts +++ b/client/src/app/videos/+video-watch/video-watch.module.ts | |||
@@ -12,6 +12,7 @@ import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' | |||
12 | import { RecommendationsModule } from '@app/videos/recommendations/recommendations.module' | 12 | import { RecommendationsModule } from '@app/videos/recommendations/recommendations.module' |
13 | import { VideoWatchPlaylistComponent } from '@app/videos/+video-watch/video-watch-playlist.component' | 13 | import { VideoWatchPlaylistComponent } from '@app/videos/+video-watch/video-watch-playlist.component' |
14 | import { QRCodeModule } from 'angularx-qrcode' | 14 | import { QRCodeModule } from 'angularx-qrcode' |
15 | import { InputSwitchModule } from 'primeng/inputswitch' | ||
15 | 16 | ||
16 | @NgModule({ | 17 | @NgModule({ |
17 | imports: [ | 18 | imports: [ |
@@ -19,7 +20,8 @@ import { QRCodeModule } from 'angularx-qrcode' | |||
19 | SharedModule, | 20 | SharedModule, |
20 | NgbTooltipModule, | 21 | NgbTooltipModule, |
21 | QRCodeModule, | 22 | QRCodeModule, |
22 | RecommendationsModule | 23 | RecommendationsModule, |
24 | InputSwitchModule | ||
23 | ], | 25 | ], |
24 | 26 | ||
25 | declarations: [ | 27 | declarations: [ |
diff --git a/client/src/app/videos/recommendations/recommended-videos.component.html b/client/src/app/videos/recommendations/recommended-videos.component.html index 5f223078a..c82642c1c 100644 --- a/client/src/app/videos/recommendations/recommended-videos.component.html +++ b/client/src/app/videos/recommendations/recommended-videos.component.html | |||
@@ -4,15 +4,17 @@ | |||
4 | <div i18n class="title-page title-page-single"> | 4 | <div i18n class="title-page title-page-single"> |
5 | Other videos | 5 | Other videos |
6 | </div> | 6 | </div> |
7 | <div class="d-flex title-page-autoplay"> | 7 | <div *ngIf="!playlist" class="d-flex title-page-autoplay"> |
8 | <span>Autoplay</span> | 8 | <span i18n>Autoplay</span> |
9 | <p-inputSwitch [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></p-inputSwitch> | 9 | <p-inputSwitch [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></p-inputSwitch> |
10 | </div> | 10 | </div> |
11 | </div> | 11 | </div> |
12 | 12 | ||
13 | <div *ngFor="let video of (videos$ | async)"> | 13 | <div *ngFor="let video of (videos$ | async); let i = index; let length = count"> |
14 | <my-video-miniature [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()"> | 14 | <my-video-miniature [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()"> |
15 | </my-video-miniature> | 15 | </my-video-miniature> |
16 | |||
17 | <hr *ngIf="!playlist && i == 0 && length > 1" /> | ||
16 | </div> | 18 | </div> |
17 | </ng-container> | 19 | </ng-container> |
18 | </div> | 20 | </div> |
diff --git a/client/src/app/videos/recommendations/recommended-videos.component.ts b/client/src/app/videos/recommendations/recommended-videos.component.ts index 4c3cde225..771ae54a2 100644 --- a/client/src/app/videos/recommendations/recommended-videos.component.ts +++ b/client/src/app/videos/recommendations/recommended-videos.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Component, Input, Output, OnChanges, EventEmitter } from '@angular/core' | 1 | import { Component, Input, Output, OnChanges, EventEmitter } from '@angular/core' |
2 | import { Observable } from 'rxjs' | 2 | import { Observable } from 'rxjs' |
3 | import { Video } from '@app/shared/video/video.model' | 3 | import { Video } from '@app/shared/video/video.model' |
4 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | ||
4 | import { RecommendationInfo } from '@app/shared/video/recommendation-info.model' | 5 | import { RecommendationInfo } from '@app/shared/video/recommendation-info.model' |
5 | import { RecommendedVideosStore } from '@app/videos/recommendations/recommended-videos.store' | 6 | import { RecommendedVideosStore } from '@app/videos/recommendations/recommended-videos.store' |
6 | import { User } from '@app/shared' | 7 | import { User } from '@app/shared' |
@@ -14,10 +15,11 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' | |||
14 | styleUrls: [ './recommended-videos.component.scss' ] | 15 | styleUrls: [ './recommended-videos.component.scss' ] |
15 | }) | 16 | }) |
16 | export class RecommendedVideosComponent implements OnChanges { | 17 | export class RecommendedVideosComponent implements OnChanges { |
17 | private static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video' | 18 | static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video' |
18 | 19 | ||
19 | @Input() inputRecommendation: RecommendationInfo | 20 | @Input() inputRecommendation: RecommendationInfo |
20 | @Input() user: User | 21 | @Input() user: User |
22 | @Input() playlist: VideoPlaylist | ||
21 | @Output() gotRecommendations = new EventEmitter<Video[]>() | 23 | @Output() gotRecommendations = new EventEmitter<Video[]>() |
22 | 24 | ||
23 | readonly hasVideos$: Observable<boolean> | 25 | readonly hasVideos$: Observable<boolean> |