diff options
Diffstat (limited to 'client/src')
5 files changed, 90 insertions, 8 deletions
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index 6e4fb4c6f..738bcedee 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -56,8 +56,8 @@ | |||
56 | 56 | ||
57 | <td class="action-cell"> | 57 | <td class="action-cell"> |
58 | <my-video-actions-dropdown | 58 | <my-video-actions-dropdown |
59 | placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" | 59 | placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [displayOptions]="videoActionsOptions" |
60 | [displayOptions]="videoActionsOptions" (videoRemoved)="reloadData()" (videoFilesRemoved)="reloadData()" | 60 | (videoRemoved)="reloadData()" (videoFilesRemoved)="reloadData()" (transcodingCreated)="reloadData()" |
61 | ></my-video-actions-dropdown> | 61 | ></my-video-actions-dropdown> |
62 | </td> | 62 | </td> |
63 | 63 | ||
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index 3c21adb44..4aed5221b 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -40,7 +40,8 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
40 | duplicate: true, | 40 | duplicate: true, |
41 | mute: true, | 41 | mute: true, |
42 | liveInfo: false, | 42 | liveInfo: false, |
43 | removeFiles: true | 43 | removeFiles: true, |
44 | transcoding: true | ||
44 | } | 45 | } |
45 | 46 | ||
46 | loading = true | 47 | loading = true |
@@ -90,15 +91,27 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
90 | ], | 91 | ], |
91 | [ | 92 | [ |
92 | { | 93 | { |
94 | label: $localize`Run HLS transcoding`, | ||
95 | handler: videos => this.runTranscoding(videos, 'hls'), | ||
96 | isDisplayed: videos => videos.every(v => v.canRunTranscoding(this.authUser)), | ||
97 | iconName: 'cog' | ||
98 | }, | ||
99 | { | ||
100 | label: $localize`Run WebTorrent transcoding`, | ||
101 | handler: videos => this.runTranscoding(videos, 'webtorrent'), | ||
102 | isDisplayed: videos => videos.every(v => v.canRunTranscoding(this.authUser)), | ||
103 | iconName: 'cog' | ||
104 | }, | ||
105 | { | ||
93 | label: $localize`Delete HLS files`, | 106 | label: $localize`Delete HLS files`, |
94 | handler: videos => this.removeVideoFiles(videos, 'hls'), | 107 | handler: videos => this.removeVideoFiles(videos, 'hls'), |
95 | isDisplayed: videos => this.authUser.hasRight(UserRight.MANAGE_VIDEO_FILES) && videos.every(v => v.hasHLS() && v.hasWebTorrent()), | 108 | isDisplayed: videos => videos.every(v => v.canRemoveFiles(this.authUser)), |
96 | iconName: 'delete' | 109 | iconName: 'delete' |
97 | }, | 110 | }, |
98 | { | 111 | { |
99 | label: $localize`Delete WebTorrent files`, | 112 | label: $localize`Delete WebTorrent files`, |
100 | handler: videos => this.removeVideoFiles(videos, 'webtorrent'), | 113 | handler: videos => this.removeVideoFiles(videos, 'webtorrent'), |
101 | isDisplayed: videos => this.authUser.hasRight(UserRight.MANAGE_VIDEO_FILES) && videos.every(v => v.hasHLS() && v.hasWebTorrent()), | 114 | isDisplayed: videos => videos.every(v => v.canRemoveFiles(this.authUser)), |
102 | iconName: 'delete' | 115 | iconName: 'delete' |
103 | } | 116 | } |
104 | ] | 117 | ] |
@@ -226,4 +239,17 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
226 | error: err => this.notifier.error(err.message) | 239 | error: err => this.notifier.error(err.message) |
227 | }) | 240 | }) |
228 | } | 241 | } |
242 | |||
243 | private runTranscoding (videos: Video[], type: 'hls' | 'webtorrent') { | ||
244 | this.videoService.runTranscoding(videos.map(v => v.id), type) | ||
245 | .subscribe({ | ||
246 | next: () => { | ||
247 | this.notifier.success($localize`Transcoding jobs created.`) | ||
248 | |||
249 | this.reloadData() | ||
250 | }, | ||
251 | |||
252 | error: err => this.notifier.error(err.message) | ||
253 | }) | ||
254 | } | ||
229 | } | 255 | } |
diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts index 4203ff1c0..eefa90489 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts | |||
@@ -220,6 +220,18 @@ export class Video implements VideoServerModel { | |||
220 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) | 220 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) |
221 | } | 221 | } |
222 | 222 | ||
223 | canRemoveFiles (user: AuthUser) { | ||
224 | return user.hasRight(UserRight.MANAGE_VIDEO_FILES) && | ||
225 | this.state.id !== VideoState.TO_TRANSCODE && | ||
226 | this.hasHLS() && | ||
227 | this.hasWebTorrent() | ||
228 | } | ||
229 | |||
230 | canRunTranscoding (user: AuthUser) { | ||
231 | return user.hasRight(UserRight.RUN_VIDEO_TRANSCODING) && | ||
232 | this.state.id !== VideoState.TO_TRANSCODE | ||
233 | } | ||
234 | |||
223 | hasHLS () { | 235 | hasHLS () { |
224 | return this.streamingPlaylists?.some(p => p.type === VideoStreamingPlaylistType.HLS) | 236 | return this.streamingPlaylists?.some(p => p.type === VideoStreamingPlaylistType.HLS) |
225 | } | 237 | } |
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts index d135a27dc..9bfa397f8 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts | |||
@@ -21,6 +21,7 @@ import { | |||
21 | VideoInclude, | 21 | VideoInclude, |
22 | VideoPrivacy, | 22 | VideoPrivacy, |
23 | VideoSortField, | 23 | VideoSortField, |
24 | VideoTranscodingCreate, | ||
24 | VideoUpdate | 25 | VideoUpdate |
25 | } from '@shared/models' | 26 | } from '@shared/models' |
26 | import { environment } from '../../../../environments/environment' | 27 | import { environment } from '../../../../environments/environment' |
@@ -308,6 +309,17 @@ export class VideoService { | |||
308 | ) | 309 | ) |
309 | } | 310 | } |
310 | 311 | ||
312 | runTranscoding (videoIds: (number | string)[], type: 'hls' | 'webtorrent') { | ||
313 | const body: VideoTranscodingCreate = { transcodingType: type } | ||
314 | |||
315 | return from(videoIds) | ||
316 | .pipe( | ||
317 | concatMap(id => this.authHttp.post(VideoService.BASE_VIDEO_URL + '/' + id + '/transcoding', body)), | ||
318 | toArray(), | ||
319 | catchError(err => this.restExtractor.handleError(err)) | ||
320 | ) | ||
321 | } | ||
322 | |||
311 | loadCompleteDescription (descriptionPath: string) { | 323 | loadCompleteDescription (descriptionPath: string) { |
312 | return this.authHttp | 324 | return this.authHttp |
313 | .get<{ description: string }>(environment.apiUrl + descriptionPath) | 325 | .get<{ description: string }>(environment.apiUrl + descriptionPath) |
diff --git a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts index 82c084791..2ab9f4739 100644 --- a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts +++ b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts | |||
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, Output, ViewChild } from '@a | |||
2 | import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core' | 2 | import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core' |
3 | import { BlocklistService, VideoBlockComponent, VideoBlockService, VideoReportComponent } from '@app/shared/shared-moderation' | 3 | import { BlocklistService, VideoBlockComponent, VideoBlockService, VideoReportComponent } from '@app/shared/shared-moderation' |
4 | import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' | 4 | import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' |
5 | import { UserRight, VideoCaption } from '@shared/models' | 5 | import { UserRight, VideoCaption, VideoState } from '@shared/models' |
6 | import { | 6 | import { |
7 | Actor, | 7 | Actor, |
8 | DropdownAction, | 8 | DropdownAction, |
@@ -28,6 +28,7 @@ export type VideoActionsDisplayType = { | |||
28 | mute?: boolean | 28 | mute?: boolean |
29 | liveInfo?: boolean | 29 | liveInfo?: boolean |
30 | removeFiles?: boolean | 30 | removeFiles?: boolean |
31 | transcoding?: boolean | ||
31 | } | 32 | } |
32 | 33 | ||
33 | @Component({ | 34 | @Component({ |
@@ -56,7 +57,9 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
56 | report: true, | 57 | report: true, |
57 | duplicate: true, | 58 | duplicate: true, |
58 | mute: true, | 59 | mute: true, |
59 | liveInfo: false | 60 | liveInfo: false, |
61 | removeFiles: false, | ||
62 | transcoding: false | ||
60 | } | 63 | } |
61 | @Input() placement = 'left' | 64 | @Input() placement = 'left' |
62 | 65 | ||
@@ -71,6 +74,7 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
71 | @Output() videoUnblocked = new EventEmitter() | 74 | @Output() videoUnblocked = new EventEmitter() |
72 | @Output() videoBlocked = new EventEmitter() | 75 | @Output() videoBlocked = new EventEmitter() |
73 | @Output() videoAccountMuted = new EventEmitter() | 76 | @Output() videoAccountMuted = new EventEmitter() |
77 | @Output() transcodingCreated = new EventEmitter() | ||
74 | @Output() modalOpened = new EventEmitter() | 78 | @Output() modalOpened = new EventEmitter() |
75 | 79 | ||
76 | videoActions: DropdownAction<{ video: Video }>[][] = [] | 80 | videoActions: DropdownAction<{ video: Video }>[][] = [] |
@@ -177,7 +181,11 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
177 | } | 181 | } |
178 | 182 | ||
179 | canRemoveVideoFiles () { | 183 | canRemoveVideoFiles () { |
180 | return this.user.hasRight(UserRight.MANAGE_VIDEO_FILES) && this.video.hasHLS() && this.video.hasWebTorrent() | 184 | return this.video.canRemoveFiles(this.user) |
185 | } | ||
186 | |||
187 | canRunTranscoding () { | ||
188 | return this.video.canRunTranscoding(this.user) | ||
181 | } | 189 | } |
182 | 190 | ||
183 | /* Action handlers */ | 191 | /* Action handlers */ |
@@ -268,6 +276,18 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
268 | }) | 276 | }) |
269 | } | 277 | } |
270 | 278 | ||
279 | runTranscoding (video: Video, type: 'hls' | 'webtorrent') { | ||
280 | this.videoService.runTranscoding([ video.id ], type) | ||
281 | .subscribe({ | ||
282 | next: () => { | ||
283 | this.notifier.success($localize`Transcoding jobs created for ${video.name}.`) | ||
284 | this.transcodingCreated.emit() | ||
285 | }, | ||
286 | |||
287 | error: err => this.notifier.error(err.message) | ||
288 | }) | ||
289 | } | ||
290 | |||
271 | onVideoBlocked () { | 291 | onVideoBlocked () { |
272 | this.videoBlocked.emit() | 292 | this.videoBlocked.emit() |
273 | } | 293 | } |
@@ -342,6 +362,18 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
342 | ], | 362 | ], |
343 | [ | 363 | [ |
344 | { | 364 | { |
365 | label: $localize`Run HLS transcoding`, | ||
366 | handler: ({ video }) => this.runTranscoding(video, 'hls'), | ||
367 | isDisplayed: () => this.displayOptions.transcoding && this.canRunTranscoding(), | ||
368 | iconName: 'cog' | ||
369 | }, | ||
370 | { | ||
371 | label: $localize`Run WebTorrent transcoding`, | ||
372 | handler: ({ video }) => this.runTranscoding(video, 'webtorrent'), | ||
373 | isDisplayed: () => this.displayOptions.transcoding && this.canRunTranscoding(), | ||
374 | iconName: 'cog' | ||
375 | }, | ||
376 | { | ||
345 | label: $localize`Delete HLS files`, | 377 | label: $localize`Delete HLS files`, |
346 | handler: ({ video }) => this.removeVideoFiles(video, 'hls'), | 378 | handler: ({ video }) => this.removeVideoFiles(video, 'hls'), |
347 | isDisplayed: () => this.displayOptions.removeFiles && this.canRemoveVideoFiles(), | 379 | isDisplayed: () => this.displayOptions.removeFiles && this.canRemoveVideoFiles(), |