aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/shared')
-rw-r--r--client/src/app/shared/video-playlist/video-add-to-playlist.component.ts8
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-element-miniature.component.html100
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss32
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-element-miniature.component.ts61
-rw-r--r--client/src/app/shared/video-playlist/video-playlist-element.model.ts24
-rw-r--r--client/src/app/shared/video-playlist/video-playlist.service.ts46
-rw-r--r--client/src/app/shared/video/video.model.ts6
-rw-r--r--client/src/app/shared/video/video.service.ts18
8 files changed, 191 insertions, 104 deletions
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
index c6cff03a4..08ceb21bc 100644
--- 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
@@ -37,6 +37,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
37 } 37 }
38 displayOptions = false 38 displayOptions = false
39 39
40 private playlistElementId: number
41
40 constructor ( 42 constructor (
41 protected formValidatorService: FormValidatorService, 43 protected formValidatorService: FormValidatorService,
42 private authService: AuthService, 44 private authService: AuthService,
@@ -96,6 +98,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
96 startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined, 98 startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined,
97 stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined 99 stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined
98 }) 100 })
101
102 this.playlistElementId = existingPlaylist ? existingPlaylist.playlistElementId : undefined
99 } 103 }
100 104
101 this.cd.markForCheck() 105 this.cd.markForCheck()
@@ -177,7 +181,9 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
177 } 181 }
178 182
179 private removeVideoFromPlaylist (playlist: PlaylistSummary) { 183 private removeVideoFromPlaylist (playlist: PlaylistSummary) {
180 this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, this.video.id) 184 if (!this.playlistElementId) return
185
186 this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, this.playlistElementId)
181 .subscribe( 187 .subscribe(
182 () => { 188 () => {
183 this.notifier.success(this.i18n('Video removed from {{name}}', { name: playlist.displayName })) 189 this.notifier.success(this.i18n('Video removed from {{name}}', { name: playlist.displayName }))
diff --git a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.html b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.html
index ab5a78928..25d4783fb 100644
--- a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.html
+++ b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.html
@@ -6,66 +6,82 @@
6 </div> 6 </div>
7 7
8 <my-video-thumbnail 8 <my-video-thumbnail
9 [video]="video" [nsfw]="isVideoBlur(video)" 9 *ngIf="playlistElement.video"
10 [video]="playlistElement.video" [nsfw]="isVideoBlur(playlistElement.video)"
10 [routerLink]="buildRouterLink()" [queryParams]="buildRouterQuery()" 11 [routerLink]="buildRouterLink()" [queryParams]="buildRouterQuery()"
11 ></my-video-thumbnail> 12 ></my-video-thumbnail>
12 13
14 <div class="fake-thumbnail" *ngIf="!playlistElement.video"></div>
15
13 <div class="video-info"> 16 <div class="video-info">
14 <a tabindex="-1" class="video-info-name" 17 <ng-container *ngIf="playlistElement.video">
15 [routerLink]="buildRouterLink()" [queryParams]="buildRouterQuery()" 18 <a tabindex="-1" class="video-info-name"
16 [attr.title]="video.name" 19 [routerLink]="buildRouterLink()" [queryParams]="buildRouterQuery()"
17 >{{ video.name }}</a> 20 [attr.title]="playlistElement.video.name"
21 >{{ playlistElement.video.name }}</a>
22
23 <a *ngIf="accountLink" tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', playlistElement.video.byAccount ]">
24 {{ playlistElement.video.byAccount }}
25 </a>
26 <span *ngIf="!accountLink" tabindex="-1" class="video-info-account">{{ playlistElement.video.byAccount }}</span>
18 27
19 <a *ngIf="accountLink" tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', video.byAccount ]">{{ video.byAccount }}</a> 28 <span tabindex="-1" class="video-info-timestamp">{{ formatTimestamp(playlistElement) }}</span>
20 <span *ngIf="!accountLink" tabindex="-1" class="video-info-account">{{ video.byAccount }}</span> 29 </ng-container>
21 30
22 <span tabindex="-1" class="video-info-timestamp">{{ formatTimestamp(video) }}</span> 31 <span *ngIf="!playlistElement.video" class="video-info-name">
32 <ng-container i18n *ngIf="isUnavailable(playlistElement)">Unavailable</ng-container>
33 <ng-container i18n *ngIf="isPrivate(playlistElement)">Private</ng-container>
34 <ng-container i18n *ngIf="isDeleted(playlistElement)">Deleted</ng-container>
35 </span>
23 </div> 36 </div>
24 </a> 37 </a>
25 38
26 <div *ngIf="owned" class="more" ngbDropdown #moreDropdown="ngbDropdown" placement="bottom-right" (openChange)="onDropdownOpenChange()" 39 <div *ngIf="owned" class="more" ngbDropdown #moreDropdown="ngbDropdown" placement="bottom-right"
27 autoClose="outside"> 40 (openChange)="onDropdownOpenChange()" autoClose="outside"
41 >
28 <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button" class="icon-more" (click)="$event.preventDefault()"></my-global-icon> 42 <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button" class="icon-more" (click)="$event.preventDefault()"></my-global-icon>
29 43
30 <div ngbDropdownMenu> 44 <div ngbDropdownMenu>
31 <div class="dropdown-item" (click)="toggleDisplayTimestampsOptions($event, video)"> 45 <ng-container *ngIf="playlistElement.video">
32 <my-global-icon iconName="edit"></my-global-icon> 46 <div class="dropdown-item" (click)="toggleDisplayTimestampsOptions($event, playlistElement)">
33 <ng-container i18n>Edit starts/stops at</ng-container> 47 <my-global-icon iconName="edit"></my-global-icon>
34 </div> 48 <ng-container i18n>Edit starts/stops at</ng-container>
49 </div>
35 50
36 <div class="timestamp-options" *ngIf="displayTimestampOptions"> 51 <div class="timestamp-options" *ngIf="displayTimestampOptions">
37 <div> 52 <div>
38 <my-peertube-checkbox 53 <my-peertube-checkbox
39 inputName="startAt" [(ngModel)]="timestampOptions.startTimestampEnabled" 54 inputName="startAt" [(ngModel)]="timestampOptions.startTimestampEnabled"
40 i18n-labelText labelText="Start at" 55 i18n-labelText labelText="Start at"
41 ></my-peertube-checkbox> 56 ></my-peertube-checkbox>
42 57
43 <my-timestamp-input 58 <my-timestamp-input
44 [timestamp]="timestampOptions.startTimestamp" 59 [timestamp]="timestampOptions.startTimestamp"
45 [maxTimestamp]="video.duration" 60 [maxTimestamp]="playlistElement.video.duration"
46 [disabled]="!timestampOptions.startTimestampEnabled" 61 [disabled]="!timestampOptions.startTimestampEnabled"
47 [(ngModel)]="timestampOptions.startTimestamp" 62 [(ngModel)]="timestampOptions.startTimestamp"
48 ></my-timestamp-input> 63 ></my-timestamp-input>
49 </div> 64 </div>
50 65
51 <div> 66 <div>
52 <my-peertube-checkbox 67 <my-peertube-checkbox
53 inputName="stopAt" [(ngModel)]="timestampOptions.stopTimestampEnabled" 68 inputName="stopAt" [(ngModel)]="timestampOptions.stopTimestampEnabled"
54 i18n-labelText labelText="Stop at" 69 i18n-labelText labelText="Stop at"
55 ></my-peertube-checkbox> 70 ></my-peertube-checkbox>
56 71
57 <my-timestamp-input 72 <my-timestamp-input
58 [timestamp]="timestampOptions.stopTimestamp" 73 [timestamp]="timestampOptions.stopTimestamp"
59 [maxTimestamp]="video.duration" 74 [maxTimestamp]="playlistElement.video.duration"
60 [disabled]="!timestampOptions.stopTimestampEnabled" 75 [disabled]="!timestampOptions.stopTimestampEnabled"
61 [(ngModel)]="timestampOptions.stopTimestamp" 76 [(ngModel)]="timestampOptions.stopTimestamp"
62 ></my-timestamp-input> 77 ></my-timestamp-input>
63 </div> 78 </div>
64 79
65 <input type="submit" i18n-value value="Save" (click)="updateTimestamps(video)"> 80 <input type="submit" i18n-value value="Save" (click)="updateTimestamps(playlistElement)">
66 </div> 81 </div>
82 </ng-container>
67 83
68 <span class="dropdown-item" (click)="removeFromPlaylist(video)"> 84 <span class="dropdown-item" (click)="removeFromPlaylist(playlistElement)">
69 <my-global-icon iconName="delete"></my-global-icon> <ng-container i18n>Delete from {{ playlist?.displayName }}</ng-container> 85 <my-global-icon iconName="delete"></my-global-icon> <ng-container i18n>Delete from {{ playlist?.displayName }}</ng-container>
70 </span> 86 </span>
71 </div> 87 </div>
diff --git a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss
index cb7072d7f..9f4061b02 100644
--- a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss
+++ b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.scss
@@ -2,9 +2,21 @@
2@import '_mixins'; 2@import '_mixins';
3@import '_miniature'; 3@import '_miniature';
4 4
5$thumbnail-width: 130px;
6$thumbnail-height: 72px;
7
5my-video-thumbnail { 8my-video-thumbnail {
6 @include thumbnail-size-component(130px, 72px); 9 @include thumbnail-size-component($thumbnail-width, $thumbnail-height);
10}
7 11
12.fake-thumbnail {
13 width: $thumbnail-width;
14 height: $thumbnail-height;
15 background-color: #ececec;
16}
17
18my-video-thumbnail,
19.fake-thumbnail {
8 display: flex; // Avoids an issue with line-height that adds space below the element 20 display: flex; // Avoids an issue with line-height that adds space below the element
9 margin-right: 10px; 21 margin-right: 10px;
10} 22}
@@ -31,6 +43,7 @@ my-video-thumbnail {
31 a { 43 a {
32 @include disable-default-a-behaviour; 44 @include disable-default-a-behaviour;
33 45
46 color: var(--mainForegroundColor);
34 display: flex; 47 display: flex;
35 min-width: 0; 48 min-width: 0;
36 align-items: center; 49 align-items: center;
@@ -58,7 +71,6 @@ my-video-thumbnail {
58 min-width: 0; 71 min-width: 0;
59 72
60 a { 73 a {
61 color: var(--mainForegroundColor);
62 width: auto; 74 width: auto;
63 75
64 &:hover { 76 &:hover {
@@ -66,20 +78,20 @@ my-video-thumbnail {
66 } 78 }
67 } 79 }
68 80
69 .video-info-name {
70 font-size: 18px;
71 font-weight: $font-semibold;
72 display: inline-block;
73
74 @include ellipsis;
75 }
76
77 .video-info-account, .video-info-timestamp { 81 .video-info-account, .video-info-timestamp {
78 color: $grey-foreground-color; 82 color: $grey-foreground-color;
79 } 83 }
80 } 84 }
81 } 85 }
82 86
87 .video-info-name {
88 font-size: 18px;
89 font-weight: $font-semibold;
90 display: inline-block;
91
92 @include ellipsis;
93 }
94
83 .more { 95 .more {
84 justify-self: flex-end; 96 justify-self: flex-end;
85 margin-left: auto; 97 margin-left: auto;
diff --git a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.ts b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.ts
index 62cf6536d..a8e5a4885 100644
--- a/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.ts
+++ b/client/src/app/shared/video-playlist/video-playlist-element-miniature.component.ts
@@ -1,6 +1,6 @@
1import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core' 1import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'
2import { Video } from '@app/shared/video/video.model' 2import { Video } from '@app/shared/video/video.model'
3import { VideoPlaylistElementUpdate } from '@shared/models' 3import { VideoPlaylistElementType, VideoPlaylistElementUpdate } from '@shared/models'
4import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core' 4import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core'
5import { ActivatedRoute } from '@angular/router' 5import { ActivatedRoute } from '@angular/router'
6import { I18n } from '@ngx-translate/i18n-polyfill' 6import { I18n } from '@ngx-translate/i18n-polyfill'
@@ -9,6 +9,7 @@ import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.
9import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' 9import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
10import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' 10import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
11import { secondsToTime } from '../../../assets/player/utils' 11import { secondsToTime } from '../../../assets/player/utils'
12import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model'
12 13
13@Component({ 14@Component({
14 selector: 'my-video-playlist-element-miniature', 15 selector: 'my-video-playlist-element-miniature',
@@ -20,14 +21,14 @@ export class VideoPlaylistElementMiniatureComponent {
20 @ViewChild('moreDropdown', { static: false }) moreDropdown: NgbDropdown 21 @ViewChild('moreDropdown', { static: false }) moreDropdown: NgbDropdown
21 22
22 @Input() playlist: VideoPlaylist 23 @Input() playlist: VideoPlaylist
23 @Input() video: Video 24 @Input() playlistElement: VideoPlaylistElement
24 @Input() owned = false 25 @Input() owned = false
25 @Input() playing = false 26 @Input() playing = false
26 @Input() rowLink = false 27 @Input() rowLink = false
27 @Input() accountLink = true 28 @Input() accountLink = true
28 @Input() position: number 29 @Input() position: number // Keep this property because we're in the OnPush change detection strategy
29 30
30 @Output() elementRemoved = new EventEmitter<Video>() 31 @Output() elementRemoved = new EventEmitter<VideoPlaylistElement>()
31 32
32 displayTimestampOptions = false 33 displayTimestampOptions = false
33 34
@@ -50,6 +51,18 @@ export class VideoPlaylistElementMiniatureComponent {
50 private cdr: ChangeDetectorRef 51 private cdr: ChangeDetectorRef
51 ) {} 52 ) {}
52 53
54 isUnavailable (e: VideoPlaylistElement) {
55 return e.type === VideoPlaylistElementType.UNAVAILABLE
56 }
57
58 isPrivate (e: VideoPlaylistElement) {
59 return e.type === VideoPlaylistElementType.PRIVATE
60 }
61
62 isDeleted (e: VideoPlaylistElement) {
63 return e.type === VideoPlaylistElementType.DELETED
64 }
65
53 buildRouterLink () { 66 buildRouterLink () {
54 if (!this.playlist) return null 67 if (!this.playlist) return null
55 68
@@ -57,12 +70,12 @@ export class VideoPlaylistElementMiniatureComponent {
57 } 70 }
58 71
59 buildRouterQuery () { 72 buildRouterQuery () {
60 if (!this.video) return {} 73 if (!this.playlistElement || !this.playlistElement.video) return {}
61 74
62 return { 75 return {
63 videoId: this.video.uuid, 76 videoId: this.playlistElement.video.uuid,
64 start: this.video.playlistElement.startTimestamp, 77 start: this.playlistElement.startTimestamp,
65 stop: this.video.playlistElement.stopTimestamp 78 stop: this.playlistElement.stopTimestamp
66 } 79 }
67 } 80 }
68 81
@@ -70,13 +83,13 @@ export class VideoPlaylistElementMiniatureComponent {
70 return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig()) 83 return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig())
71 } 84 }
72 85
73 removeFromPlaylist (video: Video) { 86 removeFromPlaylist (playlistElement: VideoPlaylistElement) {
74 this.videoPlaylistService.removeVideoFromPlaylist(this.playlist.id, video.id) 87 this.videoPlaylistService.removeVideoFromPlaylist(this.playlist.id, playlistElement.id)
75 .subscribe( 88 .subscribe(
76 () => { 89 () => {
77 this.notifier.success(this.i18n('Video removed from {{name}}', { name: this.playlist.displayName })) 90 this.notifier.success(this.i18n('Video removed from {{name}}', { name: this.playlist.displayName }))
78 91
79 this.elementRemoved.emit(this.video) 92 this.elementRemoved.emit(playlistElement)
80 }, 93 },
81 94
82 err => this.notifier.error(err.message) 95 err => this.notifier.error(err.message)
@@ -85,19 +98,19 @@ export class VideoPlaylistElementMiniatureComponent {
85 this.moreDropdown.close() 98 this.moreDropdown.close()
86 } 99 }
87 100
88 updateTimestamps (video: Video) { 101 updateTimestamps (playlistElement: VideoPlaylistElement) {
89 const body: VideoPlaylistElementUpdate = {} 102 const body: VideoPlaylistElementUpdate = {}
90 103
91 body.startTimestamp = this.timestampOptions.startTimestampEnabled ? this.timestampOptions.startTimestamp : null 104 body.startTimestamp = this.timestampOptions.startTimestampEnabled ? this.timestampOptions.startTimestamp : null
92 body.stopTimestamp = this.timestampOptions.stopTimestampEnabled ? this.timestampOptions.stopTimestamp : null 105 body.stopTimestamp = this.timestampOptions.stopTimestampEnabled ? this.timestampOptions.stopTimestamp : null
93 106
94 this.videoPlaylistService.updateVideoOfPlaylist(this.playlist.id, video.id, body) 107 this.videoPlaylistService.updateVideoOfPlaylist(this.playlist.id, playlistElement.id, body)
95 .subscribe( 108 .subscribe(
96 () => { 109 () => {
97 this.notifier.success(this.i18n('Timestamps updated')) 110 this.notifier.success(this.i18n('Timestamps updated'))
98 111
99 video.playlistElement.startTimestamp = body.startTimestamp 112 playlistElement.startTimestamp = body.startTimestamp
100 video.playlistElement.stopTimestamp = body.stopTimestamp 113 playlistElement.stopTimestamp = body.stopTimestamp
101 114
102 this.cdr.detectChanges() 115 this.cdr.detectChanges()
103 }, 116 },
@@ -108,9 +121,9 @@ export class VideoPlaylistElementMiniatureComponent {
108 this.moreDropdown.close() 121 this.moreDropdown.close()
109 } 122 }
110 123
111 formatTimestamp (video: Video) { 124 formatTimestamp (playlistElement: VideoPlaylistElement) {
112 const start = video.playlistElement.startTimestamp 125 const start = playlistElement.startTimestamp
113 const stop = video.playlistElement.stopTimestamp 126 const stop = playlistElement.stopTimestamp
114 127
115 const startFormatted = secondsToTime(start, true, ':') 128 const startFormatted = secondsToTime(start, true, ':')
116 const stopFormatted = secondsToTime(stop, true, ':') 129 const stopFormatted = secondsToTime(stop, true, ':')
@@ -127,7 +140,7 @@ export class VideoPlaylistElementMiniatureComponent {
127 this.displayTimestampOptions = false 140 this.displayTimestampOptions = false
128 } 141 }
129 142
130 toggleDisplayTimestampsOptions (event: Event, video: Video) { 143 toggleDisplayTimestampsOptions (event: Event, playlistElement: VideoPlaylistElement) {
131 event.preventDefault() 144 event.preventDefault()
132 145
133 this.displayTimestampOptions = !this.displayTimestampOptions 146 this.displayTimestampOptions = !this.displayTimestampOptions
@@ -137,17 +150,17 @@ export class VideoPlaylistElementMiniatureComponent {
137 startTimestampEnabled: false, 150 startTimestampEnabled: false,
138 stopTimestampEnabled: false, 151 stopTimestampEnabled: false,
139 startTimestamp: 0, 152 startTimestamp: 0,
140 stopTimestamp: video.duration 153 stopTimestamp: playlistElement.video.duration
141 } 154 }
142 155
143 if (video.playlistElement.startTimestamp) { 156 if (playlistElement.startTimestamp) {
144 this.timestampOptions.startTimestampEnabled = true 157 this.timestampOptions.startTimestampEnabled = true
145 this.timestampOptions.startTimestamp = video.playlistElement.startTimestamp 158 this.timestampOptions.startTimestamp = playlistElement.startTimestamp
146 } 159 }
147 160
148 if (video.playlistElement.stopTimestamp) { 161 if (playlistElement.stopTimestamp) {
149 this.timestampOptions.stopTimestampEnabled = true 162 this.timestampOptions.stopTimestampEnabled = true
150 this.timestampOptions.stopTimestamp = video.playlistElement.stopTimestamp 163 this.timestampOptions.stopTimestamp = playlistElement.stopTimestamp
151 } 164 }
152 } 165 }
153 166
diff --git a/client/src/app/shared/video-playlist/video-playlist-element.model.ts b/client/src/app/shared/video-playlist/video-playlist-element.model.ts
new file mode 100644
index 000000000..f1c46d1eb
--- /dev/null
+++ b/client/src/app/shared/video-playlist/video-playlist-element.model.ts
@@ -0,0 +1,24 @@
1import { VideoPlaylistElement as ServerVideoPlaylistElement, VideoPlaylistElementType } from '../../../../../shared/models/videos'
2import { Video } from '@app/shared/video/video.model'
3
4export class VideoPlaylistElement implements ServerVideoPlaylistElement {
5 id: number
6 position: number
7 startTimestamp: number
8 stopTimestamp: number
9
10 type: VideoPlaylistElementType
11
12 video?: Video
13
14 constructor (hash: ServerVideoPlaylistElement, translations: {}) {
15 this.id = hash.id
16 this.position = hash.position
17 this.startTimestamp = hash.startTimestamp
18 this.stopTimestamp = hash.stopTimestamp
19
20 this.type = hash.type
21
22 if (hash.video) this.video = new Video(hash.video, translations)
23 }
24}
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 da7437507..b93a19356 100644
--- a/client/src/app/shared/video-playlist/video-playlist.service.ts
+++ b/client/src/app/shared/video-playlist/video-playlist.service.ts
@@ -18,6 +18,9 @@ import { Account } from '@app/shared/account/account.model'
18import { RestService } from '@app/shared/rest' 18import { RestService } from '@app/shared/rest'
19import { VideoExistInPlaylist } from '@shared/models/videos/playlist/video-exist-in-playlist.model' 19import { VideoExistInPlaylist } from '@shared/models/videos/playlist/video-exist-in-playlist.model'
20import { VideoPlaylistReorder } from '@shared/models/videos/playlist/video-playlist-reorder.model' 20import { VideoPlaylistReorder } from '@shared/models/videos/playlist/video-playlist-reorder.model'
21import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
22import { VideoPlaylistElement as ServerVideoPlaylistElement } from '@shared/models/videos/playlist/video-playlist-element.model'
23import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model'
21 24
22@Injectable() 25@Injectable()
23export class VideoPlaylistService { 26export class VideoPlaylistService {
@@ -110,16 +113,16 @@ export class VideoPlaylistService {
110 ) 113 )
111 } 114 }
112 115
113 updateVideoOfPlaylist (playlistId: number, videoId: number, body: VideoPlaylistElementUpdate) { 116 updateVideoOfPlaylist (playlistId: number, playlistElementId: number, body: VideoPlaylistElementUpdate) {
114 return this.authHttp.put(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + videoId, body) 117 return this.authHttp.put(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + playlistElementId, body)
115 .pipe( 118 .pipe(
116 map(this.restExtractor.extractDataBool), 119 map(this.restExtractor.extractDataBool),
117 catchError(err => this.restExtractor.handleError(err)) 120 catchError(err => this.restExtractor.handleError(err))
118 ) 121 )
119 } 122 }
120 123
121 removeVideoFromPlaylist (playlistId: number, videoId: number) { 124 removeVideoFromPlaylist (playlistId: number, playlistElementId: number) {
122 return this.authHttp.delete(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + videoId) 125 return this.authHttp.delete(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos/' + playlistElementId)
123 .pipe( 126 .pipe(
124 map(this.restExtractor.extractDataBool), 127 map(this.restExtractor.extractDataBool),
125 catchError(err => this.restExtractor.handleError(err)) 128 catchError(err => this.restExtractor.handleError(err))
@@ -139,6 +142,24 @@ export class VideoPlaylistService {
139 ) 142 )
140 } 143 }
141 144
145 getPlaylistVideos (
146 videoPlaylistId: number | string,
147 componentPagination: ComponentPagination
148 ): Observable<ResultList<VideoPlaylistElement>> {
149 const path = VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + videoPlaylistId + '/videos'
150 const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
151
152 let params = new HttpParams()
153 params = this.restService.addRestGetParams(params, pagination)
154
155 return this.authHttp
156 .get<ResultList<ServerVideoPlaylistElement>>(path, { params })
157 .pipe(
158 switchMap(res => this.extractVideoPlaylistElements(res)),
159 catchError(err => this.restExtractor.handleError(err))
160 )
161 }
162
142 doesVideoExistInPlaylist (videoId: number) { 163 doesVideoExistInPlaylist (videoId: number) {
143 this.videoExistsInPlaylistSubject.next(videoId) 164 this.videoExistsInPlaylistSubject.next(videoId)
144 165
@@ -167,6 +188,23 @@ export class VideoPlaylistService {
167 .pipe(map(translations => new VideoPlaylist(playlist, translations))) 188 .pipe(map(translations => new VideoPlaylist(playlist, translations)))
168 } 189 }
169 190
191 extractVideoPlaylistElements (result: ResultList<ServerVideoPlaylistElement>) {
192 return this.serverService.localeObservable
193 .pipe(
194 map(translations => {
195 const elementsJson = result.data
196 const total = result.total
197 const elements: VideoPlaylistElement[] = []
198
199 for (const elementJson of elementsJson) {
200 elements.push(new VideoPlaylistElement(elementJson, translations))
201 }
202
203 return { total, data: elements }
204 })
205 )
206 }
207
170 private doVideosExistInPlaylist (videoIds: number[]): Observable<VideoExistInPlaylist> { 208 private doVideosExistInPlaylist (videoIds: number[]): Observable<VideoExistInPlaylist> {
171 const url = VideoPlaylistService.MY_VIDEO_PLAYLIST_URL + 'videos-exist' 209 const url = VideoPlaylistService.MY_VIDEO_PLAYLIST_URL + 'videos-exist'
172 let params = new HttpParams() 210 let params = new HttpParams()
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index 6f9de9241..fb98d5382 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -1,5 +1,5 @@
1import { User } from '../' 1import { User } from '../'
2import { PlaylistElement, UserRight, Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../../../shared' 2import { UserRight, Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../../../shared'
3import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 3import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
4import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model' 4import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model'
5import { durationToString, getAbsoluteAPIUrl } from '../misc/utils' 5import { durationToString, getAbsoluteAPIUrl } from '../misc/utils'
@@ -48,8 +48,6 @@ export class Video implements VideoServerModel {
48 blacklisted?: boolean 48 blacklisted?: boolean
49 blacklistedReason?: string 49 blacklistedReason?: string
50 50
51 playlistElement?: PlaylistElement
52
53 account: { 51 account: {
54 id: number 52 id: number
55 name: string 53 name: string
@@ -126,8 +124,6 @@ export class Video implements VideoServerModel {
126 this.blacklistedReason = hash.blacklistedReason 124 this.blacklistedReason = hash.blacklistedReason
127 125
128 this.userHistory = hash.userHistory 126 this.userHistory = hash.userHistory
129
130 this.playlistElement = hash.playlistElement
131 } 127 }
132 128
133 isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { 129 isVideoNSFWForUser (user: User, serverConfig: ServerConfig) {
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index 114b014ad..45366e3e3 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -31,7 +31,6 @@ import { ServerService } from '@app/core'
31import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service' 31import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service'
32import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 32import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
33import { I18n } from '@ngx-translate/i18n-polyfill' 33import { I18n } from '@ngx-translate/i18n-polyfill'
34import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
35 34
36export interface VideosProvider { 35export interface VideosProvider {
37 getVideos (parameters: { 36 getVideos (parameters: {
@@ -172,23 +171,6 @@ export class VideoService implements VideosProvider {
172 ) 171 )
173 } 172 }
174 173
175 getPlaylistVideos (
176 videoPlaylistId: number | string,
177 videoPagination: ComponentPagination
178 ): Observable<ResultList<Video>> {
179 const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
180
181 let params = new HttpParams()
182 params = this.restService.addRestGetParams(params, pagination)
183
184 return this.authHttp
185 .get<ResultList<Video>>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + videoPlaylistId + '/videos', { params })
186 .pipe(
187 switchMap(res => this.extractVideos(res)),
188 catchError(err => this.restExtractor.handleError(err))
189 )
190 }
191
192 getUserSubscriptionVideos (parameters: { 174 getUserSubscriptionVideos (parameters: {
193 videoPagination: ComponentPagination, 175 videoPagination: ComponentPagination,
194 sort: VideoSortField 176 sort: VideoSortField