WIP plugins: update plugin
[oweals/peertube.git] / client / src / app / shared / video-playlist / video-add-to-playlist.component.ts
1 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
2 import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
3 import { AuthService, Notifier } from '@app/core'
4 import { forkJoin } from 'rxjs'
5 import { Video, VideoPlaylistCreate, VideoPlaylistElementCreate, VideoPlaylistPrivacy } from '@shared/models'
6 import { FormReactive, FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/forms'
7 import { I18n } from '@ngx-translate/i18n-polyfill'
8 import { secondsToTime } from '../../../assets/player/utils'
9
10 type PlaylistSummary = {
11   id: number
12   inPlaylist: boolean
13   displayName: string
14
15   startTimestamp?: number
16   stopTimestamp?: number
17 }
18
19 @Component({
20   selector: 'my-video-add-to-playlist',
21   styleUrls: [ './video-add-to-playlist.component.scss' ],
22   templateUrl: './video-add-to-playlist.component.html',
23   changeDetection: ChangeDetectionStrategy.OnPush
24 })
25 export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, OnChanges {
26   @Input() video: Video
27   @Input() currentVideoTimestamp: number
28   @Input() lazyLoad = false
29
30   isNewPlaylistBlockOpened = false
31   videoPlaylists: PlaylistSummary[] = []
32   timestampOptions: {
33     startTimestampEnabled: boolean
34     startTimestamp: number
35     stopTimestampEnabled: boolean
36     stopTimestamp: number
37   }
38   displayOptions = false
39
40   constructor (
41     protected formValidatorService: FormValidatorService,
42     private authService: AuthService,
43     private notifier: Notifier,
44     private i18n: I18n,
45     private videoPlaylistService: VideoPlaylistService,
46     private videoPlaylistValidatorsService: VideoPlaylistValidatorsService,
47     private cd: ChangeDetectorRef
48   ) {
49     super()
50   }
51
52   get user () {
53     return this.authService.getUser()
54   }
55
56   ngOnInit () {
57     this.buildForm({
58       displayName: this.videoPlaylistValidatorsService.VIDEO_PLAYLIST_DISPLAY_NAME
59     })
60   }
61
62   ngOnChanges (simpleChanges: SimpleChanges) {
63     if (simpleChanges['video']) {
64       this.reload()
65     }
66   }
67
68   init () {
69     this.resetOptions(true)
70
71     if (this.lazyLoad !== true) this.load()
72   }
73
74   reload () {
75     this.videoPlaylists = []
76
77     this.init()
78
79     this.cd.markForCheck()
80   }
81
82   load () {
83     forkJoin([
84       this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'),
85       this.videoPlaylistService.doesVideoExistInPlaylist(this.video.id)
86     ])
87       .subscribe(
88         ([ playlistsResult, existResult ]) => {
89           for (const playlist of playlistsResult.data) {
90             const existingPlaylist = existResult[ this.video.id ].find(p => p.playlistId === playlist.id)
91
92             this.videoPlaylists.push({
93               id: playlist.id,
94               displayName: playlist.displayName,
95               inPlaylist: !!existingPlaylist,
96               startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined,
97               stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined
98             })
99           }
100
101           this.cd.markForCheck()
102         }
103       )
104   }
105
106   openChange (opened: boolean) {
107     if (opened === false) {
108       this.isNewPlaylistBlockOpened = false
109       this.displayOptions = false
110     }
111   }
112
113   openCreateBlock (event: Event) {
114     event.preventDefault()
115
116     this.isNewPlaylistBlockOpened = true
117   }
118
119   togglePlaylist (event: Event, playlist: PlaylistSummary) {
120     event.preventDefault()
121
122     if (playlist.inPlaylist === true) {
123       this.removeVideoFromPlaylist(playlist)
124     } else {
125       this.addVideoInPlaylist(playlist)
126     }
127
128     playlist.inPlaylist = !playlist.inPlaylist
129     this.resetOptions()
130
131     this.cd.markForCheck()
132   }
133
134   createPlaylist () {
135     const displayName = this.form.value[ 'displayName' ]
136
137     const videoPlaylistCreate: VideoPlaylistCreate = {
138       displayName,
139       privacy: VideoPlaylistPrivacy.PRIVATE
140     }
141
142     this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe(
143       res => {
144         this.videoPlaylists.push({
145           id: res.videoPlaylist.id,
146           displayName,
147           inPlaylist: false
148         })
149
150         this.isNewPlaylistBlockOpened = false
151
152         this.cd.markForCheck()
153       },
154
155       err => this.notifier.error(err.message)
156     )
157   }
158
159   resetOptions (resetTimestamp = false) {
160     this.displayOptions = false
161
162     this.timestampOptions = {} as any
163     this.timestampOptions.startTimestampEnabled = false
164     this.timestampOptions.stopTimestampEnabled = false
165
166     if (resetTimestamp) {
167       this.timestampOptions.startTimestamp = 0
168       this.timestampOptions.stopTimestamp = this.video.duration
169     }
170   }
171
172   formatTimestamp (playlist: PlaylistSummary) {
173     const start = playlist.startTimestamp ? secondsToTime(playlist.startTimestamp) : ''
174     const stop = playlist.stopTimestamp ? secondsToTime(playlist.stopTimestamp) : ''
175
176     return `(${start}-${stop})`
177   }
178
179   private removeVideoFromPlaylist (playlist: PlaylistSummary) {
180     this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, this.video.id)
181         .subscribe(
182           () => {
183             this.notifier.success(this.i18n('Video removed from {{name}}', { name: playlist.displayName }))
184
185             playlist.inPlaylist = false
186           },
187
188           err => {
189             this.notifier.error(err.message)
190
191             playlist.inPlaylist = true
192           },
193
194           () => this.cd.markForCheck()
195         )
196   }
197
198   private addVideoInPlaylist (playlist: PlaylistSummary) {
199     const body: VideoPlaylistElementCreate = { videoId: this.video.id }
200
201     if (this.timestampOptions.startTimestampEnabled) body.startTimestamp = this.timestampOptions.startTimestamp
202     if (this.timestampOptions.stopTimestampEnabled) body.stopTimestamp = this.timestampOptions.stopTimestamp
203
204     this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
205       .subscribe(
206         () => {
207           playlist.inPlaylist = true
208
209           playlist.startTimestamp = body.startTimestamp
210           playlist.stopTimestamp = body.stopTimestamp
211
212           const message = body.startTimestamp || body.stopTimestamp
213             ? this.i18n('Video added in {{n}} at timestamps {{t}}', { n: playlist.displayName, t: this.formatTimestamp(playlist) })
214             : this.i18n('Video added in {{n}}', { n: playlist.displayName })
215
216           this.notifier.success(message)
217         },
218
219         err => {
220           this.notifier.error(err.message)
221
222           playlist.inPlaylist = false
223         },
224
225         () => this.cd.markForCheck()
226       )
227   }
228 }