aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-07-28 11:07:03 +0200
committerChocobozzz <me@florianbigard.com>2023-07-28 11:09:03 +0200
commit89aa3331106874266f6feeee7bff852da2c1727e (patch)
tree6b03c6c4e4019b3d71da80f88a0775c2b5cbdd65 /client/src
parentac8f81e3732548a28e0df03d588bf6777fad55cb (diff)
downloadPeerTube-89aa3331106874266f6feeee7bff852da2c1727e.tar.gz
PeerTube-89aa3331106874266f6feeee7bff852da2c1727e.tar.zst
PeerTube-89aa3331106874266f6feeee7bff852da2c1727e.zip
Add ability to force transcoding
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/+admin/overview/videos/video-list.component.ts6
-rw-r--r--client/src/app/shared/shared-main/video/video.model.ts7
-rw-r--r--client/src/app/shared/shared-main/video/video.service.ts52
-rw-r--r--client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts12
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'
3import { Component, OnInit, ViewChild } from '@angular/core' 3import { Component, OnInit, ViewChild } from '@angular/core'
4import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
5import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' 5import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
6import { formatICU } from '@app/helpers' 6import { formatICU, getAbsoluteAPIUrl } from '@app/helpers'
7import { AdvancedInputFilter } from '@app/shared/shared-forms' 7import { AdvancedInputFilter } from '@app/shared/shared-forms'
8import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' 8import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
9import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' 9import { 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 @@
1import { SortMeta } from 'primeng/api' 1import { SortMeta } from 'primeng/api'
2import { from, Observable, of } from 'rxjs' 2import { from, Observable, of, throwError } from 'rxjs'
3import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators' 3import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators'
4import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' 4import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
5import { Injectable } from '@angular/core' 5import { Injectable } from '@angular/core'
6import { AuthService, ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core' 6import { AuthService, ComponentPaginationLight, ConfirmService, RestExtractor, RestService, ServerService, UserService } from '@app/core'
7import { objectToFormData } from '@app/helpers' 7import { objectToFormData } from '@app/helpers'
8import { arrayify } from '@shared/core-utils' 8import { arrayify } from '@shared/core-utils'
9import { 9import {
@@ -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'
33import { VideoChannel, VideoChannelService } from '../video-channel' 34import { VideoChannel, VideoChannelService } from '../video-channel'
34import { VideoDetails } from './video-details.model' 35import { VideoDetails } from './video-details.model'
35import { VideoEdit } from './video-edit.model' 36import { VideoEdit } from './video-edit.model'
36import { Video } from './video.model'
37import { VideoPasswordService } from './video-password.service' 37import { VideoPasswordService } from './video-password.service'
38import { Video } from './video.model'
38 39
39export type CommonVideoParams = { 40export 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 {