diff --git a/FAQ.md b/FAQ.md index 9d836b28..6316ee9e 100644 --- a/FAQ.md +++ b/FAQ.md @@ -60,6 +60,7 @@ or the `environment:` section in `compose.yaml` file. | YTP_THUMB_CONCURRENCY | The number of concurrent ffmpeg thumbnail generations allowed. | `2` | | YTP_THUMB_GENERATE | Enable ffmpeg thumbnail generation when no local thumbnail exists. | `true` | | YTP_THUMB_SIDECAR | Save generated thumbnails next to media instead of temp cache. | `false` | +| YTP_DISABLE_EXEC | Strip some dangerous yt-dlp options. | `false` | > [!NOTE] > To raise the maximum workers for specific extractor, you need to add a ENV variable that follows the pattern `YTP_MAX_WORKERS_FOR_`. @@ -143,6 +144,11 @@ a tool that by design can execute commands. Auth is the mechanism that controls YTPTube already gates other powerful features behind explicit opt-in: the built-in terminal, file browser actions and internal URL requests for example. The `cli` field is no different, its power is by design, and access control is your responsibility. +> [!NOTE] +> If you choose to run without authentication but still want to reduce at least some impact, you can set +> `YTP_DISABLE_EXEC=true`. This strips some dangerous options at run time. However, understand that this is not a +> substitute for auth an unauthenticated API is still fully open for all other operations. + # I cant download anything If you are receiving errors like: diff --git a/README.md b/README.md index b1c24c33..e42217bd 100644 --- a/README.md +++ b/README.md @@ -109,17 +109,14 @@ For simple API documentation, you can refer to the [API documentation](API.md). This project is not affiliated with yt-dlp or any other service. -It’s a personal project designed to make downloading videos from the internet more convenient. It’s not intended for -piracy or any unlawful use. +This is a personal project designed to make downloading videos from the internet more convenient for me. It is not +intended for piracy or any unlawful use. This project was built primarily for my own use and preferences. -AI-based tools may have been used to assist with parts of this project. Regardless of how a change is produced, every -change is reviewed and approved by the human maintainer before it is included. +AI-assisted tools are used in this project. If you are uncomfortable with this, you should not use this project. -This project was built primarily for my own needs and preferences. The UI might not be the most polished or visually -refined, but I’m happy with it as it is. You can, however, create and load your own UI for complete customization. - -Contributions are welcome, but I may decline changes that don’t align with my vision for the project. Unsolicited pull -requests may be ignored. For suggestions or feature requests, please open a discussion or join the Discord server. +Contributions are welcome, but I may decline changes that do not interest me or do not align with my vision for this +project. Unsolicited pull requests will be closed. For suggestions or feature requests, please open a discussion or +join the Discord server. # Social contact diff --git a/app/conftest.py b/app/conftest.py index e75a390b..5a976bac 100644 --- a/app/conftest.py +++ b/app/conftest.py @@ -16,7 +16,10 @@ def pytest_configure(config) -> None: if getattr(config.option, "basetemp", None) is None: config.option.basetemp = str(get_test_run_root() / "pytest") + os.environ["YTP_FILE_LOGGING"] = "false" + def pytest_unconfigure(config) -> None: del config + os.environ.pop("YTP_FILE_LOGGING", None) cleanup_test_run_root() diff --git a/app/features/ytdlp/ytdlp_opts.py b/app/features/ytdlp/ytdlp_opts.py index 1d4693c9..80234459 100644 --- a/app/features/ytdlp/ytdlp_opts.py +++ b/app/features/ytdlp/ytdlp_opts.py @@ -397,6 +397,30 @@ def get_all(self, keep: bool = False) -> dict: data: dict = merge_dict(user_cli, merge_dict(self._item_opts, merge_dict(self._preset_opts, default_opts))) + if self._config.disable_exec: + stripped: list[str] = [] + if data.pop("netrc_cmd", None): + stripped.append("netrc_cmd") + + if "postprocessors" in data: + exec_pps = [ + pp for pp in data["postprocessors"] if isinstance(pp, dict) and pp.get("key", "").startswith("Exec") + ] + if exec_pps: + stripped.extend(pp.get("key") for pp in exec_pps) + data["postprocessors"] = [ + pp + for pp in data["postprocessors"] + if not (isinstance(pp, dict) and pp.get("key", "").startswith("Exec")) + ] + + if stripped: + LOG.warning( + "Stripped %d dangerous options from yt-dlp options.", + len(stripped), + extra={"stripped": stripped, "reason": "YTP_DISABLE_EXEC is enabled"}, + ) + if not keep: self.reset() diff --git a/app/library/config.py b/app/library/config.py index e1224d39..3baff0b5 100644 --- a/app/library/config.py +++ b/app/library/config.py @@ -110,6 +110,9 @@ class Config(metaclass=Singleton): auth_password: str | None = None """The password to use for basic authentication.""" + disable_exec: bool = False + """Strip some dangerous yt-dlp options.""" + remove_files: bool = False """Remove downloaded files when removing the record.""" @@ -312,6 +315,7 @@ class Config(metaclass=Singleton): "check_for_updates", "thumb_generate", "thumb_sidecar", + "disable_exec", ) "The variables that are booleans." diff --git a/sc_short.jpg b/sc_short.jpg index d1e28ae4..864876e1 100644 Binary files a/sc_short.jpg and b/sc_short.jpg differ diff --git a/sc_simple.jpg b/sc_simple.jpg index cc2f96d8..45c9a11b 100644 Binary files a/sc_simple.jpg and b/sc_simple.jpg differ diff --git a/ui/app/assets/css/tailwind.css b/ui/app/assets/css/tailwind.css index b8f550b5..786d1cdf 100644 --- a/ui/app/assets/css/tailwind.css +++ b/ui/app/assets/css/tailwind.css @@ -151,3 +151,19 @@ --ui-container: 96rem; --ui-header-height: 4.25rem; } + +html:not(.no-page-anim) .page-enter-active { + transition: + opacity 0.25s ease, + transform 0.25s ease; +} +html:not(.no-page-anim) .page-leave-active { + transition: opacity 0.1s ease; +} +html:not(.no-page-anim) .page-enter-from { + opacity: 0; + transform: translateY(-4px); +} +html:not(.no-page-anim) .page-leave-to { + opacity: 0; +} diff --git a/ui/app/components/LogDetailModal.vue b/ui/app/components/LogDetailModal.vue new file mode 100644 index 00000000..8a9e34f8 --- /dev/null +++ b/ui/app/components/LogDetailModal.vue @@ -0,0 +1,509 @@ + + + diff --git a/ui/app/components/NewDownload.vue b/ui/app/components/NewDownload.vue index 39123242..d1d8f54d 100644 --- a/ui/app/components/NewDownload.vue +++ b/ui/app/components/NewDownload.vue @@ -103,15 +103,17 @@ />
- diff --git a/ui/app/components/PresetForm.vue b/ui/app/components/PresetForm.vue index bb6f6aa4..951ee1e3 100644 --- a/ui/app/components/PresetForm.vue +++ b/ui/app/components/PresetForm.vue @@ -30,15 +30,17 @@ - diff --git a/ui/app/components/SettingsPanel.vue b/ui/app/components/SettingsPanel.vue index 4f613b22..b94ff349 100644 --- a/ui/app/components/SettingsPanel.vue +++ b/ui/app/components/SettingsPanel.vue @@ -45,6 +45,15 @@ :label="simpleMode ? 'Simple View' : 'Regular View'" description="The simple view is ideal for non-technical users and mobile devices." /> + + @@ -307,6 +316,7 @@ const show_popover = useStorage('show_popover', true); const thumbnail_ratio = useStorage<'is-16by9' | 'is-3by1'>('thumbnail_ratio', 'is-3by1'); const separator = useStorage('url_separator', separators[0]?.value ?? ','); const simpleMode = useStorage('simple_mode', config.app.simple_mode || false); +const page_anims = useStorage('page_anims', true); const queue_auto_refresh = useStorage('queue_auto_refresh', true); const queue_auto_refresh_delay = useStorage('queue_auto_refresh_delay', 10000); const isSecureContext = ref(false); diff --git a/ui/app/components/Simple.vue b/ui/app/components/Simple.vue index 084da2b1..446366d5 100644 --- a/ui/app/components/Simple.vue +++ b/ui/app/components/Simple.vue @@ -122,15 +122,17 @@ - @@ -205,7 +207,7 @@ - diff --git a/ui/app/components/TaskForm.vue b/ui/app/components/TaskForm.vue index 5f0c9c4f..1099cb8f 100644 --- a/ui/app/components/TaskForm.vue +++ b/ui/app/components/TaskForm.vue @@ -247,17 +247,19 @@ : undefined " > - diff --git a/ui/app/components/TaskInspect.vue b/ui/app/components/TaskInspect.vue index ad46702d..184ef856 100644 --- a/ui/app/components/TaskInspect.vue +++ b/ui/app/components/TaskInspect.vue @@ -29,15 +29,18 @@ :ui="fieldUi" description="Select a preset to apply its settings during inspection. In real scenario, the preset will be based on what is selected when creating the task." > - diff --git a/ui/app/components/YTDLPOptions.vue b/ui/app/components/YTDLPOptions.vue index d503dfd7..d7dfd23c 100644 --- a/ui/app/components/YTDLPOptions.vue +++ b/ui/app/components/YTDLPOptions.vue @@ -17,46 +17,54 @@ - - - - diff --git a/ui/app/layouts/default.vue b/ui/app/layouts/default.vue index 1656db34..a23a84d5 100644 --- a/ui/app/layouts/default.vue +++ b/ui/app/layouts/default.vue @@ -568,6 +568,7 @@ const loadedImage = ref(); const loadingImage = ref(false); const bg_enable = useStorage('random_bg', true); const bg_opacity = useStorage('random_bg_opacity', 0.95); +const page_anims = useStorage('page_anims', true); const app_shutdown = ref(false); const simpleMode = useStorage('simple_mode', config.app.simple_mode || false); const show_settings = ref(false); @@ -1029,6 +1030,18 @@ watch(bg_opacity, () => { syncOpacity(); }); +watch( + page_anims, + (val) => { + if (val) { + document.documentElement.classList.remove('no-page-anim'); + } else { + document.documentElement.classList.add('no-page-anim'); + } + }, + { immediate: true }, +); + watch(loadedImage, () => { if (false === bg_enable.value) { return; diff --git a/ui/app/pages/browser/[...slug].vue b/ui/app/pages/browser/[...slug].vue index 3fca59c5..d08c2d72 100644 --- a/ui/app/pages/browser/[...slug].vue +++ b/ui/app/pages/browser/[...slug].vue @@ -323,8 +323,9 @@ 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
- Press Enter to run single-line input, Shift+Enter to - switch to multi-line, and Ctrl+Enter to run multi-line input. + Shift+Enter to switch to multi-line input.

diff --git a/ui/app/pages/dl_fields.vue b/ui/app/pages/dl_fields.vue index 293494d6..e12519fa 100644 --- a/ui/app/pages/dl_fields.vue +++ b/ui/app/pages/dl_fields.vue @@ -238,8 +238,9 @@