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