diff --git a/app/library/DownloadQueue.py b/app/library/DownloadQueue.py index 10079d4e..fc718055 100644 --- a/app/library/DownloadQueue.py +++ b/app/library/DownloadQueue.py @@ -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, ) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index e49453da..7369cf46 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -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 ) diff --git a/app/library/Utils.py b/app/library/Utils.py index 078ec1c3..b8e3fe7d 100644 --- a/app/library/Utils.py +++ b/app/library/Utils.py @@ -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: diff --git a/ui/components/NewDownload.vue b/ui/components/NewDownload.vue index 885989c5..8cf879ee 100644 --- a/ui/components/NewDownload.vue +++ b/ui/components/NewDownload.vue @@ -20,8 +20,9 @@
@@ -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 + } +}) diff --git a/ui/components/TaskForm.vue b/ui/components/TaskForm.vue index e625494f..338dbe53 100644 --- a/ui/components/TaskForm.vue +++ b/ui/components/TaskForm.vue @@ -32,7 +32,7 @@format cookiefile, paths, and outtmpl etc.
- Warning: Use with caution some of those options can break yt-dlp or the frontend.
+ cookiefile, paths, and outtmpl etc. Warning: Use with caution
+ some of those options can break yt-dlp or the frontend.
@@ -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
+ }
+})
diff --git a/ui/utils/index.js b/ui/utils/index.js
index 69cdfabc..47960e61 100644
--- a/ui/utils/index.js
+++ b/ui/utils/index.js
@@ -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 {