Add to playlist dropdown
[oweals/peertube.git] / client / src / app / shared / video-playlist / video-add-to-playlist.component.ts
1 import { Component, Input, OnInit } 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, timeToInt } 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 })
24 export class VideoAddToPlaylistComponent extends FormReactive implements OnInit {
25   @Input() video: Video
26   @Input() currentVideoTimestamp: number
27
28   isNewPlaylistBlockOpened = false
29   videoPlaylists: PlaylistSummary[] = []
30   timestampOptions: {
31     startTimestampEnabled: boolean
32     startTimestamp: number
33     stopTimestampEnabled: boolean
34     stopTimestamp: number
35   }
36   displayOptions = false
37
38   constructor (
39     protected formValidatorService: FormValidatorService,
40     private authService: AuthService,
41     private notifier: Notifier,
42     private i18n: I18n,
43     private videoPlaylistService: VideoPlaylistService,
44     private videoPlaylistValidatorsService: VideoPlaylistValidatorsService
45   ) {
46     super()
47   }
48
49   get user () {
50     return this.authService.getUser()
51   }
52
53   ngOnInit () {
54     this.resetOptions(true)
55
56     this.buildForm({
57       'display-name': this.videoPlaylistValidatorsService.VIDEO_PLAYLIST_DISPLAY_NAME
58     })
59
60     forkJoin([
61       this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'),
62       this.videoPlaylistService.doesVideoExistInPlaylist(this.video.id)
63     ])
64       .subscribe(
65         ([ playlistsResult, existResult ]) => {
66           for (const playlist of playlistsResult.data) {
67             const existingPlaylist = existResult[ this.video.id ].find(p => p.playlistId === playlist.id)
68
69             this.videoPlaylists.push({
70               id: playlist.id,
71               displayName: playlist.displayName,
72               inPlaylist: !!existingPlaylist,
73               startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined,
74               stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined
75             })
76           }
77         }
78       )
79   }
80
81   openChange (opened: boolean) {
82     if (opened === false) {
83       this.isNewPlaylistBlockOpened = false
84       this.displayOptions = false
85     }
86   }
87
88   openCreateBlock (event: Event) {
89     event.preventDefault()
90
91     this.isNewPlaylistBlockOpened = true
92   }
93
94   togglePlaylist (event: Event, playlist: PlaylistSummary) {
95     event.preventDefault()
96
97     if (playlist.inPlaylist === true) {
98       this.removeVideoFromPlaylist(playlist)
99     } else {
100       this.addVideoInPlaylist(playlist)
101     }
102
103     playlist.inPlaylist = !playlist.inPlaylist
104     this.resetOptions()
105   }
106
107   createPlaylist () {
108     const displayName = this.form.value[ 'display-name' ]
109
110     const videoPlaylistCreate: VideoPlaylistCreate = {
111       displayName,
112       privacy: VideoPlaylistPrivacy.PRIVATE
113     }
114
115     this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe(
116       res => {
117         this.videoPlaylists.push({
118           id: res.videoPlaylist.id,
119           displayName,
120           inPlaylist: false
121         })
122
123         this.isNewPlaylistBlockOpened = false
124       },
125
126       err => this.notifier.error(err.message)
127     )
128   }
129
130   resetOptions (resetTimestamp = false) {
131     this.displayOptions = false
132
133     this.timestampOptions = {} as any
134     this.timestampOptions.startTimestampEnabled = false
135     this.timestampOptions.stopTimestampEnabled = false
136
137     if (resetTimestamp) {
138       this.timestampOptions.startTimestamp = 0
139       this.timestampOptions.stopTimestamp = this.video.duration
140     }
141   }
142
143   formatTimestamp (playlist: PlaylistSummary) {
144     const start = playlist.startTimestamp ? secondsToTime(playlist.startTimestamp) : ''
145     const stop = playlist.stopTimestamp ? secondsToTime(playlist.stopTimestamp) : ''
146
147     return `(${start}-${stop})`
148   }
149
150   private removeVideoFromPlaylist (playlist: PlaylistSummary) {
151     this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, this.video.id)
152         .subscribe(
153           () => {
154             this.notifier.success(this.i18n('Video removed from {{name}}', { name: playlist.displayName }))
155
156             playlist.inPlaylist = false
157           },
158
159           err => {
160             this.notifier.error(err.message)
161
162             playlist.inPlaylist = true
163           }
164         )
165   }
166
167   private addVideoInPlaylist (playlist: PlaylistSummary) {
168     const body: VideoPlaylistElementCreate = { videoId: this.video.id }
169
170     if (this.timestampOptions.startTimestampEnabled) body.startTimestamp = this.timestampOptions.startTimestamp
171     if (this.timestampOptions.stopTimestampEnabled) body.stopTimestamp = this.timestampOptions.stopTimestamp
172
173     this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
174       .subscribe(
175         () => {
176           playlist.inPlaylist = true
177
178           playlist.startTimestamp = body.startTimestamp
179           playlist.stopTimestamp = body.stopTimestamp
180
181           const message = body.startTimestamp || body.stopTimestamp
182             ? this.i18n('Video added in {{n}} at timestamps {{t}}', { n: playlist.displayName, t: this.formatTimestamp(playlist) })
183             : this.i18n('Video added in {{n}}', { n: playlist.displayName })
184
185           this.notifier.success(message)
186         },
187
188         err => {
189           this.notifier.error(err.message)
190
191           playlist.inPlaylist = false
192         }
193       )
194   }
195 }