diff options
22 files changed, 133 insertions, 33 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 48678a194..5f0a5ff6c 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -436,8 +436,25 @@ | |||
436 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 436 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> |
437 | 437 | ||
438 | <ng-container formGroupName="import"> | 438 | <ng-container formGroupName="import"> |
439 | |||
439 | <ng-container formGroupName="videos"> | 440 | <ng-container formGroupName="videos"> |
440 | 441 | ||
442 | <div class="form-group mt-4"> | ||
443 | <label i18n for="importConcurrency">Import jobs concurrency</label> | ||
444 | <span class="text-muted ml-1"> | ||
445 | <span i18n>allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span> | ||
446 | </span> | ||
447 | |||
448 | <div class="peertube-select-container"> | ||
449 | <select id="importConcurrency" formControlName="concurrency" class="form-control"> | ||
450 | <option *ngFor="let option of concurrencyOptions" [value]="option"> | ||
451 | {{ option }} | ||
452 | </option> | ||
453 | </select> | ||
454 | </div> | ||
455 | <div *ngIf="formErrors.import.concurrency" class="form-error">{{ formErrors.import.concurrency }}</div> | ||
456 | </div> | ||
457 | |||
441 | <div class="form-group" formGroupName="http"> | 458 | <div class="form-group" formGroupName="http"> |
442 | <my-peertube-checkbox | 459 | <my-peertube-checkbox |
443 | inputName="importVideosHttpEnabled" formControlName="enabled" | 460 | inputName="importVideosHttpEnabled" formControlName="enabled" |
@@ -886,6 +903,22 @@ | |||
886 | </div> | 903 | </div> |
887 | 904 | ||
888 | <div class="form-group mt-4" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }"> | 905 | <div class="form-group mt-4" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }"> |
906 | <label i18n for="transcodingConcurrency">Transcoding jobs concurrency</label> | ||
907 | <span class="text-muted ml-1"> | ||
908 | <span i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart.</span> | ||
909 | </span> | ||
910 | |||
911 | <div class="peertube-select-container"> | ||
912 | <select id="transcodingConcurrency" formControlName="concurrency" class="form-control"> | ||
913 | <option *ngFor="let option of concurrencyOptions" [value]="option"> | ||
914 | {{ option }} | ||
915 | </option> | ||
916 | </select> | ||
917 | </div> | ||
918 | <div *ngIf="formErrors.transcoding.concurrency" class="form-error">{{ formErrors.transcoding.concurrency }}</div> | ||
919 | </div> | ||
920 | |||
921 | <div class="form-group mt-4" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }"> | ||
889 | <label i18n for="transcodingProfile">Transcoding profile</label> | 922 | <label i18n for="transcodingProfile">Transcoding profile</label> |
890 | <span class="text-muted ml-1" i18n>new transcoding profiles can be added by PeerTube plugins</span> | 923 | <span class="text-muted ml-1" i18n>new transcoding profiles can be added by PeerTube plugins</span> |
891 | 924 | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index ae6a9e844..48fb86968 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -9,6 +9,7 @@ import { | |||
9 | ADMIN_EMAIL_VALIDATOR, | 9 | ADMIN_EMAIL_VALIDATOR, |
10 | CACHE_CAPTIONS_SIZE_VALIDATOR, | 10 | CACHE_CAPTIONS_SIZE_VALIDATOR, |
11 | CACHE_PREVIEWS_SIZE_VALIDATOR, | 11 | CACHE_PREVIEWS_SIZE_VALIDATOR, |
12 | CONCURRENCY_VALIDATOR, | ||
12 | INDEX_URL_VALIDATOR, | 13 | INDEX_URL_VALIDATOR, |
13 | INSTANCE_NAME_VALIDATOR, | 14 | INSTANCE_NAME_VALIDATOR, |
14 | INSTANCE_SHORT_DESCRIPTION_VALIDATOR, | 15 | INSTANCE_SHORT_DESCRIPTION_VALIDATOR, |
@@ -36,6 +37,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
36 | 37 | ||
37 | resolutions: { id: string, label: string, description?: string }[] = [] | 38 | resolutions: { id: string, label: string, description?: string }[] = [] |
38 | liveResolutions: { id: string, label: string, description?: string }[] = [] | 39 | liveResolutions: { id: string, label: string, description?: string }[] = [] |
40 | concurrencyOptions: number[] = [] | ||
39 | transcodingThreadOptions: { label: string, value: number }[] = [] | 41 | transcodingThreadOptions: { label: string, value: number }[] = [] |
40 | liveMaxDurationOptions: { label: string, value: number }[] = [] | 42 | liveMaxDurationOptions: { label: string, value: number }[] = [] |
41 | 43 | ||
@@ -103,6 +105,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
103 | { value: 4, label: '4' }, | 105 | { value: 4, label: '4' }, |
104 | { value: 8, label: '8' } | 106 | { value: 8, label: '8' } |
105 | ] | 107 | ] |
108 | this.concurrencyOptions = [ 1, 2, 3, 4, 5, 6 ] | ||
106 | 109 | ||
107 | this.vodTranscodingProfileOptions = [ 'default' ] | 110 | this.vodTranscodingProfileOptions = [ 'default' ] |
108 | this.liveTranscodingProfileOptions = [ 'default' ] | 111 | this.liveTranscodingProfileOptions = [ 'default' ] |
@@ -230,6 +233,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
230 | }, | 233 | }, |
231 | import: { | 234 | import: { |
232 | videos: { | 235 | videos: { |
236 | concurrency: CONCURRENCY_VALIDATOR, | ||
233 | http: { | 237 | http: { |
234 | enabled: null | 238 | enabled: null |
235 | }, | 239 | }, |
@@ -262,6 +266,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
262 | allowAdditionalExtensions: null, | 266 | allowAdditionalExtensions: null, |
263 | allowAudioFiles: null, | 267 | allowAudioFiles: null, |
264 | profile: null, | 268 | profile: null, |
269 | concurrency: CONCURRENCY_VALIDATOR, | ||
265 | resolutions: {}, | 270 | resolutions: {}, |
266 | hls: { | 271 | hls: { |
267 | enabled: null | 272 | enabled: null |
diff --git a/client/src/app/shared/form-validators/custom-config-validators.ts b/client/src/app/shared/form-validators/custom-config-validators.ts index 41b3cbba9..23f2156c2 100644 --- a/client/src/app/shared/form-validators/custom-config-validators.ts +++ b/client/src/app/shared/form-validators/custom-config-validators.ts | |||
@@ -65,6 +65,14 @@ export const TRANSCODING_THREADS_VALIDATOR: BuildFormValidator = { | |||
65 | } | 65 | } |
66 | } | 66 | } |
67 | 67 | ||
68 | export const CONCURRENCY_VALIDATOR: BuildFormValidator = { | ||
69 | VALIDATORS: [Validators.required, Validators.min(1)], | ||
70 | MESSAGES: { | ||
71 | 'required': $localize`Concurrency is required.`, | ||
72 | 'min': $localize`Concurrency should be greater or equal to 1.` | ||
73 | } | ||
74 | } | ||
75 | |||
68 | export const INDEX_URL_VALIDATOR: BuildFormValidator = { | 76 | export const INDEX_URL_VALIDATOR: BuildFormValidator = { |
69 | VALIDATORS: [Validators.pattern(/^https:\/\//)], | 77 | VALIDATORS: [Validators.pattern(/^https:\/\//)], |
70 | MESSAGES: { | 78 | MESSAGES: { |
diff --git a/config/default.yaml b/config/default.yaml index 95df2e06c..3bbb3e5c4 100644 --- a/config/default.yaml +++ b/config/default.yaml | |||
@@ -233,7 +233,10 @@ transcoding: | |||
233 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | 233 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file |
234 | allow_audio_files: true | 234 | allow_audio_files: true |
235 | 235 | ||
236 | # Amount of threads used by ffmpeg for 1 transcoding job | ||
236 | threads: 1 | 237 | threads: 1 |
238 | # Amount of transcoding jobs to execute in parallel | ||
239 | concurrency: 1 | ||
237 | 240 | ||
238 | # Choose the transcoding profile | 241 | # Choose the transcoding profile |
239 | # New profiles can be added by plugins | 242 | # New profiles can be added by plugins |
@@ -312,6 +315,9 @@ live: | |||
312 | import: | 315 | import: |
313 | # Add ability for your users to import remote videos (from YouTube, torrent...) | 316 | # Add ability for your users to import remote videos (from YouTube, torrent...) |
314 | videos: | 317 | videos: |
318 | # Amount of import jobs to execute in parallel | ||
319 | concurrency: 1 | ||
320 | |||
315 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | 321 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html |
316 | enabled: false | 322 | enabled: false |
317 | 323 | ||
diff --git a/config/production.yaml.example b/config/production.yaml.example index 13a646918..d75e30276 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -244,7 +244,10 @@ transcoding: | |||
244 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | 244 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file |
245 | allow_audio_files: true | 245 | allow_audio_files: true |
246 | 246 | ||
247 | # Amount of threads used by ffmpeg for 1 transcoding job | ||
247 | threads: 1 | 248 | threads: 1 |
249 | # Amount of transcoding jobs to execute in parallel | ||
250 | concurrency: 1 | ||
248 | 251 | ||
249 | # Choose the transcoding profile | 252 | # Choose the transcoding profile |
250 | # New profiles can be added by plugins | 253 | # New profiles can be added by plugins |
@@ -323,6 +326,9 @@ live: | |||
323 | import: | 326 | import: |
324 | # Add ability for your users to import remote videos (from YouTube, torrent...) | 327 | # Add ability for your users to import remote videos (from YouTube, torrent...) |
325 | videos: | 328 | videos: |
329 | # Amount of import jobs to execute in parallel | ||
330 | concurrency: 1 | ||
331 | |||
326 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | 332 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html |
327 | enabled: false | 333 | enabled: false |
328 | 334 | ||
diff --git a/config/test.yaml b/config/test.yaml index 6fedb1dc3..ae8011ba5 100644 --- a/config/test.yaml +++ b/config/test.yaml | |||
@@ -71,6 +71,7 @@ transcoding: | |||
71 | allow_additional_extensions: false | 71 | allow_additional_extensions: false |
72 | allow_audio_files: false | 72 | allow_audio_files: false |
73 | threads: 2 | 73 | threads: 2 |
74 | concurrency: 2 | ||
74 | resolutions: | 75 | resolutions: |
75 | 0p: false | 76 | 0p: false |
76 | 240p: true | 77 | 240p: true |
@@ -106,6 +107,7 @@ live: | |||
106 | 107 | ||
107 | import: | 108 | import: |
108 | videos: | 109 | videos: |
110 | concurrency: 2 | ||
109 | http: | 111 | http: |
110 | enabled: true | 112 | enabled: true |
111 | proxy: | 113 | proxy: |
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts index eb620aeca..5f56d6d36 100755 --- a/scripts/create-transcoding-job.ts +++ b/scripts/create-transcoding-job.ts | |||
@@ -53,7 +53,8 @@ async function run () { | |||
53 | videoUUID: video.uuid, | 53 | videoUUID: video.uuid, |
54 | resolution, | 54 | resolution, |
55 | isPortraitMode: false, | 55 | isPortraitMode: false, |
56 | copyCodecs: false | 56 | copyCodecs: false, |
57 | isMaxQuality: false | ||
57 | }) | 58 | }) |
58 | } | 59 | } |
59 | } else if (options.resolution !== undefined) { | 60 | } else if (options.resolution !== undefined) { |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 7fda06a87..5c242da04 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -417,6 +417,7 @@ function customConfig (): CustomConfig { | |||
417 | allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, | 417 | allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, |
418 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, | 418 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, |
419 | threads: CONFIG.TRANSCODING.THREADS, | 419 | threads: CONFIG.TRANSCODING.THREADS, |
420 | concurrency: CONFIG.TRANSCODING.CONCURRENCY, | ||
420 | profile: CONFIG.TRANSCODING.PROFILE, | 421 | profile: CONFIG.TRANSCODING.PROFILE, |
421 | resolutions: { | 422 | resolutions: { |
422 | '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'], | 423 | '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'], |
@@ -458,6 +459,7 @@ function customConfig (): CustomConfig { | |||
458 | }, | 459 | }, |
459 | import: { | 460 | import: { |
460 | videos: { | 461 | videos: { |
462 | concurrency: CONFIG.IMPORT.VIDEOS.CONCURRENCY, | ||
461 | http: { | 463 | http: { |
462 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | 464 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED |
463 | }, | 465 | }, |
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts index 979c97a8b..2b00e2047 100644 --- a/server/initializers/checker-after-init.ts +++ b/server/initializers/checker-after-init.ts | |||
@@ -116,6 +116,16 @@ function checkConfig () { | |||
116 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && CONFIG.TRANSCODING.HLS.ENABLED === false) { | 116 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && CONFIG.TRANSCODING.HLS.ENABLED === false) { |
117 | return 'You need to enable at least WebTorrent transcoding or HLS transcoding.' | 117 | return 'You need to enable at least WebTorrent transcoding or HLS transcoding.' |
118 | } | 118 | } |
119 | |||
120 | if (CONFIG.TRANSCODING.CONCURRENCY <= 0) { | ||
121 | return 'Transcoding concurrency should be > 0' | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED || CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED) { | ||
126 | if (CONFIG.IMPORT.VIDEOS.CONCURRENCY <= 0) { | ||
127 | return 'Video import concurrency should be > 0' | ||
128 | } | ||
119 | } | 129 | } |
120 | 130 | ||
121 | // Broadcast message | 131 | // Broadcast message |
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index cac24f0b6..a186afbdd 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -22,10 +22,10 @@ function checkMissedConfig () { | |||
22 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', | 22 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', |
23 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', | 23 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', |
24 | 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', | 24 | 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', |
25 | 'transcoding.profile', | 25 | 'transcoding.profile', 'transcoding.concurrency', |
26 | 'transcoding.resolutions.0p', 'transcoding.resolutions.240p', 'transcoding.resolutions.360p', 'transcoding.resolutions.480p', | 26 | 'transcoding.resolutions.0p', 'transcoding.resolutions.240p', 'transcoding.resolutions.360p', 'transcoding.resolutions.480p', |
27 | 'transcoding.resolutions.720p', 'transcoding.resolutions.1080p', 'transcoding.resolutions.1440p', 'transcoding.resolutions.2160p', | 27 | 'transcoding.resolutions.720p', 'transcoding.resolutions.1080p', 'transcoding.resolutions.1440p', 'transcoding.resolutions.2160p', |
28 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'auto_blacklist.videos.of_users.enabled', | 28 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled', |
29 | 'trending.videos.interval_days', | 29 | 'trending.videos.interval_days', |
30 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', | 30 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', |
31 | 'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', | 31 | 'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 3b44d82ed..930fd784e 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -188,6 +188,7 @@ const CONFIG = { | |||
188 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, | 188 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, |
189 | get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') }, | 189 | get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') }, |
190 | get THREADS () { return config.get<number>('transcoding.threads') }, | 190 | get THREADS () { return config.get<number>('transcoding.threads') }, |
191 | get CONCURRENCY () { return config.get<number>('transcoding.concurrency') }, | ||
191 | get PROFILE () { return config.get<string>('transcoding.profile') }, | 192 | get PROFILE () { return config.get<string>('transcoding.profile') }, |
192 | RESOLUTIONS: { | 193 | RESOLUTIONS: { |
193 | get '0p' () { return config.get<boolean>('transcoding.resolutions.0p') }, | 194 | get '0p' () { return config.get<boolean>('transcoding.resolutions.0p') }, |
@@ -237,6 +238,8 @@ const CONFIG = { | |||
237 | }, | 238 | }, |
238 | IMPORT: { | 239 | IMPORT: { |
239 | VIDEOS: { | 240 | VIDEOS: { |
241 | get CONCURRENCY () { return config.get<number>('import.videos.concurrency') }, | ||
242 | |||
240 | HTTP: { | 243 | HTTP: { |
241 | get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }, | 244 | get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }, |
242 | get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') }, | 245 | get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') }, |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 9d9b3966c..7beaca238 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -146,14 +146,12 @@ const JOB_ATTEMPTS: { [id in JobType]: number } = { | |||
146 | 'video-redundancy': 1, | 146 | 'video-redundancy': 1, |
147 | 'video-live-ending': 1 | 147 | 'video-live-ending': 1 |
148 | } | 148 | } |
149 | const JOB_CONCURRENCY: { [id in JobType]: number } = { | 149 | const JOB_CONCURRENCY: { [id in JobType]?: number } = { |
150 | 'activitypub-http-broadcast': 1, | 150 | 'activitypub-http-broadcast': 1, |
151 | 'activitypub-http-unicast': 5, | 151 | 'activitypub-http-unicast': 5, |
152 | 'activitypub-http-fetcher': 1, | 152 | 'activitypub-http-fetcher': 1, |
153 | 'activitypub-follow': 1, | 153 | 'activitypub-follow': 1, |
154 | 'video-file-import': 1, | 154 | 'video-file-import': 1, |
155 | 'video-transcoding': 1, | ||
156 | 'video-import': 1, | ||
157 | 'email': 5, | 155 | 'email': 5, |
158 | 'videos-views': 1, | 156 | 'videos-views': 1, |
159 | 'activitypub-refresher': 1, | 157 | 'activitypub-refresher': 1, |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 4718a7d5c..e248b645e 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -76,7 +76,7 @@ async function processVideoTranscoding (job: Bull.Job) { | |||
76 | // Job handlers | 76 | // Job handlers |
77 | // --------------------------------------------------------------------------- | 77 | // --------------------------------------------------------------------------- |
78 | 78 | ||
79 | async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, video: MVideoFullLight) { | 79 | async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, video: MVideoFullLight, user: MUser) { |
80 | const videoFileInput = payload.copyCodecs | 80 | const videoFileInput = payload.copyCodecs |
81 | ? video.getWebTorrentFile(payload.resolution) | 81 | ? video.getWebTorrentFile(payload.resolution) |
82 | : video.getMaxQualityFile() | 82 | : video.getMaxQualityFile() |
@@ -93,7 +93,7 @@ async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, vide | |||
93 | job | 93 | job |
94 | }) | 94 | }) |
95 | 95 | ||
96 | await retryTransactionWrapper(onHlsPlaylistGeneration, video, payload.resolution) | 96 | await retryTransactionWrapper(onHlsPlaylistGeneration, video, user, payload) |
97 | } | 97 | } |
98 | 98 | ||
99 | async function handleNewWebTorrentResolutionJob ( | 99 | async function handleNewWebTorrentResolutionJob ( |
@@ -110,9 +110,7 @@ async function handleNewWebTorrentResolutionJob ( | |||
110 | async function handleWebTorrentMergeAudioJob (job: Bull.Job, payload: MergeAudioTranscodingPayload, video: MVideoFullLight, user: MUserId) { | 110 | async function handleWebTorrentMergeAudioJob (job: Bull.Job, payload: MergeAudioTranscodingPayload, video: MVideoFullLight, user: MUserId) { |
111 | await mergeAudioVideofile(video, payload.resolution, job) | 111 | await mergeAudioVideofile(video, payload.resolution, job) |
112 | 112 | ||
113 | await retryTransactionWrapper(onNewWebTorrentFileResolution, video, user, payload) | 113 | await retryTransactionWrapper(onVideoFileOptimizer, video, payload, 'video', user) |
114 | |||
115 | await createLowerResolutionsJobs(video, user, payload.resolution, false) | ||
116 | } | 114 | } |
117 | 115 | ||
118 | async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTranscodingPayload, video: MVideoFullLight, user: MUserId) { | 116 | async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTranscodingPayload, video: MVideoFullLight, user: MUserId) { |
@@ -123,13 +121,11 @@ async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTran | |||
123 | 121 | ||
124 | // --------------------------------------------------------------------------- | 122 | // --------------------------------------------------------------------------- |
125 | 123 | ||
126 | async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: number) { | 124 | async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, payload: HLSTranscodingPayload) { |
127 | if (video === undefined) return undefined | 125 | if (video === undefined) return undefined |
128 | 126 | ||
129 | const maxQualityFile = video.getMaxQualityFile() | 127 | if (payload.isMaxQuality && CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false) { |
130 | 128 | // Remove webtorrent files if not enabled | |
131 | // We generated the max quality HLS playlist, we don't need the webtorrent files anymore if the admin disabled it | ||
132 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && video.hasWebTorrentFiles() && maxQualityFile.resolution === resolution) { | ||
133 | for (const file of video.VideoFiles) { | 129 | for (const file of video.VideoFiles) { |
134 | await video.removeFile(file) | 130 | await video.removeFile(file) |
135 | await video.removeTorrent(file) | 131 | await video.removeTorrent(file) |
@@ -137,6 +133,9 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: numb | |||
137 | } | 133 | } |
138 | 134 | ||
139 | video.VideoFiles = [] | 135 | video.VideoFiles = [] |
136 | |||
137 | // Create HLS new resolution jobs | ||
138 | await createLowerResolutionsJobs(video, user, payload.resolution, payload.isPortraitMode, 'hls') | ||
140 | } | 139 | } |
141 | 140 | ||
142 | return publishAndFederateIfNeeded(video) | 141 | return publishAndFederateIfNeeded(video) |
@@ -144,7 +143,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: numb | |||
144 | 143 | ||
145 | async function onVideoFileOptimizer ( | 144 | async function onVideoFileOptimizer ( |
146 | videoArg: MVideoWithFile, | 145 | videoArg: MVideoWithFile, |
147 | payload: OptimizeTranscodingPayload, | 146 | payload: OptimizeTranscodingPayload | MergeAudioTranscodingPayload, |
148 | transcodeType: TranscodeOptionsType, | 147 | transcodeType: TranscodeOptionsType, |
149 | user: MUserId | 148 | user: MUserId |
150 | ) { | 149 | ) { |
@@ -166,11 +165,12 @@ async function onVideoFileOptimizer ( | |||
166 | isPortraitMode, | 165 | isPortraitMode, |
167 | resolution: videoDatabase.getMaxQualityFile().resolution, | 166 | resolution: videoDatabase.getMaxQualityFile().resolution, |
168 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues | 167 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues |
169 | copyCodecs: transcodeType !== 'quick-transcode' | 168 | copyCodecs: transcodeType !== 'quick-transcode', |
169 | isMaxQuality: true | ||
170 | }) | 170 | }) |
171 | await createHlsJobIfEnabled(user, originalFileHLSPayload) | 171 | await createHlsJobIfEnabled(user, originalFileHLSPayload) |
172 | 172 | ||
173 | const hasNewResolutions = createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode) | 173 | const hasNewResolutions = await createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode, 'webtorrent') |
174 | 174 | ||
175 | if (!hasNewResolutions) { | 175 | if (!hasNewResolutions) { |
176 | // No transcoding to do, it's now published | 176 | // No transcoding to do, it's now published |
@@ -193,7 +193,7 @@ async function onNewWebTorrentFileResolution ( | |||
193 | ) { | 193 | ) { |
194 | await publishAndFederateIfNeeded(video) | 194 | await publishAndFederateIfNeeded(video) |
195 | 195 | ||
196 | await createHlsJobIfEnabled(user, Object.assign({}, payload, { copyCodecs: true })) | 196 | await createHlsJobIfEnabled(user, Object.assign({}, payload, { copyCodecs: true, isMaxQuality: false })) |
197 | } | 197 | } |
198 | 198 | ||
199 | // --------------------------------------------------------------------------- | 199 | // --------------------------------------------------------------------------- |
@@ -210,6 +210,7 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { | |||
210 | resolution: number | 210 | resolution: number |
211 | isPortraitMode?: boolean | 211 | isPortraitMode?: boolean |
212 | copyCodecs: boolean | 212 | copyCodecs: boolean |
213 | isMaxQuality: boolean | ||
213 | }) { | 214 | }) { |
214 | if (!payload || CONFIG.TRANSCODING.HLS.ENABLED !== true) return | 215 | if (!payload || CONFIG.TRANSCODING.HLS.ENABLED !== true) return |
215 | 216 | ||
@@ -222,7 +223,8 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { | |||
222 | videoUUID: payload.videoUUID, | 223 | videoUUID: payload.videoUUID, |
223 | resolution: payload.resolution, | 224 | resolution: payload.resolution, |
224 | isPortraitMode: payload.isPortraitMode, | 225 | isPortraitMode: payload.isPortraitMode, |
225 | copyCodecs: payload.copyCodecs | 226 | copyCodecs: payload.copyCodecs, |
227 | isMaxQuality: payload.isMaxQuality | ||
226 | } | 228 | } |
227 | 229 | ||
228 | return JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: hlsTranscodingPayload }, jobOptions) | 230 | return JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: hlsTranscodingPayload }, jobOptions) |
@@ -232,7 +234,8 @@ async function createLowerResolutionsJobs ( | |||
232 | video: MVideoFullLight, | 234 | video: MVideoFullLight, |
233 | user: MUserId, | 235 | user: MUserId, |
234 | videoFileResolution: number, | 236 | videoFileResolution: number, |
235 | isPortraitMode: boolean | 237 | isPortraitMode: boolean, |
238 | type: 'hls' | 'webtorrent' | ||
236 | ) { | 239 | ) { |
237 | // Create transcoding jobs if there are enabled resolutions | 240 | // Create transcoding jobs if there are enabled resolutions |
238 | const resolutionsEnabled = computeResolutionsToTranscode(videoFileResolution, 'vod') | 241 | const resolutionsEnabled = computeResolutionsToTranscode(videoFileResolution, 'vod') |
@@ -250,7 +253,7 @@ async function createLowerResolutionsJobs ( | |||
250 | for (const resolution of resolutionsEnabled) { | 253 | for (const resolution of resolutionsEnabled) { |
251 | let dataInput: VideoTranscodingPayload | 254 | let dataInput: VideoTranscodingPayload |
252 | 255 | ||
253 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED) { | 256 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { |
254 | // WebTorrent will create subsequent HLS job | 257 | // WebTorrent will create subsequent HLS job |
255 | dataInput = { | 258 | dataInput = { |
256 | type: 'new-resolution-to-webtorrent', | 259 | type: 'new-resolution-to-webtorrent', |
@@ -258,13 +261,16 @@ async function createLowerResolutionsJobs ( | |||
258 | resolution, | 261 | resolution, |
259 | isPortraitMode | 262 | isPortraitMode |
260 | } | 263 | } |
261 | } else if (CONFIG.TRANSCODING.HLS.ENABLED) { | 264 | } |
265 | |||
266 | if (CONFIG.TRANSCODING.HLS.ENABLED && type === 'hls') { | ||
262 | dataInput = { | 267 | dataInput = { |
263 | type: 'new-resolution-to-hls', | 268 | type: 'new-resolution-to-hls', |
264 | videoUUID: video.uuid, | 269 | videoUUID: video.uuid, |
265 | resolution, | 270 | resolution, |
266 | isPortraitMode, | 271 | isPortraitMode, |
267 | copyCodecs: false | 272 | copyCodecs: false, |
273 | isMaxQuality: false | ||
268 | } | 274 | } |
269 | } | 275 | } |
270 | 276 | ||
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index 38b1d6f1f..72fed6072 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { jobStates } from '@server/helpers/custom-validators/jobs' | 2 | import { jobStates } from '@server/helpers/custom-validators/jobs' |
3 | import { CONFIG } from '@server/initializers/config' | ||
3 | import { processVideoRedundancy } from '@server/lib/job-queue/handlers/video-redundancy' | 4 | import { processVideoRedundancy } from '@server/lib/job-queue/handlers/video-redundancy' |
4 | import { | 5 | import { |
5 | ActivitypubFollowPayload, | 6 | ActivitypubFollowPayload, |
@@ -105,11 +106,11 @@ class JobQueue { | |||
105 | } | 106 | } |
106 | } | 107 | } |
107 | 108 | ||
108 | for (const handlerName of Object.keys(handlers)) { | 109 | for (const handlerName of (Object.keys(handlers) as JobType[])) { |
109 | const queue = new Bull(handlerName, queueOptions) | 110 | const queue = new Bull(handlerName, queueOptions) |
110 | const handler = handlers[handlerName] | 111 | const handler = handlers[handlerName] |
111 | 112 | ||
112 | queue.process(JOB_CONCURRENCY[handlerName], handler) | 113 | queue.process(this.getJobConcurrency(handlerName), handler) |
113 | .catch(err => logger.error('Error in job queue processor %s.', handlerName, { err })) | 114 | .catch(err => logger.error('Error in job queue processor %s.', handlerName, { err })) |
114 | 115 | ||
115 | queue.on('failed', (job, err) => { | 116 | queue.on('failed', (job, err) => { |
@@ -235,6 +236,13 @@ class JobQueue { | |||
235 | return jobTypes.filter(t => t === jobType) | 236 | return jobTypes.filter(t => t === jobType) |
236 | } | 237 | } |
237 | 238 | ||
239 | private getJobConcurrency (jobType: JobType) { | ||
240 | if (jobType === 'video-transcoding') return CONFIG.TRANSCODING.CONCURRENCY | ||
241 | if (jobType === 'video-import') return CONFIG.IMPORT.VIDEOS.CONCURRENCY | ||
242 | |||
243 | return JOB_CONCURRENCY[jobType] | ||
244 | } | ||
245 | |||
238 | static get Instance () { | 246 | static get Instance () { |
239 | return this.instance || (this.instance = new this()) | 247 | return this.instance || (this.instance = new this()) |
240 | } | 248 | } |
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index 88a6e0673..a58c9dd20 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts | |||
@@ -272,7 +272,7 @@ async function generateHlsPlaylistCommon (options: { | |||
272 | const { type, video, inputPath, resolution, copyCodecs, isPortraitMode, isAAC, job } = options | 272 | const { type, video, inputPath, resolution, copyCodecs, isPortraitMode, isAAC, job } = options |
273 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | 273 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR |
274 | 274 | ||
275 | const videoTranscodedBasePath = join(transcodeDirectory, type, video.uuid) | 275 | const videoTranscodedBasePath = join(transcodeDirectory, type) |
276 | await ensureDir(videoTranscodedBasePath) | 276 | await ensureDir(videoTranscodedBasePath) |
277 | 277 | ||
278 | const videoFilename = generateVideoStreamingPlaylistName(video.uuid, resolution) | 278 | const videoFilename = generateVideoStreamingPlaylistName(video.uuid, resolution) |
@@ -337,8 +337,6 @@ async function generateHlsPlaylistCommon (options: { | |||
337 | await move(playlistFileTranscodePath, playlistPath, { overwrite: true }) | 337 | await move(playlistFileTranscodePath, playlistPath, { overwrite: true }) |
338 | // Move video file | 338 | // Move video file |
339 | await move(join(videoTranscodedBasePath, videoFilename), videoFilePath, { overwrite: true }) | 339 | await move(join(videoTranscodedBasePath, videoFilename), videoFilePath, { overwrite: true }) |
340 | // Cleanup directory | ||
341 | await remove(videoTranscodedBasePath) | ||
342 | 340 | ||
343 | const stats = await stat(videoFilePath) | 341 | const stats = await stat(videoFilePath) |
344 | 342 | ||
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 52c28799f..71098ff99 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -39,6 +39,7 @@ const customConfigUpdateValidator = [ | |||
39 | body('transcoding.enabled').isBoolean().withMessage('Should have a valid transcoding enabled boolean'), | 39 | body('transcoding.enabled').isBoolean().withMessage('Should have a valid transcoding enabled boolean'), |
40 | body('transcoding.allowAdditionalExtensions').isBoolean().withMessage('Should have a valid additional extensions boolean'), | 40 | body('transcoding.allowAdditionalExtensions').isBoolean().withMessage('Should have a valid additional extensions boolean'), |
41 | body('transcoding.threads').isInt().withMessage('Should have a valid transcoding threads number'), | 41 | body('transcoding.threads').isInt().withMessage('Should have a valid transcoding threads number'), |
42 | body('transcoding.concurrency').isInt({ min: 1 }).withMessage('Should have a valid transcoding concurrency number'), | ||
42 | body('transcoding.resolutions.0p').isBoolean().withMessage('Should have a valid transcoding 0p resolution enabled boolean'), | 43 | body('transcoding.resolutions.0p').isBoolean().withMessage('Should have a valid transcoding 0p resolution enabled boolean'), |
43 | body('transcoding.resolutions.240p').isBoolean().withMessage('Should have a valid transcoding 240p resolution enabled boolean'), | 44 | body('transcoding.resolutions.240p').isBoolean().withMessage('Should have a valid transcoding 240p resolution enabled boolean'), |
44 | body('transcoding.resolutions.360p').isBoolean().withMessage('Should have a valid transcoding 360p resolution enabled boolean'), | 45 | body('transcoding.resolutions.360p').isBoolean().withMessage('Should have a valid transcoding 360p resolution enabled boolean'), |
@@ -51,6 +52,7 @@ const customConfigUpdateValidator = [ | |||
51 | body('transcoding.webtorrent.enabled').isBoolean().withMessage('Should have a valid webtorrent transcoding enabled boolean'), | 52 | body('transcoding.webtorrent.enabled').isBoolean().withMessage('Should have a valid webtorrent transcoding enabled boolean'), |
52 | body('transcoding.hls.enabled').isBoolean().withMessage('Should have a valid hls transcoding enabled boolean'), | 53 | body('transcoding.hls.enabled').isBoolean().withMessage('Should have a valid hls transcoding enabled boolean'), |
53 | 54 | ||
55 | body('import.videos.concurrency').isInt({ min: 0 }).withMessage('Should have a valid import concurrency number'), | ||
54 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), | 56 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), |
55 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), | 57 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), |
56 | 58 | ||
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 3f6fd8dc0..14e80a3ba 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -345,7 +345,6 @@ export type AvailableForListIDsOptions = { | |||
345 | include: [ | 345 | include: [ |
346 | { | 346 | { |
347 | model: VideoFileModel, | 347 | model: VideoFileModel, |
348 | separate: true, // We may have multiple files, having multiple redundancies so let's separate this join | ||
349 | required: false, | 348 | required: false, |
350 | include: subInclude | 349 | include: subInclude |
351 | } | 350 | } |
@@ -372,7 +371,6 @@ export type AvailableForListIDsOptions = { | |||
372 | include: [ | 371 | include: [ |
373 | { | 372 | { |
374 | model: VideoStreamingPlaylistModel.unscoped(), | 373 | model: VideoStreamingPlaylistModel.unscoped(), |
375 | separate: true, // We may have multiple streaming playlists, having multiple redundancies so let's separate this join | ||
376 | required: false, | 374 | required: false, |
377 | include: subInclude | 375 | include: subInclude |
378 | } | 376 | } |
@@ -1689,7 +1687,7 @@ export class VideoModel extends Model { | |||
1689 | 1687 | ||
1690 | channelModel.Account = accountModel | 1688 | channelModel.Account = accountModel |
1691 | 1689 | ||
1692 | const videoModel = new VideoModel(pick(row, videoKeys)) | 1690 | const videoModel = new VideoModel(pick(row, videoKeys), buildOpts) |
1693 | videoModel.VideoChannel = channelModel | 1691 | videoModel.VideoChannel = channelModel |
1694 | 1692 | ||
1695 | videoModel.UserVideoHistories = [] | 1693 | videoModel.UserVideoHistories = [] |
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index d6c20f7af..c7eb3189b 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -86,6 +86,7 @@ describe('Test config API validators', function () { | |||
86 | enabled: true, | 86 | enabled: true, |
87 | allowAdditionalExtensions: true, | 87 | allowAdditionalExtensions: true, |
88 | allowAudioFiles: true, | 88 | allowAudioFiles: true, |
89 | concurrency: 1, | ||
89 | threads: 1, | 90 | threads: 1, |
90 | profile: 'vod_profile', | 91 | profile: 'vod_profile', |
91 | resolutions: { | 92 | resolutions: { |
@@ -130,6 +131,7 @@ describe('Test config API validators', function () { | |||
130 | }, | 131 | }, |
131 | import: { | 132 | import: { |
132 | videos: { | 133 | videos: { |
134 | concurrency: 1, | ||
133 | http: { | 135 | http: { |
134 | enabled: false | 136 | enabled: false |
135 | }, | 137 | }, |
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index 26df8373e..b2371614f 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -70,6 +70,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) { | |||
70 | expect(data.transcoding.allowAdditionalExtensions).to.be.false | 70 | expect(data.transcoding.allowAdditionalExtensions).to.be.false |
71 | expect(data.transcoding.allowAudioFiles).to.be.false | 71 | expect(data.transcoding.allowAudioFiles).to.be.false |
72 | expect(data.transcoding.threads).to.equal(2) | 72 | expect(data.transcoding.threads).to.equal(2) |
73 | expect(data.transcoding.concurrency).to.equal(2) | ||
73 | expect(data.transcoding.profile).to.equal('default') | 74 | expect(data.transcoding.profile).to.equal('default') |
74 | expect(data.transcoding.resolutions['240p']).to.be.true | 75 | expect(data.transcoding.resolutions['240p']).to.be.true |
75 | expect(data.transcoding.resolutions['360p']).to.be.true | 76 | expect(data.transcoding.resolutions['360p']).to.be.true |
@@ -97,6 +98,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) { | |||
97 | expect(data.live.transcoding.resolutions['1440p']).to.be.false | 98 | expect(data.live.transcoding.resolutions['1440p']).to.be.false |
98 | expect(data.live.transcoding.resolutions['2160p']).to.be.false | 99 | expect(data.live.transcoding.resolutions['2160p']).to.be.false |
99 | 100 | ||
101 | expect(data.import.videos.concurrency).to.equal(2) | ||
100 | expect(data.import.videos.http.enabled).to.be.true | 102 | expect(data.import.videos.http.enabled).to.be.true |
101 | expect(data.import.videos.torrent.enabled).to.be.true | 103 | expect(data.import.videos.torrent.enabled).to.be.true |
102 | expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.false | 104 | expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.false |
@@ -159,6 +161,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
159 | 161 | ||
160 | expect(data.transcoding.enabled).to.be.true | 162 | expect(data.transcoding.enabled).to.be.true |
161 | expect(data.transcoding.threads).to.equal(1) | 163 | expect(data.transcoding.threads).to.equal(1) |
164 | expect(data.transcoding.concurrency).to.equal(3) | ||
162 | expect(data.transcoding.allowAdditionalExtensions).to.be.true | 165 | expect(data.transcoding.allowAdditionalExtensions).to.be.true |
163 | expect(data.transcoding.allowAudioFiles).to.be.true | 166 | expect(data.transcoding.allowAudioFiles).to.be.true |
164 | expect(data.transcoding.profile).to.equal('vod_profile') | 167 | expect(data.transcoding.profile).to.equal('vod_profile') |
@@ -186,6 +189,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
186 | expect(data.live.transcoding.resolutions['1080p']).to.be.true | 189 | expect(data.live.transcoding.resolutions['1080p']).to.be.true |
187 | expect(data.live.transcoding.resolutions['2160p']).to.be.true | 190 | expect(data.live.transcoding.resolutions['2160p']).to.be.true |
188 | 191 | ||
192 | expect(data.import.videos.concurrency).to.equal(4) | ||
189 | expect(data.import.videos.http.enabled).to.be.false | 193 | expect(data.import.videos.http.enabled).to.be.false |
190 | expect(data.import.videos.torrent.enabled).to.be.false | 194 | expect(data.import.videos.torrent.enabled).to.be.false |
191 | expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.true | 195 | expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.true |
@@ -323,6 +327,7 @@ describe('Test config', function () { | |||
323 | allowAdditionalExtensions: true, | 327 | allowAdditionalExtensions: true, |
324 | allowAudioFiles: true, | 328 | allowAudioFiles: true, |
325 | threads: 1, | 329 | threads: 1, |
330 | concurrency: 3, | ||
326 | profile: 'vod_profile', | 331 | profile: 'vod_profile', |
327 | resolutions: { | 332 | resolutions: { |
328 | '0p': false, | 333 | '0p': false, |
@@ -364,6 +369,7 @@ describe('Test config', function () { | |||
364 | }, | 369 | }, |
365 | import: { | 370 | import: { |
366 | videos: { | 371 | videos: { |
372 | concurrency: 4, | ||
367 | http: { | 373 | http: { |
368 | enabled: false | 374 | enabled: false |
369 | }, | 375 | }, |
diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts index db5a473ca..efe569243 100644 --- a/shared/extra-utils/server/config.ts +++ b/shared/extra-utils/server/config.ts | |||
@@ -112,6 +112,7 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
112 | allowAdditionalExtensions: true, | 112 | allowAdditionalExtensions: true, |
113 | allowAudioFiles: true, | 113 | allowAudioFiles: true, |
114 | threads: 1, | 114 | threads: 1, |
115 | concurrency: 3, | ||
115 | profile: 'default', | 116 | profile: 'default', |
116 | resolutions: { | 117 | resolutions: { |
117 | '0p': false, | 118 | '0p': false, |
@@ -153,6 +154,7 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
153 | }, | 154 | }, |
154 | import: { | 155 | import: { |
155 | videos: { | 156 | videos: { |
157 | concurrency: 3, | ||
156 | http: { | 158 | http: { |
157 | enabled: false | 159 | enabled: false |
158 | }, | 160 | }, |
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index d23b8abef..93b2d3417 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -87,6 +87,7 @@ export interface CustomConfig { | |||
87 | allowAudioFiles: boolean | 87 | allowAudioFiles: boolean |
88 | 88 | ||
89 | threads: number | 89 | threads: number |
90 | concurrency: number | ||
90 | 91 | ||
91 | profile: string | 92 | profile: string |
92 | 93 | ||
@@ -120,6 +121,8 @@ export interface CustomConfig { | |||
120 | 121 | ||
121 | import: { | 122 | import: { |
122 | videos: { | 123 | videos: { |
124 | concurrency: number | ||
125 | |||
123 | http: { | 126 | http: { |
124 | enabled: boolean | 127 | enabled: boolean |
125 | } | 128 | } |
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index ddd678b91..44f92abf1 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -106,6 +106,7 @@ export interface HLSTranscodingPayload extends BaseTranscodingPayload { | |||
106 | isPortraitMode?: boolean | 106 | isPortraitMode?: boolean |
107 | resolution: VideoResolution | 107 | resolution: VideoResolution |
108 | copyCodecs: boolean | 108 | copyCodecs: boolean |
109 | isMaxQuality: boolean | ||
109 | } | 110 | } |
110 | 111 | ||
111 | export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | 112 | export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { |