support format key in ytdlp.json, using the key will ignore the selected preset.

This commit is contained in:
ArabCoders 2025-02-27 14:58:06 +03:00
parent 0cb90645cd
commit c5924b02cc
6 changed files with 92 additions and 19 deletions

View file

@ -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,
)

View file

@ -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
)

View file

@ -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:

View file

@ -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>

View file

@ -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>

View file

@ -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 {