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