]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/shared/video-playlist/video-add-to-playlist.component.ts
Update translations
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / video-playlist / video-add-to-playlist.component.ts
1 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'
2 import { CachedPlaylist, VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
3 import { AuthService, Notifier } from '@app/core'
4 import { Subject, Subscription } from 'rxjs'
5 import { debounceTime, filter } from 'rxjs/operators'
6 import { Video, VideoPlaylistCreate, VideoPlaylistElementCreate, VideoPlaylistPrivacy } from '@shared/models'
7 import { FormReactive, FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/forms'
8 import { I18n } from '@ngx-translate/i18n-polyfill'
9 import { secondsToTime } from '../../../assets/player/utils'
10 import * as debug from 'debug'
11 import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
12 import { VideoExistInPlaylist } from '@shared/models/videos/playlist/video-exist-in-playlist.model'
13
14 const logger = debug('peertube:playlists:VideoAddToPlaylistComponent')
15
16 type PlaylistSummary = {
17 id: number
18 inPlaylist: boolean
19 displayName: string
20
21 playlistElementId?: number
22 startTimestamp?: number
23 stopTimestamp?: number
24 }
25
26 @Component({
27 selector: 'my-video-add-to-playlist',
28 styleUrls: [ './video-add-to-playlist.component.scss' ],
29 templateUrl: './video-add-to-playlist.component.html',
30 changeDetection: ChangeDetectionStrategy.OnPush
31 })
32 export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, OnChanges, OnDestroy, DisableForReuseHook {
33 @Input() video: Video
34 @Input() currentVideoTimestamp: number
35 @Input() lazyLoad = false
36
37 isNewPlaylistBlockOpened = false
38 videoPlaylistSearch: string
39 videoPlaylistSearchChanged = new Subject<string>()
40 videoPlaylists: PlaylistSummary[] = []
41 timestampOptions: {
42 startTimestampEnabled: boolean
43 startTimestamp: number
44 stopTimestampEnabled: boolean
45 stopTimestamp: number
46 }
47 displayOptions = false
48
49 private disabled = false
50
51 private listenToPlaylistChangeSub: Subscription
52 private playlistsData: CachedPlaylist[] = []
53
54 constructor (
55 protected formValidatorService: FormValidatorService,
56 private authService: AuthService,
57 private notifier: Notifier,
58 private i18n: I18n,
59 private videoPlaylistService: VideoPlaylistService,
60 private videoPlaylistValidatorsService: VideoPlaylistValidatorsService,
61 private cd: ChangeDetectorRef
62 ) {
63 super()
64 }
65
66 get user () {
67 return this.authService.getUser()
68 }
69
70 ngOnInit () {
71 this.buildForm({
72 displayName: this.videoPlaylistValidatorsService.VIDEO_PLAYLIST_DISPLAY_NAME
73 })
74
75 this.videoPlaylistService.listenToMyAccountPlaylistsChange()
76 .subscribe(result => {
77 this.playlistsData = result.data
78
79 this.videoPlaylistService.runPlaylistCheck(this.video.id)
80 })
81
82 this.videoPlaylistSearchChanged
83 .pipe(debounceTime(500))
84 .subscribe(() => this.load())
85
86 if (this.lazyLoad === false) this.load()
87 }
88
89 ngOnChanges (simpleChanges: SimpleChanges) {
90 if (simpleChanges['video']) {
91 this.reload()
92 }
93 }
94
95 ngOnDestroy () {
96 this.unsubscribePlaylistChanges()
97 }
98
99 disableForReuse () {
100 this.disabled = true
101 }
102
103 enabledForReuse () {
104 this.disabled = false
105 }
106
107 reload () {
108 logger('Reloading component')
109
110 this.videoPlaylists = []
111 this.videoPlaylistSearch = undefined
112
113 this.resetOptions(true)
114 this.load()
115
116 this.cd.markForCheck()
117 }
118
119 load () {
120 logger('Loading component')
121
122 this.listenToPlaylistChanges()
123
124 this.videoPlaylistService.listMyPlaylistWithCache(this.user, this.videoPlaylistSearch)
125 .subscribe(playlistsResult => {
126 this.playlistsData = playlistsResult.data
127
128 this.videoPlaylistService.runPlaylistCheck(this.video.id)
129 })
130 }
131
132 openChange (opened: boolean) {
133 if (opened === false) {
134 this.isNewPlaylistBlockOpened = false
135 this.displayOptions = false
136 }
137 }
138
139 openCreateBlock (event: Event) {
140 event.preventDefault()
141
142 this.isNewPlaylistBlockOpened = true
143 }
144
145 togglePlaylist (event: Event, playlist: PlaylistSummary) {
146 event.preventDefault()
147
148 if (playlist.inPlaylist === true) {
149 this.removeVideoFromPlaylist(playlist)
150 } else {
151 this.addVideoInPlaylist(playlist)
152 }
153
154 playlist.inPlaylist = !playlist.inPlaylist
155 this.resetOptions()
156
157 this.cd.markForCheck()
158 }
159
160 createPlaylist () {
161 const displayName = this.form.value[ 'displayName' ]
162
163 const videoPlaylistCreate: VideoPlaylistCreate = {
164 displayName,
165 privacy: VideoPlaylistPrivacy.PRIVATE
166 }
167
168 this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe(
169 () => {
170 this.isNewPlaylistBlockOpened = false
171
172 this.cd.markForCheck()
173 },
174
175 err => this.notifier.error(err.message)
176 )
177 }
178
179 resetOptions (resetTimestamp = false) {
180 this.displayOptions = false
181
182 this.timestampOptions = {} as any
183 this.timestampOptions.startTimestampEnabled = false
184 this.timestampOptions.stopTimestampEnabled = false
185
186 if (resetTimestamp) {
187 this.timestampOptions.startTimestamp = 0
188 this.timestampOptions.stopTimestamp = this.video.duration
189 }
190 }
191
192 formatTimestamp (playlist: PlaylistSummary) {
193 const start = playlist.startTimestamp ? secondsToTime(playlist.startTimestamp) : ''
194 const stop = playlist.stopTimestamp ? secondsToTime(playlist.stopTimestamp) : ''
195
196 return `(${start}-${stop})`
197 }
198
199 onVideoPlaylistSearchChanged () {
200 this.videoPlaylistSearchChanged.next()
201 }
202
203 private removeVideoFromPlaylist (playlist: PlaylistSummary) {
204 if (!playlist.playlistElementId) return
205
206 this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, playlist.playlistElementId, this.video.id)
207 .subscribe(
208 () => {
209 this.notifier.success(this.i18n('Video removed from {{name}}', { name: playlist.displayName }))
210 },
211
212 err => {
213 this.notifier.error(err.message)
214 },
215
216 () => this.cd.markForCheck()
217 )
218 }
219
220 private listenToPlaylistChanges () {
221 this.unsubscribePlaylistChanges()
222
223 this.listenToPlaylistChangeSub = this.videoPlaylistService.listenToVideoPlaylistChange(this.video.id)
224 .pipe(filter(() => this.disabled === false))
225 .subscribe(existResult => this.rebuildPlaylists(existResult))
226 }
227
228 private unsubscribePlaylistChanges () {
229 if (this.listenToPlaylistChangeSub) {
230 this.listenToPlaylistChangeSub.unsubscribe()
231 this.listenToPlaylistChangeSub = undefined
232 }
233 }
234
235 private rebuildPlaylists (existResult: VideoExistInPlaylist[]) {
236 logger('Got existing results for %d.', this.video.id, existResult)
237
238 this.videoPlaylists = []
239 for (const playlist of this.playlistsData) {
240 const existingPlaylist = existResult.find(p => p.playlistId === playlist.id)
241
242 this.videoPlaylists.push({
243 id: playlist.id,
244 displayName: playlist.displayName,
245 inPlaylist: !!existingPlaylist,
246 playlistElementId: existingPlaylist ? existingPlaylist.playlistElementId : undefined,
247 startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined,
248 stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined
249 })
250 }
251
252 logger('Rebuilt playlist state for video %d.', this.video.id, this.videoPlaylists)
253
254 this.cd.markForCheck()
255 }
256
257 private addVideoInPlaylist (playlist: PlaylistSummary) {
258 const body: VideoPlaylistElementCreate = { videoId: this.video.id }
259
260 if (this.timestampOptions.startTimestampEnabled) body.startTimestamp = this.timestampOptions.startTimestamp
261 if (this.timestampOptions.stopTimestampEnabled) body.stopTimestamp = this.timestampOptions.stopTimestamp
262
263 this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
264 .subscribe(
265 () => {
266 const message = body.startTimestamp || body.stopTimestamp
267 ? this.i18n('Video added in {{n}} at timestamps {{t}}', { n: playlist.displayName, t: this.formatTimestamp(playlist) })
268 : this.i18n('Video added in {{n}}', { n: playlist.displayName })
269
270 this.notifier.success(message)
271 },
272
273 err => {
274 this.notifier.error(err.message)
275 },
276
277 () => this.cd.markForCheck()
278 )
279 }
280 }