From a9a963f9e1eedd91d3123d2e828a0391f18758b0 Mon Sep 17 00:00:00 2001 From: vhsdream Date: Sun, 24 Aug 2025 20:19:09 -0400 Subject: [PATCH] Autocaliweb --- ct/autocaliweb.sh | 76 +++++++ frontend/public/json/autocaliweb.json | 35 +++ install/autocaliweb-install.sh | 310 ++++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 ct/autocaliweb.sh create mode 100644 frontend/public/json/autocaliweb.json create mode 100644 install/autocaliweb-install.sh diff --git a/ct/autocaliweb.sh b/ct/autocaliweb.sh new file mode 100644 index 00000000..cc728dd6 --- /dev/null +++ b/ct/autocaliweb.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: vhsdream +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/gelbphoenix/autocaliweb + +APP="Autocaliweb" +var_tags="${var_tags:-ebooks}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-6}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/autocaliweb ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + setup_uv + + RELEASE=$(curl -fsSL https://api.github.com/repos/gelbphoenix/autocaliweb/releases/latest | jq '.tag_name' | sed 's/^v//') + if [[ "${RELEASE}" != "$(cat ~/.autocaliweb 2>/dev/null)" ]] || [[ ! -f ~/.autocaliweb ]]; then + msg_info "Stopping Services" + systemctl stop autocaliweb metadata-change-detector acw-ingestor acw-auto-zipper + msg_ok "Stopped Services" + + INSTALL_DIR="/opt/autocaliweb" + VIRTUAL_ENV="${INSTALL_DIR}/venv" + $STD tar -cf ~/autocaliweb_bkp.tar "$INSTALL_DIR"/{metadata_change_logs,dirs.json,scripts/ingest_watcher.sh,scripts/auto_zipper_wrapper.sh,scripts/metadata_change_detector_wrapper.sh} + fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb" + msg_info "Updating ${APP}" + cd "$INSTALL_DIR" + $STD uv sync --all-extras --active + cd "$INSTALL_DIR"/koreader/plugins + PLUGIN_DIGEST="$(find acwsync.koplugin -type f -name "*.lua" -o -name "*.json" | sort | xargs sha256sum | sha256sum | cut -d' ' -f1)" + echo "Plugin files digest: $PLUGIN_DIGEST" >acwsync.koplugin/${PLUGIN_DIGEST}.digest + echo "Build date: $(date)" >>acwsync.koplugin/${PLUGIN_DIGEST}.digest + echo "Files included:" >>acwsync.koplugin/${PLUGIN_DIGEST}.digest + zip -r koplugin.zip acwsync.koplugin/ + cp -r koplugin.zip "$INSTALL_DIR"/cps/static + mkdir -p "$INSTALL_DIR"/metadata_temp + $STD tar -xf ~/autocaliweb_bkp.tar --directory / + chown -R acw:acw "$INSTALL_DIR" + msg_ok "Updated $APP" + + msg_info "Starting Services" + systemctl start autocaliweb metadata-change-detector acw-ingestor acw-auto-zipper + msg_ok "Started Services" + + msg_ok "Updated Successfully" + else + msg_ok "Already up to date" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8083${CL}" diff --git a/frontend/public/json/autocaliweb.json b/frontend/public/json/autocaliweb.json new file mode 100644 index 00000000..792645a2 --- /dev/null +++ b/frontend/public/json/autocaliweb.json @@ -0,0 +1,35 @@ +{ + "name": "Autocaliweb", + "slug": "autocaliweb", + "categories": [ + 13 + ], + "date_created": "2025-08-30", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8083, + "documentation": "https://github.com/gelbphoenix/autocaliweb/wiki", + "config_path": "/etc/autocaliweb", + "website": "https://github.com/gelbphoenix/autocaliweb", + "logo": "https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/master/cps/static/icon-dark.svg", + "description": "A modern web management system for eBooks, eComics and PDFs", + "install_methods": [ + { + "type": "default", + "script": "ct/autocaliweb.sh", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 6, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": "admin", + "password": "admin123" + }, + "notes": [] +} diff --git a/install/autocaliweb-install.sh b/install/autocaliweb-install.sh new file mode 100644 index 00000000..e9ed0dd4 --- /dev/null +++ b/install/autocaliweb-install.sh @@ -0,0 +1,310 @@ +#!/usr/bin/env bash + +# Copyright (c) 2025 Community Scripts ORG +# Author: vhsdream +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/gelbphoenix/autocaliweb + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing dependencies" +$STD apt-get install -y --no-install-recommends \ + git \ + sqlite3 \ + build-essential \ + libldap2-dev \ + libssl-dev \ + libsasl-dev \ + imagemagick \ + ghostscript \ + libmagic1 \ + libxi6 \ + libxslt1.1 \ + libxtst6 \ + libxrandr2 \ + libxkbfile1 \ + libxcomposite1 \ + libopengl0 \ + libnss3 \ + libxkbcommon0 \ + libegl1 \ + libxdamage1 \ + libgl1 \ + libglx-mesa0 \ + xz-utils \ + xdg-utils \ + inotify-tools \ + binutils \ + unrar-free \ + zip +msg_ok "Installed dependencies" + +fetch_and_deploy_gh_release "kepubify" "pgaskin/kepubify" "singlefile" "latest" "/usr/bin" "kepubify-linux-64bit" +fetch_and_deploy_gh_release "calibre" "kovidgoyal/calibre" "prebuild" "latest" "/opt/calibre" "calibre-*-x86_64.txz" + +setup_uv + +fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb" + +msg_info "Configuring Autocaliweb" +INSTALL_DIR="/opt/autocaliweb" +CONFIG_DIR="/etc/autocaliweb" +CALIBRE_LIB_DIR="/opt/calibre-library" +INGEST_DIR="/opt/acw-book-ingest" +SERVICE_USER="acw" +SERVICE_GROUP="acw" +SCRIPTS_DIR="${INSTALL_DIR}/scripts" +VIRTUAL_ENV="${INSTALL_DIR}/venv" + +mkdir -p "$CONFIG_DIR"/{.config/calibre/plugins,log_archive,.acw_conversion_tmp} +mkdir -p "$CONFIG_DIR"/processed_books/{converted,imported,failed,fixed_originals} +mkdir -p "$INSTALL_DIR"/{metadata_change_logs,metadata_temp} +mkdir -p {"$CALIBRE_LIB_DIR","$INGEST_DIR"} + +cd "$INSTALL_DIR" +$STD uv venv "$VIRTUAL_ENV" +$STD uv sync --all-extras --active +cat <./dirs.json +{ + "ingest_folder": "$INGEST_DIR", + "calibre_library_dir": "$CALIBRE_LIB_DIR", + "tmp_conversion_dir": "$CONFIG_DIR/.acw_conversion_tmp" +} +EOF +useradd -s /usr/sbin/nologin -d "$CONFIG_DIR" -M "SERVICE_USER" +msg_ok "Configured Autocaliweb" + +msg_info "Creating ACWSync Plugin for KOReader" +cd "$INSTALL_DIR"/koreader/plugins +PLUGIN_DIGEST="$(find acwsync.koplugin -type f -name "*.lua" -o -name "*.json" | sort | xargs sha256sum | sha256sum | cut -d' ' -f1)" +echo "Plugin files digest: $PLUGIN_DIGEST" >acwsync.koplugin/${PLUGIN_DIGEST}.digest +echo "Build date: $(date)" >>acwsync.koplugin/${PLUGIN_DIGEST}.digest +echo "Files included:" >>acwsync.koplugin/${PLUGIN_DIGEST}.digest +zip -r koplugin.zip acwsync.koplugin/ +cp -r koplugin.zip "$INSTALL_DIR"/cps/static +msg_ok "Created ACWSync Plugin" + +msg_info "Initializing databases" +KEPUBIFY_PATH=$(command -v kepubify 2>/dev/null || echo "/usr/bin/kepubify") +EBOOK_CONVERT_PATH=$(command -v ebook-convert 2>/dev/null || echo "/usr/bin/ebook-convert") +CALIBRE_BIN_DIR=$(dirname "$EBOOK_CONVERT_PATH") +cp "$INSTALL_DIR"/library/metadata.db "$CALIBRE_LIB_DIR"/metadata.db + +cp "$INSTALL_DIR"/library/app.db "$CONFIG_DIR"/app.db +sqlite3 "$CONFIG_DIR/app.db" <"$SCRIPTS_DIR"/ingest_watcher.sh +#!/bin/bash + +WATCH_FOLDER=\$(grep -o '"ingest_folder": "[^"]*' \${INSTALL_DIR}/dirs.json | grep -o '[^"]*\$') +echo "[acw-ingest-service] Watching folder: \$WATCH_FOLDER" + +# Monitor the folder for new files +/usr/bin/inotifywait -m -r --format="%e %w%f" -e close_write -e moved_to "\$WATCH_FOLDER" | +while read -r events filepath ; do + echo "[acw-ingest-service] New files detected - \$filepath - Starting Ingest Processor..." + # Use the Python interpreter from the virtual environment + \${VIRTUAL_ENV}/bin/python \${SCRIPTS_DIR}/ingest_processor.py "\$filepath" +done +EOF + +# auto-zipper +cat <"$SCRIPTS_DIR"/auto_zipper_wrapper.sh +#!/bin/bash + +# Source virtual environment +source ${VIRTUAL_ENV}/bin/activate + +WAKEUP="23:59" + +while true; do + # Replace expr with modern Bash arithmetic (safer and less prone to parsing issues) + # fix: expr: non-integer argument and sleep: missing operand + SECS=\$(( \$(date -d "\$WAKEUP" +%s) - \$(date -d "now" +%s) )) + if [[ \$SECS -lt 0 ]]; then + SECS=\$(( \$(date -d "tomorrow \$WAKEUP" +%s) - \$(date -d "now" +%s) )) + fi + echo "[acw-auto-zipper] Next run in \$SECS seconds." + sleep \$SECS & + wait \$! + + # Use virtual environment python + python ${SCRIPTS_DIR}/auto_zip.py + + if [[ \$? == 1 ]]; then + echo "[acw-auto-zipper] Error occurred during script initialisation." + elif [[ \$? == 2 ]]; then + echo "[acw-auto-zipper] Error occurred while zipping today's files." + elif [[ \$? == 3 ]]; then + echo "[acw-auto-zipper] Error occurred while trying to remove zipped files." + fi + + sleep 60 +done +EOF + +# metadata change detector +cat <"$SCRIPTS_DIR"/metadata_change_detector_wrapper.sh +#!/bin/bash +# metadata_change_detector_wrapper.sh - Wrapper for periodic metadata enforcement + +# Source virtual environment +source ${VIRTUAL_ENV}/bin/activate + +# Configuration +CHECK_INTERVAL=300 # Check every 5 minutes (300 seconds) +METADATA_LOGS_DIR="${INSTALL_DIR}/metadata_change_logs" + +echo "[metadata-change-detector] Starting metadata change detector service..." +echo "[metadata-change-detector] Checking for changes every \$CHECK_INTERVAL seconds" + +while true; do + # Check if there are any log files to process + if [ -d "\$METADATA_LOGS_DIR" ] && [ "\$(ls -A \$METADATA_LOGS_DIR 2>/dev/null)" ]; then + echo "[metadata-change-detector] Found metadata change logs, processing..." + + # Process each log file + for log_file in "\$METADATA_LOGS_DIR"/*.json; do + if [ -f "\$log_file" ]; then + log_name=\$(basename "\$log_file") + echo "[metadata-change-detector] Processing log: \$log_name" + + # Call cover_enforcer.py with the log file + ${INSTALL_DIR}/venv/bin/python ${SCRIPTS_DIR}/cover_enforcer.py --log "\$log_name" + + if [ \$? -eq 0 ]; then + echo "[metadata-change-detector] Successfully processed \$log_name" + else + echo "[metadata-change-detector] Error processing \$log_name" + fi + fi + done + else + echo "[metadata-change-detector] No metadata changes detected" + fi + + echo "[metadata-change-detector] Sleeping for \$CHECK_INTERVAL seconds..." + sleep \$CHECK_INTERVAL +done +EOF +chmod +x "$SCRIPTS_DIR"/{ingest_watcher.sh,auto_zipper_wrapper.sh,metadata_change_detector_wrapper.sh} +chown -R "$SERVICE_USER":"$SERVICE_GROUP" {"$INSTALL_DIR","$CONFIG_DIR","$INGEST_DIR","$CALIBRE_LIB_DIR"} + +# systemd service files +SYS_PATH="/etc/systemd/system" +cat <"$SYS_PATH"/autocaliweb.service +[Unit] +Description=Autocaliweb +After=network.target +Wants=network-online.target +After=network-online.target + +[Service] +Type=simple +User=$SERVICE_USER +Group=$SERVICE_GROUP +WorkingDirectory=$INSTALL_DIR +Environment=PATH=$INSTALL_DIR/venv/bin:/usr/bin:/bin +Environment=PYTHONPATH=$SCRIPTS_DIR:$INSTALL_DIR +Environment=PYTHONDONTWRITEBYTECODE=1 +Environment=PYTHONUNBUFFERED=1 +Environment=CALIBRE_DBPATH=$CONFIG_DIR +ExecStart=$INSTALL_DIR/venv/bin/python $INSTALL_DIR/cps.py -p $CONFIG_DIR/app.db + +Restart=always +RestartSec=10 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + +cat <"$SYS_PATH"/acw-ingestor.service +[Unit] +Description=Autocaliweb Ingest Processor Service +After=autocaliweb.service +Requires=autocaliweb.service + +[Service] +User=${SERVICE_USER} +Group=${SERVICE_GROUP} +WorkingDirectory=${INSTALL_DIR} +Environment=CALIBRE_DBPATH=${CONFIG_DIR} +Environment=HOME=${CONFIG_DIR} +ExecStart=/bin/bash ${SCRIPTS_DIR}/ingest_watcher.sh +Restart=always +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + +cat <"$SYS_PATH"/acw-auto-zipper.service +[Unit] +Description=Autocaliweb Auto Zipper Service +After=network.target + +[Service] +User=${SERVICE_USER} +Group=${SERVICE_GROUP} +WorkingDirectory=${INSTALL_DIR} +Environment=CALIBRE_DBPATH=${CONFIG_DIR} +ExecStart=${SCRIPTS_DIR}/auto_zipper_wrapper.sh +Restart=always +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + +cat <"$SYS_PATH"/metadata-change-detector.service +[Unit] +Description=Autocaliweb Metadata Change Detector +After=network.target + +[Service] +User=${SERVICE_USER} +Group=${SERVICE_GROUP} +WorkingDirectory=${INSTALL_DIR} +ExecStart=/bin/bash ${SCRIPTS_DIR}/metadata_change_detector_wrapper.sh +Restart=always +StandardOutput=journal +StandardError=journal +Environment=CALIBRE_DBPATH=${CONFIG_DIR} +Environment=HOME=${CONFIG_DIR} +[Install] +WantedBy=multi-user.target +EOF + +systemctl -q enable --now autocaliweb acw-ingestor acw-auto-zipper metadata-change-detector +msg_ok "Created scripts and service files" + +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned"