aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/video-playlist
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-03-07 17:06:00 +0100
committerChocobozzz <chocobozzz@cpy.re>2019-03-18 11:17:59 +0100
commitf0a3988066f72a28bb44520af072f18d91d77dde (patch)
treedfa3a92102557b567530c5dd014c90866621140a /client/src/app/shared/video-playlist
parent830b4faff15fb9c81d88e8e69fcdf94aad32bef8 (diff)
downloadPeerTube-f0a3988066f72a28bb44520af072f18d91d77dde.tar.gz
PeerTube-f0a3988066f72a28bb44520af072f18d91d77dde.tar.zst
PeerTube-f0a3988066f72a28bb44520af072f18d91d77dde.zip
Add to playlist dropdown
Diffstat (limited to 'client/src/app/shared/video-playlist')
-rw-r--r--client/src/app/shared/video-playlist/video-add-to-playlist.component.html74
-rw-r--r--client/src/app/shared/video-playlist/video-add-to-playlist.component.scss98
-rw-r--r--client/src/app/shared/video-playlist/video-add-to-playlist.component.ts195
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-miniature.component.html6
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-miniature.component.scss11
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-miniature.component.ts8
-rw-r--r--client/src/app/shared/video-playlist/video-playlist.model.ts5
-rw-r--r--client/src/app/shared/video-playlist/video-playlist.service.ts77
8 files changed, 461 insertions, 13 deletions
diff --git a/client/src/app/shared/video-playlist/video-add-to-playlist.component.html b/client/src/app/shared/video-playlist/video-add-to-playlist.component.html
new file mode 100644
index 000000000..ed3cd8dc5
--- /dev/null
+++ b/client/src/app/shared/video-playlist/video-add-to-playlist.component.html
@@ -0,0 +1,74 @@
1<div class="header">
2 <div class="first-row">
3 <div i18n class="title">Save to</div>
4
5 <div i18n class="options" (click)="displayOptions = !displayOptions">
6 <my-global-icon iconName="cog"></my-global-icon>
7
8 Options
9 </div>
10 </div>
11
12 <div class="options-row" *ngIf="displayOptions">
13 <div>
14 <my-peertube-checkbox
15 inputName="startAt" [(ngModel)]="timestampOptions.startTimestampEnabled"
16 i18n-labelText labelText="Start at"
17 ></my-peertube-checkbox>
18
19 <my-timestamp-input
20 [timestamp]="timestampOptions.startTimestamp"
21 [maxTimestamp]="video.duration"
22 [disabled]="!timestampOptions.startTimestampEnabled"
23 [(ngModel)]="timestampOptions.startTimestamp"
24 ></my-timestamp-input>
25 </div>
26
27 <div>
28 <my-peertube-checkbox
29 inputName="stopAt" [(ngModel)]="timestampOptions.stopTimestampEnabled"
30 i18n-labelText labelText="Stop at"
31 ></my-peertube-checkbox>
32
33 <my-timestamp-input
34 [timestamp]="timestampOptions.stopTimestamp"
35 [maxTimestamp]="video.duration"
36 [disabled]="!timestampOptions.stopTimestampEnabled"
37 [(ngModel)]="timestampOptions.stopTimestamp"
38 ></my-timestamp-input>
39 </div>
40 </div>
41</div>
42
43<div class="playlist dropdown-item" *ngFor="let playlist of videoPlaylists" (click)="togglePlaylist($event, playlist)">
44 <my-peertube-checkbox [inputName]="'in-playlist-' + playlist.id" [(ngModel)]="playlist.inPlaylist"></my-peertube-checkbox>
45
46 <div class="display-name">
47 {{ playlist.displayName }}
48
49 <div *ngIf="playlist.inPlaylist && (playlist.startTimestamp || playlist.stopTimestamp)" class="timestamp-info">
50 {{ formatTimestamp(playlist) }}
51 </div>
52 </div>
53</div>
54
55<div class="new-playlist-button dropdown-item" (click)="openCreateBlock($event)" [hidden]="isNewPlaylistBlockOpened">
56 <my-global-icon iconName="add"></my-global-icon>
57
58 Create a new playlist
59</div>
60
61<form class="new-playlist-block dropdown-item" *ngIf="isNewPlaylistBlockOpened" (ngSubmit)="createPlaylist()" [formGroup]="form">
62 <div class="form-group">
63 <label i18n for="display-name">Display name</label>
64 <input
65 type="text" id="display-name"
66 formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
67 >
68 <div *ngIf="formErrors['display-name']" class="form-error">
69 {{ formErrors['display-name'] }}
70 </div>
71 </div>
72
73 <input type="submit" i18n-value value="Create" [disabled]="!form.valid">
74</form>
diff --git a/client/src/app/shared/video-playlist/video-add-to-playlist.component.scss b/client/src/app/shared/video-playlist/video-add-to-playlist.component.scss
new file mode 100644
index 000000000..68dcda1eb
--- /dev/null
+++ b/client/src/app/shared/video-playlist/video-add-to-playlist.component.scss
@@ -0,0 +1,98 @@
1@import '_variables';
2@import '_mixins';
3
4.header {
5 min-width: 240px;
6 padding: 6px 24px 10px 24px;
7
8 margin-bottom: 10px;
9 border-bottom: 1px solid $separator-border-color;
10
11 .first-row {
12 display: flex;
13 align-items: center;
14
15 .title {
16 font-size: 18px;
17 flex-grow: 1;
18 }
19
20 .options {
21 font-size: 14px;
22 cursor: pointer;
23
24 my-global-icon {
25 @include apply-svg-color(#333);
26
27 width: 16px;
28 height: 16px;
29 }
30 }
31 }
32
33 .options-row {
34 margin-top: 10px;
35
36 > div {
37 display: flex;
38 align-items: center;
39 }
40 }
41}
42
43.dropdown-item {
44 padding: 6px 24px;
45}
46
47.playlist {
48 display: flex;
49 cursor: pointer;
50
51 my-peertube-checkbox {
52 margin-right: 10px;
53 }
54
55 .display-name {
56 display: flex;
57 align-items: flex-end;
58
59 .timestamp-info {
60 font-size: 0.9em;
61 color: $grey-foreground-color;
62 margin-left: 5px;
63 }
64 }
65}
66
67.new-playlist-button,
68.new-playlist-block {
69 padding-top: 10px;
70 margin-top: 10px;
71 border-top: 1px solid $separator-border-color;
72}
73
74.new-playlist-button {
75 cursor: pointer;
76
77 my-global-icon {
78 @include apply-svg-color(#333);
79
80 position: relative;
81 left: -1px;
82 top: -1px;
83 margin-right: 4px;
84 width: 21px;
85 height: 21px;
86 }
87}
88
89input[type=text] {
90 @include peertube-input-text(200px);
91
92 display: block;
93}
94
95input[type=submit] {
96 @include peertube-button;
97 @include orange-button;
98}
diff --git a/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts
new file mode 100644
index 000000000..c6fb6dbed
--- /dev/null
+++ b/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts
@@ -0,0 +1,195 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
3import { AuthService, Notifier } from '@app/core'
4import { forkJoin } from 'rxjs'
5import { Video, VideoPlaylistCreate, VideoPlaylistElementCreate, VideoPlaylistPrivacy } from '@shared/models'
6import { FormReactive, FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/forms'
7import { I18n } from '@ngx-translate/i18n-polyfill'
8import { secondsToTime, timeToInt } from '../../../assets/player/utils'
9
10type 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})
24export 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}
diff --git a/client/src/app/shared/video-playlist/video-playlist-miniature.component.html b/client/src/app/shared/video-playlist/video-playlist-miniature.component.html
index 1a39f5fe5..a136f9233 100644
--- a/client/src/app/shared/video-playlist/video-playlist-miniature.component.html
+++ b/client/src/app/shared/video-playlist/video-playlist-miniature.component.html
@@ -1,6 +1,6 @@
1<div class="miniature"> 1<div class="miniature" [ngClass]="{ 'no-videos': playlist.videosLength === 0, 'to-manage': toManage }">
2 <a 2 <a
3 [routerLink]="[ '/videos/watch' ]" [attr.title]="playlist.displayName" 3 [routerLink]="getPlaylistUrl()" [attr.title]="playlist.displayName"
4 class="miniature-thumbnail" 4 class="miniature-thumbnail"
5 > 5 >
6 <img alt="" [attr.aria-labelledby]="playlist.displayName" [attr.src]="playlist.thumbnailUrl" /> 6 <img alt="" [attr.aria-labelledby]="playlist.displayName" [attr.src]="playlist.thumbnailUrl" />
@@ -15,7 +15,7 @@
15 </a> 15 </a>
16 16
17 <div class="miniature-bottom"> 17 <div class="miniature-bottom">
18 <a tabindex="-1" class="miniature-name" [routerLink]="[ '/videos/watch' ]" [attr.title]="playlist.displayName"> 18 <a tabindex="-1" class="miniature-name" [routerLink]="getPlaylistUrl()" [attr.title]="playlist.displayName">
19 {{ playlist.displayName }} 19 {{ playlist.displayName }}
20 </a> 20 </a>
21 </div> 21 </div>
diff --git a/client/src/app/shared/video-playlist/video-playlist-miniature.component.scss b/client/src/app/shared/video-playlist/video-playlist-miniature.component.scss
index a47206577..f8cd47f73 100644
--- a/client/src/app/shared/video-playlist/video-playlist-miniature.component.scss
+++ b/client/src/app/shared/video-playlist/video-playlist-miniature.component.scss
@@ -5,6 +5,17 @@
5.miniature { 5.miniature {
6 display: inline-block; 6 display: inline-block;
7 7
8 &.no-videos:not(.to-manage){
9 a {
10 cursor: default !important;
11 }
12 }
13
14 &.to-manage .play-overlay,
15 &.no-videos {
16 display: none;
17 }
18
8 .miniature-thumbnail { 19 .miniature-thumbnail {
9 @include miniature-thumbnail; 20 @include miniature-thumbnail;
10 21
diff --git a/client/src/app/shared/video-playlist/video-playlist-miniature.component.ts b/client/src/app/shared/video-playlist/video-playlist-miniature.component.ts
index b3bba7c87..cb5803400 100644
--- a/client/src/app/shared/video-playlist/video-playlist-miniature.component.ts
+++ b/client/src/app/shared/video-playlist/video-playlist-miniature.component.ts
@@ -8,4 +8,12 @@ import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
8}) 8})
9export class VideoPlaylistMiniatureComponent { 9export class VideoPlaylistMiniatureComponent {
10 @Input() playlist: VideoPlaylist 10 @Input() playlist: VideoPlaylist
11 @Input() toManage = false
12
13 getPlaylistUrl () {
14 if (this.toManage) return [ '/my-account/video-playlists', this.playlist.uuid ]
15 if (this.playlist.videosLength === 0) return null
16
17 return [ '/videos/watch/playlist', this.playlist.uuid ]
18 }
11} 19}
diff --git a/client/src/app/shared/video-playlist/video-playlist.model.ts b/client/src/app/shared/video-playlist/video-playlist.model.ts
index 9d0b02789..ec8013e89 100644
--- a/client/src/app/shared/video-playlist/video-playlist.model.ts
+++ b/client/src/app/shared/video-playlist/video-playlist.model.ts
@@ -46,6 +46,7 @@ export class VideoPlaylist implements ServerVideoPlaylist {
46 this.isLocal = hash.isLocal 46 this.isLocal = hash.isLocal
47 47
48 this.displayName = hash.displayName 48 this.displayName = hash.displayName
49
49 this.description = hash.description 50 this.description = hash.description
50 this.privacy = hash.privacy 51 this.privacy = hash.privacy
51 52
@@ -70,5 +71,9 @@ export class VideoPlaylist implements ServerVideoPlaylist {
70 } 71 }
71 72
72 this.privacy.label = peertubeTranslate(this.privacy.label, translations) 73 this.privacy.label = peertubeTranslate(this.privacy.label, translations)
74
75 if (this.type.id === VideoPlaylistType.WATCH_LATER) {
76 this.displayName = peertubeTranslate(this.displayName, translations)
77 }
73 } 78 }
74} 79}
diff --git a/client/src/app/shared/video-playlist/video-playlist.service.ts b/client/src/app/shared/video-playlist/video-playlist.service.ts
index 8b66e122c..f7b37f83a 100644
--- a/client/src/app/shared/video-playlist/video-playlist.service.ts
+++ b/client/src/app/shared/video-playlist/video-playlist.service.ts
@@ -1,9 +1,9 @@
1import { catchError, map, switchMap } from 'rxjs/operators' 1import { bufferTime, catchError, filter, first, map, share, switchMap } from 'rxjs/operators'
2import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
3import { Observable } from 'rxjs' 3import { Observable, ReplaySubject, Subject } from 'rxjs'
4import { RestExtractor } from '../rest/rest-extractor.service' 4import { RestExtractor } from '../rest/rest-extractor.service'
5import { HttpClient } from '@angular/common/http' 5import { HttpClient, HttpParams } from '@angular/common/http'
6import { ResultList } from '../../../../../shared' 6import { ResultList, VideoPlaylistElementCreate, VideoPlaylistElementUpdate } from '../../../../../shared'
7import { environment } from '../../../environments/environment' 7import { environment } from '../../../environments/environment'
8import { VideoPlaylist as VideoPlaylistServerModel } from '@shared/models/videos/playlist/video-playlist.model' 8import { VideoPlaylist as VideoPlaylistServerModel } from '@shared/models/videos/playlist/video-playlist.model'
9import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 9import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
@@ -15,16 +15,31 @@ import { ServerService } from '@app/core'
15import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' 15import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
16import { AccountService } from '@app/shared/account/account.service' 16import { AccountService } from '@app/shared/account/account.service'
17import { Account } from '@app/shared/account/account.model' 17import { Account } from '@app/shared/account/account.model'
18import { RestService } from '@app/shared/rest'
19import { VideoExistInPlaylist } from '@shared/models/videos/playlist/video-exist-in-playlist.model'
18 20
19@Injectable() 21@Injectable()
20export class VideoPlaylistService { 22export class VideoPlaylistService {
21 static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/' 23 static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/'
24 static MY_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/users/me/video-playlists/'
25
26 // Use a replay subject because we "next" a value before subscribing
27 private videoExistsInPlaylistSubject: Subject<number> = new ReplaySubject(1)
28 private readonly videoExistsInPlaylistObservable: Observable<VideoExistInPlaylist>
22 29
23 constructor ( 30 constructor (
24 private authHttp: HttpClient, 31 private authHttp: HttpClient,
25 private serverService: ServerService, 32 private serverService: ServerService,
26 private restExtractor: RestExtractor 33 private restExtractor: RestExtractor,
27 ) { } 34 private restService: RestService
35 ) {
36 this.videoExistsInPlaylistObservable = this.videoExistsInPlaylistSubject.pipe(
37 bufferTime(500),
38 filter(videoIds => videoIds.length !== 0),
39 switchMap(videoIds => this.doVideosExistInPlaylist(videoIds)),
40 share()
41 )
42 }
28 43
29 listChannelPlaylists (videoChannel: VideoChannel): Observable<ResultList<VideoPlaylist>> { 44 listChannelPlaylists (videoChannel: VideoChannel): Observable<ResultList<VideoPlaylist>> {
30 const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/video-playlists' 45 const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/video-playlists'
@@ -36,10 +51,13 @@ export class VideoPlaylistService {
36 ) 51 )
37 } 52 }
38 53
39 listAccountPlaylists (account: Account): Observable<ResultList<VideoPlaylist>> { 54 listAccountPlaylists (account: Account, sort: string): Observable<ResultList<VideoPlaylist>> {
40 const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-playlists' 55 const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-playlists'
41 56
42 return this.authHttp.get<ResultList<VideoPlaylist>>(url) 57 let params = new HttpParams()
58 params = this.restService.addRestGetParams(params, undefined, sort)
59
60 return this.authHttp.get<ResultList<VideoPlaylist>>(url, { params })
43 .pipe( 61 .pipe(
44 switchMap(res => this.extractPlaylists(res)), 62 switchMap(res => this.extractPlaylists(res)),
45 catchError(err => this.restExtractor.handleError(err)) 63 catchError(err => this.restExtractor.handleError(err))
@@ -59,9 +77,8 @@ export class VideoPlaylistService {
59 createVideoPlaylist (body: VideoPlaylistCreate) { 77 createVideoPlaylist (body: VideoPlaylistCreate) {
60 const data = objectToFormData(body) 78 const data = objectToFormData(body)
61 79
62 return this.authHttp.post(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data) 80 return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data)
63 .pipe( 81 .pipe(
64 map(this.restExtractor.extractDataBool),
65 catchError(err => this.restExtractor.handleError(err)) 82 catchError(err => this.restExtractor.handleError(err))
66 ) 83 )
67 } 84 }
@@ -84,6 +101,36 @@ export class VideoPlaylistService {
84 ) 101 )
85 } 102 }
86 103
104 addVideoInPlaylist (playlistId: number, body: VideoPlaylistElementCreate) {
105 return this.authHttp.post(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos', body)
106 .pipe(
107 map(this.restExtractor.extractDataBool),
108 catchError(err => this.restExtractor.handleError(err))
109 )
110 }
111
112 updateVideoOfPlaylist (playlistId: number, videoId: number, body: VideoPlaylistElementUpdate) {
113 return this.authHttp.put(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + videoId, body)
114 .pipe(
115 map(this.restExtractor.extractDataBool),
116 catchError(err => this.restExtractor.handleError(err))
117 )
118 }
119
120 removeVideoFromPlaylist (playlistId: number, videoId: number) {
121 return this.authHttp.delete(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + videoId)
122 .pipe(
123 map(this.restExtractor.extractDataBool),
124 catchError(err => this.restExtractor.handleError(err))
125 )
126 }
127
128 doesVideoExistInPlaylist (videoId: number) {
129 this.videoExistsInPlaylistSubject.next(videoId)
130
131 return this.videoExistsInPlaylistObservable.pipe(first())
132 }
133
87 extractPlaylists (result: ResultList<VideoPlaylistServerModel>) { 134 extractPlaylists (result: ResultList<VideoPlaylistServerModel>) {
88 return this.serverService.localeObservable 135 return this.serverService.localeObservable
89 .pipe( 136 .pipe(
@@ -105,4 +152,14 @@ export class VideoPlaylistService {
105 return this.serverService.localeObservable 152 return this.serverService.localeObservable
106 .pipe(map(translations => new VideoPlaylist(playlist, translations))) 153 .pipe(map(translations => new VideoPlaylist(playlist, translations)))
107 } 154 }
155
156 private doVideosExistInPlaylist (videoIds: number[]): Observable<VideoExistInPlaylist> {
157 const url = VideoPlaylistService.MY_VIDEO_PLAYLIST_URL + 'videos-exist'
158 let params = new HttpParams()
159
160 params = this.restService.addObjectParams(params, { videoIds })
161
162 return this.authHttp.get<VideoExistInPlaylist>(url, { params })
163 .pipe(catchError(err => this.restExtractor.handleError(err)))
164 }
108} 165}