### Example: Setting Autocaliweb Installation Directory Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Use this example to set a custom installation directory for Autocaliweb's core application files during a manual installation. ```bash export ACW_INSTALL_DIR="/usr/local/autocaliweb" ``` -------------------------------- ### Example: Setting Ingest Directory Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Use this example to specify the directory where new books will be placed for processing by the manual installation script. ```bash export INGEST_DIR="/mnt/storage/NewBooks" ``` -------------------------------- ### Example: Setting Autocaliweb Configuration Directory Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Use this example to specify a custom directory for Autocaliweb's configuration files, databases, and logs during a manual installation. ```bash export ACW_CONFIG_DIR="/etc/autocaliweb" ``` -------------------------------- ### Example: Setting Autocaliweb User Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Use this example to define the user account under which Autocaliweb services will run and own files during a manual installation. ```bash export ACW_USER="autocali" ``` -------------------------------- ### Run Autocaliweb Installation Script Source: https://github.com/gelbphoenix/autocaliweb/wiki/Manual-Installation Navigate to the cloned directory and execute the manual installation script. This script handles dependency installation, environment setup, and service configuration. ```bash cd /app/autocaliweb chmod +x scripts/manual_install_acw.sh ./scripts/manual_install_acw.sh ``` -------------------------------- ### Example: Setting Calibre Library Directory Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration This example shows how to set the root directory for your Calibre library, where books and metadata are stored. It can be used for manual installs or via command-line. ```bash export LIBRARY_DIR="/mnt/books/MyCalibreLibrary" ``` -------------------------------- ### Configuration Priority: Command-line Argument Example Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Illustrates the highest priority configuration source: command-line arguments. This example shows overriding the installation directory directly when running the script. ```bash manual_install_acw.sh --install-dir "/home/youruser/apps/autocaliweb" ``` -------------------------------- ### Example: Setting Autocaliweb Group Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Use this example to set the primary group for Autocaliweb services and file ownership during a manual installation. ```bash export ACW_GROUP="acwusers" ``` -------------------------------- ### Configuration Priority: Environment Variable Example Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration Demonstrates how setting an environment variable like ACW_INSTALL_DIR before running the manual install script will override the script's default installation directory. ```bash export ACW_INSTALL_DIR="/usr/local/autocaliweb"; manual_install_acw.sh ``` -------------------------------- ### Execute Manual Installation Script Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Make the downloaded script executable and run it as root to perform the manual installation of Autocaliweb. Follow the on-screen prompts. ```bash sudo chmod +x ./manual_install_acw.sh && sudo ./manual_install_acw.sh ``` -------------------------------- ### Manually Start Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/wiki/Manual-Installation Manually start Autocaliweb by executing its start script. This method is an alternative to using systemd. ```bash /app/autocaliweb/start_autocaliweb.sh ``` -------------------------------- ### Download Manual Installation Script Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Download the manual installation script for Autocaliweb. It is recommended to check the script's content before execution. ```bash curl -Lo ./manual_install_acw.sh https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/main/scripts/manual_install_acw.sh ``` -------------------------------- ### Autocaliweb Manual Installation Environment Variables Source: https://github.com/gelbphoenix/autocaliweb/wiki/Configuration These variables are for manual installations to customize installation paths, directories, and user/group ownership. They take precedence over script defaults. ```bash ACW_INSTALL_DIR= ACW_CONFIG_DIR= ACW_USER= ACW_GROUP= INGEST_DIR= ``` -------------------------------- ### Install Autocaliweb via Proxmox VE Helper-Script (Gitea) Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md This command installs Autocaliweb on Proxmox VE using the community-maintained Helper-Scripts. Use this link if the GitHub source is unavailable or as directed. ```bash bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/ct/autocaliweb.sh)" ``` -------------------------------- ### Install Autocaliweb via Proxmox VE Helper-Script (GitHub) Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md This command installs Autocaliweb on Proxmox VE using the community-maintained Helper-Scripts. It fetches the script directly from GitHub. ```bash bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/autocaliweb.sh)" ``` -------------------------------- ### Start Autocaliweb with Docker Compose Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Navigate to the directory containing your docker-compose.yml file and run this command to start Autocaliweb in detached mode. ```bash docker compose up -d ``` -------------------------------- ### Start Autocaliweb Service using Systemd Source: https://github.com/gelbphoenix/autocaliweb/wiki/Manual-Installation Start and check the status of the Autocaliweb service using systemctl. This is the recommended method for managing the application's lifecycle. ```bash sudo systemctl start autocaliweb sudo systemctl status autocaliweb ``` -------------------------------- ### Install JavaScript Dev Dependencies Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Installs the necessary development dependencies for JavaScript linting and other tools. Run this command in the project's root directory. ```bash npm install ``` -------------------------------- ### JavaScript for Library Refresh Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/layout.html Handles asynchronous fetching and display of library refresh status messages. Includes functions to start, stop, and update the refresh status. ```javascript let checkMessagesInterval = null; // Store interval ID function refreshLibrary() { fetch("/acw-library-refresh", { method: "POST", headers: { "Content-Type": "application/json" } }) .then(response => response.json()) .then(data => { updateLibraryRefreshMessage(data.message); // Show immediate confirmation startCheckingMessages(); // Start checking for messages }) .catch(error => console.error("Error:", error)); } function checkLibraryMessages() { fetch("/acw-library-refresh/messages") .then(response => response.json()) .then(data => { if (data.messages.length > 0) { updateLibraryRefreshMessage(data.messages.join("
")); // Show messages stopCheckingMessages(); // Stop checking once we get a message } }) .catch(error => console.error("Error fetching messages:", error)); } function startCheckingMessages() { if (!checkMessagesInterval) { // Prevent multiple intervals checkMessagesInterval = setInterval(checkLibraryMessages, 500); } } function stopCheckingMessages() { if (checkMessagesInterval) { clearInterval(checkMessagesInterval); checkMessagesInterval = null; } } function updateLibraryRefreshMessage(message) { const messageDiv = document.getElementById("message_library_refresh"); const messagePara = document.getElementById("library_refresh_message") if (messageDiv) { messagePara.innerHTML = message; // Set the message inside the div messageDiv.style.display = "inline-flex"; // Make sure it's visible } } function dismissLibraryRefreshMessage() { const messageDiv = document.getElementById("message_library_refresh"); const messagePara = document.getElementById("library_refresh_message") if (messageDiv) { messagePara.innerHTML = ""; // Set the message inside the div messageDiv.style.display = "none"; // Make sure it's visible } } ``` -------------------------------- ### Uninstall Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/wiki/Manual-Installation Navigate to the installation directory and execute the uninstallation script to remove Autocaliweb. Ensure you have the necessary permissions. ```bash cd /app/autocaliweb chmod +x scripts/Uninstall_acw.sh ./scripts/Uninstall_acw.sh ``` -------------------------------- ### Autocaliweb OIDC Provider Settings Source: https://github.com/gelbphoenix/autocaliweb/wiki/Single-Sign-On-and-OpenID-Connect Configuration parameters within Autocaliweb to establish the connection with the VoidAuth OIDC provider. Ensure these match the VoidAuth client setup. ```text generic OAuth Client Id: your-client-id generic OAuth Client Secret: your-client-secret generic OAuth scope: openid profile email generic OAuth Metadata URL: Copy from OIDC Info in VoidAuth (Well-Known Endpoint) generic OAuth Username mapper: preferred_username generic OAuth Email mapper: email generic OAuth Login Button: VoidAuth ``` -------------------------------- ### SoundManager Setup for HTML5 Audio Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/listenmp3.html Configures SoundManager to use HTML5 Audio, disabling Flash fallback. This snippet is essential for enabling audio playback in modern browsers. ```javascript soundManager.setup({ useHTML5Audio: true, preferFlash: false, url: "/path/to/swf-files/", onready: function () { var mySound = soundManager.createSound({ // id: 'aSound', // url: "{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}" }); mySound.play(); }, ontimeout: function () { // Hrmm, SM2 could not start. Missing SWF? Flash blocked? Show an error, etc.? }, }); ``` -------------------------------- ### Initialize Custom Theme UI and Pickr Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Sets up the custom theme UI, including the color swatch and potentially a color picker (Pickr). It retrieves saved theme colors and applies them, also determining text color contrast. ```javascript (function () { var swatch = document.getElementById("customThemeSwatch"); var saved = window.themes && window.themes.customTheme && window.themes.customTheme.bgColor ? window.themes.customTheme.bgColor : "#ffffff"; if (swatch) swatch.style.background = saved; function _hexToRgb(hex) { hex = hex.replace("#", ""); if (hex.length === 3) { hex = hex .split("") .map(function (h) { return h + h; }) .join(""); } var bigint = parseInt(hex, 16); return { r: (bigint >> 16) & 255, g: (bigint >> 8) & 255, b: bigint & 255, }; } // Better contrast decision using WCAG relative luminance and contrast ratio // Returns true if black text is the better choice (i.e. background is light) function _isLight(hex) { try { var rgb = _hexToRgb(hex); // convert 0-255 to 0-1 var srgb = { r: rgb.r / 255, g: rgb.g / 255, b: rgb.b / 255 }; function lin(c) { return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); } var R = lin(srgb.r), G = lin(srgb.g), B = lin(srgb.b); var L = 0.2126 * R + 0.7152 * G + 0.0722 * B; // relative luminance // contrast ratios against black (L=0) and white (L=1) var contrastWithBlack = (L + 0.05) / (0.0 + 0.05); var contrastWithWhite = (1.0 + 0.05) / (L + 0.05); // pick the text color that gives higher contrast. ``` -------------------------------- ### Initialize Color Picker and Theme Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Initializes the Pickr color picker component if available, allowing users to select a custom theme color. It applies the selected color immediately and also responds to the save action. ```javascript function ensurePickrAndInit() { if (window.Pickr) { try { var pickr = Pickr.create({ el: "#customThemeSwatch", theme: "classic", default: saved, components: { preview: true, opacity: false, hue: true, interaction: { hex: true, input: true, save: true, }, }, }); // Immediate apply when color changes in the picker pickr.on("change", function (color, instance) { try { var hex = color.toHEXA().toString(); if (swatch) swatch.style.background = hex; applyCustomColor(hex); } catch (e) {} }); // Also respond to save (some pickr configs use save) pickr.on("save", function (color, instance) { try { var hex = color.toHEXA().toString(); if (swatch) swatch.style.background = hex; applyCustomColor(hex); pickr.hide(); } catch (e) {} }); // Clicking swatch opens pickr if (swatch) swatch.addEventListener("click", function () { pickr.show(); }); } catch (e) { console.error("Pickr init failed", e); } return; } // wait a bit setTimeout(ensurePickrAndInit, 150); } ensurePickrAndInit(); })(); ``` -------------------------------- ### Autocaliweb Docker Compose Configuration Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md This is a sample Docker Compose file for setting up Autocaliweb. Ensure you configure Timezone and volume binds according to your environment. ```yaml services: autocaliweb: image: gelbphoenix/autocaliweb:latest container_name: autocaliweb restart: unless-stopped ports: - "8083:8083" environment: - TZ=Etc/UTC # Change to your specific timezone (e.g. Europe/Berlin, America/Denver) - PUID=1000 - PGID=1000 volumes: - /path/to/config:/config - /path/to/book/ingest:/acw-book-ingest - /path/to/library:/calibre-library stop_signal: SIGINT stop_grace_period: 15s ``` -------------------------------- ### Download Docker Compose Template Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Use this command to download the Docker Compose template file. Save it to your desired data directory for Autocaliweb. ```bash curl -Lo ./docker-compose.yml https://raw.githubusercontent.com/gelbphoenix/autocaliweb/main/docker-compose.yml ``` -------------------------------- ### Comic Reader Initialization Script Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/readcbr.html Initializes the Comic Reader application, setting up bookmarking functionality based on user authentication and stored bookmark data. It fetches the book content from the server. ```javascript window.calibre = { bookmarkUrl: "{{ url_for('web.set_bookmark', book_id=comicfile, book_format=extension.upper()) }}", bookmark: "{{ bookmark.bookmark_key if bookmark != None }}", useBookmarks: "{{ current_user.is_authenticated | tojson }}", }; document.onreadystatechange = function () { if (document.readyState == "complete") { if (calibre.useBookmarks) { currentImage = eval(calibre.bookmark); if (typeof currentImage !== "number") { currentImage = 0; } } init( "{{ url_for('web.serve_book', book_id=comicfile, book_format=extension) }}" ); } }; ``` -------------------------------- ### Configure Authelia Client for Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/wiki/Single-Sign-On-and-OpenID-Connect Add this client configuration to your Authelia `configuration.yaml` to enable Autocaliweb as an OIDC client. Ensure the redirect URI matches your Autocaliweb domain. ```yaml identity_providers: oidc: # ... clients: - id: autocaliweb description: Autocaliweb secret: public: false authorization_policy: one_factor # if you want to require 2FA, set this to `two_factor` redirect_uris: - "https:///login/generic/authorized" scopes: - openid - profile - email userinfo_signed_response_alg: none ``` -------------------------------- ### Calibre Web Application Configuration Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/listenmp3.html Sets up global JavaScript variables for the Calibre web application, including paths to static assets, book URLs, and bookmarking configurations. This is used to interface with the backend for managing book data and user progress. ```javascript window.calibre = { filePath: "{{ url_for('static', filename='js/libs/') }}", cssPath: "{{ url_for('static', filename='css/') }}", bookUrl: "{{ url_for('static', filename=mp3file) }}/", bookmarkUrl: "{{ url_for('web.set_bookmark', book_id=mp3file, book_format=audioformat.upper()) }}", bookmark: "{{ bookmark.bookmark_key if bookmark != None }}", useBookmarks: "{{ current_user.is_authenticated | tojson }}", }; ``` -------------------------------- ### VoidAuth OIDC Client Configuration Source: https://github.com/gelbphoenix/autocaliweb/wiki/Single-Sign-On-and-OpenID-Connect Configuration details for setting up a new OIDC client within the VoidAuth portal. These values are required for the Autocaliweb integration. ```text Client ID: your-client-id Auth Method: Client Secret Basic Client Secret: your-client-secret Redirect URLs: https://autocaliweb.example.com/login/generic/authorized ``` -------------------------------- ### Kobo API Endpoint Configuration Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/generate_kobo_auth_url.html Add this line to the .kobo/Kobo/Kobo eReader.conf file to set the API endpoint for Kobo eReader authentication. Ensure the auth_token is correctly generated. ```html {% extends "fragment.html" %} {% block body %} {% if not warning %} {{\_('Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):')}} api_endpoint={{url_for("kobo.TopLevelEndpoint", auth_token=auth_token, _external=True)}} {% else %} {{warning}} {% endif %} {% endblock %} ``` -------------------------------- ### Jinja Macro for Book Cover Image Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/image.html Generates a Markdown image link for a book cover. It sets the image title and alt text, constructs a srcset attribute, and creates a URL for the book's cover image, including a cache-busting parameter based on the last modification time. ```html {% macro book_cover(book, alt=None) -%} {%- set image_title = book.title if book.title else book.name -%} {%- set image_alt = alt if alt else image_title -%} {% set srcset = book|get_cover_srcset %} ![{{ image_alt }}]({{ url_for('web.get_cover', book_id=book.id, resolution='og', c=book|last_modified) }}) {%- endmacro %} ``` -------------------------------- ### Configure Libre Workspace OIDC Provider in Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/wiki/Single-Sign-On-and-OpenID-Connect Use these settings to configure Autocaliweb to use Libre Workspace as an OIDC provider. Ensure you replace placeholders with your actual client ID, secret, and portal domain. ```text generic OAuth Client Id: generic OAuth Client Secret: generic OAuth scope: openid profile email admin generic OAuth Metadata URL: https:///.well-known/openid-configuration Use Manual URLs: [] generic OAuth Username mapper: preferred_username generic OAuth Email mapper: email generic OAuth Login Button: (Libre Workspace or your own custom name) ``` -------------------------------- ### Apply Theme Settings Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Applies background and title bar colors from a theme object based on the provided ID. Falls back to default white for title bar color if not specified. ```javascript document.getElementById("main").style.backgroundColor = themes[id]["bgColor"]; document.getElementById("titlebar").style.color = themes[id]["title-color"] || "#fff"; document.getElementById("progress").style.color = themes[id]["title-color"] || "#fff"; ``` -------------------------------- ### Epub Reader Theme Selection Logic Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Handles the logic for selecting and applying themes in the Epub Reader. It updates the UI to show the selected theme and applies the theme to the reader's iframe. ```javascript function selectTheme(id) { let tickSpans = document .getElementById("themes") .querySelectorAll("span"); // Remove tick mark from all theme buttons tickSpans.forEach(function (tickSpan) { try { tickSpan.textContent = ""; } catch (e) {} }); // Add tick mark to the button corresponding to the currently selected theme var el = document.getElementById(id); if (el) { var sp = el.querySelector("span"); if (sp) sp.textContent = "✓"; } else { var spById = document.getElementById(id + "Selected") || document.getElementById("customSelected"); if (spById) spById.textContent = "✓"; } // Saving theme to local storage localStorage.setItem("calibre.reader.theme", id); // If selecting custom theme, ensure epubjs theme is registered with chosen bg color if (id === "customTheme") { var customColor = window.themes.customTheme.bgColor || "#ffffff"; try { if (reader && reader.rendition && reader.rendition.themes) { reader.rendition.themes.register("customTheme", { body: { background: customColor, }, }); reader.rendition.themes.select("customTheme"); } } catch (e) { console.error("Failed to register/select customTheme", e); } } else { // Apply theme to epubjs iframe try { reader.rendition.themes.select(id); } catch (e) {} } // Apply theme to rest of the page. ``` -------------------------------- ### Clone Autocaliweb Source Code Source: https://github.com/gelbphoenix/autocaliweb/wiki/Manual-Installation Clone the Autocaliweb repository to the required /app/autocaliweb path and set ownership. This step is crucial for mimicking the Docker environment's directory structure. ```bash sudo git clone https://github.com/gelbphoenix/autocaliweb.git /app/autocaliweb sudo chown -R $USER:$USER /app ``` -------------------------------- ### Initialize Navigation Mode on Load Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Immediately invoked function that retrieves the saved navigation mode from localStorage or defaults to 'sizes', then applies it using the selectNavMode function. ```javascript (function () { var savedMode = localStorage.getItem("calibre.reader.navMode") || "sizes"; selectNavMode(savedMode); })(); ``` -------------------------------- ### Basic Pagination Controls Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/basic_index.html Displays 'Previous' and 'Next' pagination links if they exist. Links are generated using url_for_other_page. ```html {% if pagination.has_prev %} [« {{_('Previous')}}]({{ (pagination.page - 1)|url_for_other_page }}) {% endif %} {% if pagination.has_next %} [{_('Next')} »]({{ (pagination.page + 1)|url_for_other_page }}) {% endif %} ``` -------------------------------- ### Configure PDF Viewer Options Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/readpdf.html Sets various options for the PDF viewer application upon loading, such as disabling auto-fetch, configuring cmap URL, and specifying worker source. This is useful for customizing the viewer's behavior and resource loading. ```javascript window.addEventListener("webviewerloaded", function () { PDFViewerApplicationOptions.set("disableAutoFetch", true); PDFViewerApplicationOptions.set("disableRange", false); PDFViewerApplicationOptions.set("disableStream", true); PDFViewerApplicationOptions.set("disablePreferences", true); PDFViewerApplicationOptions.set( "cMapUrl", "{{ url_for('static', filename='cmaps/') }}" ); PDFViewerApplicationOptions.set("sidebarViewOnLoad", 0); PDFViewerApplicationOptions.set( "imageResourcesPath", "{{ url_for('static', filename='css/images/') }}" ); PDFViewerApplicationOptions.set( "workerSrc", "{{ url_for('static', filename='js/libs/pdf.worker.js') }}" ); PDFViewerApplicationOptions.set( "defaultUrl", "{{ url_for('web.serve_book', book_id=pdffile, book_format='pdf') }}" ); }); ``` -------------------------------- ### Run JavaScript Linting (CI Alias) Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md A CI-friendly alias for running JavaScript linting. This command is typically used in continuous integration pipelines. ```bash npm run lint:ci ``` -------------------------------- ### Generate Book Cover with Cache Busting Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/book_edit.html Triggers a POST request to generate a book cover. On success, it reloads the cover image using a cache-busting query parameter and updates the button state. Handles errors by showing alerts. ```javascript $(document).ready(() => { $('#confirm-generate-cover').click(() => { $.ajax({ type: 'POST', url: "{{ url_for('edit-book.generate_book_cover', book_id=book.id) }}", success: (response) => { if (response.success) { const coImg = document.getElementById('detailcover'); let cuSrc = coImg.src; let newSrc; if (cuSrc.includes("?")) { newSrc = cuSrc + "&reload=" + new Date().getTime(); } else { newSrc = cuSrc + "?reload=" + new Date().getTime(); } coImg.src = newSrc; const genButton = document.getElementById('generate-cover'); genButton.disabled = true; genButton.innerText = "{{ _('Cover Generated – Click Save to save it') }}"; } else { alert("{{ _('Error generating cover:') }} " + (response.error || "{{ _('Unknown error') }}")); } }, error: () => { alert("{{ _('Error communicating with server') }}"); } }); $('#generateCoverModal').modal('hide'); }) }) ``` -------------------------------- ### Main Entry Loop with Conditional Break Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/list.html Iterates through a list of 'entries'. It includes a conditional check to potentially insert content after a certain number of items, specifically when the list length is greater than 20 and the current item is near the middle. ```html {% for entry in entries %} {% if loop.index0 == (loop.length/2+loop.length%2)|int and loop.length > 20 %} {% endif %} {{entry[1]}} [{% if entry.name %} {% for number in range(entry.name|int) %} {% if loop.last and loop.index < 5 %} {% for numer in range(5 - loop.index) %} {% endfor %} {% endif %} {% endfor %} {% else %} {% if entry.format %} {{entry.format}} {% else %} {{entry[0].name}}{% endif %}{% endif %}]({% if entry.format %}{{url_for('web.books_list', data=data, sort_param='stored', book_id=entry.format )}}{% else %}{{url_for('web.books_list', data=data, sort_param='stored', book_id=entry[0].id )}}{% endif %}) {% endfor %} ``` -------------------------------- ### Run JavaScript Linting Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Executes ESLint to check for code style and potential errors in the JavaScript files. This command helps maintain code quality. ```bash npm run lint ``` -------------------------------- ### Compare and Display Cover Image Dimensions Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/book_edit.html Compares the dimensions of a newly loaded image with an existing cover image and updates the display text with 'smaller' or 'larger' class if dimensions differ. ```javascript function coverDimensions(el) { var existing_cover = document.querySelector("#detailcover") el.nextElementSibling.innerText = el.naturalWidth + 'x' + el.naturalHeight if (existing_cover.naturalHeight*existing_cover.naturalWidth > el.naturalWidth * el.naturalHeight){ el.nextElementSibling.classList.add("smaller") } else if (existing_cover.naturalHeight*existing_cover.naturalWidth < el.naturalWidth * el.naturalHeight){ el.nextElementSibling.classList.add("larger") } } ``` -------------------------------- ### Jinja Macro for Series Cover Image Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/image.html Generates a Markdown image link for a series cover. It sets the alt text and constructs a srcset attribute. The image URL is created for the series cover, incorporating a cache timestamp. ```html {% macro series(series, alt=None) -%} {%- set image_alt = alt if alt else image_title -%} {% set srcset = series|get_series_srcset %} ![{{ title }}]({{ url_for('web.get_series_cover', series_id=series.id, resolution='og', c='day'|cache_timestamp) }}) {%- endmacro %} ``` -------------------------------- ### Basic Search Form Fields Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/search_form.html Renders input fields for book title, author, publisher, and date ranges. Includes options for read status and selection of tags, series, shelves, languages, and extensions. ```html {% extends "layout.html" %} {% block body %} {{title}} ========= {{_('Book Title')}} {{_('Author')}} {{_('Publisher')}} {{_('Published Date From')}} {{_('Published Date To')}} {{_('Read Status')}} {{\_('Any')}} {{\_('Empty')}} {{\_('Yes')}} {{\_('No')}} {{_('Tags')}} {% for tag in tags %} {{tag.name}} {% endfor %} {{_('Exclude Tags')}} {% for tag in tags %} {{tag.name}} {% endfor %} {{_('Series')}} {% for serie in series %} {{serie.name}} {% endfor %} {{_('Exclude Series')}} {% for serie in series %} {{serie.name}} {% endfor %} {{_('Shelves')}} {% for shelf in shelves %} {{shelf.name}} {% endfor %} {{_('Exclude Shelves')}} {% for shelf in shelves %} {{shelf.name}} {% endfor %} {% if languages %} {{_('Languages')}} {% for language in languages %} {{language.name}} {% endfor %} {{_('Exclude Languages')}} {% for language in languages %} {{language.name}} {% endfor %} {% endif%} {{_('Extensions')}} {% for extension in extensions %} {{extension.format}} {% endfor %} {{_('Exclude Extensions')}} {% for extension in extensions %} {{extension.format}} {% endfor %} {{_('Rating Above')}} {{_('Rating Below')}} {{_('Description')}} {% if cc|length > 0 %} {% for c in cc %} {{ c.name }} {% if c.datatype == 'bool' %} {{\_('Any')}} {{\_('Empty')}} {{\_('Yes')}} {{\_('No')}} {% endif %} {% if c.datatype == 'int' %} {{_('From:')}} {{_('To:')}} {% endif %} {% if c.datatype == 'float' %} {{_('From:')}} {{_('To:')}} {% endif %} {% if c.datatype == 'datetime' %} {{_('From:')}} {{_('To:')}} {% endif %} {% if c.datatype in ['text', 'series', 'comments'] and not c.is_multiple %} {% endif %} {% if c.datatype in ['text', 'series'] and c.is_multiple %} {% endif %} {% if c.datatype == 'enumeration' %} {% for opt in c.get_display_dict().enum_values %} {{ opt }} {% endfor %} {% endif %} {% if c.datatype == 'rating' %} {% endif %} {% endfor %} {% endif %} {{_('Search')}} {% endblock %} ``` -------------------------------- ### Initialize ACW Auto-Ingest Automerge Settings Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/acw_settings.html This script initializes the ACW Auto-Ingest Automerge settings on page load. It fetches available metadata providers, populates the provider list, sets up drag-and-drop functionality for reordering, and handles fallback mechanisms if API calls fail. ```javascript document.addEventListener('DOMContentLoaded', () => { // Get current hierarchy from Autocaliweb settings const currentHierarchyStr = {{ acw_settings.get("metadata_provider_hierarchy", '["ibdb","google","dnb"]') | tojson }}; let providerHierarchy = []; try { if (typeof currentHierarchyStr === 'string') { providerHierarchy = JSON.parse(currentHierarchyStr); } else { providerHierarchy = currentHierarchyStr; } } catch (e) { console.error('Error parsing hierarchy:', e); providerHierarchy = ["ibdb", "google", "dnb"]; // fallback } // Fetch available providers from the API fetch('/metadata/provider') .then(response => response.json()) .then(providers => { populateProviderList(providers, providerHierarchy); setupDragAndDrop(); }) .catch(error => { console.error('Error fetching providers:', error); // Fallback with static list const fallbackProviders = [ {id: 'google', name: 'Google Books', active: true}, {id: 'dnb', name: 'DNB', active: true}, {id: 'ibdb', name: 'IBDb', active: true}, {id: 'comicvine', name: 'ComicVine', active: true}, {id: 'douban', name: 'Douban', active: true} ]; populateProviderList(fallbackProviders, providerHierarchy); setupDragAndDrop(); }); function populateProviderList(providers, hierarchy) { const container = document.getElementById('metadata_provider_list'); const hiddenInput = document.getElementById('metadata_provider_hierarchy_hidden'); // Clear any existing content container.innerHTML = ''; // Create a map of providers by ID for easy lookup const providerMap = {}; providers.forEach(p => { providerMap[p.id] = p; }); // First add providers in the current hierarchy order (this is the saved user preference) hierarchy.forEach(providerId => { if (providerMap[providerId]) { addProviderItem(container, providerMap[providerId]); delete providerMap[providerId]; // Remove so we don't add twice } }); // Then add any remaining providers that weren't in the hierarchy (new providers) // These will be added in the order they come from the API (alphabetical) Object.values(providerMap).forEach(provider => { addProviderItem(container, provider); }); updateHiddenInput(); } function addProviderItem(container, provider) { const item = document.createElement('div'); item.className = 'metadata-provider-item'; item.draggable = false; // Disable native drag item.dataset.providerId = provider.id; // For admin settings, show all providers as enabled/available item.innerHTML = ` `; container.appendChild(item); } function setupDragAndDrop() { const container = document.getElementById('metadata_provider_list'); let draggedElement = null; let isDragging = false; let startY = 0; let startX = 0; container.addEventListener('mousedown', function(e) { const item = e.target.closest('.metadata-provider-item'); if (!item) return; draggedElement = item; isDragging = true; startY = e.clientY; startX = e.clientX; item.classList.add('dragging'); document.body.style.userSelect = 'none'; e.preventDefault(); }); document.addEventListener('mousemove', function(e) { if (!isDragging || !draggedElement) return; const container = document.getElementById('metadata_provider_list'); const afterElement = getMouseAfterElement(container, e.clientY); if (afterElement == null) { container.appendChild(draggedElement); } else { container.insertBefore(draggedElement, afterElement); } }); document.addEventListener('mouseup', function(e) { if (!isDragging) return; isDragging = false; if (draggedElement) { draggedElement.classList.remove('dragging'); draggedElement = null; } document.body.style.userSelect = ''; updateHiddenInput(); }); } function getMouseAfterElement(container, y) { const draggableElements = [...container.querySelectorAll('.metadata-provider-item:not(.dragging)')]; return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY }).element; } function updateHiddenInput() { const container = document.getElementById('metadata_provider_list'); const hiddenInput = document.getElementById('metadata_provider_hierarchy_hidden'); const items = container.querySelectorAll('.metadata-provider-item'); const hierarchy = Array.from(items).map(item => item.dataset.providerId); hiddenInput.value = JSON.stringify(hierarchy); } // Initialize the hidden input value updateHiddenInput(); }); ``` -------------------------------- ### Configure Pocket ID OIDC Provider in Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/wiki/Single-Sign-On-and-OpenID-Connect Configure Autocaliweb to use Pocket ID as an OIDC provider. Replace placeholders with your obtained Client ID, Client Secret, and OIDC Discovery URL. ```text generic OAuth Client Id: generic OAuth Client Secret: generic OAuth scope: openid profile email generic OAuth Metadata URL: Use Manual URLs: [] generic OAuth Username mapper: preferred_username generic OAuth Email mapper: email generic OAuth Login Button: Pocket ID ``` -------------------------------- ### Select Navigation Mode Function Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Controls the navigation mode (sides or gestures) by updating UI indicators and saving the preference to localStorage. It also calls an external function to apply the mode. ```javascript function selectNavMode(mode) { var tickSides = document.getElementById("navSidesTick"); var tickGest = document.getElementById("navGesturesTick"); tickSides.textContent = mode === "sides" ? "✓" : ""; tickGest.textContent = mode === "gestures" ? "✓" : ""; localStorage.setItem("calibre.reader.navMode", mode); if (window.applyNavigationMode) { window.applyNavigationMode(mode); } } ``` -------------------------------- ### Default Admin Credentials for Autocaliweb Source: https://github.com/gelbphoenix/autocaliweb/blob/main/README.md Use these default credentials to log in to your Autocaliweb instance for the first time. Ensure you change them after initial access for security. ```text Username: admin Password: admin123 ``` -------------------------------- ### Conditional Display of 'All' Link Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/list.html Displays the translated string 'All' if the 'charlist' has any elements. This is typically used to show a link to view all items. ```html {% if charlist|length %} {{\_('All')}} {% endif %} ``` -------------------------------- ### Epub Reader JavaScript Configuration Source: https://github.com/gelbphoenix/autocaliweb/blob/main/cps/templates/read.html Defines global JavaScript variables for the Epub Reader, including paths, URLs, and book-specific information. This configuration is essential for the reader's functionality. ```javascript window.calibre = { filePath: "{{ url_for('static', filename='js/libs/') }}", cssPath: "{{ url_for('static', filename='css/') }}", bookmarkUrl: "{{ url_for('web.set_bookmark', book_id=bookid, book_format=book_format) }}", bookUrl: "{{ url_for('web.serve_book', book_id=bookid, book_format=book_format, anyname='file.epub') }}", bookmark: "{{ bookmark.bookmark_key if bookmark != None }}", useBookmarks: "{{ current_user.is_authenticated | tojson }}", }; var _savedCustomThemeColor = null; try { _savedCustomThemeColor = localStorage.getItem("calibre.reader.customTheme") } catch (e) {} ```