]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts
Allow configuration to be static/readonly (#4315)
[github/Chocobozzz/PeerTube.git] / client / src / app / +videos / +video-watch / shared / playlist / video-watch-playlist.component.ts
CommitLineData
d142c7b9 1import { Component, EventEmitter, Input, Output } from '@angular/core'
72675ebe 2import { Router } from '@angular/router'
67ed6552 3import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core'
67ed6552 4import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
66357162 5import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
d142c7b9 6import { VideoPlaylistPrivacy } from '@shared/models'
72675ebe
C
7
8@Component({
9 selector: 'my-video-watch-playlist',
10 templateUrl: './video-watch-playlist.component.html',
11 styleUrls: [ './video-watch-playlist.component.scss' ]
12})
13export class VideoWatchPlaylistComponent {
bee29df8 14 static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
88a7f93f 15 static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist'
bee29df8 16
72675ebe
C
17 @Input() playlist: VideoPlaylist
18
d142c7b9
C
19 @Output() videoFound = new EventEmitter<string>()
20
bfbd9128 21 playlistElements: VideoPlaylistElement[] = []
72675ebe
C
22 playlistPagination: ComponentPagination = {
23 currentPage: 1,
24 itemsPerPage: 30,
25 totalItems: null
26 }
27
bee29df8
RK
28 autoPlayNextVideoPlaylist: boolean
29 autoPlayNextVideoPlaylistSwitchText = ''
88a7f93f
RK
30 loopPlaylist: boolean
31 loopPlaylistSwitchText = ''
72675ebe 32 noPlaylistVideos = false
d142c7b9
C
33
34 currentPlaylistPosition: number
72675ebe
C
35
36 constructor (
bee29df8 37 private userService: UserService,
72675ebe 38 private auth: AuthService,
bee29df8 39 private notifier: Notifier,
bfbd9128 40 private videoPlaylist: VideoPlaylistService,
d3217560 41 private localStorageService: LocalStorageService,
9df52d66 42 private sessionStorage: SessionStorageService,
72675ebe 43 private router: Router
bee29df8 44 ) {
706c5a47 45 // defaults to true
bee29df8
RK
46 this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
47 ? this.auth.getUser().autoPlayNextVideoPlaylist
d3217560 48 : this.localStorageService.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
d142c7b9 49
bee29df8 50 this.setAutoPlayNextVideoPlaylistSwitchText()
88a7f93f 51
706c5a47 52 // defaults to false
9df52d66 53 this.loopPlaylist = this.sessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
88a7f93f 54 this.setLoopPlaylistSwitchText()
bee29df8 55 }
72675ebe 56
d142c7b9 57 onPlaylistVideosNearOfBottom (position?: number) {
72675ebe
C
58 // Last page
59 if (this.playlistPagination.totalItems <= (this.playlistPagination.currentPage * this.playlistPagination.itemsPerPage)) return
60
61 this.playlistPagination.currentPage += 1
d142c7b9 62 this.loadPlaylistElements(this.playlist, false, position)
72675ebe
C
63 }
64
bfbd9128
C
65 onElementRemoved (playlistElement: VideoPlaylistElement) {
66 this.playlistElements = this.playlistElements.filter(e => e.id !== playlistElement.id)
72675ebe
C
67
68 this.playlistPagination.totalItems--
69 }
70
71 isPlaylistOwned () {
1acd784c
C
72 return this.playlist.isLocal === true &&
73 this.auth.isLoggedIn() &&
74 this.playlist.ownerAccount.name === this.auth.getUser().username
72675ebe
C
75 }
76
77 isUnlistedPlaylist () {
78 return this.playlist.privacy.id === VideoPlaylistPrivacy.UNLISTED
79 }
80
81 isPrivatePlaylist () {
82 return this.playlist.privacy.id === VideoPlaylistPrivacy.PRIVATE
83 }
84
85 isPublicPlaylist () {
86 return this.playlist.privacy.id === VideoPlaylistPrivacy.PUBLIC
87 }
88
d142c7b9 89 loadPlaylistElements (playlist: VideoPlaylist, redirectToFirst = false, position?: number) {
bfbd9128 90 this.videoPlaylist.getPlaylistVideos(playlist.uuid, this.playlistPagination)
93cae479 91 .subscribe(({ total, data }) => {
bfbd9128 92 this.playlistElements = this.playlistElements.concat(data)
93cae479 93 this.playlistPagination.totalItems = total
72675ebe 94
d142c7b9
C
95 const firstAvailableVideo = this.playlistElements.find(e => !!e.video)
96 if (!firstAvailableVideo) {
72675ebe
C
97 this.noPlaylistVideos = true
98 return
99 }
100
d142c7b9 101 if (position) this.updatePlaylistIndex(position)
72675ebe
C
102
103 if (redirectToFirst) {
104 const extras = {
f1d9b2d6 105 queryParams: {
d142c7b9
C
106 start: firstAvailableVideo.startTimestamp,
107 stop: firstAvailableVideo.stopTimestamp,
108 playlistPosition: firstAvailableVideo.position
f1d9b2d6 109 },
72675ebe
C
110 replaceUrl: true
111 }
112 this.router.navigate([], extras)
113 }
114 })
115 }
116
d142c7b9
C
117 updatePlaylistIndex (position: number) {
118 if (this.playlistElements.length === 0 || !position) return
72675ebe 119
e771e82d
FC
120 // Handle the reverse index
121 if (position < 0) position = this.playlist.videosLength + position + 1
122
bfbd9128 123 for (const playlistElement of this.playlistElements) {
d142c7b9
C
124 // >= if the previous videos were not valid
125 if (playlistElement.video && playlistElement.position >= position) {
bfbd9128 126 this.currentPlaylistPosition = playlistElement.position
d142c7b9
C
127
128 this.videoFound.emit(playlistElement.video.uuid)
129
130 setTimeout(() => {
131 document.querySelector('.element-' + this.currentPlaylistPosition).scrollIntoView(false)
c894a1ea 132 })
d142c7b9 133
72675ebe
C
134 return
135 }
136 }
137
138 // Load more videos to find our video
d142c7b9 139 this.onPlaylistVideosNearOfBottom(position)
72675ebe
C
140 }
141
33d21a9b 142 navigateToPreviousPlaylistVideo () {
fd78d2e2 143 const previous = this.findPlaylistVideo(this.currentPlaylistPosition - 1, 'previous')
33d21a9b
P
144 if (!previous) return
145
146 const start = previous.startTimestamp
147 const stop = previous.stopTimestamp
9df52d66 148 this.router.navigate([], { queryParams: { playlistPosition: previous.position, start, stop } })
33d21a9b
P
149 }
150
fd78d2e2
C
151 findPlaylistVideo (position: number, type: 'previous' | 'next'): VideoPlaylistElement {
152 if (
153 (type === 'next' && position > this.playlistPagination.totalItems) ||
154 (type === 'previous' && position < 1)
155 ) {
156 // End of the playlist: end the recursion if we're not in the loop mode
157 if (!this.loopPlaylist) return
158
159 // Loop mode
160 position = type === 'previous'
161 ? this.playlistPagination.totalItems
162 : 1
706c5a47
RK
163 }
164
fd78d2e2 165 const found = this.playlistElements.find(e => e.position === position)
9df52d66 166 if (found?.video) return found
bfbd9128 167
fd78d2e2
C
168 const newPosition = type === 'previous'
169 ? position - 1
170 : position + 1
706c5a47 171
fd78d2e2 172 return this.findPlaylistVideo(newPosition, type)
706c5a47
RK
173 }
174
175 navigateToNextPlaylistVideo () {
fd78d2e2 176 const next = this.findPlaylistVideo(this.currentPlaylistPosition + 1, 'next')
706c5a47 177 if (!next) return
d142c7b9 178
706c5a47
RK
179 const start = next.startTimestamp
180 const stop = next.stopTimestamp
9df52d66 181 this.router.navigate([], { queryParams: { playlistPosition: next.position, start, stop } })
72675ebe 182 }
bee29df8
RK
183
184 switchAutoPlayNextVideoPlaylist () {
185 this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
186 this.setAutoPlayNextVideoPlaylistSwitchText()
187
188 peertubeLocalStorage.setItem(
189 VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
190 this.autoPlayNextVideoPlaylist.toString()
191 )
192
193 if (this.auth.isLoggedIn()) {
194 const details = {
195 autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
196 }
197
1378c0d3
C
198 this.userService.updateMyProfile(details)
199 .subscribe({
200 next: () => {
201 this.auth.refreshUserInformation()
202 },
203
204 error: err => this.notifier.error(err.message)
205 })
bee29df8
RK
206 }
207 }
208
88a7f93f
RK
209 switchLoopPlaylist () {
210 this.loopPlaylist = !this.loopPlaylist
211 this.setLoopPlaylistSwitchText()
212
213 peertubeSessionStorage.setItem(
214 VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
215 this.loopPlaylist.toString()
216 )
217 }
218
bee29df8 219 private setAutoPlayNextVideoPlaylistSwitchText () {
88a7f93f 220 this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist
66357162
C
221 ? $localize`Stop autoplaying next video`
222 : $localize`Autoplay next video`
88a7f93f
RK
223 }
224
225 private setLoopPlaylistSwitchText () {
226 this.loopPlaylistSwitchText = this.loopPlaylist
66357162
C
227 ? $localize`Stop looping playlist videos`
228 : $localize`Loop playlist videos`
bee29df8 229 }
72675ebe 230}