aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+videos/+video-watch/video-watch-playlist.component.html7
-rw-r--r--client/src/app/+videos/+video-watch/video-watch-playlist.component.ts49
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.html3
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts16
-rw-r--r--client/src/app/shared/shared-main/angular/infinite-scroller.directive.ts6
-rw-r--r--client/src/app/shared/shared-share-modal/video-share.component.ts5
-rw-r--r--client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts2
7 files changed, 54 insertions, 34 deletions
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 246ef83cf..c270142a3 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
@@ -1,4 +1,7 @@
1<div *ngIf="playlist && video" class="playlist" myInfiniteScroller [autoInit]="true" [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()"> 1<div
2 *ngIf="playlist && currentPlaylistPosition" class="playlist"
3 myInfiniteScroller [autoInit]="true" [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()"
4>
2 <div class="playlist-info"> 5 <div class="playlist-info">
3 <div class="playlist-display-name"> 6 <div class="playlist-display-name">
4 {{ playlist.displayName }} 7 {{ playlist.displayName }}
@@ -36,7 +39,7 @@
36 </div> 39 </div>
37 </div> 40 </div>
38 41
39 <div *ngFor="let playlistElement of playlistElements"> 42 <div *ngFor="let playlistElement of playlistElements" [ngClass]="'element-' + playlistElement.position">
40 <my-video-playlist-element-miniature 43 <my-video-playlist-element-miniature
41 [playlistElement]="playlistElement" [playlist]="playlist" [owned]="isPlaylistOwned()" (elementRemoved)="onElementRemoved($event)" 44 [playlistElement]="playlistElement" [playlist]="playlist" [owned]="isPlaylistOwned()" (elementRemoved)="onElementRemoved($event)"
42 [playing]="currentPlaylistPosition === playlistElement.position" [accountLink]="false" [position]="playlistElement.position" 45 [playing]="currentPlaylistPosition === playlistElement.position" [accountLink]="false" [position]="playlistElement.position"
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 c60ca4671..d76d0bbd2 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
@@ -1,9 +1,10 @@
1import { Component, Input } from '@angular/core' 1
2import { Component, EventEmitter, Input, Output } from '@angular/core'
2import { Router } from '@angular/router' 3import { Router } from '@angular/router'
3import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core' 4import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core'
4import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' 5import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
5import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage' 6import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
6import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' 7import { VideoPlaylistPrivacy } from '@shared/models'
7 8
8@Component({ 9@Component({
9 selector: 'my-video-watch-playlist', 10 selector: 'my-video-watch-playlist',
@@ -14,9 +15,10 @@ export class VideoWatchPlaylistComponent {
14 static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist' 15 static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
15 static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist' 16 static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist'
16 17
17 @Input() video: VideoDetails
18 @Input() playlist: VideoPlaylist 18 @Input() playlist: VideoPlaylist
19 19
20 @Output() videoFound = new EventEmitter<string>()
21
20 playlistElements: VideoPlaylistElement[] = [] 22 playlistElements: VideoPlaylistElement[] = []
21 playlistPagination: ComponentPagination = { 23 playlistPagination: ComponentPagination = {
22 currentPage: 1, 24 currentPage: 1,
@@ -29,7 +31,8 @@ export class VideoWatchPlaylistComponent {
29 loopPlaylist: boolean 31 loopPlaylist: boolean
30 loopPlaylistSwitchText = '' 32 loopPlaylistSwitchText = ''
31 noPlaylistVideos = false 33 noPlaylistVideos = false
32 currentPlaylistPosition = 1 34
35 currentPlaylistPosition: number
33 36
34 constructor ( 37 constructor (
35 private userService: UserService, 38 private userService: UserService,
@@ -44,6 +47,7 @@ export class VideoWatchPlaylistComponent {
44 this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn() 47 this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
45 ? this.auth.getUser().autoPlayNextVideoPlaylist 48 ? this.auth.getUser().autoPlayNextVideoPlaylist
46 : this.localStorageService.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false' 49 : this.localStorageService.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
50
47 this.setAutoPlayNextVideoPlaylistSwitchText() 51 this.setAutoPlayNextVideoPlaylistSwitchText()
48 52
49 // defaults to false 53 // defaults to false
@@ -51,12 +55,12 @@ export class VideoWatchPlaylistComponent {
51 this.setLoopPlaylistSwitchText() 55 this.setLoopPlaylistSwitchText()
52 } 56 }
53 57
54 onPlaylistVideosNearOfBottom () { 58 onPlaylistVideosNearOfBottom (position?: number) {
55 // Last page 59 // Last page
56 if (this.playlistPagination.totalItems <= (this.playlistPagination.currentPage * this.playlistPagination.itemsPerPage)) return 60 if (this.playlistPagination.totalItems <= (this.playlistPagination.currentPage * this.playlistPagination.itemsPerPage)) return
57 61
58 this.playlistPagination.currentPage += 1 62 this.playlistPagination.currentPage += 1
59 this.loadPlaylistElements(this.playlist,false) 63 this.loadPlaylistElements(this.playlist, false, position)
60 } 64 }
61 65
62 onElementRemoved (playlistElement: VideoPlaylistElement) { 66 onElementRemoved (playlistElement: VideoPlaylistElement) {
@@ -83,26 +87,26 @@ export class VideoWatchPlaylistComponent {
83 return this.playlist.privacy.id === VideoPlaylistPrivacy.PUBLIC 87 return this.playlist.privacy.id === VideoPlaylistPrivacy.PUBLIC
84 } 88 }
85 89
86 loadPlaylistElements (playlist: VideoPlaylist, redirectToFirst = false) { 90 loadPlaylistElements (playlist: VideoPlaylist, redirectToFirst = false, position?: number) {
87 this.videoPlaylist.getPlaylistVideos(playlist.uuid, this.playlistPagination) 91 this.videoPlaylist.getPlaylistVideos(playlist.uuid, this.playlistPagination)
88 .subscribe(({ total, data }) => { 92 .subscribe(({ total, data }) => {
89 this.playlistElements = this.playlistElements.concat(data) 93 this.playlistElements = this.playlistElements.concat(data)
90 this.playlistPagination.totalItems = total 94 this.playlistPagination.totalItems = total
91 95
92 const firstAvailableVideos = this.playlistElements.find(e => !!e.video) 96 const firstAvailableVideo = this.playlistElements.find(e => !!e.video)
93 if (!firstAvailableVideos) { 97 if (!firstAvailableVideo) {
94 this.noPlaylistVideos = true 98 this.noPlaylistVideos = true
95 return 99 return
96 } 100 }
97 101
98 this.updatePlaylistIndex(this.video) 102 if (position) this.updatePlaylistIndex(position)
99 103
100 if (redirectToFirst) { 104 if (redirectToFirst) {
101 const extras = { 105 const extras = {
102 queryParams: { 106 queryParams: {
103 start: firstAvailableVideos.startTimestamp, 107 start: firstAvailableVideo.startTimestamp,
104 stop: firstAvailableVideos.stopTimestamp, 108 stop: firstAvailableVideo.stopTimestamp,
105 videoId: firstAvailableVideos.video.uuid 109 playlistPosition: firstAvailableVideo.position
106 }, 110 },
107 replaceUrl: true 111 replaceUrl: true
108 } 112 }
@@ -111,18 +115,26 @@ export class VideoWatchPlaylistComponent {
111 }) 115 })
112 } 116 }
113 117
114 updatePlaylistIndex (video: VideoDetails) { 118 updatePlaylistIndex (position: number) {
115 if (this.playlistElements.length === 0 || !video) return 119 if (this.playlistElements.length === 0 || !position) return
116 120
117 for (const playlistElement of this.playlistElements) { 121 for (const playlistElement of this.playlistElements) {
118 if (playlistElement.video && playlistElement.video.id === video.id) { 122 // >= if the previous videos were not valid
123 if (playlistElement.video && playlistElement.position >= position) {
119 this.currentPlaylistPosition = playlistElement.position 124 this.currentPlaylistPosition = playlistElement.position
125
126 this.videoFound.emit(playlistElement.video.uuid)
127
128 setTimeout(() => {
129 document.querySelector('.element-' + this.currentPlaylistPosition).scrollIntoView(false)
130 }, 0)
131
120 return 132 return
121 } 133 }
122 } 134 }
123 135
124 // Load more videos to find our video 136 // Load more videos to find our video
125 this.onPlaylistVideosNearOfBottom() 137 this.onPlaylistVideosNearOfBottom(position)
126 } 138 }
127 139
128 findNextPlaylistVideo (position = this.currentPlaylistPosition): VideoPlaylistElement { 140 findNextPlaylistVideo (position = this.currentPlaylistPosition): VideoPlaylistElement {
@@ -147,9 +159,10 @@ export class VideoWatchPlaylistComponent {
147 navigateToNextPlaylistVideo () { 159 navigateToNextPlaylistVideo () {
148 const next = this.findNextPlaylistVideo(this.currentPlaylistPosition + 1) 160 const next = this.findNextPlaylistVideo(this.currentPlaylistPosition + 1)
149 if (!next) return 161 if (!next) return
162
150 const start = next.startTimestamp 163 const start = next.startTimestamp
151 const stop = next.stopTimestamp 164 const stop = next.stopTimestamp
152 this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } }) 165 this.router.navigate([],{ queryParams: { playlistPosition: next.position, start, stop } })
153 } 166 }
154 167
155 switchAutoPlayNextVideoPlaylist () { 168 switchAutoPlayNextVideoPlaylist () {
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 4279437d2..076c6205f 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.html
+++ b/client/src/app/+videos/+video-watch/video-watch.component.html
@@ -11,7 +11,8 @@
11 11
12 <my-video-watch-playlist 12 <my-video-watch-playlist
13 #videoWatchPlaylist 13 #videoWatchPlaylist
14 [video]="video" [playlist]="playlist" class="playlist" 14 [playlist]="playlist" class="playlist"
15 (videoFound)="onPlaylistVideoFound($event)"
15 ></my-video-watch-playlist> 16 ></my-video-watch-playlist>
16 </div> 17 </div>
17 18
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 4df2c6c5e..7ff860e79 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -53,6 +53,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
53 video: VideoDetails = null 53 video: VideoDetails = null
54 videoCaptions: VideoCaption[] = [] 54 videoCaptions: VideoCaption[] = []
55 55
56 playlistPosition: number
56 playlist: VideoPlaylist = null 57 playlist: VideoPlaylist = null
57 58
58 completeDescriptionShown = false 59 completeDescriptionShown = false
@@ -140,9 +141,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
140 if (playlistId) this.loadPlaylist(playlistId) 141 if (playlistId) this.loadPlaylist(playlistId)
141 }) 142 })
142 143
143 this.queryParamsSub = this.route.queryParams.subscribe(async queryParams => { 144 this.queryParamsSub = this.route.queryParams.subscribe(queryParams => {
144 const videoId = queryParams[ 'videoId' ] 145 this.playlistPosition = queryParams[ 'playlistPosition' ]
145 if (videoId) this.loadVideo(videoId) 146 this.videoWatchPlaylist.updatePlaylistIndex(this.playlistPosition)
146 147
147 const start = queryParams[ 'start' ] 148 const start = queryParams[ 'start' ]
148 if (this.player && start) this.player.currentTime(parseInt(start, 10)) 149 if (this.player && start) this.player.currentTime(parseInt(start, 10))
@@ -335,6 +336,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
335 return genericChannelDisplayName.includes(this.video.channel.displayName) 336 return genericChannelDisplayName.includes(this.video.channel.displayName)
336 } 337 }
337 338
339 onPlaylistVideoFound (videoId: string) {
340 this.loadVideo(videoId)
341 }
342
338 private loadVideo (videoId: string) { 343 private loadVideo (videoId: string) {
339 // Video did not change 344 // Video did not change
340 if (this.video && this.video.uuid === videoId) return 345 if (this.video && this.video.uuid === videoId) return
@@ -392,8 +397,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
392 .subscribe(playlist => { 397 .subscribe(playlist => {
393 this.playlist = playlist 398 this.playlist = playlist
394 399
395 const videoId = this.route.snapshot.queryParams['videoId'] 400 this.videoWatchPlaylist.loadPlaylistElements(playlist, !this.playlistPosition, this.playlistPosition)
396 this.videoWatchPlaylist.loadPlaylistElements(playlist, !videoId)
397 }) 401 })
398 } 402 }
399 403
@@ -458,8 +462,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
458 this.remoteServerDown = false 462 this.remoteServerDown = false
459 this.currentTime = undefined 463 this.currentTime = undefined
460 464
461 this.videoWatchPlaylist.updatePlaylistIndex(video)
462
463 if (this.isVideoBlur(this.video)) { 465 if (this.isVideoBlur(this.video)) {
464 const res = await this.confirmService.confirm( 466 const res = await this.confirmService.confirm(
465 $localize`This video contains mature or explicit content. Are you sure you want to watch it?`, 467 $localize`This video contains mature or explicit content. Are you sure you want to watch it?`,
diff --git a/client/src/app/shared/shared-main/angular/infinite-scroller.directive.ts b/client/src/app/shared/shared-main/angular/infinite-scroller.directive.ts
index f09c3d1fc..d2cf53227 100644
--- a/client/src/app/shared/shared-main/angular/infinite-scroller.directive.ts
+++ b/client/src/app/shared/shared-main/angular/infinite-scroller.directive.ts
@@ -1,6 +1,6 @@
1import { fromEvent, Observable, Subscription } from 'rxjs'
1import { distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators' 2import { distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators'
2import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' 3import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
3import { fromEvent, Observable, Subscription } from 'rxjs'
4 4
5@Directive({ 5@Directive({
6 selector: '[myInfiniteScroller]' 6 selector: '[myInfiniteScroller]'
@@ -80,7 +80,9 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy, AfterConten
80 } 80 }
81 81
82 private getMaximumScroll () { 82 private getMaximumScroll () {
83 return this.container.scrollHeight - window.innerHeight 83 const elementHeight = this.onItself ? this.container.clientHeight : window.innerHeight
84
85 return this.container.scrollHeight - elementHeight
84 } 86 }
85 87
86 private hasScroll () { 88 private hasScroll () {
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts
index 8d8e8a3a5..f57a50770 100644
--- a/client/src/app/shared/shared-share-modal/video-share.component.ts
+++ b/client/src/app/shared/shared-share-modal/video-share.component.ts
@@ -37,6 +37,7 @@ export class VideoShareComponent {
37 @Input() video: VideoDetails = null 37 @Input() video: VideoDetails = null
38 @Input() videoCaptions: VideoCaption[] = [] 38 @Input() videoCaptions: VideoCaption[] = []
39 @Input() playlist: VideoPlaylist = null 39 @Input() playlist: VideoPlaylist = null
40 @Input() playlistPosition: number = null
40 41
41 activeVideoId: TabId = 'url' 42 activeVideoId: TabId = 'url'
42 activePlaylistId: TabId = 'url' 43 activePlaylistId: TabId = 'url'
@@ -45,8 +46,6 @@ export class VideoShareComponent {
45 isAdvancedCustomizationCollapsed = true 46 isAdvancedCustomizationCollapsed = true
46 includeVideoInPlaylist = false 47 includeVideoInPlaylist = false
47 48
48 private playlistPosition: number = null
49
50 constructor (private modalService: NgbModal) { } 49 constructor (private modalService: NgbModal) { }
51 50
52 show (currentVideoTimestamp?: number, currentPlaylistPosition?: number) { 51 show (currentVideoTimestamp?: number, currentPlaylistPosition?: number) {
@@ -107,7 +106,7 @@ export class VideoShareComponent {
107 106
108 if (!this.includeVideoInPlaylist) return base 107 if (!this.includeVideoInPlaylist) return base
109 108
110 return base + '?videoId=' + this.video.uuid 109 return base + '?playlistPosition=' + this.playlistPosition
111 } 110 }
112 111
113 notSecure () { 112 notSecure () {
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
index 5879c4978..7c083ae26 100644
--- a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
+++ b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
@@ -78,7 +78,7 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
78 if (!this.playlistElement || !this.playlistElement.video) return {} 78 if (!this.playlistElement || !this.playlistElement.video) return {}
79 79
80 return { 80 return {
81 videoId: this.playlistElement.video.uuid, 81 playlistPosition: this.playlistElement.position,
82 start: this.playlistElement.startTimestamp, 82 start: this.playlistElement.startTimestamp,
83 stop: this.playlistElement.stopTimestamp, 83 stop: this.playlistElement.stopTimestamp,
84 resume: true 84 resume: true