diff options
Diffstat (limited to 'client/src/app/videos')
8 files changed, 65 insertions, 25 deletions
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.html b/client/src/app/videos/+video-watch/modal/video-share.component.html index 9f3c37fe8..955b2b80c 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.html +++ b/client/src/app/videos/+video-watch/modal/video-share.component.html | |||
@@ -6,11 +6,19 @@ | |||
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
8 | 8 | ||
9 | <div *ngIf="currentVideoTimestampString" class="start-at"> | 9 | <div class="start-at"> |
10 | <my-peertube-checkbox | 10 | <my-peertube-checkbox |
11 | inputName="startAt" [(ngModel)]="startAtCheckbox" | 11 | inputName="startAt" [(ngModel)]="startAtCheckbox" |
12 | i18n-labelText [labelText]="getStartCheckboxLabel()" | 12 | i18n-labelText labelText="Start at" |
13 | ></my-peertube-checkbox> | 13 | ></my-peertube-checkbox> |
14 | |||
15 | <my-timestamp-input | ||
16 | [timestamp]="currentVideoTimestamp" | ||
17 | [maxTimestamp]="video.duration" | ||
18 | [disabled]="!startAtCheckbox" | ||
19 | [(ngModel)]="currentVideoTimestamp" | ||
20 | > | ||
21 | </my-timestamp-input> | ||
14 | </div> | 22 | </div> |
15 | 23 | ||
16 | <div class="form-group"> | 24 | <div class="form-group"> |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.scss b/client/src/app/videos/+video-watch/modal/video-share.component.scss index 4937506b9..472a45920 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.scss +++ b/client/src/app/videos/+video-watch/modal/video-share.component.scss | |||
@@ -13,4 +13,9 @@ | |||
13 | display: flex; | 13 | display: flex; |
14 | justify-content: center; | 14 | justify-content: center; |
15 | margin-top: 10px; | 15 | margin-top: 10px; |
16 | align-items: center; | ||
17 | |||
18 | my-timestamp-input { | ||
19 | margin-left: 10px; | ||
20 | } | ||
16 | } | 21 | } |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.ts b/client/src/app/videos/+video-watch/modal/video-share.component.ts index c6205e355..6565d7f88 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-share.component.ts | |||
@@ -16,10 +16,8 @@ export class VideoShareComponent { | |||
16 | 16 | ||
17 | @Input() video: VideoDetails = null | 17 | @Input() video: VideoDetails = null |
18 | 18 | ||
19 | currentVideoTimestamp: number | ||
19 | startAtCheckbox = false | 20 | startAtCheckbox = false |
20 | currentVideoTimestampString: string | ||
21 | |||
22 | private currentVideoTimestamp: number | ||
23 | 21 | ||
24 | constructor ( | 22 | constructor ( |
25 | private modalService: NgbModal, | 23 | private modalService: NgbModal, |
@@ -28,8 +26,7 @@ export class VideoShareComponent { | |||
28 | ) { } | 26 | ) { } |
29 | 27 | ||
30 | show (currentVideoTimestamp?: number) { | 28 | show (currentVideoTimestamp?: number) { |
31 | this.currentVideoTimestamp = Math.floor(currentVideoTimestamp) | 29 | this.currentVideoTimestamp = currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0 |
32 | this.currentVideoTimestampString = durationToString(this.currentVideoTimestamp) | ||
33 | 30 | ||
34 | this.modalService.open(this.modal) | 31 | this.modalService.open(this.modal) |
35 | } | 32 | } |
@@ -52,10 +49,6 @@ export class VideoShareComponent { | |||
52 | this.notifier.success(this.i18n('Copied')) | 49 | this.notifier.success(this.i18n('Copied')) |
53 | } | 50 | } |
54 | 51 | ||
55 | getStartCheckboxLabel () { | ||
56 | return this.i18n('Start at {{timestamp}}', { timestamp: this.currentVideoTimestampString }) | ||
57 | } | ||
58 | |||
59 | private getVideoTimestampIfEnabled () { | 52 | private getVideoTimestampIfEnabled () { |
60 | if (this.startAtCheckbox === true) return this.currentVideoTimestamp | 53 | if (this.startAtCheckbox === true) return this.currentVideoTimestamp |
61 | 54 | ||
diff --git a/client/src/app/videos/+video-watch/video-watch-routing.module.ts b/client/src/app/videos/+video-watch/video-watch-routing.module.ts index bdd4f945e..0d7809044 100644 --- a/client/src/app/videos/+video-watch/video-watch-routing.module.ts +++ b/client/src/app/videos/+video-watch/video-watch-routing.module.ts | |||
@@ -7,7 +7,16 @@ import { VideoWatchComponent } from './video-watch.component' | |||
7 | 7 | ||
8 | const videoWatchRoutes: Routes = [ | 8 | const videoWatchRoutes: Routes = [ |
9 | { | 9 | { |
10 | path: '', | 10 | path: 'playlist/:uuid', |
11 | component: VideoWatchComponent, | ||
12 | canActivate: [ MetaGuard ] | ||
13 | }, | ||
14 | { | ||
15 | path: ':uuid/comments/:commentId', | ||
16 | redirectTo: ':uuid' | ||
17 | }, | ||
18 | { | ||
19 | path: ':uuid', | ||
11 | component: VideoWatchComponent, | 20 | component: VideoWatchComponent, |
12 | canActivate: [ MetaGuard ] | 21 | canActivate: [ MetaGuard ] |
13 | } | 22 | } |
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 fffcc1275..615b88bd6 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -65,17 +65,31 @@ | |||
65 | <my-global-icon iconName="dislike"></my-global-icon> | 65 | <my-global-icon iconName="dislike"></my-global-icon> |
66 | </div> | 66 | </div> |
67 | 67 | ||
68 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button action-button-support"> | 68 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button"> |
69 | <my-global-icon iconName="heart"></my-global-icon> | 69 | <my-global-icon iconName="heart"></my-global-icon> |
70 | <span class="icon-text" i18n>Support</span> | 70 | <span class="icon-text" i18n>Support</span> |
71 | </div> | 71 | </div> |
72 | 72 | ||
73 | <div (click)="showShareModal()" class="action-button action-button-share" role="button"> | 73 | <div (click)="showShareModal()" class="action-button" role="button"> |
74 | <my-global-icon iconName="share"></my-global-icon> | 74 | <my-global-icon iconName="share"></my-global-icon> |
75 | <span class="icon-text" i18n>Share</span> | 75 | <span class="icon-text" i18n>Share</span> |
76 | </div> | 76 | </div> |
77 | 77 | ||
78 | <div class="action-more" ngbDropdown placement="top" role="button"> | 78 | <div |
79 | class="action-dropdown" ngbDropdown placement="top" role="button" autoClose="outside" | ||
80 | *ngIf="isUserLoggedIn()" (openChange)="addContent.openChange($event)" | ||
81 | > | ||
82 | <div class="action-button action-button-save" ngbDropdownToggle role="button"> | ||
83 | <my-global-icon iconName="playlist-add"></my-global-icon> | ||
84 | <span class="icon-text" i18n>Save</span> | ||
85 | </div> | ||
86 | |||
87 | <div ngbDropdownMenu> | ||
88 | <my-video-add-to-playlist #addContent [video]="video"></my-video-add-to-playlist> | ||
89 | </div> | ||
90 | </div> | ||
91 | |||
92 | <div class="action-dropdown" ngbDropdown placement="top" role="button"> | ||
79 | <div class="action-button" ngbDropdownToggle role="button"> | 93 | <div class="action-button" ngbDropdownToggle role="button"> |
80 | <my-global-icon class="more-icon" iconName="more"></my-global-icon> | 94 | <my-global-icon class="more-icon" iconName="more"></my-global-icon> |
81 | </div> | 95 | </div> |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index 33d77e62c..ff321fdbc 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss | |||
@@ -176,7 +176,7 @@ $other-videos-width: 260px; | |||
176 | display: flex; | 176 | display: flex; |
177 | align-items: center; | 177 | align-items: center; |
178 | 178 | ||
179 | .action-button:not(:first-child), .action-more { | 179 | .action-button:not(:first-child), .action-dropdown { |
180 | margin-left: 10px; | 180 | margin-left: 10px; |
181 | } | 181 | } |
182 | 182 | ||
@@ -212,12 +212,19 @@ $other-videos-width: 260px; | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | &.action-button-save { | ||
216 | my-global-icon { | ||
217 | top: 0 !important; | ||
218 | right: -1px; | ||
219 | } | ||
220 | } | ||
221 | |||
215 | .icon-text { | 222 | .icon-text { |
216 | margin-left: 3px; | 223 | margin-left: 3px; |
217 | } | 224 | } |
218 | } | 225 | } |
219 | 226 | ||
220 | .action-more { | 227 | .action-dropdown { |
221 | display: inline-block; | 228 | display: inline-block; |
222 | 229 | ||
223 | .dropdown-menu .dropdown-item { | 230 | .dropdown-menu .dropdown-item { |
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 0f04441ba..359217f3b 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -59,6 +59,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
59 | remoteServerDown = false | 59 | remoteServerDown = false |
60 | hotkeys: Hotkey[] | 60 | hotkeys: Hotkey[] |
61 | 61 | ||
62 | private currentTime: number | ||
62 | private paramsSub: Subscription | 63 | private paramsSub: Subscription |
63 | 64 | ||
64 | constructor ( | 65 | constructor ( |
@@ -114,10 +115,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
114 | ) | 115 | ) |
115 | .subscribe(([ video, captionsResult ]) => { | 116 | .subscribe(([ video, captionsResult ]) => { |
116 | const startTime = this.route.snapshot.queryParams.start | 117 | const startTime = this.route.snapshot.queryParams.start |
118 | const stopTime = this.route.snapshot.queryParams.stop | ||
117 | const subtitle = this.route.snapshot.queryParams.subtitle | 119 | const subtitle = this.route.snapshot.queryParams.subtitle |
118 | const playerMode = this.route.snapshot.queryParams.mode | 120 | const playerMode = this.route.snapshot.queryParams.mode |
119 | 121 | ||
120 | this.onVideoFetched(video, captionsResult.data, { startTime, subtitle, playerMode }) | 122 | this.onVideoFetched(video, captionsResult.data, { startTime, stopTime, subtitle, playerMode }) |
121 | .catch(err => this.handleError(err)) | 123 | .catch(err => this.handleError(err)) |
122 | }) | 124 | }) |
123 | }) | 125 | }) |
@@ -219,7 +221,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
219 | showShareModal () { | 221 | showShareModal () { |
220 | const currentTime = this.player ? this.player.currentTime() : undefined | 222 | const currentTime = this.player ? this.player.currentTime() : undefined |
221 | 223 | ||
222 | this.videoShareModal.show(currentTime) | 224 | this.videoShareModal.show(this.currentTime) |
223 | } | 225 | } |
224 | 226 | ||
225 | showDownloadModal (event: Event) { | 227 | showDownloadModal (event: Event) { |
@@ -371,7 +373,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
371 | private async onVideoFetched ( | 373 | private async onVideoFetched ( |
372 | video: VideoDetails, | 374 | video: VideoDetails, |
373 | videoCaptions: VideoCaption[], | 375 | videoCaptions: VideoCaption[], |
374 | urlOptions: { startTime?: number, subtitle?: string, playerMode?: string } | 376 | urlOptions: { startTime?: number, stopTime?: number, subtitle?: string, playerMode?: string } |
375 | ) { | 377 | ) { |
376 | this.video = video | 378 | this.video = video |
377 | 379 | ||
@@ -379,6 +381,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
379 | this.descriptionLoading = false | 381 | this.descriptionLoading = false |
380 | this.completeDescriptionShown = false | 382 | this.completeDescriptionShown = false |
381 | this.remoteServerDown = false | 383 | this.remoteServerDown = false |
384 | this.currentTime = undefined | ||
382 | 385 | ||
383 | let startTime = urlOptions.startTime || (this.video.userHistory ? this.video.userHistory.currentTime : 0) | 386 | let startTime = urlOptions.startTime || (this.video.userHistory ? this.video.userHistory.currentTime : 0) |
384 | // If we are at the end of the video, reset the timer | 387 | // If we are at the end of the video, reset the timer |
@@ -420,6 +423,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
420 | inactivityTimeout: 2500, | 423 | inactivityTimeout: 2500, |
421 | poster: this.video.previewUrl, | 424 | poster: this.video.previewUrl, |
422 | startTime, | 425 | startTime, |
426 | stopTime: urlOptions.stopTime, | ||
423 | 427 | ||
424 | theaterMode: true, | 428 | theaterMode: true, |
425 | captions: videoCaptions.length !== 0, | 429 | captions: videoCaptions.length !== 0, |
@@ -466,6 +470,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
466 | this.zone.runOutsideAngular(async () => { | 470 | this.zone.runOutsideAngular(async () => { |
467 | this.player = await PeertubePlayerManager.initialize(mode, options) | 471 | this.player = await PeertubePlayerManager.initialize(mode, options) |
468 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | 472 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) |
473 | |||
474 | this.player.on('timeupdate', () => { | ||
475 | this.currentTime = Math.floor(this.player.currentTime()) | ||
476 | }) | ||
469 | }) | 477 | }) |
470 | 478 | ||
471 | this.setVideoDescriptionHTML() | 479 | this.setVideoDescriptionHTML() |
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 58988ffd1..69a9232ce 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts | |||
@@ -78,11 +78,7 @@ const videosRoutes: Routes = [ | |||
78 | } | 78 | } |
79 | }, | 79 | }, |
80 | { | 80 | { |
81 | path: 'watch/:uuid/comments/:commentId', | 81 | path: 'watch', |
82 | redirectTo: 'watch/:uuid' | ||
83 | }, | ||
84 | { | ||
85 | path: 'watch/:uuid', | ||
86 | loadChildren: 'app/videos/+video-watch/video-watch.module#VideoWatchModule', | 82 | loadChildren: 'app/videos/+video-watch/video-watch.module#VideoWatchModule', |
87 | data: { | 83 | data: { |
88 | preload: 3000 | 84 | preload: 3000 |