diff --git a/app/library/Utils.py b/app/library/Utils.py index 4ba05617..a86074f4 100644 --- a/app/library/Utils.py +++ b/app/library/Utils.py @@ -643,7 +643,7 @@ def arg_converter( # important to ignore external config files. args = "--ignore-config " + args - opts = yt_dlp.parse_options(shlex.split(args)).ydl_opts + opts = yt_dlp.parse_options(shlex.split(args, posix=os.name != "nt")).ydl_opts diff = {k: v for k, v in opts.items() if default_opts[k] != v} if not keep_defaults else opts.items() if "postprocessors" in diff: diff["postprocessors"] = [pp for pp in diff["postprocessors"] if pp not in default_opts["postprocessors"]] @@ -1702,6 +1702,9 @@ def list_folders(path: Path, base: Path, depth_limit: int) -> list[str]: list[str]: A list of folder paths relative to the base path, up to the specified """ + if "/" == str(path): + return [] + rel_depth: int = len(path.relative_to(base).parts) if rel_depth > depth_limit: return [] diff --git a/app/library/config.py b/app/library/config.py index be384bbb..6fca0d6a 100644 --- a/app/library/config.py +++ b/app/library/config.py @@ -117,13 +117,13 @@ class Config(metaclass=Singleton): extract_info_timeout: int = 70 """The timeout to use for extracting video information.""" - db_file: str = "{config_path}/ytptube.db" + db_file: str = "{config_path}{os_sep}ytptube.db" """The path to the database file.""" - archive_file: str = "{config_path}/archive.log" + archive_file: str = "{config_path}{os_sep}archive.log" """The path to the download archive file.""" - apprise_config: str = "{config_path}/apprise.yml" + apprise_config: str = "{config_path}{os_sep}apprise.yml" """The path to the Apprise configuration file.""" ui_update_title: bool = True @@ -295,6 +295,9 @@ class Config(metaclass=Singleton): _manager: SyncManager | None = None "The manager instance." + os_sep: str = os.path.sep + "The system path separator." + @staticmethod def get_instance(is_native: bool = False) -> "Config": cls = Config(is_native) @@ -528,7 +531,7 @@ class Config(metaclass=Singleton): dict[str, str]: The replacer variables. """ - keys: tuple[str] = ("download_path", "temp_path", "config_path", "archive_file") + keys: tuple[str] = ("os_sep", "download_path", "temp_path", "config_path", "archive_file") return {k: getattr(self, k) for k in keys} @staticmethod diff --git a/app/local.py b/app/local.py index 9ddc7d2b..cae170ad 100644 --- a/app/local.py +++ b/app/local.py @@ -69,6 +69,8 @@ def open_browser_when_ready(url: str, timeout: float = 5.0) -> None: def app_start(host: str, port: int) -> None: import asyncio + from aiohttp.web_runner import GracefulExit + from app.main import Main try: @@ -77,7 +79,10 @@ def app_start(host: str, port: int) -> None: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - Main(is_native=True).start(host, port) + try: + Main(is_native=True).start(host, port) + except GracefulExit: + sys.exit(0) def update_env_file(env_file: pathlib.Path, port: int) -> None: diff --git a/app/routes/api/system.py b/app/routes/api/system.py index a1edbd99..79a538b8 100644 --- a/app/routes/api/system.py +++ b/app/routes/api/system.py @@ -4,6 +4,7 @@ import time from aiohttp import web from aiohttp.web import Request, Response +from aiohttp.web_runner import GracefulExit from app.library.config import Config from app.library.DownloadQueue import DownloadQueue @@ -117,6 +118,7 @@ async def shutdown_system(request: Request, config: Config, encoder: Encoder, no await asyncio.sleep(0.5) await app.shutdown() await app.cleanup() + raise GracefulExit # Schedule shutdown after response asyncio.create_task(do_shutdown()) diff --git a/app/routes/socket/terminal.py b/app/routes/socket/terminal.py index 401951dd..146c39ff 100644 --- a/app/routes/socket/terminal.py +++ b/app/routes/socket/terminal.py @@ -38,7 +38,7 @@ async def cli_post(config: Config, notify: EventBus, sid: str, data: str): try: LOG.info(f"Cli command from client '{sid}'. '{data}'") - args: list[str] = ["yt-dlp", *shlex.split(data)] + args: list[str] = ["yt-dlp", *shlex.split(data, posix=os.name != "nt")] _env: dict[str, str] = os.environ.copy() _env.update( { diff --git a/entrypoint.sh b/entrypoint.sh index 85246d8d..28a47d04 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -19,14 +19,14 @@ if [ ! -w "${YTP_CONFIG_PATH}" ]; then exit 1 fi -if [ ! -w "${YTP_DOWNLOAD_PATH}" ]; then +if [ "${YTP_DOWNLOAD_PATH}" != "/" ] && [ ! -w "${YTP_DOWNLOAD_PATH}" ]; then CH_USER=$(stat -c "%u" "${YTP_DOWNLOAD_PATH}") CH_GRP=$(stat -c "%g" "${YTP_DOWNLOAD_PATH}") echo_err "ERROR: Unable to write to '${YTP_DOWNLOAD_PATH}' downloads directory. Current user id '${UID}' while directory owner is '${CH_USER}'." echo_err "[Running under docker]" echo_err "change compose.yaml user: to user:\"${CH_USER}:${CH_GRP}\"" echo_err "Run the following command to change the directory ownership" - echo_err "chown -R \"${CH_USER}:${CH_GRP}\" ./config" + echo_err "chown -R \"${CH_USER}:${CH_GRP}\" ./downloads" echo_err "[Running under podman]" echo_err "change compose.yaml user: to user:\"0:0\"" exit 1