diff --git a/.env.example b/.env.example index 0cffb77..816abb4 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,21 @@ # Copy this file to `.env` and customize the paths to match your environment. # Relative paths are resolved from the repository root when running locally. +# Each `*_DIR` value below points to a directory on the host. Docker Compose +# mounts it into the container at the standard path noted in the comment. +# Host directory that stores JSON settings. Mounted to /config in Docker. ABOGEN_SETTINGS_DIR=./config + +# Host directory for rendered audio/subtitle files. Mounted to /data/outputs +# in Docker. ABOGEN_OUTPUT_DIR=./storage/output # Temporary working directory. When running in Docker, keep this inside the -# mounted /data volume so non-root users can write to it. For local (non-Docker) -# usage, change this to a path that makes sense on your machine or comment it out -# to fall back to the OS cache directory. -ABOGEN_TEMP_DIR=/data/cache +# mounted data volume (or another writable host path) so non-root users can +# write to it. For local (non-Docker) usage, change this to a path that makes +# sense on your machine or comment it out to fall back to the OS cache +# directory. Mounted to /data/cache in Docker. +ABOGEN_TEMP_DIR=./storage/tmp # UID/GID used when running the Docker container. 1000:1000 matches most Linux hosts. # Find your current values with: diff --git a/README.md b/README.md index ace3d4b..3fdd8f2 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,12 @@ Browse to http://localhost:8808. Uploaded source files are stored in `/data/uplo | `ABOGEN_PORT` | `8808` | HTTP port | | `ABOGEN_DEBUG` | `false` | Enable Flask debug mode | | `ABOGEN_UPLOAD_ROOT` | `/data/uploads` | Directory where uploaded files are stored | -| `ABOGEN_OUTPUT_ROOT` | `/data/outputs` | Directory for generated audio and subtitles | +| `ABOGEN_OUTPUT_ROOT` | `/data/outputs` | Directory for generated audio and subtitles (legacy alias of `ABOGEN_OUTPUT_DIR`) | +| `ABOGEN_OUTPUT_DIR` | `/data/outputs` | Container path for rendered audio/subtitles | +| `ABOGEN_SETTINGS_DIR` | `/config` | Container path for JSON settings/configuration | +| `ABOGEN_TEMP_DIR` | `/data/cache` (Docker) or platform cache dir | Container path for temporary files | | `ABOGEN_UID` | `1000` | UID that the container should run as (matches host user) | | `ABOGEN_GID` | `1000` | GID that the container should run as (matches host group) | -| `ABOGEN_TEMP_DIR` | `/data/cache` (Docker) or platform cache dir | Override the cache/temp directory | -| `ABOGEN_OUTPUT_DIR` | Same as `ABOGEN_OUTPUT_ROOT` | Override the rendered output directory | -| `ABOGEN_SETTINGS_DIR` | Platform config dir (e.g. `~/.config/abogen`) | Override where JSON settings (profiles, config) are stored | Set any of these with `-e VAR=value` when starting the container. @@ -67,9 +67,12 @@ id -g Use those values to populate `ABOGEN_UID` / `ABOGEN_GID` in your `.env` file. -When running via Docker Compose, the container defaults to `/data/cache` for -temporary files. Make sure the corresponding host directory is writable (the -compose volume at `${ABOGEN_DATA:-./data}` will automatically satisfy this). +When running via Docker Compose, set `ABOGEN_SETTINGS_DIR`, +`ABOGEN_OUTPUT_DIR`, and `ABOGEN_TEMP_DIR` in your `.env` file to the host +directories you want mounted into the container. Compose maps them to +`/config`, `/data/outputs`, and `/data/cache` respectively while exporting +those in-container paths to the application. Ensure each host directory exists +and is writable by the UID/GID you configure before starting the stack. ### Docker Compose (GPU by default) The repo includes `docker-compose.yaml`, which targets GPU hosts out of the box. Install the NVIDIA Container Toolkit and run: diff --git a/abogen/utils.py b/abogen/utils.py index 257c535..1d004dd 100644 --- a/abogen/utils.py +++ b/abogen/utils.py @@ -1,4 +1,5 @@ import json +import logging import os import platform import re @@ -142,14 +143,47 @@ def get_user_config_path(): # Define cache path @lru_cache(maxsize=1) def get_user_cache_root(): + logger = logging.getLogger(__name__) + + def _try_paths(*paths): + last_error = None + for candidate in paths: + if not candidate: + continue + try: + return ensure_directory(candidate) + except OSError as exc: + last_error = exc + logger.debug("Unable to use cache directory %s: %s", candidate, exc) + if last_error is not None: + raise last_error + override = os.environ.get("ABOGEN_TEMP_DIR") if override: - return ensure_directory(override) + try: + return ensure_directory(override) + except OSError as exc: + logger.warning("ABOGEN_TEMP_DIR=%s is not writable: %s", override, exc) from platformdirs import user_cache_dir - cache_dir = user_cache_dir("abogen", appauthor=False, opinion=True, ensure_exists=True) - return ensure_directory(cache_dir) + default_cache = user_cache_dir("abogen", appauthor=False, opinion=True) + + data_root = os.environ.get("ABOGEN_DATA") or os.environ.get("ABOGEN_DATA_DIR") + fallback_paths = [ + default_cache, + os.path.join(data_root, "cache") if data_root else None, + "/data/cache", + "/tmp/abogen-cache", + ] + + try: + return _try_paths(*fallback_paths) + except OSError: + # Final safety net – attempt a tmp directory unique to this process. + tmp_candidate = os.path.join("/tmp", f"abogen-cache-{os.getpid()}") + logger.warning("Falling back to temp cache directory %s", tmp_candidate) + return ensure_directory(tmp_candidate) def get_user_cache_path(folder=None): diff --git a/docker-compose.yaml b/docker-compose.yaml index 4d9c882..828029e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -12,12 +12,17 @@ services: - "${ABOGEN_PORT:-8808}:8808" volumes: - ${ABOGEN_DATA:-./data}:/data + - ${ABOGEN_SETTINGS_DIR:-./config}:/config + - ${ABOGEN_OUTPUT_DIR:-./storage/output}:/data/outputs + - ${ABOGEN_TEMP_DIR:-./storage/tmp}:/data/cache environment: ABOGEN_HOST: 0.0.0.0 ABOGEN_PORT: 8808 + ABOGEN_SETTINGS_DIR: "/config" ABOGEN_UPLOAD_ROOT: /data/uploads - ABOGEN_OUTPUT_ROOT: /data/outputs - ABOGEN_TEMP_DIR: "${ABOGEN_TEMP_DIR:-/data/cache}" + ABOGEN_OUTPUT_DIR: "/data/outputs" + ABOGEN_OUTPUT_ROOT: "/data/outputs" + ABOGEN_TEMP_DIR: "/data/cache" # --- GPU support ----------------------------------------------------- # These settings assume the NVIDIA Container Toolkit is installed. # Leave them in place for GPU acceleration; comment out the entire block