From c58faa28c9b580b7dc596d8c20e7eed5056982f1 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Tue, 4 Mar 2025 20:27:26 +0300 Subject: [PATCH 1/2] added button to run task now --- ui/components/PresetForm.vue | 20 +-- ui/components/TaskForm.vue | 334 ++++++++++++++++++----------------- ui/pages/presets.vue | 29 ++- ui/pages/tasks.vue | 70 +++++++- 4 files changed, 268 insertions(+), 185 deletions(-) diff --git a/ui/components/PresetForm.vue b/ui/components/PresetForm.vue index b155187c..558dff89 100644 --- a/ui/components/PresetForm.vue +++ b/ui/components/PresetForm.vue @@ -208,21 +208,21 @@ const props = defineProps({ }, }) -const toast = useToast(); -const convertInProgress = ref(false); -const form = reactive(props.preset); -const opts = ref(''); -const json_preset = ref(''); -const importExpanded = ref(false); -const convertExpanded = ref(false); +const toast = useToast() +const convertInProgress = ref(false) +const form = reactive( JSON.parse(JSON.stringify(props.preset))) +const opts = ref('') +const json_preset = ref('') +const importExpanded = ref(false) +const convertExpanded = ref(false) onMounted(() => { if (props.preset?.args && (typeof props.preset.args === 'object')) { - form.args = JSON.stringify(props.preset.args, null, 2); + form.args = JSON.stringify(props.preset.args, null, 2) } if (props.preset?.postprocessors && (typeof props.preset.postprocessors === 'object')) { - form.postprocessors = JSON.stringify(props.preset.postprocessors, null, 2); + form.postprocessors = JSON.stringify(props.preset.postprocessors, null, 2) } }) @@ -231,7 +231,7 @@ const checkInfo = async () => { for (const key of required) { if (!form[key]) { toast.error(`The ${key} field is required.`); - return; + return } } diff --git a/ui/components/TaskForm.vue b/ui/components/TaskForm.vue index 338dbe53..e9b7393d 100644 --- a/ui/components/TaskForm.vue +++ b/ui/components/TaskForm.vue @@ -1,186 +1,188 @@ diff --git a/ui/pages/tasks.vue b/ui/pages/tasks.vue index 9fa32c7e..535e1a5f 100644 --- a/ui/pages/tasks.vue +++ b/ui/pages/tasks.vue @@ -79,11 +79,11 @@ div.is-centered {

- {{ calcPath(item.folder) }} + {{ item.folder ? calcPath(item.folder) : config.app.download_path }}

- {{ item.template ?? config.app.output_template }} + {{ item.template ? item.template : config.app.output_template }}

@@ -99,7 +99,7 @@ div.is-centered {

+ @@ -146,6 +152,7 @@ watch(() => config.app.basic_mode, async () => { watch(() => socket.isConnected, async () => { if (socket.isConnected && initialLoad.value) { + socket.on('status', statusHandler) await reloadContent(true) initialLoad.value = false } @@ -278,7 +285,13 @@ const calcPath = path => { return loc } -onMounted(async () => socket.isConnected ? await reloadContent(true) : '') +onMounted(async () => { + if (!socket.isConnected){ + return; + } + socket.on('status', statusHandler) + await reloadContent(true) +}); const tryParse = expression => { try { @@ -287,4 +300,53 @@ const tryParse = expression => { return "Invalid" } } + +const runNow = item => { + if (true !== confirm(`Run '${item.name}' now? it will also run at the scheduled time.`)) { + return + } + + let data = { + url: item.url, + preset: item.preset, + } + + if (item.folder) { + data.folder = item.folder + } + + if (item.template) { + data.template = item.template + } + + if (item.cookies) { + data.cookies = item.cookies + } + + if (item.config) { + if (typeof item.config === 'object') { + data.config = JSON.stringify(item.config) + } + + try { + JSON.parse(data.config) + } catch (e) { + toast.error(`Invalid JSON yt-dlp config. ${e.message}`) + return + } + } + + socket.emit('add_url', data) +} + +onUnmounted(() => socket.off('status', statusHandler)) + +const statusHandler = async stream => { + const { status, msg } = JSON.parse(stream) + + if ('error' === status) { + toast.error(msg) + return + } +} From 4036dcacc4fee82229310c8b1a21cae31d2bf91d Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Tue, 4 Mar 2025 21:08:08 +0300 Subject: [PATCH 2/2] updated readme with new changes --- README.md | 143 ++++++++++++++--------------------- ui/components/PresetForm.vue | 10 +-- 2 files changed, 58 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 87a72fc0..385e1e7a 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,10 @@ Your `yt-dlp` config should include the following options for optimal working co ```json { - "windowsfilenames": true, - "live_from_start": true, - "format_sort": [ - "codec:avc:m4a" - ] + "windowsfilenames": true, + "continue_dl": true, + "live_from_start": true, + "format_sort": [ "codec:avc:m4a" ], } ``` * Note, the `format_sort`, forces YouTube to use x264 instead of vp9 codec, you can ignore it if you want. i prefer the media in x264. @@ -144,7 +143,6 @@ Before asking a question or submitting an issue for YTPTube, please remember tha In order to test with the yt-dlp command directly, you can either download it and run it locally, or for a better simulation of its actual conditions, you can run it within the YTPTube container itself. - #### Via HTTP Simply go to `Console` button in your navbar and directly use the yt-dlp command. @@ -186,97 +184,66 @@ A Docker image can be built locally (it will build the UI too): docker build . -t ytptube ``` -### ytdlp.json File +## ytdlp.json file -The `config/ytdlp.json`, is a json file which can be used to alter the default `yt-dlp` config settings. For example these are the options i personally use, +The `config/ytdlp.json`, is a json file which can be used to alter the default `yt-dlp` config settings globally. +We recommend not use this file for options that aren't **truly global**, everything that can be done via the `ytdlp.json` file +can be done via a preset, which only effects the download that uses it. For example, my personal preset that i use for all +my jp video downloads is: ```json5 { - // Make the final filename windows compatible. - "windowsfilenames": true, - // Write subtitles if the stream has them. - "writesubtitles": true, - // Write info.json file for each download. It can be used by many tools to generate info etc. - "writeinfojson": true, - // Write thumbnail if available. - "writethumbnail": true, - // Do not download automatically generated subtitles. - "writeautomaticsub": false, - // MP4 is limited with the codecs we use, so "mkv" make sense. - "merge_output_format": "mkv", - // Record live stream from the start. - "live_from_start": true, - // For YouTube try to force H264 video codec & AAC audio. - "format_sort": [ - "codec:avc:m4a" - ], - // Your choice of subtitle languages to download. - "subtitleslangs": [ "en", "ar" ], - // postprocessors to run on the file + "name": "jp_videos", + "format": "bv[ext=mp4]+(ba[ext=m4a][format_note*=original]/ba)/bv[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b", + "args": { + "writesubtitles": true, + "writeinfojson": true, + "writethumbnail": true, + "merge_output_format": "mkv", + "final_ext": "mkv", + "format_sort": [ "codec:avc:m4a" ], + "subtitleslangs": [ "en", "ar" ] + }, "postprocessors": [ - // this processor convert the downloaded thumbnail to jpg. - { - "key": "FFmpegThumbnailsConvertor", - "format": "jpg" - }, - // This processor convert subtitles to srt format. - { - "key": "FFmpegSubtitlesConvertor", - "format": "srt" - }, - // This processor embed metadata & info.json file into the final mkv file. - { - "key": "FFmpegMetadata", - "add_infojson": true, - "add_metadata": true - }, - // This process embed subtitles into the final file if it doesn't have subtitles embedded. - { - "key": "FFmpegEmbedSubtitle", - "already_have_subtitle": false - } + { + "key": "FFmpegVideoRemuxer", + "preferedformat": "mkv" + }, + { + "key": "FFmpegConcat", + "only_multi_video": true, + "when": "playlist" + }, + { + "key": "FFmpegThumbnailsConvertor", + "format": "jpg" + }, + { + "key": "FFmpegSubtitlesConvertor", + "format": "srt" + }, + { + "key": "FFmpegMetadata", + "add_chapters": true, + "add_infojson": true, + "add_metadata": true + }, + { + "key": "FFmpegEmbedSubtitle", + "already_have_subtitle": false + }, + { + "key": "Exec", + "exec_cmd": "/usr/bin/mkvpropedit %(filepath)q --edit track:a1 --set language=jpn --set name=Japanese --add-track-statistics-tags", + "when": "after_move" + } ] } -``` -The options can be fount at [yt-dlp YoutubeDL.py](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L214) file. -And for the postprocessors at [yt-dlp postprocessor](https://github.com/yt-dlp/yt-dlp/tree/master/yt_dlp/postprocessor). - -> [!NOTE] -> You can use the `yt-dlp json config` box in the new Download page to convert your cli options to json format. - -### presets.json File - -The `config/presets.json`, is a json file, which can be used to add custom presets for selection in WebUI. - -The file is supposed to be an array of objects, each object represent a preset, the schema for the object is as the following. -```json5 -[ - { - // (name: string) - REQUIRED - The preset name. - "name": "My super preset", - // (format: string) - REQUIRED - The required yt-dlp format. i.e. -f option in yt-dlp cli. - "format": "best", - // (postprocessors: array) - OPTIONAL - The postprocessors to run on the file. if it's preset or set to empty array, it will override the default postprocessors. - "postprocessors": [ - // for example to embed thumbnail. - { - "key": "EmbedThumbnail", - "already_have_thumbnail": false - } - ], - // (args: dict) - OPTIONAL - Extra yt-dlp arguments to pass to yt-dlp. - "args": { - // (key: string) - REQUIRED - The yt-dlp argument key. - "writethumbnail": true - } - }, - { - // another preset, etc... - } -] ``` -For more expanded example please take look at the default presets file found in [app/library/presets.json](app/library/presets.json). +You can convert your own yt-dlp command arguments into a preset using the box found in the presets add page. For reference, +The options can be fount at [yt-dlp YoutubeDL.py](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L214) file. +And for the postprocessors at [yt-dlp postprocessor](https://github.com/yt-dlp/yt-dlp/tree/master/yt_dlp/postprocessor). ## Authentication diff --git a/ui/components/PresetForm.vue b/ui/components/PresetForm.vue index 558dff89..1234aa55 100644 --- a/ui/components/PresetForm.vue +++ b/ui/components/PresetForm.vue @@ -88,9 +88,7 @@
- +