support format key in ytdlp.json, using the key will ignore the selected preset.
This commit is contained in:
parent
0cb90645cd
commit
c5924b02cc
6 changed files with 92 additions and 19 deletions
|
|
@ -395,7 +395,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
"func": lambda _, msg: logs.append(msg),
|
||||
"level": logging.WARNING,
|
||||
},
|
||||
**merge_config(self.config.ytdl_options, config),
|
||||
**get_opts(preset, merge_config(self.config.ytdl_options, config)),
|
||||
}
|
||||
|
||||
if cookies:
|
||||
|
|
@ -408,7 +408,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
entry = await asyncio.wait_for(
|
||||
fut=asyncio.get_running_loop().run_in_executor(
|
||||
None, extract_info, get_opts(preset, yt_conf), url, bool(self.config.ytdl_debug)
|
||||
None, extract_info, yt_conf, url, bool(self.config.ytdl_debug)
|
||||
),
|
||||
timeout=self.config.extract_info_timeout,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,15 @@ from .Playlist import Playlist
|
|||
from .Segments import Segments
|
||||
from .Subtitle import Subtitle
|
||||
from .Tasks import Task, Tasks
|
||||
from .Utils import StreamingError, arg_converter, calc_download_path, get_video_info, validate_url, validate_uuid
|
||||
from .Utils import (
|
||||
IGNORED_KEYS,
|
||||
StreamingError,
|
||||
arg_converter,
|
||||
calc_download_path,
|
||||
get_video_info,
|
||||
validate_url,
|
||||
validate_uuid,
|
||||
)
|
||||
|
||||
LOG = logging.getLogger("http_api")
|
||||
MIME = magic.Magic(mime=True)
|
||||
|
|
@ -347,11 +355,28 @@ class HttpAPI(Common):
|
|||
return web.json_response(data={"error": "args param is required."}, status=web.HTTPBadRequest.status_code)
|
||||
|
||||
try:
|
||||
return web.json_response(data=arg_converter(args), status=web.HTTPOk.status_code)
|
||||
response = {"opts": {}, "output_template": None, "download_path": None}
|
||||
|
||||
data = arg_converter(args)
|
||||
|
||||
if "outtmpl" in data and "default" in data["outtmpl"]:
|
||||
response["output_template"] = data["outtmpl"]["default"]
|
||||
|
||||
if "paths" in data and "home" in data["paths"]:
|
||||
response["download_path"] = data["paths"]["home"]
|
||||
|
||||
for key in data:
|
||||
if key in IGNORED_KEYS:
|
||||
continue
|
||||
if not key.startswith("_"):
|
||||
response["opts"][key] = data[key]
|
||||
|
||||
return web.json_response(data=response, status=web.HTTPOk.status_code)
|
||||
except Exception as e:
|
||||
err = str(e).strip()
|
||||
err = err.split("\n")[-1] if "\n" in err else err
|
||||
LOG.error(f"Failed to convert args. '{err}'.")
|
||||
LOG.exception(e)
|
||||
return web.json_response(
|
||||
data={"error": f"Failed to convert args. '{err}'."}, status=web.HTTPBadRequest.status_code
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ IGNORED_KEYS: tuple[str] = (
|
|||
"outtmpl",
|
||||
"progress_hooks",
|
||||
"postprocessor_hooks",
|
||||
"format",
|
||||
"download_archive",
|
||||
)
|
||||
YTDLP_INFO_CLS: yt_dlp.YoutubeDL = None
|
||||
|
|
@ -45,6 +44,11 @@ def get_opts(preset: str, ytdl_opts: dict) -> dict:
|
|||
ytdl extra options
|
||||
|
||||
"""
|
||||
if "format" in ytdl_opts and len(ytdl_opts["format"]) > 2:
|
||||
format = ytdl_opts["format"]
|
||||
LOG.info(f"Format '{format}' was given via yt-dlp options. Therefore, the preset will be ignored.")
|
||||
return ytdl_opts
|
||||
|
||||
opts = copy.deepcopy(ytdl_opts)
|
||||
|
||||
if "default" == preset:
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@
|
|||
</div>
|
||||
<div class="control is-expanded">
|
||||
<div class="select is-fullwidth">
|
||||
<select id="preset" class="is-fullwidth" :disabled="!socket.isConnected || addInProgress"
|
||||
v-model="selectedPreset">
|
||||
<select id="preset" class="is-fullwidth"
|
||||
:disabled="!socket.isConnected || addInProgress || hasFormatInConfig" v-model="selectedPreset"
|
||||
v-tooltip.bottom="hasFormatInConfig ? 'Presets are disabled. Format key is present in the config.' : ''">
|
||||
<option v-for="item in config.presets" :key="item.name" :value="item.name">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
|
|
@ -81,7 +82,7 @@
|
|||
<label class="label is-inline" for="ytdlpConfig"
|
||||
v-tooltip="'Extends current global yt-dlp config. (JSON)'">
|
||||
JSON yt-dlp config or CLI options.
|
||||
<NuxtLink v-if="ytdlpConfig && !ytdlpConfig.trim().startsWith('{')" @click="convertOptions()">
|
||||
<NuxtLink v-if="ytdlpConfig && ytdlpConfig.trim() && !ytdlpConfig.trim().startsWith('{')" @click="convertOptions()">
|
||||
Convert to JSON
|
||||
</NuxtLink>
|
||||
</label>
|
||||
|
|
@ -93,8 +94,10 @@
|
|||
<span class="help">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>Extends current global yt-dlp config with given options. Some fields are ignored like
|
||||
<code>format</code> <code>cookiefile</code>, <code>paths</code>, and <code>outtmpl</code> etc.
|
||||
Warning: Use with caution some of those options can break yt-dlp or the frontend.</span>
|
||||
<code>cookiefile</code>, <code>paths</code>, and <code>outtmpl</code> etc. Warning: Use with caution
|
||||
some of those options can break yt-dlp or the frontend. If <code>Format</code> key is present
|
||||
in the config, <span class="has-text-danger">the preset and all it's options will be
|
||||
ignored</span>.</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -242,7 +245,15 @@ const convertOptions = async () => {
|
|||
|
||||
try {
|
||||
convertInProgress.value = true
|
||||
ytdlpConfig.value = await convertCliOptions(ytdlpConfig.value)
|
||||
const response = await convertCliOptions(ytdlpConfig.value)
|
||||
ytdlpConfig.value = JSON.stringify(response.opts, null, 2)
|
||||
if (response.output_template) {
|
||||
output_template.value = response.output_template
|
||||
}
|
||||
if (response.download_path) {
|
||||
downloadPath.value = response.download_path
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
toast.error(e.message)
|
||||
} finally {
|
||||
|
|
@ -262,4 +273,16 @@ onUnmounted(() => {
|
|||
socket.off('status', statusHandler)
|
||||
socket.off('error', unlockDownload)
|
||||
})
|
||||
|
||||
const hasFormatInConfig = computed(() => {
|
||||
if (!ytdlpConfig.value) {
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const config = JSON.parse(ytdlpConfig.value)
|
||||
return "format" in config
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<div class="column is-6-tablet is-12-mobile">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="url">
|
||||
Channel or Playlist URL
|
||||
URL
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<input type="url" class="input" id="url" v-model="form.url" :disabled="addInProgress">
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
<span class="help">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>The YouTube channel or playlist URL</span>
|
||||
<span>The channel or playlist URL.</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -69,7 +69,9 @@
|
|||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<div class="select is-fullwidth">
|
||||
<select id="preset" class="is-fullwidth" v-model="form.preset" :disabled="addInProgress">
|
||||
<select id="preset" class="is-fullwidth" v-model="form.preset"
|
||||
:disabled="addInProgress || hasFormatInConfig"
|
||||
v-tooltip.bottom="hasFormatInConfig ? 'Presets are disabled. Format key is present in the config.' : ''">
|
||||
<option v-for="item in config.presets" :key="item.name" :value="item.name">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
|
|
@ -79,7 +81,8 @@
|
|||
</div>
|
||||
<span class="help">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>Select the preset to use for this URL.</span>
|
||||
<span>Select the preset to use for this URL. The preset will be ignored if format key is present in
|
||||
config.</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -138,8 +141,8 @@
|
|||
<span class="help">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span> Extends current global yt-dlp config with given options. Some fields are ignored like
|
||||
<code>format</code> <code>cookiefile</code>, <code>paths</code>, and <code>outtmpl</code> etc.
|
||||
Warning: Use with caution some of those options can break yt-dlp or the frontend.</span>
|
||||
<code>cookiefile</code>, <code>paths</code>, and <code>outtmpl</code> etc. Warning: Use with caution
|
||||
some of those options can break yt-dlp or the frontend.</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -278,7 +281,14 @@ const convertOptions = async () => {
|
|||
|
||||
try {
|
||||
convertInProgress.value = true
|
||||
form.config = await convertCliOptions(form.config)
|
||||
const response = await convertCliOptions(form.config)
|
||||
form.config = JSON.stringify(response.opts, null, 2)
|
||||
if (response.output_template) {
|
||||
form.template = response.output_template
|
||||
}
|
||||
if (response.download_path) {
|
||||
form.folder = response.download_path
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error(e.message)
|
||||
} finally {
|
||||
|
|
@ -286,4 +296,15 @@ const convertOptions = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
const hasFormatInConfig = computed(() => {
|
||||
if (!form.config) {
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const config = JSON.parse(form.config)
|
||||
return "format" in config
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ const convertCliOptions = async opts => {
|
|||
throw new Error(`Error: (${response.status}): ${data.error}`)
|
||||
}
|
||||
|
||||
return JSON.stringify(data, null, 2)
|
||||
return data
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
|||
Loading…
Reference in a new issue