diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-28 11:07:03 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-07-28 11:09:03 +0200 |
commit | 89aa3331106874266f6feeee7bff852da2c1727e (patch) | |
tree | 6b03c6c4e4019b3d71da80f88a0775c2b5cbdd65 /client/src | |
parent | ac8f81e3732548a28e0df03d588bf6777fad55cb (diff) | |
download | PeerTube-89aa3331106874266f6feeee7bff852da2c1727e.tar.gz PeerTube-89aa3331106874266f6feeee7bff852da2c1727e.tar.zst PeerTube-89aa3331106874266f6feeee7bff852da2c1727e.zip |
Add ability to force transcoding
Diffstat (limited to 'client/src')
4 files changed, 59 insertions, 18 deletions
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 52f02d8d0..2792a2d8a 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -3,7 +3,7 @@ import { finalize } from 'rxjs/operators' | |||
3 | import { Component, OnInit, ViewChild } from '@angular/core' | 3 | import { Component, OnInit, ViewChild } from '@angular/core' |
4 | import { ActivatedRoute, Router } from '@angular/router' | 4 | import { ActivatedRoute, Router } from '@angular/router' |
5 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' | 5 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' |
6 | import { formatICU } from '@app/helpers' | 6 | import { formatICU, getAbsoluteAPIUrl } from '@app/helpers' |
7 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 7 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
9 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' | 9 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' |
@@ -166,7 +166,7 @@ export class VideoListComponent extends RestTable <Video> implements OnInit { | |||
166 | 166 | ||
167 | const files = getAllFiles(video) | 167 | const files = getAllFiles(video) |
168 | 168 | ||
169 | return files.some(f => !f.fileUrl.startsWith(window.location.origin)) | 169 | return files.some(f => !f.fileUrl.startsWith(getAbsoluteAPIUrl())) |
170 | } | 170 | } |
171 | 171 | ||
172 | canRemoveOneFile (video: Video) { | 172 | canRemoveOneFile (video: Video) { |
@@ -294,7 +294,7 @@ export class VideoListComponent extends RestTable <Video> implements OnInit { | |||
294 | } | 294 | } |
295 | 295 | ||
296 | private runTranscoding (videos: Video[], type: 'hls' | 'web-video') { | 296 | private runTranscoding (videos: Video[], type: 'hls' | 'web-video') { |
297 | this.videoService.runTranscoding(videos.map(v => v.id), type) | 297 | this.videoService.runTranscoding({ videoIds: videos.map(v => v.id), type, askForForceTranscodingIfNeeded: false }) |
298 | .subscribe({ | 298 | .subscribe({ |
299 | next: () => { | 299 | next: () => { |
300 | this.notifier.success($localize`Transcoding jobs created.`) | 300 | this.notifier.success($localize`Transcoding jobs created.`) |
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 a5bf1db8b..392dcadd0 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts | |||
@@ -257,9 +257,12 @@ export class Video implements VideoServerModel { | |||
257 | } | 257 | } |
258 | 258 | ||
259 | canRunTranscoding (user: AuthUser) { | 259 | canRunTranscoding (user: AuthUser) { |
260 | return this.canRunForcedTranscoding(user) && this.state.id !== VideoState.TO_TRANSCODE | ||
261 | } | ||
262 | |||
263 | canRunForcedTranscoding (user: AuthUser) { | ||
260 | return this.isLocal && | 264 | return this.isLocal && |
261 | user && user.hasRight(UserRight.RUN_VIDEO_TRANSCODING) && | 265 | user && user.hasRight(UserRight.RUN_VIDEO_TRANSCODING) |
262 | this.state.id !== VideoState.TO_TRANSCODE | ||
263 | } | 266 | } |
264 | 267 | ||
265 | hasHLS () { | 268 | hasHLS () { |
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 20145b9c5..cd0a300e2 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { from, Observable, of } from 'rxjs' | 2 | import { from, Observable, of, throwError } from 'rxjs' |
3 | import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators' | 3 | import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators' |
4 | import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' | 4 | import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' |
5 | import { Injectable } from '@angular/core' | 5 | import { Injectable } from '@angular/core' |
6 | import { AuthService, ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core' | 6 | import { AuthService, ComponentPaginationLight, ConfirmService, RestExtractor, RestService, ServerService, UserService } from '@app/core' |
7 | import { objectToFormData } from '@app/helpers' | 7 | import { objectToFormData } from '@app/helpers' |
8 | import { arrayify } from '@shared/core-utils' | 8 | import { arrayify } from '@shared/core-utils' |
9 | import { | 9 | import { |
@@ -11,6 +11,7 @@ import { | |||
11 | FeedFormat, | 11 | FeedFormat, |
12 | NSFWPolicyType, | 12 | NSFWPolicyType, |
13 | ResultList, | 13 | ResultList, |
14 | ServerErrorCode, | ||
14 | Storyboard, | 15 | Storyboard, |
15 | UserVideoRate, | 16 | UserVideoRate, |
16 | UserVideoRateType, | 17 | UserVideoRateType, |
@@ -33,8 +34,8 @@ import { AccountService } from '../account/account.service' | |||
33 | import { VideoChannel, VideoChannelService } from '../video-channel' | 34 | import { VideoChannel, VideoChannelService } from '../video-channel' |
34 | import { VideoDetails } from './video-details.model' | 35 | import { VideoDetails } from './video-details.model' |
35 | import { VideoEdit } from './video-edit.model' | 36 | import { VideoEdit } from './video-edit.model' |
36 | import { Video } from './video.model' | ||
37 | import { VideoPasswordService } from './video-password.service' | 37 | import { VideoPasswordService } from './video-password.service' |
38 | import { Video } from './video.model' | ||
38 | 39 | ||
39 | export type CommonVideoParams = { | 40 | export type CommonVideoParams = { |
40 | videoPagination?: ComponentPaginationLight | 41 | videoPagination?: ComponentPaginationLight |
@@ -64,7 +65,8 @@ export class VideoService { | |||
64 | private authHttp: HttpClient, | 65 | private authHttp: HttpClient, |
65 | private restExtractor: RestExtractor, | 66 | private restExtractor: RestExtractor, |
66 | private restService: RestService, | 67 | private restService: RestService, |
67 | private serverService: ServerService | 68 | private serverService: ServerService, |
69 | private confirmService: ConfirmService | ||
68 | ) {} | 70 | ) {} |
69 | 71 | ||
70 | getVideoViewUrl (uuid: string) { | 72 | getVideoViewUrl (uuid: string) { |
@@ -325,17 +327,53 @@ export class VideoService { | |||
325 | .pipe(catchError(err => this.restExtractor.handleError(err))) | 327 | .pipe(catchError(err => this.restExtractor.handleError(err))) |
326 | } | 328 | } |
327 | 329 | ||
328 | runTranscoding (videoIds: (number | string)[], type: 'hls' | 'web-video') { | 330 | runTranscoding (options: { |
329 | const body: VideoTranscodingCreate = { transcodingType: type } | 331 | videoIds: (number | string)[] |
332 | type: 'hls' | 'web-video' | ||
333 | askForForceTranscodingIfNeeded: boolean | ||
334 | forceTranscoding?: boolean | ||
335 | }): Observable<any> { | ||
336 | const { videoIds, type, askForForceTranscodingIfNeeded, forceTranscoding } = options | ||
337 | |||
338 | if (askForForceTranscodingIfNeeded && videoIds.length !== 1) { | ||
339 | throw new Error('Cannot ask to force transcoding on multiple videos') | ||
340 | } | ||
341 | |||
342 | const body: VideoTranscodingCreate = { transcodingType: type, forceTranscoding } | ||
330 | 343 | ||
331 | return from(videoIds) | 344 | return from(videoIds) |
332 | .pipe( | 345 | .pipe( |
333 | concatMap(id => this.authHttp.post(VideoService.BASE_VIDEO_URL + '/' + id + '/transcoding', body)), | 346 | concatMap(id => { |
347 | return this.authHttp.post(VideoService.BASE_VIDEO_URL + '/' + id + '/transcoding', body) | ||
348 | .pipe( | ||
349 | catchError(err => { | ||
350 | if (askForForceTranscodingIfNeeded && err.error?.code === ServerErrorCode.VIDEO_ALREADY_BEING_TRANSCODED) { | ||
351 | const message = $localize`PeerTube considers this video is already being transcoded.` + | ||
352 | // eslint-disable-next-line max-len | ||
353 | $localize` If you think PeerTube is wrong (video in broken state after a crash etc.), you can force transcoding on this video.` + | ||
354 | ` Do you still want to run transcoding?` | ||
355 | |||
356 | return from(this.confirmService.confirm(message, $localize`Force transcoding`)) | ||
357 | .pipe( | ||
358 | switchMap(res => { | ||
359 | if (res === false) return throwError(() => err) | ||
360 | |||
361 | return this.runTranscoding({ videoIds, type, askForForceTranscodingIfNeeded: false, forceTranscoding: true }) | ||
362 | }) | ||
363 | ) | ||
364 | } | ||
365 | |||
366 | return throwError(() => err) | ||
367 | }) | ||
368 | ) | ||
369 | }), | ||
334 | toArray(), | 370 | toArray(), |
335 | catchError(err => this.restExtractor.handleError(err)) | 371 | catchError(err => this.restExtractor.handleError(err)) |
336 | ) | 372 | ) |
337 | } | 373 | } |
338 | 374 | ||
375 | // --------------------------------------------------------------------------- | ||
376 | |||
339 | loadCompleteDescription (descriptionPath: string) { | 377 | loadCompleteDescription (descriptionPath: string) { |
340 | return this.authHttp | 378 | return this.authHttp |
341 | .get<{ description: string }>(environment.apiUrl + descriptionPath) | 379 | .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 0a3ada711..9891aae2e 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 | |||
@@ -198,8 +198,8 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
198 | return this.video.canRemoveFiles(this.user) | 198 | return this.video.canRemoveFiles(this.user) |
199 | } | 199 | } |
200 | 200 | ||
201 | canRunTranscoding () { | 201 | canRunForcedTranscoding () { |
202 | return this.video.canRunTranscoding(this.user) | 202 | return this.video.canRunForcedTranscoding(this.user) |
203 | } | 203 | } |
204 | 204 | ||
205 | /* Action handlers */ | 205 | /* Action handlers */ |
@@ -291,10 +291,10 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
291 | } | 291 | } |
292 | 292 | ||
293 | runTranscoding (video: Video, type: 'hls' | 'web-video') { | 293 | runTranscoding (video: Video, type: 'hls' | 'web-video') { |
294 | this.videoService.runTranscoding([ video.id ], type) | 294 | this.videoService.runTranscoding({ videoIds: [ video.id ], type, askForForceTranscodingIfNeeded: true }) |
295 | .subscribe({ | 295 | .subscribe({ |
296 | next: () => { | 296 | next: () => { |
297 | this.notifier.success($localize`Transcoding jobs created for ${video.name}.`) | 297 | this.notifier.success($localize`Transcoding jobs created for "${video.name}".`) |
298 | this.transcodingCreated.emit() | 298 | this.transcodingCreated.emit() |
299 | }, | 299 | }, |
300 | 300 | ||
@@ -390,13 +390,13 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
390 | { | 390 | { |
391 | label: $localize`Run HLS transcoding`, | 391 | label: $localize`Run HLS transcoding`, |
392 | handler: ({ video }) => this.runTranscoding(video, 'hls'), | 392 | handler: ({ video }) => this.runTranscoding(video, 'hls'), |
393 | isDisplayed: () => this.displayOptions.transcoding && this.canRunTranscoding(), | 393 | isDisplayed: () => this.displayOptions.transcoding && this.canRunForcedTranscoding(), |
394 | iconName: 'cog' | 394 | iconName: 'cog' |
395 | }, | 395 | }, |
396 | { | 396 | { |
397 | label: $localize`Run Web Video transcoding`, | 397 | label: $localize`Run Web Video transcoding`, |
398 | handler: ({ video }) => this.runTranscoding(video, 'web-video'), | 398 | handler: ({ video }) => this.runTranscoding(video, 'web-video'), |
399 | isDisplayed: () => this.displayOptions.transcoding && this.canRunTranscoding(), | 399 | isDisplayed: () => this.displayOptions.transcoding && this.canRunForcedTranscoding(), |
400 | iconName: 'cog' | 400 | iconName: 'cog' |
401 | }, | 401 | }, |
402 | { | 402 | { |