]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/videos/+video-watch/video-watch-playlist.component.ts
Add next video button to the player
[github/Chocobozzz/PeerTube.git] / client / src / app / videos / +video-watch / video-watch-playlist.component.ts
CommitLineData
72675ebe
C
1import { Component, Input } from '@angular/core'
2import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
3import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
72675ebe 4import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models'
72675ebe 5import { Router } from '@angular/router'
88a7f93f 6import { UserService } from '@app/shared'
bee29df8 7import { AuthService, Notifier } from '@app/core'
bfbd9128
C
8import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
9import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model'
88a7f93f 10import { peertubeLocalStorage, peertubeSessionStorage } from '@app/shared/misc/peertube-web-storage'
bee29df8 11import { I18n } from '@ngx-translate/i18n-polyfill'
72675ebe
C
12
13@Component({
14 selector: 'my-video-watch-playlist',
15 templateUrl: './video-watch-playlist.component.html',
16 styleUrls: [ './video-watch-playlist.component.scss' ]
17})
18export class VideoWatchPlaylistComponent {
bee29df8 19 static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
88a7f93f 20 static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist'
bee29df8 21
72675ebe
C
22 @Input() video: VideoDetails
23 @Input() playlist: VideoPlaylist
24
bfbd9128 25 playlistElements: VideoPlaylistElement[] = []
72675ebe
C
26 playlistPagination: ComponentPagination = {
27 currentPage: 1,
28 itemsPerPage: 30,
29 totalItems: null
30 }
31
bee29df8
RK
32 autoPlayNextVideoPlaylist: boolean
33 autoPlayNextVideoPlaylistSwitchText = ''
88a7f93f
RK
34 loopPlaylist: boolean
35 loopPlaylistSwitchText = ''
72675ebe
C
36 noPlaylistVideos = false
37 currentPlaylistPosition = 1
38
39 constructor (
bee29df8 40 private userService: UserService,
72675ebe 41 private auth: AuthService,
bee29df8
RK
42 private notifier: Notifier,
43 private i18n: I18n,
bfbd9128 44 private videoPlaylist: VideoPlaylistService,
72675ebe 45 private router: Router
bee29df8 46 ) {
706c5a47 47 // defaults to true
bee29df8
RK
48 this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
49 ? this.auth.getUser().autoPlayNextVideoPlaylist
50 : peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
51 this.setAutoPlayNextVideoPlaylistSwitchText()
88a7f93f 52
706c5a47 53 // defaults to false
88a7f93f
RK
54 this.loopPlaylist = peertubeSessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
55 this.setLoopPlaylistSwitchText()
bee29df8 56 }
72675ebe
C
57
58 onPlaylistVideosNearOfBottom () {
59 // Last page
60 if (this.playlistPagination.totalItems <= (this.playlistPagination.currentPage * this.playlistPagination.itemsPerPage)) return
61
62 this.playlistPagination.currentPage += 1
63 this.loadPlaylistElements(this.playlist,false)
64 }
65
bfbd9128
C
66 onElementRemoved (playlistElement: VideoPlaylistElement) {
67 this.playlistElements = this.playlistElements.filter(e => e.id !== playlistElement.id)
72675ebe
C
68
69 this.playlistPagination.totalItems--
70 }
71
72 isPlaylistOwned () {
1acd784c
C
73 return this.playlist.isLocal === true &&
74 this.auth.isLoggedIn() &&
75 this.playlist.ownerAccount.name === this.auth.getUser().username
72675ebe
C
76 }
77
78 isUnlistedPlaylist () {
79 return this.playlist.privacy.id === VideoPlaylistPrivacy.UNLISTED
80 }
81
82 isPrivatePlaylist () {
83 return this.playlist.privacy.id === VideoPlaylistPrivacy.PRIVATE
84 }
85
86 isPublicPlaylist () {
87 return this.playlist.privacy.id === VideoPlaylistPrivacy.PUBLIC
88 }
89
90 loadPlaylistElements (playlist: VideoPlaylist, redirectToFirst = false) {
bfbd9128 91 this.videoPlaylist.getPlaylistVideos(playlist.uuid, this.playlistPagination)
93cae479 92 .subscribe(({ total, data }) => {
bfbd9128 93 this.playlistElements = this.playlistElements.concat(data)
93cae479 94 this.playlistPagination.totalItems = total
72675ebe 95
bfbd9128
C
96 const firstAvailableVideos = this.playlistElements.find(e => !!e.video)
97 if (!firstAvailableVideos) {
72675ebe
C
98 this.noPlaylistVideos = true
99 return
100 }
101
102 this.updatePlaylistIndex(this.video)
103
104 if (redirectToFirst) {
105 const extras = {
f1d9b2d6
C
106 queryParams: {
107 start: firstAvailableVideos.startTimestamp,
108 stop: firstAvailableVideos.stopTimestamp,
109 videoId: firstAvailableVideos.video.uuid
110 },
72675ebe
C
111 replaceUrl: true
112 }
113 this.router.navigate([], extras)
114 }
115 })
116 }
117
118 updatePlaylistIndex (video: VideoDetails) {
bfbd9128 119 if (this.playlistElements.length === 0 || !video) return
72675ebe 120
bfbd9128
C
121 for (const playlistElement of this.playlistElements) {
122 if (playlistElement.video && playlistElement.video.id === video.id) {
123 this.currentPlaylistPosition = playlistElement.position
72675ebe
C
124 return
125 }
126 }
127
128 // Load more videos to find our video
129 this.onPlaylistVideosNearOfBottom()
130 }
131
706c5a47
RK
132 findNextPlaylistVideo (position = this.currentPlaylistPosition): VideoPlaylistElement {
133 if (this.currentPlaylistPosition >= this.playlistPagination.totalItems) {
134 // we have reached the end of the playlist: either loop or stop
135 if (this.loopPlaylist) {
136 this.currentPlaylistPosition = position = 0
137 } else {
bfbd9128
C
138 return
139 }
706c5a47
RK
140 }
141
142 const next = this.playlistElements.find(e => e.position === position)
bfbd9128 143
706c5a47
RK
144 if (!next || !next.video) {
145 return this.findNextPlaylistVideo(position + 1)
72675ebe 146 }
706c5a47
RK
147
148 return next
149 }
150
151 navigateToNextPlaylistVideo () {
152 const next = this.findNextPlaylistVideo(this.currentPlaylistPosition + 1)
153 if (!next) return
154 const start = next.startTimestamp
155 const stop = next.stopTimestamp
156 this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } })
72675ebe 157 }
bee29df8
RK
158
159 switchAutoPlayNextVideoPlaylist () {
160 this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
161 this.setAutoPlayNextVideoPlaylistSwitchText()
162
163 peertubeLocalStorage.setItem(
164 VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
165 this.autoPlayNextVideoPlaylist.toString()
166 )
167
168 if (this.auth.isLoggedIn()) {
169 const details = {
170 autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
171 }
172
173 this.userService.updateMyProfile(details).subscribe(
174 () => {
175 this.auth.refreshUserInformation()
176 },
177 err => this.notifier.error(err.message)
178 )
179 }
180 }
181
88a7f93f
RK
182 switchLoopPlaylist () {
183 this.loopPlaylist = !this.loopPlaylist
184 this.setLoopPlaylistSwitchText()
185
186 peertubeSessionStorage.setItem(
187 VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
188 this.loopPlaylist.toString()
189 )
190 }
191
bee29df8 192 private setAutoPlayNextVideoPlaylistSwitchText () {
88a7f93f
RK
193 this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist
194 ? this.i18n('Stop autoplaying next video')
195 : this.i18n('Autoplay next video')
196 }
197
198 private setLoopPlaylistSwitchText () {
199 this.loopPlaylistSwitchText = this.loopPlaylist
200 ? this.i18n('Stop looping playlist videos')
201 : this.i18n('Loop playlist videos')
bee29df8 202 }
72675ebe 203}