Skip to content

Instantly share code, notes, and snippets.

@boypt
Last active September 28, 2025 15:45
Show Gist options
  • Select an option

  • Save boypt/3a9ec68832f27df6d0d0efb913071595 to your computer and use it in GitHub Desktop.

Select an option

Save boypt/3a9ec68832f27df6d0d0efb913071595 to your computer and use it in GitHub Desktop.
Installation script to install assistant.koplugin in KOReader
#!/bin/sh
# This script downloads and installs/updates the assistant.koplugin for KOReader.
# Exit immediately if a command exits with a non-zero status.
set -e
# --- Configuration ---
# Set the version to download (e.g., a tag like 'v1.08' or a branch like 'main').
# Defaults to 'main' branch if no argument is given.
# Usage: ./assi.sh v1.08
VERSION=${1:-main}
# Base URL for GitHub. Can be changed to a mirror/proxy if needed.
GITHUB_BASE=https://github.com
#GITHUB_BASE=https://gh.llkk.cc/$GITHUB_BASE
#GITHUB_BASE=https://ghfast.top/$GITHUB_BASE
# The repository to download from.
RELEASE_REPO=omer-faruq/assistant.koplugin
#RELEASE_REPO=boypt/assistant.koplugin
# --- URL and Path Construction ---
# Determine the archive path based on the version format.
# If VERSION starts with 'v' (e.g., v1.0.8), assume it's a tag.
[[ "${VERSION#v}" != "$VERSION" ]] && REPO_ARCHIVE=archive/refs/tags/$VERSION.tar.gz
# Otherwise, assume it's a branch name (e.g., main).
[[ -z $REPO_ARCHIVE ]] && REPO_ARCHIVE=archive/refs/heads/$VERSION.tar.gz
# Construct the full download URL.
RELEASE_URL=$GITHUB_BASE/$RELEASE_REPO/$REPO_ARCHIVE
echo "--> Download From: $RELEASE_URL"
# Get the absolute path of the directory where the script is located.
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# Determine KOReader's root directory. Default to the script's directory if not set.
[[ -z $KOREADER_DIR ]] && KOREADER_DIR=$SCRIPT_DIR
[[ ! -d $KOREADER_DIR ]] && exit 1
# Define plugin and temporary directory paths.
ASSISTANT_DIR=assistant.koplugin
PLUGIN_DIR=$KOREADER_DIR/plugins
UPDATE_TMPDIR=$PLUGIN_DIR/assit_update
DL_TAR="$UPDATE_TMPDIR/SOURCE.tar.gz"
# Set the 'tar' command. Use koreader's bundled tar
TAR="$KOREADER_DIR/tar"
TAR_OPTIONS=" --exclude='*/.*' --exclude='*/LEXRANK_LANGUAGES.md' --exclude='*/l10n/templates' --exclude='*/l10n/AI_TRANSLATE.sh' --exclude='*/l10n/Makefile' --exclude='*/l10n/README.md'"
if [[ ! -x $TAR ]]; then
# if bundled tar not exists, fallback to system tar (does not support --exclude)
TAR=tar
TAR_OPTIONS=""
fi
# --- Helper Function ---
download_file() {
echo -e "--> Downloading from: $1\n--> Saving to $2"
# Try to download using curl, wget, or a fallback luajit script.
if command -v curl >/dev/null 2>&1; then
curl -L -o "$2" "$1" # -L to follow redirects
elif command -v wget >/dev/null 2>&1; then
wget -O "$2" "$1"
elif [[ -e $SCRIPT_DIR/luaget.lua ]]; then
env LUA_PATH="$SCRIPT_DIR/common/?.lua;;" LUA_CPATH="$SCRIPT_DIR/common/?.so;;" \
$SCRIPT_DIR/luajit $SCRIPT_DIR/luaget.lua "$1" "$2"
else
echo "Error: Neither curl, wget, nor luaget.lua found. Cannot download."
return 1
fi
}
# --- Main Script Logic ---
# 1. Create a temporary directory for the download and extraction process.
echo "--> Creating temporary directory..."
mkdir -p "$UPDATE_TMPDIR"
# 2. Download the release archive.
download_file "$RELEASE_URL" "$DL_TAR"
# 3. Verify the integrity of the downloaded archive. Exit if it's corrupted.
if ! $TAR -tvf "$DL_TAR" >/dev/null; then
echo "--> Downloaded file is corrupted, exiting."
rm -rf "$UPDATE_TMPDIR"
exit 1
fi
# 4. If an old version of the plugin exists, back it up.
if [[ -e "$PLUGIN_DIR/$ASSISTANT_DIR" ]]; then
echo "--> Backing up existing plugin directory..."
mv "$PLUGIN_DIR/$ASSISTANT_DIR" "$PLUGIN_DIR/old.$ASSISTANT_DIR"
fi
# 5. Extract the new version from the archive, excluding unnecessary files,
# and move it to the plugins directory.
echo "--> Extracting new plugin version..."
eval $TAR -xzf "$DL_TAR" -C "$UPDATE_TMPDIR" $TAR_OPTIONS
mv "$UPDATE_TMPDIR/assistant.koplugin"* "$PLUGIN_DIR/$ASSISTANT_DIR"
echo "--> New plugin directory is ready."
# 6. If a backup of the old plugin exists, restore user configuration and libraries,
# then remove the backup directory.
if [[ -d "$PLUGIN_DIR/old.$ASSISTANT_DIR" ]]; then
echo "--> Restoring configuration from backup..."
for _OLDFILE in configuration.lua lib; do
if [[ -e "$PLUGIN_DIR/old.$ASSISTANT_DIR/$_OLDFILE" ]]; then
mv "$PLUGIN_DIR/old.$ASSISTANT_DIR/$_OLDFILE" "$PLUGIN_DIR/$ASSISTANT_DIR/"
fi
done
rm -rf "$PLUGIN_DIR/old.$ASSISTANT_DIR"
echo "--> Removed backup directory."
fi
# 7. Clean up the temporary download directory.
rm -rf "$UPDATE_TMPDIR"
echo "--> Removed temporary download directory."
# 8. If a `configuration.lua` file exists alongside the script, move it into the
# plugin directory. This is useful for initial setup.
if [[ -e "$SCRIPT_DIR/configuration.lua" ]]; then
echo "--> Found configuration.lua, moving to plugin directory..."
if [[ -e "$PLUGIN_DIR/$ASSISTANT_DIR/configuration.lua" ]]; then
mv "$PLUGIN_DIR/$ASSISTANT_DIR/configuration.lua" "$PLUGIN_DIR/$ASSISTANT_DIR/configuration.lua.bak"
fi
mv "$SCRIPT_DIR/configuration.lua" "$PLUGIN_DIR/$ASSISTANT_DIR/"
fi
echo "--> Update complete."
-- Set search path for `require()`.
package.path =
"common/?.lua;frontend/?.lua;plugins/exporter.koplugin/?.lua;" ..
package.path
package.cpath =
"common/?.so;common/?.dll;/usr/lib/lua/?.so;" ..
package.cpath
local socket = require("socket")
local ltn12 = require("ltn12")
local http = require("socket.http")
local url = arg[1]
local output_file = arg[2]
if not url then
io.stderr:write("Usage: lua luaget.lua <url> [output_file]\n")
print(" url: URL to download from")
print(" output_file: Optional filename to save to (default: stdout)")
os.exit(1)
end
print("Downloading from: " .. url)
if output_file then
print("Saving to file: " .. output_file)
end
local file_handle = nil
local success = false
local status_code = 0
local headers = {}
local sink
if output_file then
file_handle = io.open(output_file, "wb") -- "wb" for write binary
if not file_handle then
io.stderr:write("Error: Could not open file for writing: " .. output_file .. "\n")
os.exit(1)
end
sink = ltn12.sink.file(file_handle)
else
sink = ltn12.sink.file(io.stdout)
end
local success, status_code, headers = http.request{
url = url,
method = "GET",
sink = sink,
}
if success then
print(string.format("Download successful. \nHTTP Status: %d", status_code))
for k, v in pairs(headers) do
if type(v) == "string" and (k:lower() == "content-type" or k:lower() == "content-length") then
print(string.format(" %s: %s", k, v))
end
end
os.exit(0)
end
io.stderr:write("Error: " .. tostring(success) .. "\n")
os.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment