aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/+admin/overview/videos/video-list.component.html4
-rw-r--r--client/src/app/+admin/overview/videos/video-list.component.ts32
-rw-r--r--client/src/app/shared/shared-main/video/video.model.ts12
-rw-r--r--client/src/app/shared/shared-main/video/video.service.ts12
-rw-r--r--client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts38
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'
26import { environment } from '../../../../environments/environment' 27import { 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
2import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core' 2import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core'
3import { BlocklistService, VideoBlockComponent, VideoBlockService, VideoReportComponent } from '@app/shared/shared-moderation' 3import { BlocklistService, VideoBlockComponent, VideoBlockService, VideoReportComponent } from '@app/shared/shared-moderation'
4import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' 4import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
5import { UserRight, VideoCaption } from '@shared/models' 5import { UserRight, VideoCaption, VideoState } from '@shared/models'
6import { 6import {
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(),