@@ -436,8 +436,25 @@ | |||
<div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | |||
<ng-container formGroupName="import"> | |||
<ng-container formGroupName="videos"> | |||
<div class="form-group mt-4"> | |||
<label i18n for="importConcurrency">Import jobs concurrency</label> | |||
<span class="text-muted ml-1"> | |||
<span i18n>allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span> | |||
</span> | |||
<div class="peertube-select-container"> | |||
<select id="importConcurrency" formControlName="concurrency" class="form-control"> | |||
<option *ngFor="let option of concurrencyOptions" [value]="option"> | |||
{{ option }} | |||
</option> | |||
</select> | |||
</div> | |||
<div *ngIf="formErrors.import.concurrency" class="form-error">{{ formErrors.import.concurrency }}</div> | |||
</div> | |||
<div class="form-group" formGroupName="http"> | |||
<my-peertube-checkbox | |||
inputName="importVideosHttpEnabled" formControlName="enabled" | |||
@@ -885,6 +902,22 @@ | |||
<div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div> | |||
</div> | |||
<div class="form-group mt-4" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }"> | |||
<label i18n for="transcodingConcurrency">Transcoding jobs concurrency</label> | |||
<span class="text-muted ml-1"> | |||
<span i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart.</span> | |||
</span> | |||
<div class="peertube-select-container"> | |||
<select id="transcodingConcurrency" formControlName="concurrency" class="form-control"> | |||
<option *ngFor="let option of concurrencyOptions" [value]="option"> | |||
{{ option }} | |||
</option> | |||
</select> | |||
</div> | |||
<div *ngIf="formErrors.transcoding.concurrency" class="form-error">{{ formErrors.transcoding.concurrency }}</div> | |||
</div> | |||
<div class="form-group mt-4" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }"> | |||
<label i18n for="transcodingProfile">Transcoding profile</label> | |||
<span class="text-muted ml-1" i18n>new transcoding profiles can be added by PeerTube plugins</span> | |||
@@ -9,6 +9,7 @@ import { | |||
ADMIN_EMAIL_VALIDATOR, | |||
CACHE_CAPTIONS_SIZE_VALIDATOR, | |||
CACHE_PREVIEWS_SIZE_VALIDATOR, | |||
CONCURRENCY_VALIDATOR, | |||
INDEX_URL_VALIDATOR, | |||
INSTANCE_NAME_VALIDATOR, | |||
INSTANCE_SHORT_DESCRIPTION_VALIDATOR, | |||
@@ -36,6 +37,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
resolutions: { id: string, label: string, description?: string }[] = [] | |||
liveResolutions: { id: string, label: string, description?: string }[] = [] | |||
concurrencyOptions: number[] = [] | |||
transcodingThreadOptions: { label: string, value: number }[] = [] | |||
liveMaxDurationOptions: { label: string, value: number }[] = [] | |||
@@ -103,6 +105,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
{ value: 4, label: '4' }, | |||
{ value: 8, label: '8' } | |||
] | |||
this.concurrencyOptions = [ 1, 2, 3, 4, 5, 6 ] | |||
this.vodTranscodingProfileOptions = [ 'default' ] | |||
this.liveTranscodingProfileOptions = [ 'default' ] | |||
@@ -230,6 +233,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
}, | |||
import: { | |||
videos: { | |||
concurrency: CONCURRENCY_VALIDATOR, | |||
http: { | |||
enabled: null | |||
}, | |||
@@ -262,6 +266,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A | |||
allowAdditionalExtensions: null, | |||
allowAudioFiles: null, | |||
profile: null, | |||
concurrency: CONCURRENCY_VALIDATOR, | |||
resolutions: {}, | |||
hls: { | |||
enabled: null | |||
@@ -65,6 +65,14 @@ export const TRANSCODING_THREADS_VALIDATOR: BuildFormValidator = { | |||
} | |||
} | |||
export const CONCURRENCY_VALIDATOR: BuildFormValidator = { | |||
VALIDATORS: [Validators.required, Validators.min(1)], | |||
MESSAGES: { | |||
'required': $localize`Concurrency is required.`, | |||
'min': $localize`Concurrency should be greater or equal to 1.` | |||
} | |||
} | |||
export const INDEX_URL_VALIDATOR: BuildFormValidator = { | |||
VALIDATORS: [Validators.pattern(/^https:\/\//)], | |||
MESSAGES: { | |||
@@ -233,7 +233,10 @@ transcoding: | |||
# If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | |||
allow_audio_files: true | |||
# Amount of threads used by ffmpeg for 1 transcoding job | |||
threads: 1 | |||
# Amount of transcoding jobs to execute in parallel | |||
concurrency: 1 | |||
# Choose the transcoding profile | |||
# New profiles can be added by plugins | |||
@@ -312,6 +315,9 @@ live: | |||
import: | |||
# Add ability for your users to import remote videos (from YouTube, torrent...) | |||
videos: | |||
# Amount of import jobs to execute in parallel | |||
concurrency: 1 | |||
http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | |||
enabled: false | |||
@@ -244,7 +244,10 @@ transcoding: | |||
# If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | |||
allow_audio_files: true | |||
# Amount of threads used by ffmpeg for 1 transcoding job | |||
threads: 1 | |||
# Amount of transcoding jobs to execute in parallel | |||
concurrency: 1 | |||
# Choose the transcoding profile | |||
# New profiles can be added by plugins | |||
@@ -323,6 +326,9 @@ live: | |||
import: | |||
# Add ability for your users to import remote videos (from YouTube, torrent...) | |||
videos: | |||
# Amount of import jobs to execute in parallel | |||
concurrency: 1 | |||
http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | |||
enabled: false | |||
@@ -71,6 +71,7 @@ transcoding: | |||
allow_additional_extensions: false | |||
allow_audio_files: false | |||
threads: 2 | |||
concurrency: 2 | |||
resolutions: | |||
0p: false | |||
240p: true | |||
@@ -106,6 +107,7 @@ live: | |||
import: | |||
videos: | |||
concurrency: 2 | |||
http: | |||
enabled: true | |||
proxy: | |||
@@ -53,7 +53,8 @@ async function run () { | |||
videoUUID: video.uuid, | |||
resolution, | |||
isPortraitMode: false, | |||
copyCodecs: false | |||
copyCodecs: false, | |||
isMaxQuality: false | |||
}) | |||
} | |||
} else if (options.resolution !== undefined) { | |||
@@ -417,6 +417,7 @@ function customConfig (): CustomConfig { | |||
allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, | |||
allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, | |||
threads: CONFIG.TRANSCODING.THREADS, | |||
concurrency: CONFIG.TRANSCODING.CONCURRENCY, | |||
profile: CONFIG.TRANSCODING.PROFILE, | |||
resolutions: { | |||
'0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'], | |||
@@ -458,6 +459,7 @@ function customConfig (): CustomConfig { | |||
}, | |||
import: { | |||
videos: { | |||
concurrency: CONFIG.IMPORT.VIDEOS.CONCURRENCY, | |||
http: { | |||
enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | |||
}, | |||
@@ -116,6 +116,16 @@ function checkConfig () { | |||
if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && CONFIG.TRANSCODING.HLS.ENABLED === false) { | |||
return 'You need to enable at least WebTorrent transcoding or HLS transcoding.' | |||
} | |||
if (CONFIG.TRANSCODING.CONCURRENCY <= 0) { | |||
return 'Transcoding concurrency should be > 0' | |||
} | |||
} | |||
if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED || CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED) { | |||
if (CONFIG.IMPORT.VIDEOS.CONCURRENCY <= 0) { | |||
return 'Video import concurrency should be > 0' | |||
} | |||
} | |||
// Broadcast message | |||
@@ -22,10 +22,10 @@ function checkMissedConfig () { | |||
'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', | |||
'redundancy.videos.strategies', 'redundancy.videos.check_interval', | |||
'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', | |||
'transcoding.profile', | |||
'transcoding.profile', 'transcoding.concurrency', | |||
'transcoding.resolutions.0p', 'transcoding.resolutions.240p', 'transcoding.resolutions.360p', 'transcoding.resolutions.480p', | |||
'transcoding.resolutions.720p', 'transcoding.resolutions.1080p', 'transcoding.resolutions.1440p', 'transcoding.resolutions.2160p', | |||
'import.videos.http.enabled', 'import.videos.torrent.enabled', 'auto_blacklist.videos.of_users.enabled', | |||
'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled', | |||
'trending.videos.interval_days', | |||
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', | |||
'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', | |||
@@ -188,6 +188,7 @@ const CONFIG = { | |||
get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, | |||
get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') }, | |||
get THREADS () { return config.get<number>('transcoding.threads') }, | |||
get CONCURRENCY () { return config.get<number>('transcoding.concurrency') }, | |||
get PROFILE () { return config.get<string>('transcoding.profile') }, | |||
RESOLUTIONS: { | |||
get '0p' () { return config.get<boolean>('transcoding.resolutions.0p') }, | |||
@@ -237,6 +238,8 @@ const CONFIG = { | |||
}, | |||
IMPORT: { | |||
VIDEOS: { | |||
get CONCURRENCY () { return config.get<number>('import.videos.concurrency') }, | |||
HTTP: { | |||
get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }, | |||
get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') }, | |||
@@ -146,14 +146,12 @@ const JOB_ATTEMPTS: { [id in JobType]: number } = { | |||
'video-redundancy': 1, | |||
'video-live-ending': 1 | |||
} | |||
const JOB_CONCURRENCY: { [id in JobType]: number } = { | |||
const JOB_CONCURRENCY: { [id in JobType]?: number } = { | |||
'activitypub-http-broadcast': 1, | |||
'activitypub-http-unicast': 5, | |||
'activitypub-http-fetcher': 1, | |||
'activitypub-follow': 1, | |||
'video-file-import': 1, | |||
'video-transcoding': 1, | |||
'video-import': 1, | |||
'email': 5, | |||
'videos-views': 1, | |||
'activitypub-refresher': 1, | |||
@@ -76,7 +76,7 @@ async function processVideoTranscoding (job: Bull.Job) { | |||
// Job handlers | |||
// --------------------------------------------------------------------------- | |||
async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, video: MVideoFullLight) { | |||
async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, video: MVideoFullLight, user: MUser) { | |||
const videoFileInput = payload.copyCodecs | |||
? video.getWebTorrentFile(payload.resolution) | |||
: video.getMaxQualityFile() | |||
@@ -93,7 +93,7 @@ async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, vide | |||
job | |||
}) | |||
await retryTransactionWrapper(onHlsPlaylistGeneration, video, payload.resolution) | |||
await retryTransactionWrapper(onHlsPlaylistGeneration, video, user, payload) | |||
} | |||
async function handleNewWebTorrentResolutionJob ( | |||
@@ -110,9 +110,7 @@ async function handleNewWebTorrentResolutionJob ( | |||
async function handleWebTorrentMergeAudioJob (job: Bull.Job, payload: MergeAudioTranscodingPayload, video: MVideoFullLight, user: MUserId) { | |||
await mergeAudioVideofile(video, payload.resolution, job) | |||
await retryTransactionWrapper(onNewWebTorrentFileResolution, video, user, payload) | |||
await createLowerResolutionsJobs(video, user, payload.resolution, false) | |||
await retryTransactionWrapper(onVideoFileOptimizer, video, payload, 'video', user) | |||
} | |||
async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTranscodingPayload, video: MVideoFullLight, user: MUserId) { | |||
@@ -123,13 +121,11 @@ async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTran | |||
// --------------------------------------------------------------------------- | |||
async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: number) { | |||
async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, payload: HLSTranscodingPayload) { | |||
if (video === undefined) return undefined | |||
const maxQualityFile = video.getMaxQualityFile() | |||
// We generated the max quality HLS playlist, we don't need the webtorrent files anymore if the admin disabled it | |||
if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && video.hasWebTorrentFiles() && maxQualityFile.resolution === resolution) { | |||
if (payload.isMaxQuality && CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false) { | |||
// Remove webtorrent files if not enabled | |||
for (const file of video.VideoFiles) { | |||
await video.removeFile(file) | |||
await video.removeTorrent(file) | |||
@@ -137,6 +133,9 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: numb | |||
} | |||
video.VideoFiles = [] | |||
// Create HLS new resolution jobs | |||
await createLowerResolutionsJobs(video, user, payload.resolution, payload.isPortraitMode, 'hls') | |||
} | |||
return publishAndFederateIfNeeded(video) | |||
@@ -144,7 +143,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, resolution: numb | |||
async function onVideoFileOptimizer ( | |||
videoArg: MVideoWithFile, | |||
payload: OptimizeTranscodingPayload, | |||
payload: OptimizeTranscodingPayload | MergeAudioTranscodingPayload, | |||
transcodeType: TranscodeOptionsType, | |||
user: MUserId | |||
) { | |||
@@ -166,11 +165,12 @@ async function onVideoFileOptimizer ( | |||
isPortraitMode, | |||
resolution: videoDatabase.getMaxQualityFile().resolution, | |||
// If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues | |||
copyCodecs: transcodeType !== 'quick-transcode' | |||
copyCodecs: transcodeType !== 'quick-transcode', | |||
isMaxQuality: true | |||
}) | |||
await createHlsJobIfEnabled(user, originalFileHLSPayload) | |||
const hasNewResolutions = createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode) | |||
const hasNewResolutions = await createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode, 'webtorrent') | |||
if (!hasNewResolutions) { | |||
// No transcoding to do, it's now published | |||
@@ -193,7 +193,7 @@ async function onNewWebTorrentFileResolution ( | |||
) { | |||
await publishAndFederateIfNeeded(video) | |||
await createHlsJobIfEnabled(user, Object.assign({}, payload, { copyCodecs: true })) | |||
await createHlsJobIfEnabled(user, Object.assign({}, payload, { copyCodecs: true, isMaxQuality: false })) | |||
} | |||
// --------------------------------------------------------------------------- | |||
@@ -210,6 +210,7 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { | |||
resolution: number | |||
isPortraitMode?: boolean | |||
copyCodecs: boolean | |||
isMaxQuality: boolean | |||
}) { | |||
if (!payload || CONFIG.TRANSCODING.HLS.ENABLED !== true) return | |||
@@ -222,7 +223,8 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { | |||
videoUUID: payload.videoUUID, | |||
resolution: payload.resolution, | |||
isPortraitMode: payload.isPortraitMode, | |||
copyCodecs: payload.copyCodecs | |||
copyCodecs: payload.copyCodecs, | |||
isMaxQuality: payload.isMaxQuality | |||
} | |||
return JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: hlsTranscodingPayload }, jobOptions) | |||
@@ -232,7 +234,8 @@ async function createLowerResolutionsJobs ( | |||
video: MVideoFullLight, | |||
user: MUserId, | |||
videoFileResolution: number, | |||
isPortraitMode: boolean | |||
isPortraitMode: boolean, | |||
type: 'hls' | 'webtorrent' | |||
) { | |||
// Create transcoding jobs if there are enabled resolutions | |||
const resolutionsEnabled = computeResolutionsToTranscode(videoFileResolution, 'vod') | |||
@@ -250,7 +253,7 @@ async function createLowerResolutionsJobs ( | |||
for (const resolution of resolutionsEnabled) { | |||
let dataInput: VideoTranscodingPayload | |||
if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED) { | |||
if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { | |||
// WebTorrent will create subsequent HLS job | |||
dataInput = { | |||
type: 'new-resolution-to-webtorrent', | |||
@@ -258,13 +261,16 @@ async function createLowerResolutionsJobs ( | |||
resolution, | |||
isPortraitMode | |||
} | |||
} else if (CONFIG.TRANSCODING.HLS.ENABLED) { | |||
} | |||
if (CONFIG.TRANSCODING.HLS.ENABLED && type === 'hls') { | |||
dataInput = { | |||
type: 'new-resolution-to-hls', | |||
videoUUID: video.uuid, | |||
resolution, | |||
isPortraitMode, | |||
copyCodecs: false | |||
copyCodecs: false, | |||
isMaxQuality: false | |||
} | |||
} | |||
@@ -1,5 +1,6 @@ | |||
import * as Bull from 'bull' | |||
import { jobStates } from '@server/helpers/custom-validators/jobs' | |||
import { CONFIG } from '@server/initializers/config' | |||
import { processVideoRedundancy } from '@server/lib/job-queue/handlers/video-redundancy' | |||
import { | |||
ActivitypubFollowPayload, | |||
@@ -105,11 +106,11 @@ class JobQueue { | |||
} | |||
} | |||
for (const handlerName of Object.keys(handlers)) { | |||
for (const handlerName of (Object.keys(handlers) as JobType[])) { | |||
const queue = new Bull(handlerName, queueOptions) | |||
const handler = handlers[handlerName] | |||
queue.process(JOB_CONCURRENCY[handlerName], handler) | |||
queue.process(this.getJobConcurrency(handlerName), handler) | |||
.catch(err => logger.error('Error in job queue processor %s.', handlerName, { err })) | |||
queue.on('failed', (job, err) => { | |||
@@ -235,6 +236,13 @@ class JobQueue { | |||
return jobTypes.filter(t => t === jobType) | |||
} | |||
private getJobConcurrency (jobType: JobType) { | |||
if (jobType === 'video-transcoding') return CONFIG.TRANSCODING.CONCURRENCY | |||
if (jobType === 'video-import') return CONFIG.IMPORT.VIDEOS.CONCURRENCY | |||
return JOB_CONCURRENCY[jobType] | |||
} | |||
static get Instance () { | |||
return this.instance || (this.instance = new this()) | |||
} | |||
@@ -272,7 +272,7 @@ async function generateHlsPlaylistCommon (options: { | |||
const { type, video, inputPath, resolution, copyCodecs, isPortraitMode, isAAC, job } = options | |||
const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | |||
const videoTranscodedBasePath = join(transcodeDirectory, type, video.uuid) | |||
const videoTranscodedBasePath = join(transcodeDirectory, type) | |||
await ensureDir(videoTranscodedBasePath) | |||
const videoFilename = generateVideoStreamingPlaylistName(video.uuid, resolution) | |||
@@ -337,8 +337,6 @@ async function generateHlsPlaylistCommon (options: { | |||
await move(playlistFileTranscodePath, playlistPath, { overwrite: true }) | |||
// Move video file | |||
await move(join(videoTranscodedBasePath, videoFilename), videoFilePath, { overwrite: true }) | |||
// Cleanup directory | |||
await remove(videoTranscodedBasePath) | |||
const stats = await stat(videoFilePath) | |||
@@ -39,6 +39,7 @@ const customConfigUpdateValidator = [ | |||
body('transcoding.enabled').isBoolean().withMessage('Should have a valid transcoding enabled boolean'), | |||
body('transcoding.allowAdditionalExtensions').isBoolean().withMessage('Should have a valid additional extensions boolean'), | |||
body('transcoding.threads').isInt().withMessage('Should have a valid transcoding threads number'), | |||
body('transcoding.concurrency').isInt({ min: 1 }).withMessage('Should have a valid transcoding concurrency number'), | |||
body('transcoding.resolutions.0p').isBoolean().withMessage('Should have a valid transcoding 0p resolution enabled boolean'), | |||
body('transcoding.resolutions.240p').isBoolean().withMessage('Should have a valid transcoding 240p resolution enabled boolean'), | |||
body('transcoding.resolutions.360p').isBoolean().withMessage('Should have a valid transcoding 360p resolution enabled boolean'), | |||
@@ -51,6 +52,7 @@ const customConfigUpdateValidator = [ | |||
body('transcoding.webtorrent.enabled').isBoolean().withMessage('Should have a valid webtorrent transcoding enabled boolean'), | |||
body('transcoding.hls.enabled').isBoolean().withMessage('Should have a valid hls transcoding enabled boolean'), | |||
body('import.videos.concurrency').isInt({ min: 0 }).withMessage('Should have a valid import concurrency number'), | |||
body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), | |||
body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), | |||
@@ -345,7 +345,6 @@ export type AvailableForListIDsOptions = { | |||
include: [ | |||
{ | |||
model: VideoFileModel, | |||
separate: true, // We may have multiple files, having multiple redundancies so let's separate this join | |||
required: false, | |||
include: subInclude | |||
} | |||
@@ -372,7 +371,6 @@ export type AvailableForListIDsOptions = { | |||
include: [ | |||
{ | |||
model: VideoStreamingPlaylistModel.unscoped(), | |||
separate: true, // We may have multiple streaming playlists, having multiple redundancies so let's separate this join | |||
required: false, | |||
include: subInclude | |||
} | |||
@@ -1689,7 +1687,7 @@ export class VideoModel extends Model { | |||
channelModel.Account = accountModel | |||
const videoModel = new VideoModel(pick(row, videoKeys)) | |||
const videoModel = new VideoModel(pick(row, videoKeys), buildOpts) | |||
videoModel.VideoChannel = channelModel | |||
videoModel.UserVideoHistories = [] | |||
@@ -86,6 +86,7 @@ describe('Test config API validators', function () { | |||
enabled: true, | |||
allowAdditionalExtensions: true, | |||
allowAudioFiles: true, | |||
concurrency: 1, | |||
threads: 1, | |||
profile: 'vod_profile', | |||
resolutions: { | |||
@@ -130,6 +131,7 @@ describe('Test config API validators', function () { | |||
}, | |||
import: { | |||
videos: { | |||
concurrency: 1, | |||
http: { | |||
enabled: false | |||
}, | |||
@@ -70,6 +70,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) { | |||
expect(data.transcoding.allowAdditionalExtensions).to.be.false | |||
expect(data.transcoding.allowAudioFiles).to.be.false | |||
expect(data.transcoding.threads).to.equal(2) | |||
expect(data.transcoding.concurrency).to.equal(2) | |||
expect(data.transcoding.profile).to.equal('default') | |||
expect(data.transcoding.resolutions['240p']).to.be.true | |||
expect(data.transcoding.resolutions['360p']).to.be.true | |||
@@ -97,6 +98,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) { | |||
expect(data.live.transcoding.resolutions['1440p']).to.be.false | |||
expect(data.live.transcoding.resolutions['2160p']).to.be.false | |||
expect(data.import.videos.concurrency).to.equal(2) | |||
expect(data.import.videos.http.enabled).to.be.true | |||
expect(data.import.videos.torrent.enabled).to.be.true | |||
expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.false | |||
@@ -159,6 +161,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
expect(data.transcoding.enabled).to.be.true | |||
expect(data.transcoding.threads).to.equal(1) | |||
expect(data.transcoding.concurrency).to.equal(3) | |||
expect(data.transcoding.allowAdditionalExtensions).to.be.true | |||
expect(data.transcoding.allowAudioFiles).to.be.true | |||
expect(data.transcoding.profile).to.equal('vod_profile') | |||
@@ -186,6 +189,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
expect(data.live.transcoding.resolutions['1080p']).to.be.true | |||
expect(data.live.transcoding.resolutions['2160p']).to.be.true | |||
expect(data.import.videos.concurrency).to.equal(4) | |||
expect(data.import.videos.http.enabled).to.be.false | |||
expect(data.import.videos.torrent.enabled).to.be.false | |||
expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.true | |||
@@ -323,6 +327,7 @@ describe('Test config', function () { | |||
allowAdditionalExtensions: true, | |||
allowAudioFiles: true, | |||
threads: 1, | |||
concurrency: 3, | |||
profile: 'vod_profile', | |||
resolutions: { | |||
'0p': false, | |||
@@ -364,6 +369,7 @@ describe('Test config', function () { | |||
}, | |||
import: { | |||
videos: { | |||
concurrency: 4, | |||
http: { | |||
enabled: false | |||
}, | |||
@@ -112,6 +112,7 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
allowAdditionalExtensions: true, | |||
allowAudioFiles: true, | |||
threads: 1, | |||
concurrency: 3, | |||
profile: 'default', | |||
resolutions: { | |||
'0p': false, | |||
@@ -153,6 +154,7 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti | |||
}, | |||
import: { | |||
videos: { | |||
concurrency: 3, | |||
http: { | |||
enabled: false | |||
}, | |||
@@ -87,6 +87,7 @@ export interface CustomConfig { | |||
allowAudioFiles: boolean | |||
threads: number | |||
concurrency: number | |||
profile: string | |||
@@ -120,6 +121,8 @@ export interface CustomConfig { | |||
import: { | |||
videos: { | |||
concurrency: number | |||
http: { | |||
enabled: boolean | |||
} | |||
@@ -106,6 +106,7 @@ export interface HLSTranscodingPayload extends BaseTranscodingPayload { | |||
isPortraitMode?: boolean | |||
resolution: VideoResolution | |||
copyCodecs: boolean | |||
isMaxQuality: boolean | |||
} | |||
export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | |||