Compare commits

..

8 Commits

Author SHA1 Message Date
Chris
018cc3d919 Update install/shelfmark-install.sh 2026-01-31 16:37:53 -05:00
Chris
9c2e372db1 Update install/shelfmark-install.sh 2026-01-31 16:37:41 -05:00
Tobias
cfd569f9e8 Update shelfmark-install.sh 2026-01-30 21:03:13 +01:00
Tobias
7ff64bd2fd Update shelfmark.json 2026-01-30 20:59:54 +01:00
Tobias
cfee67a110 Update shelfmark.sh 2026-01-30 20:59:08 +01:00
Chris
74510a5b9e Apply suggestion from @vhsdream 2026-01-30 14:56:48 -05:00
Chris
a720150b6c Apply suggestions from code review 2026-01-30 14:54:23 -05:00
push-app-to-main[bot]
33c82864e6 Add shelfmark (ct) 2026-01-30 16:23:01 +00:00
14 changed files with 365 additions and 586 deletions

View File

@@ -391,15 +391,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-01-31
## 2026-01-30
### 🆕 New Scripts
- languagetool ([#11370](https://github.com/community-scripts/ProxmoxVE/pull/11370))
- Ampache ([#11369](https://github.com/community-scripts/ProxmoxVE/pull/11369))
### 🚀 Updated Scripts
- #### 🔧 Refactor
@@ -415,7 +408,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### ✨ New Features
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
## 2026-01-29

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (Canbiz)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/ampache/ampache
APP="Ampache"
var_tags="${var_tags:-music}"
var_disk="${var_disk:-5}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-2048}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/ampache ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "Ampache" "ampache/ampache"; then
msg_info "Stopping Service"
systemctl stop apache2
msg_ok "Stopped Service"
msg_info "Creating Backup"
cp /opt/ampache/config/ampache.cfg.php /tmp/ampache.cfg.php.backup
cp /opt/ampache/public/rest/.htaccess /tmp/ampache_rest.htaccess.backup
cp /opt/ampache/public/play/.htaccess /tmp/ampache_play.htaccess.backup
rm -rf /opt/ampache_backup
mv /opt/ampache /opt/ampache_backup
msg_ok "Created Backup"
fetch_and_deploy_gh_release "Ampache" "ampache/ampache" "prebuild" "latest" "/opt/ampache" "ampache-*_all_php8.4.zip"
msg_info "Restoring Backup"
cp /tmp/ampache.cfg.php.backup /opt/ampache/config/ampache.cfg.php
cp /tmp/ampache_rest.htaccess.backup /opt/ampache/public/rest/.htaccess
cp /tmp/ampache_play.htaccess.backup /opt/ampache/public/play/.htaccess
chmod 664 /opt/ampache/public/rest/.htaccess /opt/ampache/public/play/.htaccess
chown -R www-data:www-data /opt/ampache
rm -f /tmp/ampache*.backup
msg_ok "Restored Configuration"
msg_info "Starting Service"
systemctl start apache2
msg_ok "Started Service"
msg_ok "Updated successfully!"
msg_custom "⚠️" "${YW}" "Complete database update by visiting: http://${LOCAL_IP}/update.php"
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}/install.php${CL}"

View File

@@ -1,6 +0,0 @@
___ __
/ | ____ ___ ____ ____ ______/ /_ ___
/ /| | / __ `__ \/ __ \/ __ `/ ___/ __ \/ _ \
/ ___ |/ / / / / / /_/ / /_/ / /__/ / / / __/
/_/ |_/_/ /_/ /_/ .___/\__,_/\___/_/ /_/\___/
/_/

View File

@@ -1,6 +0,0 @@
__ ______ __
/ / ____ _____ ____ ___ ______ _____ ____/_ __/___ ____ / /
/ / / __ `/ __ \/ __ `/ / / / __ `/ __ `/ _ \/ / / __ \/ __ \/ /
/ /___/ /_/ / / / / /_/ / /_/ / /_/ / /_/ / __/ / / /_/ / /_/ / /
/_____/\__,_/_/ /_/\__, /\__,_/\__,_/\__, /\___/_/ \____/\____/_/
/____/ /____/

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://languagetool.org/
APP="LanguageTool"
var_tags="${var_tags:-spellcheck}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-16}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/LanguageTool ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://languagetool.org/download/ | grep -oP 'LanguageTool-\K[0-9]+\.[0-9]+(\.[0-9]+)?(?=\.zip)' | sort -V | tail -n1)
if [[ "${RELEASE}" != "$(cat ~/.languagetool 2>/dev/null)" ]] || [[ ! -f ~/.languagetool ]]; then
msg_info "Stopping Service"
systemctl stop language-tool
msg_ok "Stopped Service"
msg_info "Creating Backup"
cp /opt/LanguageTool/server.properties /opt/server.properties
msg_ok "Created Backup"
msg_info "Updating LanguageTool"
rm -rf /opt/LanguageTool
download_file "https://languagetool.org/download/LanguageTool-stable.zip" /tmp/LanguageTool-stable.zip
unzip -q /tmp/LanguageTool-stable.zip -d /opt
mv /opt/LanguageTool-*/ /opt/LanguageTool/
mv /opt/server.properties /opt/LanguageTool/server.properties
rm -f /tmp/LanguageTool-stable.zip
echo "${RELEASE}" >~/.languagetool
msg_ok "Updated LanguageTool"
msg_info "Starting Service"
systemctl start language-tool
msg_ok "Started Service"
msg_ok "Updated successfuly!"
else
msg_ok "No update required. ${APP} is already at v${RELEASE}"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!"
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}:8081/v2${CL}"

90
ct/shelfmark.sh Normal file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: vhsdream
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/calibrain/shelfmark
APP="shelfmark"
var_tags="${var_tags:-ebooks}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/shelfmark ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
NODE_VERSION="22" setup_nodejs
PYTHON_VERSION="3.12" setup_uv
if check_for_gh_release "shelfmark" "calibrain/shelfmark"; then
msg_info "Stopping Service(s)"
systemctl stop shelfmark
[[ -f /etc/systemd/system/chromium.service ]] && systemctl stop chromium
msg_ok "Stopped Service(s)"
[[ -f /etc/systemd/system/flaresolverr.service ]] && if check_for_gh_release "flaresolverr" "Flaresolverr/Flaresolverr"; then
msg_info "Stopping FlareSolverr service"
systemctl stop flaresolverr
msg_ok "Stopped FlareSolverr service"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "flaresolverr" "FlareSolverr/FlareSolverr" "prebuild" "latest" "/opt/flaresolverr" "flaresolverr_linux_x64.tar.gz"
msg_info "Starting FlareSolverr Service"
systemctl start flaresolverr
msg_ok "Started FlareSolverr Service"
msg_ok "Updated FlareSolverr"
fi
cp /opt/shelfmark/start.sh /opt/start.sh.bak
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "shelfmark" "calibrain/shelfmark" "tarball" "latest" "/opt/shelfmark"
RELEASE_VERSION=$(cat "$HOME/.shelfmark")
msg_info "Updating Shelfmark"
sed -i "s/^RELEASE_VERSION=.*/RELEASE_VERSION=$RELEASE_VERSION/" /etc/shelfmark/.env
cd /opt/shelfmark/src/frontend
$STD npm ci
$STD npm run build
mv /opt/shelfmark/src/frontend/dist /opt/shelfmark/frontend-dist
cd /opt/shelfmark
$STD uv venv -c ./venv
$STD source ./venv/bin/activate
$STD uv pip install -r ./requirements-base.txt
if [[ $(sed -n '/_BYPASS=/s/[^=]*=//p' /etc/shelfmark/.env) == "true" ]] && [[ $(sed -n '/BYPASSER=/s/[^=]*=//p' /etc/shelfmark/.env) == "false" ]]; then
$STD uv pip install -r ./requirements-shelfmark.txt
fi
mv /opt/start.sh.bak /opt/shelfmark/start.sh
msg_ok "Updated Shelfmark"
msg_info "Starting Service(s)"
systemctl start shelfmark
[[ -f /etc/systemd/system/chromium.service ]] && systemctl start chromium
msg_ok "Started Service(s)"
msg_ok "Updated successfully!"
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}:8084${CL}"

View File

@@ -1,48 +0,0 @@
{
"name": "Ampache",
"slug": "ampache",
"categories": [
13
],
"date_created": "2026-01-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://github.com/ampache/ampache/wiki",
"website": "https://ampache.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/ampache.webp",
"config_path": "/opt/ampache/config/ampache.cfg.php",
"description": "Ampache is a web-based audio streaming application and file manager that allows you to access your music & videos from anywhere. It features a powerful music catalog, multiple user support, transcoding, streaming, and more.",
"install_methods": [
{
"type": "default",
"script": "ct/ampache.sh",
"resources": {
"cpu": 4,
"ram": 2048,
"hdd": 5,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Complete the web-based setup at http://IP/install.php",
"type": "info"
},
{
"text": "Database credentials are stored in `~/ampache.creds` - use only the MySQL username and password from this file",
"type": "info"
},
{
"text": "During installation, only check 'Create Tables' - leave 'Create Database' and 'Create Database User' unchecked",
"type": "info"
}
]
}

View File

@@ -1,5 +1,5 @@
{
"generated": "2026-01-31T00:19:35Z",
"generated": "2026-01-30T12:10:39Z",
"versions": [
{
"slug": "2fauth",
@@ -29,13 +29,6 @@
"pinned": false,
"date": "2025-03-20T03:06:11Z"
},
{
"slug": "ampache",
"repo": "ampache/ampache",
"version": "7.8.0",
"pinned": false,
"date": "2025-12-22T04:23:45Z"
},
{
"slug": "argus",
"repo": "release-argus/Argus",
@@ -60,9 +53,9 @@
{
"slug": "autobrr",
"repo": "autobrr/autobrr",
"version": "v1.72.1",
"version": "v1.72.0",
"pinned": false,
"date": "2026-01-30T12:57:58Z"
"date": "2026-01-27T20:53:54Z"
},
{
"slug": "autocaliweb",
@@ -242,9 +235,9 @@
{
"slug": "discopanel",
"repo": "nickheyer/discopanel",
"version": "v1.0.31",
"version": "v1.0.30",
"pinned": false,
"date": "2026-01-30T18:30:38Z"
"date": "2026-01-30T10:14:14Z"
},
{
"slug": "dispatcharr",
@@ -375,9 +368,9 @@
{
"slug": "ghostfolio",
"repo": "ghostfolio/ghostfolio",
"version": "2.234.0",
"version": "2.233.0",
"pinned": false,
"date": "2026-01-30T19:00:22Z"
"date": "2026-01-23T18:41:45Z"
},
{
"slug": "gitea",
@@ -480,16 +473,16 @@
{
"slug": "homarr",
"repo": "homarr-labs/homarr",
"version": "v1.52.0",
"version": "v1.51.0",
"pinned": false,
"date": "2026-01-30T19:41:22Z"
"date": "2026-01-23T19:29:49Z"
},
{
"slug": "homebox",
"repo": "sysadminsmedia/homebox",
"version": "v0.23.0",
"version": "v0.22.3",
"pinned": false,
"date": "2026-01-30T17:41:01Z"
"date": "2025-12-26T22:31:20Z"
},
{
"slug": "homepage",
@@ -515,9 +508,9 @@
{
"slug": "huntarr",
"repo": "plexguide/Huntarr.io",
"version": "9.1.3",
"version": "9.1.0",
"pinned": false,
"date": "2026-01-30T21:38:18Z"
"date": "2026-01-30T09:22:10Z"
},
{
"slug": "immich",
@@ -1138,9 +1131,9 @@
{
"slug": "rclone",
"repo": "rclone/rclone",
"version": "v1.73.0",
"version": "v1.72.1",
"pinned": false,
"date": "2026-01-30T22:12:03Z"
"date": "2025-12-10T14:55:44Z"
},
{
"slug": "rdtclient",
@@ -1243,9 +1236,9 @@
{
"slug": "snowshare",
"repo": "TuroYT/snowshare",
"version": "v1.2.12",
"version": "v1.2.11",
"pinned": false,
"date": "2026-01-30T13:35:56Z"
"date": "2026-01-22T13:26:11Z"
},
{
"slug": "sonarr",
@@ -1411,9 +1404,9 @@
{
"slug": "tunarr",
"repo": "chrisbenincasa/tunarr",
"version": "v1.1.11",
"version": "v1.1.10",
"pinned": false,
"date": "2026-01-30T22:34:30Z"
"date": "2026-01-30T02:10:02Z"
},
{
"slug": "uhf",

View File

@@ -1,40 +0,0 @@
{
"name": "LanguageTool",
"slug": "languagetool",
"categories": [
0
],
"date_created": "2026-01-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8081,
"documentation": "https://dev.languagetool.org/",
"config_path": "/opt/LanguageTool/server.properties",
"website": "https://languagetool.org/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/languagetool.webp",
"description": "LanguageTool is an Open Source proofreading software for English, Spanish, French, German, Portuguese, Polish, Dutch, and more than 20 other languages. It finds many errors that a simple spell checker cannot detect.",
"install_methods": [
{
"type": "default",
"script": "ct/languagetool.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 16,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "API is available at `http://<LXC_IP>:8081/v2`.",
"type": "info"
}
]
}

View File

@@ -0,0 +1,40 @@
{
"name": "Shelfmark",
"slug": "shelfmark",
"categories": [
13
],
"date_created": "2026-01-30",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8084,
"documentation": "https://github.com/calibrain/shelfmark/tree/main/docs",
"website": "https://github.com/calibrain/shelfmark",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/shelfmark.webp",
"config_path": "/etc/shelfmark",
"description": "Shelfmark is a unified web interface for searching and aggregating books and audiobook downloads from multiple sources - all in one place.",
"install_methods": [
{
"type": "default",
"script": "ct/shelfmark.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "The configuration at `/etc/shelfmark/.env` is for bootstrapping the initial install. Customize the configuration via the Shelfmark UI.",
"type": "info"
}
]
}

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (Canbiz)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/ampache/ampache
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing dependencies"
$STD apt install -y \
flac \
vorbis-tools \
lame \
ffmpeg \
inotify-tools \
libavcodec-extra \
libmp3lame-dev \
libtheora-dev \
libvorbis-dev \
libvpx-dev
msg_ok "Installed dependencies"
PHP_VERSION="8.4" PHP_APACHE="YES" setup_php
setup_mariadb
MARIADB_DB_USER="ampache" MARIADB_DB_NAME="ampache" setup_mariadb_db
fetch_and_deploy_gh_release "ampache" "ampache/ampache" "prebuild" "latest" "/opt/ampache" "ampache-*_all_php8.4.zip"
msg_info "Setting up Ampache"
rm -rf /var/www/html
ln -s /opt/ampache/public /var/www/html
mv /opt/ampache/public/rest/.htaccess.dist /opt/ampache/public/rest/.htaccess
mv /opt/ampache/public/play/.htaccess.dist /opt/ampache/public/play/.htaccess
cp /opt/ampache/config/ampache.cfg.php.dist /opt/ampache/config/ampache.cfg.php
chmod 664 /opt/ampache/public/rest/.htaccess /opt/ampache/public/play/.htaccess
msg_ok "Set up Ampache"
msg_info "Configuring Database Connection"
sed -i -e 's|^database_hostname = .*|database_hostname = "localhost"|' \
-e 's|^database_name = .*|database_name = "ampache"|' \
-e 's|^database_username = .*|database_username = "ampache"|' \
-e "s|^database_password = .*|database_password = \"${MARIADB_DB_PASS}\"|" /opt/ampache/config/ampache.cfg.php
chown -R www-data:www-data /opt/ampache
msg_ok "Configured Database Connection"
msg_info "Importing Database Schema"
mariadb -u ampache -p"${MARIADB_DB_PASS}" ampache </opt/ampache/resources/sql/ampache.sql
msg_ok "Imported Database Schema"
msg_info "Configuring PHP"
sed -i -e 's/upload_max_filesize = .*/upload_max_filesize = 100M/' \
-e 's/post_max_size = .*/post_max_size = 100M/' \
-e 's/max_execution_time = .*/max_execution_time = 600/' \
-e 's/memory_limit = .*/memory_limit = 512M/' /etc/php/8.4/apache2/php.ini
$STD a2enmod rewrite
$STD systemctl restart apache2
msg_ok "Configured PHP"
motd_ssh
customize
cleanup_lxc

View File

@@ -1,110 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://languagetool.org/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing dependencies"
$STD apt install -y fasttext
msg_ok "Installed dependencies"
JAVA_VERSION="21" setup_java
msg_info "Setting up LanguageTool"
RELEASE=$(curl -fsSL https://languagetool.org/download/ | grep -oP 'LanguageTool-\K[0-9]+\.[0-9]+(\.[0-9]+)?(?=\.zip)' | sort -V | tail -n1)
download_file "https://languagetool.org/download/LanguageTool-stable.zip" /tmp/LanguageTool-stable.zip
unzip -q /tmp/LanguageTool-stable.zip -d /opt
mv /opt/LanguageTool-*/ /opt/LanguageTool/
download_file "https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin" /opt/lid.176.bin
rm -f /tmp/LanguageTool-stable.zip
msg_ok "Setup LanguageTool"
ngram_dir=""
lang_code=""
max_attempts=3
attempt=0
while [[ $attempt -lt $max_attempts ]]; do
read -r -p "${TAB3}Enter language code (en, de, es, fr, nl) to download ngrams or press ENTER to skip: " lang_code
if [[ -z "$lang_code" ]]; then
break
fi
if [[ "$lang_code" =~ [[:space:]] ]]; then
((attempt++))
remaining=$((max_attempts - attempt))
if [[ $remaining -gt 0 ]]; then
msg_error "Please enter only ONE language code. You have $remaining attempt(s) remaining."
else
msg_error "Maximum attempts reached. Continuing without ngrams."
lang_code=""
fi
continue
fi
break
done
if [[ -n "$lang_code" ]]; then
if [[ "$lang_code" =~ ^(en|de|es|fr|nl)$ ]]; then
msg_info "Searching for $lang_code ngrams..."
filename=$(curl -fsSL https://languagetool.org/download/ngram-data/ | grep -oP "ngrams-${lang_code}-[0-9]+\.zip" | sort -uV | tail -n1)
if [[ -n "$filename" ]]; then
msg_info "Downloading $filename"
download_file "https://languagetool.org/download/ngram-data/${filename}" "/tmp/${filename}"
mkdir -p /opt/ngrams
msg_info "Extracting $lang_code ngrams to /opt/ngrams"
unzip -q "/tmp/${filename}" -d /opt/ngrams
rm "/tmp/${filename}"
ngram_dir="/opt/ngrams"
msg_ok "Installed $lang_code ngrams"
else
msg_info "No ngram file found for ${lang_code}"
fi
else
msg_error "Invalid language code: $lang_code"
fi
fi
cat <<EOF >/opt/LanguageTool/server.properties
fasttextModel=/opt/lid.176.bin
fasttextBinary=/usr/bin/fasttext
EOF
if [[ -n "$ngram_dir" ]]; then
echo "languageModel=/opt/ngrams" >> /opt/LanguageTool/server.properties
fi
echo "${RELEASE}" >~/.languagetool
msg_ok "Setup LanguageTool"
msg_info "Creating Service"
cat <<'EOF' >/etc/systemd/system/language-tool.service
[Unit]
Description=LanguageTool Service
After=network.target
[Service]
WorkingDirectory=/opt/LanguageTool
ExecStart=java -cp languagetool-server.jar org.languagetool.server.HTTPServer --config server.properties --public --allow-origin "*"
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now language-tool
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -0,0 +1,216 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: vhsdream
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/calibrain/shelfmark
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
unrar-free
ln -sf /usr/bin/unrar-free /usr/bin/unrar
msg_ok "Installed Dependencies"
mkdir -p /etc/shelfmark
cat <<EOF >/etc/shelfmark/.env
DOCKERMODE=false
CONFIG_DIR=/etc/shelfmark
TMP_DIR=/tmp/shelfmark
ENABLE_LOGGING=true
FLASK_HOST=0.0.0.0
FLASK_PORT=8084
# SESSION_COOKIES_SECURE=true
# CWA_DB_PATH=
USE_CF_BYPASS=true
USING_EXTERNAL_BYPASSER=false
# EXT_BYPASSER_URL=
# EXT_BYPASSER_PATH=/v1
EOF
echo ""
echo ""
echo -e "${BL}Shelfmark Deployment Type${CL}"
echo "─────────────────────────────────────────"
echo "Please choose your deployment type:"
echo ""
echo " 1) Use Shelfmark's internal captcha bypasser (default)"
echo " 2) Install FlareSolverr in this LXC"
echo " 3) Use an existing Flaresolverr/Byparr LXC"
echo " 4) Disable captcha bypassing altogether (not recommended)"
echo ""
read -r -p "${TAB3}Select deployment type [1]: " DEPLOYMENT_TYPE
DEPLOYMENT_TYPE="${DEPLOYMENT_TYPE:-1}"
case "$DEPLOYMENT_TYPE" in
1)
msg_ok "Using Shelfmark's internal captcha bypasser"
;;
2)
msg_ok "Proceeding with FlareSolverr installation"
;;
3)
echo ""
echo -e "${BL}Use an existing FlareSolverr/Byparr LXC${CL}"
echo "─────────────────────────────────────────"
echo "Enter the URL/IP address with port of your Flaresolverr/Byparr instance"
echo "Example: http://flaresoverr.homelab.lan:8191 or"
echo "http://192.168.10.99:8191"
echo ""
read -r -p "FlareSolverr/Byparr URL: " BYPASSER_URL
if [[ -z "$BYPASSER_URL" ]]; then
msg_warn "No Flaresolverr/Byparr URL provided. Falling back to Shelfmark's internal bypasser."
else
BYPASSER_URL="${BYPASSER_URL%/}"
msg_ok "FlareSolverr/Byparr URL: ${BYPASSER_URL}"
fi
;;
4)
msg_warn "Disabling captcha bypass. This may cause the majority of searches and downloads to fail."
;;
*)
msg_warn "Invalid selection. Reverting to default (internal bypasser)!"
;;
esac
if [[ "$DEPLOYMENT_TYPE" == "2" ]]; then
fetch_and_deploy_gh_release "flaresolverr" "FlareSolverr/FlareSolverr" "prebuild" "latest" "/opt/flaresolverr" "flaresolverr_linux_x64.tar.gz"
msg_info "Installing FlareSolverr (patience)"
$STD apt install -y xvfb
setup_deb822_repo \
"google-chrome" \
"https://dl.google.com/linux/linux_signing_key.pub" \
"https://dl.google.com/linux/chrome/deb/" \
"stable"
$STD apt install -y google-chrome-stable
rm /etc/apt/sources.list.d/google-chrome.list
sed -i -e '/BYPASSER=/s/false/true/' \
-e 's/^# EXT_/EXT_/' \
-e "s|_URL=.*|_URL=http://localhost:8191|" /etc/shelfmark/.env
msg_ok "Installed FlareSolverr"
elif [[ "$DEPLOYMENT_TYPE" == "3" ]]; then
sed -i -e '/BYPASSER=/s/false/true/' \
-e 's/^# EXT_/EXT_/' \
-e "s|_URL=.*|_URL=${BYPASSER_URL}|" /etc/shelfmark/.env
elif [[ "$DEPLOYMENT_TYPE" == "4" ]]; then
sed -i '/_BYPASS=/s/true/false/' /etc/shelfmark/.env
else
DEPLOYMENT_TYPE="1"
CHROME_VERSION=$(curl -fsSL https://raw.githubusercontent.com/calibrain/shelfmark/refs/heads/main/Dockerfile | sed -n '/chromium=/s/[^=]*=//p' | awk '{print $1}')
msg_info "Installing internal bypasser dependencies"
$STD apt install -y --no-install-recommends \
xvfb \
ffmpeg \
chromium-common=${CHROME_VERSION} \
chromium=${CHROME_VERSION} \
chromium-driver=${CHROME_VERSION} \
python3-tk
msg_ok "Installed internal bypasser dependencies"
fi
NODE_VERSION="22" setup_nodejs
PYTHON_VERSION="3.12" setup_uv
fetch_and_deploy_gh_release "shelfmark" "calibrain/shelfmark" "tarball" "latest" "/opt/shelfmark"
RELEASE_VERSION=$(cat "$HOME/.shelfmark")
msg_info "Building Shelfmark frontend"
cd /opt/shelfmark/src/frontend
echo "RELEASE_VERSION=${RELEASE_VERSION}" >>/etc/shelfmark/.env
$STD npm ci
$STD npm run build
mv /opt/shelfmark/src/frontend/dist /opt/shelfmark/frontend-dist
msg_ok "Built Shelfmark frontend"
msg_info "Configuring Shelfmark"
cd /opt/shelfmark
$STD uv venv ./venv
$STD source ./venv/bin/activate
$STD uv pip install -r ./requirements-base.txt
[[ "$DEPLOYMENT_TYPE" == "1" ]] && $STD uv pip install -r ./requirements-shelfmark.txt
mkdir -p {/var/log/shelfmark,/tmp/shelfmark}
msg_ok "Configured Shelfmark"
msg_info "Creating Services and start script"
cat <<EOF >/etc/systemd/system/shelfmark.service
[Unit]
Description=Shelfmark server
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/shelfmark
EnvironmentFile=/etc/shelfmark/.env
ExecStart=/usr/bin/bash /opt/shelfmark/start.sh
Restart=always
RestartSec=10
KillMode=mixed
[Install]
WantedBy=multi-user.target
EOF
if [[ "$DEPLOYMENT_TYPE" == "1" ]]; then
cat <<EOF >/etc/systemd/system/chromium.service
[Unit]
Description=Chromium Headless Browser
After=network.target
[Service]
User=root
ExecStart=/usr/bin/chromium --headless --no-sandbox --disable-gpu --disable-dev-shm-usage --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222 --hide-scrollbars
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now chromium
fi
if [[ "$DEPLOYMENT_TYPE" == "2" ]]; then
cat <<EOF >/etc/systemd/system/flaresolverr.service
[Unit]
Description=FlareSolverr
After=network.target
[Service]
SyslogIdentifier=flaresolverr
Restart=always
RestartSec=5
Type=simple
Environment="LOG_LEVEL=info"
Environment="CAPTCHA_SOLVER=none"
WorkingDirectory=/opt/flaresolverr
ExecStart=/opt/flaresolverr/flaresolverr
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now flaresolverr
fi
cat <<EOF >/opt/shelfmark/start.sh
#!/usr/bin/env bash
source /opt/shelfmark/venv/bin/activate
set -a
source /etc/shelfmark/.env
set +a
gunicorn --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker --workers 1 -t 300 -b 0.0.0.0:8084 shelfmark.main:app
EOF
chmod +x /opt/shelfmark/start.sh
systemctl enable -q --now shelfmark
msg_ok "Created Services and start script"
motd_ssh
customize
cleanup_lxc

View File

@@ -6246,138 +6246,3 @@ EOF
msg_ok "Docker setup completed"
}
# ------------------------------------------------------------------------------
# Fetch and deploy from URL
# Downloads an archive (zip, tar.gz, or .deb) from a URL and extracts/installs it
#
# Usage: fetch_and_deploy_from_url "url" "directory"
# url - URL to the archive (zip, tar.gz, or .deb)
# directory - Destination path where the archive will be extracted
# (not used for .deb packages)
#
# Examples:
# fetch_and_deploy_from_url "https://example.com/app.tar.gz" "/opt/myapp"
# fetch_and_deploy_from_url "https://example.com/app.zip" "/opt/myapp"
# fetch_and_deploy_from_url "https://example.com/package.deb" ""
# ------------------------------------------------------------------------------
function fetch_and_deploy_from_url() {
local url="$1"
local directory="$2"
if [[ -z "$url" ]]; then
msg_error "URL parameter is required"
return 1
fi
local filename="${url##*/}"
local archive_type="zip"
if [[ "$filename" == *.tar.gz || "$filename" == *.tgz ]]; then
archive_type="tar"
elif [[ "$filename" == *.deb ]]; then
archive_type="deb"
fi
msg_info "Downloading from $url"
local tmpdir
tmpdir=$(mktemp -d) || {
msg_error "Failed to create temporary directory"
return 1
}
curl -fsSL -o "$tmpdir/$filename" "$url" || {
msg_error "Download failed: $url"
rm -rf "$tmpdir"
return 1
}
if [[ "$archive_type" == "deb" ]]; then
msg_info "Installing .deb package"
chmod 644 "$tmpdir/$filename"
$STD apt install -y "$tmpdir/$filename" || {
$STD dpkg -i "$tmpdir/$filename" || {
msg_error "Both apt and dpkg installation failed"
rm -rf "$tmpdir"
return 1
}
}
rm -rf "$tmpdir"
msg_ok "Successfully installed .deb package"
return 0
fi
if [[ -z "$directory" ]]; then
msg_error "Directory parameter is required for archive extraction"
rm -rf "$tmpdir"
return 1
fi
msg_info "Extracting archive to $directory"
mkdir -p "$directory"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
rm -rf "${directory:?}/"*
fi
local unpack_tmp
unpack_tmp=$(mktemp -d)
if [[ "$archive_type" == "zip" ]]; then
ensure_dependencies unzip
unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || {
msg_error "Failed to extract ZIP archive"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
}
elif [[ "$archive_type" == "tar" ]]; then
tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || {
msg_error "Failed to extract TAR archive"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
}
fi
local top_entries
top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1)
if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then
local inner_dir="$top_entries"
shopt -s dotglob nullglob
if compgen -G "$inner_dir/*" >/dev/null; then
cp -r "$inner_dir"/* "$directory/" || {
msg_error "Failed to copy contents from $inner_dir to $directory"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
}
else
msg_error "Inner directory is empty: $inner_dir"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
fi
shopt -u dotglob nullglob
else
shopt -s dotglob nullglob
if compgen -G "$unpack_tmp/*" >/dev/null; then
cp -r "$unpack_tmp"/* "$directory/" || {
msg_error "Failed to copy contents to $directory"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
}
else
msg_error "Unpacked archive is empty"
rm -rf "$tmpdir" "$unpack_tmp"
return 1
fi
shopt -u dotglob nullglob
fi
rm -rf "$tmpdir" "$unpack_tmp"
msg_ok "Successfully deployed archive to $directory"
return 0
}