From cb1074e7fdbd14741436b80eea19f0f924edafe0 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:21:04 +0200 Subject: [PATCH 1/9] Create a symlink to LibationCli to not require the full path for commands --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 17019728..7c275880 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,8 @@ RUN apt-get update && apt-get -y upgrade && \ COPY --from=build /Source/bin/Publish/Linux-chardonnay /libation COPY Docker/* /libation +RUN ln -s /libation/LibationCli /usr/local/bin/LibationCli + USER ${USER_UID}:${USER_GID} CMD ["/libation/liberate.sh"] From c5a88de8a61ac60261202a557f099606859c975f Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:23:21 +0200 Subject: [PATCH 2/9] Use entrypoint instead of cmd to allow the user to supply their own cmd --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7c275880..131be19d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,4 +41,4 @@ RUN ln -s /libation/LibationCli /usr/local/bin/LibationCli USER ${USER_UID}:${USER_GID} -CMD ["/libation/liberate.sh"] +ENTRYPOINT ["/libation/liberate.sh"] From 40b75185c2517e30489dbc8f9d0ae17f2cc13c75 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:27:21 +0200 Subject: [PATCH 3/9] Support user specified cmd by not entering the loop and running the cmd while still setting up the environment. Also expand documentation and example for the interactive shell. --- Docker/liberate.sh | 9 ++++++++- docs/installation/docker.md | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Docker/liberate.sh b/Docker/liberate.sh index 9ae7f7fc..bcce0638 100755 --- a/Docker/liberate.sh +++ b/Docker/liberate.sh @@ -176,6 +176,13 @@ main() { warn "${LIBATION_BOOKS_DIR} does not appear to be mounted, books will not be saved" fi + # If a command was passed to the container (e.g. `docker run -it libation bash`), + # run that instead of the liberate loop so the environment is still set up + if [ "$#" -gt 0 ]; then + info "executing '$*' instead of the liberate loop" + exec "$@" + fi + # Let the user know what the run type will be if [[ -z "${SLEEP_TIME}" ]]; then SLEEP_TIME=-1 @@ -203,4 +210,4 @@ main() { info "exiting" } -main +main "$@" diff --git a/docs/installation/docker.md b/docs/installation/docker.md index 541c9592..e17e211c 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -37,7 +37,7 @@ Configuration in Libation is handled by two files, `AccountsSettings.json` and ` ### Adding Audible accounts without the GUI -If you run Libation on a server or in Docker and do not want to copy `AccountsSettings.json` from a desktop install, you can create or update accounts with LibationCli (same binary as in the image under `/libation/LibationCli`): +If you run Libation on a server or in Docker and do not want to copy `AccountsSettings.json` from a desktop install, you can create or update accounts with LibationCli (same binary as in the image under `/libation/LibationCli`, also available on `PATH` as `LibationCli`): - `import-account` — Import an account from a JSON file exported by [mkb79's audible-cli](https://github.com/mkb79/audible-cli) (or Libation's own compatible export). Example: `LibationCli import-account /path/to/account.json` @@ -49,7 +49,7 @@ If you run Libation on a server or in Docker and do not want to copy `AccountsSe For full syntax, overrides, and the `--libationFiles` option (or the `LIBATION_FILES_DIR` environment variable) when your Libation data directory is not the default, see [Command Line Interface](/docs/advanced/command-line-interface). -Docker tip: The entrypoint script copies your mounted config into an internal path before running LibationCli. The most reliable way to run account commands inside the same layout the container uses is to `docker exec` into an already running Libation container (so `AccountsSettings.json` and `appsettings.json` are already in place), then run `/libation/LibationCli import-account ...` or `/libation/LibationCli login-external ...`. Alternatively, run LibationCli on any host where you can point `--libationFiles` (or `LIBATION_FILES_DIR`) at the folder that you later mount as `/config` on the server. +Docker tip: The entrypoint script copies your mounted config into an internal path before running LibationCli. The most reliable way to run account commands inside the same layout the container uses is to start a container with an interactive shell instead of the default liberate loop (see [Interactive Shell](#interactive-shell) below), or to `docker exec` into an already running Libation container (so `AccountsSettings.json` and `appsettings.json` are already in place), then run `LibationCli import-account ...` or `LibationCli login-external ...`. Alternatively, run LibationCli on any host where you can point `--libationFiles` (or `LIBATION_FILES_DIR`) at the folder that you later mount as `/config` on the server. ## Running @@ -76,6 +76,19 @@ sudo docker run -d \ rmcrackan/libation:latest ``` +### Interactive Shell + +If you pass a command to `docker run` instead of using the default, the entrypoint script still performs its normal setup (copying config into place, applying `Books`/`InProgress` overrides, and locating/creating the database) but then runs your command instead of the liberate loop. This gives you a shell with the same layout the container uses at runtime, without needing an already-running container to `docker exec` into: + +```bash +sudo docker run --rm -it \ + -v /opt/libation/config:/config \ + -v /opt/libation/books:/data \ + rmcrackan/libation:latest bash +``` + +From there you can run `LibationCli import-account ...`, `LibationCli login-external ...`, or any other one-off command against the mounted config. + ## Environment Variables | Env Var | Default | Description | From 12875993fa8a105a5bf4725d67be075e25dbba29 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:35:56 +0200 Subject: [PATCH 4/9] Add missing LOG_LEVEL variable to the env variables table. --- docs/installation/docker.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/installation/docker.md b/docs/installation/docker.md index e17e211c..d9ab39c5 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -94,6 +94,7 @@ From there you can run `LibationCli import-account ...`, `LibationCli login-exte | Env Var | Default | Description | | -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------- | | SLEEP_TIME | -1 | Length of time to sleep before doing another scan/download. Set to -1 to run one. | +| LOG_LEVEL | | Set to `debug` to enable debug-level log messages from the entrypoint script. | | LIBATION_BOOKS_DIR | /data | Folder where books will be saved | | LIBATION_CONFIG_DIR | /config | Folder to read configuration from. | | LIBATION_DB_DIR | /db | Optional folder to load database from. If not mounted, will load database from `LIBATION_CONFIG_DIR`. | From a438dfd82f4abebbefe30bf77db5572f250ba882 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:51:43 +0200 Subject: [PATCH 5/9] Offer occational support for docker problems ;:) --- docs/installation/docker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/docker.md b/docs/installation/docker.md index d9ab39c5..59fc18b1 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -135,6 +135,6 @@ The docker image supports an optional database mount location defined by `LIBATI ## Getting Help -As mentioned above: docker is not officially supported. I'm adding this at the bottom of the page for anyone serious enough to have read this far. If you've tried everything above and would still like help, you can open an [issue](https://github.com/rmcrackan/Libation/issues). Please include `[docker]` in the title. There are also some docker folks who have offered occasional assistance who you can tag within your issue: `@ducamagnifico` , `@wtanksleyjr` , `@CLHatch`. +As mentioned above: docker is not officially supported. I'm adding this at the bottom of the page for anyone serious enough to have read this far. If you've tried everything above and would still like help, you can open an [issue](https://github.com/rmcrackan/Libation/issues). Please include `[docker]` in the title. There are also some docker folks who have offered occasional assistance who you can tag within your issue: `@ducamagnifico` , `@wtanksleyjr` , `@CLHatch` , `@oxivanisher`. **Reminder** that these are just friendly users who are sometimes around. They're _not_ our customer support. From 28ce71c1b7455c2c33da50102a2ada5f961213de Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 03:00:17 +0200 Subject: [PATCH 6/9] Document on how to access or redirect log files from within docker. --- docs/installation/docker.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/installation/docker.md b/docs/installation/docker.md index 59fc18b1..39a58c78 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -133,6 +133,38 @@ If the user it's running as is correct, and it still cannot write, be sure to ch The docker image supports an optional database mount location defined by `LIBATION_DB_DIR`. This allows the database to be mounted as read/write, while allowing the rest of the configuration files to be mounted as read only. This is specifically useful if running in Kubernetes where you can use Configmaps and Secrets to define the configuration. If the `LIBATION_DB_DIR` is mounted, it will be used, otherwise it will look for the database in `LIBATION_CONFIG_DIR`. If it does not find the database in the expected location, it will attempt to make an empty database there. +## Logging + +LibationCli already writes a `Log.log` file (rolling monthly) using the same logging setup as the desktop apps — no extra configuration is required to generate it. However, in the docker image the log is written to an internal path (`/config-internal`) that isn't persisted or mounted by any of the examples above, so it disappears when the container is removed. To keep it around, use one of the following: + +- **Mount the internal config path**, e.g. add `-v /opt/libation/logs:/config-internal` to your `docker run` command. Note that this directory also holds the staged copies of `AccountsSettings.json`/`Settings.json` and the database symlink, which are regenerated from `/config`/`/db` on every container start. +- **Point the log file at an already-mounted directory** by adding a `Serilog` section to your `Settings.json` (in your `/config` volume) with a `File` sink `path` pointing somewhere persisted, such as `/data/Log.log`. If `Settings.json` already contains a `Serilog` section, Libation uses it as-is instead of generating its own default: + + ```json + "Serilog": { + "MinimumLevel": "Information", + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "/data/Log.log", + "rollingInterval": "Month", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] (at {Caller}) {Message:lj}{NewLine}{Exception} {Properties:j}", + "hooks": "LibationFileManager.FileSinkHook, LibationFileManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + } + } + ], + "Using": [ + "Dinah.Core", + "Serilog.Exceptions" + ], + "Enrich": [ + "WithCaller", + "WithExceptionDetails" + ] + } + ``` + ## Getting Help As mentioned above: docker is not officially supported. I'm adding this at the bottom of the page for anyone serious enough to have read this far. If you've tried everything above and would still like help, you can open an [issue](https://github.com/rmcrackan/Libation/issues). Please include `[docker]` in the title. There are also some docker folks who have offered occasional assistance who you can tag within your issue: `@ducamagnifico` , `@wtanksleyjr` , `@CLHatch` , `@oxivanisher`. From 98f657a40b1372e31289a231d2013a1e0d71f037 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 03:03:02 +0200 Subject: [PATCH 7/9] Correct log file name and remove superfluous spaces. --- docs/installation/docker.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/installation/docker.md b/docs/installation/docker.md index 39a58c78..d1bcf817 100644 --- a/docs/installation/docker.md +++ b/docs/installation/docker.md @@ -39,12 +39,12 @@ Configuration in Libation is handled by two files, `AccountsSettings.json` and ` If you run Libation on a server or in Docker and do not want to copy `AccountsSettings.json` from a desktop install, you can create or update accounts with LibationCli (same binary as in the image under `/libation/LibationCli`, also available on `PATH` as `LibationCli`): -- `import-account` — Import an account from a JSON file exported by [mkb79's audible-cli](https://github.com/mkb79/audible-cli) (or Libation's own compatible export). Example: +- `import-account` — Import an account from a JSON file exported by [mkb79's audible-cli](https://github.com/mkb79/audible-cli) (or Libation's own compatible export). Example: `LibationCli import-account /path/to/account.json` -- `login-external` — Browser-based sign-in: the CLI prints an Audible login URL; you open it in a normal browser, sign in, then paste the final URL from the address bar back into the terminal. Example: - `LibationCli login-external --account you@example.com --locale us` +- `login-external` — Browser-based sign-in: the CLI prints an Audible login URL; you open it in a normal browser, sign in, then paste the final URL from the address bar back into the terminal. Example: + `LibationCli login-external --account you@example.com --locale us` If standard input is not a TTY (for example in some automation), pass the final URL with `--response-url "https://..."` instead of pasting interactively. -- `list-accounts` — List configured accounts and whether each has valid stored credentials (and scan-on/off). Example: +- `list-accounts` — List configured accounts and whether each has valid stored credentials (and scan-on/off). Example: `LibationCli list-accounts` or `LibationCli list-accounts --bare` for tab-separated output. For full syntax, overrides, and the `--libationFiles` option (or the `LIBATION_FILES_DIR` environment variable) when your Libation data directory is not the default, see [Command Line Interface](/docs/advanced/command-line-interface). @@ -135,7 +135,7 @@ The docker image supports an optional database mount location defined by `LIBATI ## Logging -LibationCli already writes a `Log.log` file (rolling monthly) using the same logging setup as the desktop apps — no extra configuration is required to generate it. However, in the docker image the log is written to an internal path (`/config-internal`) that isn't persisted or mounted by any of the examples above, so it disappears when the container is removed. To keep it around, use one of the following: +LibationCli already writes a `LogYYYYMM.log` file (rolling monthly) using the same logging setup as the desktop apps — no extra configuration is required to generate it. However, in the docker image the log is written to an internal path (`/config-internal`) that isn't persisted or mounted by any of the examples above, so it disappears when the container is removed. To keep it around, use one of the following: - **Mount the internal config path**, e.g. add `-v /opt/libation/logs:/config-internal` to your `docker run` command. Note that this directory also holds the staged copies of `AccountsSettings.json`/`Settings.json` and the database symlink, which are regenerated from `/config`/`/db` on every container start. - **Point the log file at an already-mounted directory** by adding a `Serilog` section to your `Settings.json` (in your `/config` volume) with a `File` sink `path` pointing somewhere persisted, such as `/data/Log.log`. If `Settings.json` already contains a `Serilog` section, Libation uses it as-is instead of generating its own default: From ccc814ce1c97d0a9fb809171ab4e4bb142ab0d16 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 03:22:16 +0200 Subject: [PATCH 8/9] Ensure .sh files are unix style --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfdb8b77 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf From 2e4c0a10b0d6e1c3cb5cc992028c16e01ce87b61 Mon Sep 17 00:00:00 2001 From: Marc Urben <264994+oxivanisher@users.noreply.github.com> Date: Sun, 2 Aug 2026 10:04:26 +0200 Subject: [PATCH 9/9] Setup libation-master.key when not set via variable --- Docker/liberate.sh | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Docker/liberate.sh b/Docker/liberate.sh index bcce0638..41246527 100755 --- a/Docker/liberate.sh +++ b/Docker/liberate.sh @@ -38,6 +38,25 @@ init_config_file() { fi } +init_master_key() { + FILE=libation-master.key + FULLPATH=${LIBATION_CONFIG_DIR}/${FILE} + if [ -n "${LIBATION_MASTER_KEY_FILE}" ]; then + debug "LIBATION_MASTER_KEY_FILE is already set, not looking for ${FILE}" + return 0 + fi + if [ -n "${LIBATION_MASTER_KEY}" ]; then + debug "LIBATION_MASTER_KEY is already set, not looking for ${FILE}" + return 0 + fi + if [ -f ${FULLPATH} ]; then + info "loading ${FILE}" + cp ${FULLPATH} ${LIBATION_CONFIG_INTERNAL}/ + else + debug "${FULLPATH} not found, assuming accounts don't use encrypted tokens" + fi +} + update_settings() { FILE=$1 KEY=$2 @@ -154,7 +173,8 @@ main() { info "initializing libation" init_config_file AccountsSettings.json init_config_file Settings.json - + init_master_key + info "loading settings" update_settings Settings.json Books "${LIBATION_BOOKS_DIR:-/data}" update_settings Settings.json InProgress /tmp