Fix import timeout inconsistency

This commit is contained in:
Chocobozzz 2022-02-09 11:40:47 +01:00
parent 474542d7ac
commit 7630e1c893
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
4 changed files with 37 additions and 34 deletions

View File

@ -90,11 +90,13 @@ export class YoutubeDLCLI {
format: string format: string
output: string output: string
processOptions: execa.NodeOptions processOptions: execa.NodeOptions
timeout: number
additionalYoutubeDLArgs?: string[] additionalYoutubeDLArgs?: string[]
}) { }) {
return this.run({ return this.run({
url: options.url, url: options.url,
processOptions: options.processOptions, processOptions: options.processOptions,
timeout: options.timeout,
args: (options.additionalYoutubeDLArgs || []).concat([ '-f', options.format, '-o', options.output ]) args: (options.additionalYoutubeDLArgs || []).concat([ '-f', options.format, '-o', options.output ])
}) })
} }
@ -145,16 +147,23 @@ export class YoutubeDLCLI {
private async run (options: { private async run (options: {
url: string url: string
args: string[] args: string[]
timeout?: number
processOptions: execa.NodeOptions processOptions: execa.NodeOptions
}) { }) {
const { url, args, processOptions } = options const { url, args, timeout, processOptions } = options
let completeArgs = this.wrapWithProxyOptions(args) let completeArgs = this.wrapWithProxyOptions(args)
completeArgs = this.wrapWithIPOptions(completeArgs) completeArgs = this.wrapWithIPOptions(completeArgs)
completeArgs = this.wrapWithFFmpegOptions(completeArgs) completeArgs = this.wrapWithFFmpegOptions(completeArgs)
const { PYTHON_PATH } = CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE const { PYTHON_PATH } = CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE
const output = await execa(PYTHON_PATH, [ youtubeDLBinaryPath, ...completeArgs, url ], processOptions) const subProcess = execa(PYTHON_PATH, [ youtubeDLBinaryPath, ...completeArgs, url ], processOptions)
if (timeout) {
setTimeout(() => subProcess.cancel(), timeout)
}
const output = await subProcess
logger.debug('Runned youtube-dl command.', { command: output.command, ...lTags() }) logger.debug('Runned youtube-dl command.', { command: output.command, ...lTags() })

View File

@ -77,38 +77,32 @@ class YoutubeDLWrapper {
const youtubeDL = await YoutubeDLCLI.safeGet() const youtubeDL = await YoutubeDLCLI.safeGet()
let timer: NodeJS.Timeout try {
const timeoutPromise = new Promise<string>((_, rej) => { await youtubeDL.download({
timer = setTimeout(() => rej(new Error('YoutubeDL download timeout.')), timeout) url: this.url,
}) format: YoutubeDLCLI.getYoutubeDLVideoFormat(this.enabledResolutions),
output: pathWithoutExtension,
const downloadPromise = youtubeDL.download({ timeout,
url: this.url, processOptions
format: YoutubeDLCLI.getYoutubeDLVideoFormat(this.enabledResolutions),
output: pathWithoutExtension,
processOptions
}).then(() => clearTimeout(timer))
.then(async () => {
// If youtube-dl did not guess an extension for our file, just use .mp4 as default
if (await pathExists(pathWithoutExtension)) {
await move(pathWithoutExtension, pathWithoutExtension + '.mp4')
}
return this.guessVideoPathWithExtension(pathWithoutExtension, fileExt)
}) })
return Promise.race([ downloadPromise, timeoutPromise ]) // If youtube-dl did not guess an extension for our file, just use .mp4 as default
.catch(err => { if (await pathExists(pathWithoutExtension)) {
this.guessVideoPathWithExtension(pathWithoutExtension, fileExt) await move(pathWithoutExtension, pathWithoutExtension + '.mp4')
.then(path => { }
logger.debug('Error in youtube-dl import, deleting file %s.', path, { err, ...lTags() })
return remove(path) return this.guessVideoPathWithExtension(pathWithoutExtension, fileExt)
}) } catch (err) {
.catch(innerErr => logger.error('Cannot remove file in youtubeDL timeout.', { innerErr, ...lTags() })) this.guessVideoPathWithExtension(pathWithoutExtension, fileExt)
.then(path => {
logger.debug('Error in youtube-dl import, deleting file %s.', path, { err, ...lTags() })
throw err return remove(path)
}) })
.catch(innerErr => logger.error('Cannot remove file in youtubeDL timeout.', { innerErr, ...lTags() }))
throw err
}
} }
private async guessVideoPathWithExtension (tmpPath: string, sourceExt: string) { private async guessVideoPathWithExtension (tmpPath: string, sourceExt: string) {

View File

@ -215,7 +215,7 @@ const REQUEST_TIMEOUTS = {
} }
const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days
const VIDEO_IMPORT_TIMEOUT = 1000 * 3600 // 1 hour const VIDEO_IMPORT_TIMEOUT = Math.floor(JOB_TTL['video-import'] * 0.9)
const SCHEDULER_INTERVALS_MS = { const SCHEDULER_INTERVALS_MS = {
ACTOR_FOLLOW_SCORES: 60000 * 60, // 1 hour ACTOR_FOLLOW_SCORES: 60000 * 60, // 1 hour

View File

@ -29,7 +29,7 @@ import { ffprobePromise, getDurationFromVideoFile, getVideoFileFPS, getVideoFile
import { logger } from '../../../helpers/logger' import { logger } from '../../../helpers/logger'
import { getSecureTorrentName } from '../../../helpers/utils' import { getSecureTorrentName } from '../../../helpers/utils'
import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent'
import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants' import { JOB_TTL } from '../../../initializers/constants'
import { sequelizeTypescript } from '../../../initializers/database' import { sequelizeTypescript } from '../../../initializers/database'
import { VideoModel } from '../../../models/video/video' import { VideoModel } from '../../../models/video/video'
import { VideoFileModel } from '../../../models/video/video-file' import { VideoFileModel } from '../../../models/video/video-file'
@ -72,7 +72,7 @@ async function processTorrentImport (job: Job, videoImport: MVideoImportDefault,
torrentName: videoImport.torrentName ? getSecureTorrentName(videoImport.torrentName) : undefined, torrentName: videoImport.torrentName ? getSecureTorrentName(videoImport.torrentName) : undefined,
uri: videoImport.magnetUri uri: videoImport.magnetUri
} }
return processFile(() => downloadWebTorrentVideo(target, VIDEO_IMPORT_TIMEOUT), videoImport, options) return processFile(() => downloadWebTorrentVideo(target, JOB_TTL['video-import']), videoImport, options)
} }
async function processYoutubeDLImport (job: Job, videoImport: MVideoImportDefault, payload: VideoImportYoutubeDLPayload) { async function processYoutubeDLImport (job: Job, videoImport: MVideoImportDefault, payload: VideoImportYoutubeDLPayload) {
@ -83,7 +83,7 @@ async function processYoutubeDLImport (job: Job, videoImport: MVideoImportDefaul
const youtubeDL = new YoutubeDLWrapper(videoImport.targetUrl, ServerConfigManager.Instance.getEnabledResolutions('vod')) const youtubeDL = new YoutubeDLWrapper(videoImport.targetUrl, ServerConfigManager.Instance.getEnabledResolutions('vod'))
return processFile( return processFile(
() => youtubeDL.downloadVideo(payload.fileExt, VIDEO_IMPORT_TIMEOUT), () => youtubeDL.downloadVideo(payload.fileExt, JOB_TTL['video-import']),
videoImport, videoImport,
options options
) )