From 22976049b67ce63f195452bf5a259f0fe0ef95c0 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Sun, 10 May 2026 22:21:49 +0200 Subject: [PATCH] dev dispatcharr --- ct/dispatcharr.sh | 173 ++++++++++++++++++++++ install/dispatcharr-install.sh | 261 +++++++++++++++++++++++++++++++++ 2 files changed, 434 insertions(+) create mode 100644 ct/dispatcharr.sh create mode 100644 install/dispatcharr-install.sh diff --git a/ct/dispatcharr.sh b/ct/dispatcharr.sh new file mode 100644 index 00000000..2b7df8df --- /dev/null +++ b/ct/dispatcharr.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: ekke85 | MickLesk +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/Dispatcharr/Dispatcharr + +APP="Dispatcharr" +var_tags="${var_tags:-media;arr}" +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}" +var_gpu="${var_gpu:-yes}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d "/opt/dispatcharr" ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + setup_uv + NODE_VERSION="24" setup_nodejs + + # Fix for nginx not allowing large files + if ! grep -q "client_max_body_size 100M;" /etc/nginx/sites-available/dispatcharr.conf; then + sed -i '/server_name _;/a \ client_max_body_size 100M;' /etc/nginx/sites-available/dispatcharr.conf + systemctl reload nginx + fi + + ensure_dependencies vlc-bin vlc-plugin-base + + if check_for_gh_release "Dispatcharr" "Dispatcharr/Dispatcharr"; then + msg_info "Stopping Services" + systemctl stop dispatcharr-celery + systemctl stop dispatcharr-celerybeat + systemctl stop dispatcharr-daphne + systemctl stop dispatcharr + msg_ok "Stopped Services" + + msg_info "Creating Backup" + if [[ -f /opt/dispatcharr/.env ]]; then + cp /opt/dispatcharr/.env /opt/dispatcharr.env.bak + fi + if [[ -f /opt/dispatcharr/start-gunicorn.sh ]]; then + rm -f /opt/dispatcharr/start-gunicorn.sh + fi + if [[ -f /opt/dispatcharr/start-celery.sh ]]; then + cp /opt/dispatcharr/start-celery.sh /opt/start-celery.sh.bak + fi + if [[ -f /opt/dispatcharr/start-celerybeat.sh ]]; then + cp /opt/dispatcharr/start-celerybeat.sh /opt/start-celerybeat.sh.bak + fi + if [[ -f /opt/dispatcharr/start-daphne.sh ]]; then + cp /opt/dispatcharr/start-daphne.sh /opt/start-daphne.sh.bak + fi + if [[ -f /opt/dispatcharr/.env ]]; then + set -o allexport + source /opt/dispatcharr/.env + set +o allexport + if [[ -n "$POSTGRES_DB" ]] && [[ -n "$POSTGRES_USER" ]] && [[ -n "$POSTGRES_PASSWORD" ]]; then + PGPASSWORD=$POSTGRES_PASSWORD pg_dump -U "$POSTGRES_USER" -h "${POSTGRES_HOST:-localhost}" -p "${POSTGRES_PORT:-5432}" "$POSTGRES_DB" >/opt/dispatcharr_db_$(date +%F).sql + fi + fi + msg_ok "Created Backup" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr" "tarball" + + msg_info "Restoring Configuration" + if [[ -f /opt/dispatcharr.env.bak ]]; then + mv /opt/dispatcharr.env.bak /opt/dispatcharr/.env + fi + if [[ -f /opt/start-celery.sh.bak ]]; then + mv /opt/start-celery.sh.bak /opt/dispatcharr/start-celery.sh + fi + if [[ -f /opt/start-celerybeat.sh.bak ]]; then + mv /opt/start-celerybeat.sh.bak /opt/dispatcharr/start-celerybeat.sh + fi + if [[ -f /opt/start-daphne.sh.bak ]]; then + mv /opt/start-daphne.sh.bak /opt/dispatcharr/start-daphne.sh + fi + + if ! grep -q "DJANGO_SECRET_KEY" /opt/dispatcharr/.env; then + DJANGO_SECRET=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-50) + echo "DJANGO_SECRET_KEY=$DJANGO_SECRET" >>/opt/dispatcharr/.env + fi + msg_ok "Restored Configuration" + + msg_info "Updating Python Environment" + cd /opt/dispatcharr + rm -rf .venv + $STD uv venv --clear + $STD uv sync + $STD uv pip install uwsgi gevent celery redis daphne + cat <<'UWSGI_EOF' >/opt/dispatcharr/start-uwsgi.sh +#!/usr/bin/env bash +cd /opt/dispatcharr +set -a +source .env +set +a +exec .venv/bin/uwsgi \ + --chdir=/opt/dispatcharr \ + --module=dispatcharr.wsgi:application \ + --master \ + --workers=4 \ + --gevent=400 \ + --http=0.0.0.0:5656 \ + --http-keepalive=1 \ + --http-timeout=600 \ + --socket-timeout=600 \ + --buffer-size=65536 \ + --post-buffering=4096 \ + --lazy-apps \ + --thunder-lock \ + --die-on-term \ + --vacuum +UWSGI_EOF + chmod +x /opt/dispatcharr/start-uwsgi.sh + if grep -q 'start-gunicorn.sh' /etc/systemd/system/dispatcharr.service; then + sed -i 's|start-gunicorn.sh|start-uwsgi.sh|g' /etc/systemd/system/dispatcharr.service + systemctl daemon-reload + fi + msg_ok "Updated Python Environment" + + msg_info "Building Frontend" + cd /opt/dispatcharr/frontend + node -e "const p=require('./package.json');p.overrides=p.overrides||{};p.overrides['webworkify-webpack']='2.1.3';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2));" + rm -f package-lock.json + $STD npm install --no-audit --progress=false + $STD npm run build + msg_ok "Built Frontend" + + msg_info "Running Database Migrations" + cd /opt/dispatcharr + if [[ -f .env ]]; then + set -o allexport + source .env + set +o allexport + fi + $STD uv run python manage.py migrate --noinput + $STD uv run python manage.py collectstatic --noinput + rm -f /opt/dispatcharr_db_*.sql + msg_ok "Ran Database Migrations" + + msg_info "Starting Services" + systemctl start dispatcharr + systemctl start dispatcharr-celery + systemctl start dispatcharr-celerybeat + systemctl start dispatcharr-daphne + msg_ok "Started Services" + 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}:9191${CL}" diff --git a/install/dispatcharr-install.sh b/install/dispatcharr-install.sh new file mode 100644 index 00000000..e98cffec --- /dev/null +++ b/install/dispatcharr-install.sh @@ -0,0 +1,261 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: ekke85 | MickLesk +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/Dispatcharr/Dispatcharr + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os +setup_hwaccel + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + python3-dev \ + libpq-dev \ + nginx \ + redis-server \ + ffmpeg \ + procps \ + vlc-bin \ + vlc-plugin-base \ + streamlink +msg_ok "Installed Dependencies" + +setup_uv +NODE_VERSION="24" setup_nodejs +PG_VERSION="16" setup_postgresql +PG_DB_NAME="dispatcharr_db" PG_DB_USER="dispatcharr_usr" setup_postgresql_db +fetch_and_deploy_gh_release "dispatcharr" "Dispatcharr/Dispatcharr" "tarball" + +msg_info "Installing Python Dependencies" +cd /opt/dispatcharr +$STD uv venv --clear +$STD uv sync +$STD uv pip install uwsgi gevent celery redis daphne +msg_ok "Installed Python Dependencies" + +msg_info "Configuring Dispatcharr" +install -d -m 755 \ + /data/{logos,recordings,plugins,db} \ + /data/uploads/{m3us,epgs} \ + /data/{m3us,epgs} +chown -R root:root /data +DJANGO_SECRET=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-50) +export DATABASE_URL="postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}" +export POSTGRES_DB=$PG_DB_NAME +export POSTGRES_USER=$PG_DB_USER +export POSTGRES_PASSWORD=$PG_DB_PASS +export POSTGRES_HOST=localhost +export DJANGO_SECRET_KEY=$DJANGO_SECRET +$STD uv run python manage.py migrate --noinput +$STD uv run python manage.py collectstatic --noinput +cat </opt/dispatcharr/.env +DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME} +POSTGRES_DB=$PG_DB_NAME +POSTGRES_USER=$PG_DB_USER +POSTGRES_PASSWORD=$PG_DB_PASS +POSTGRES_HOST=localhost +CELERY_BROKER_URL=redis://localhost:6379/0 +DJANGO_SECRET_KEY=$DJANGO_SECRET +EOF +cd /opt/dispatcharr/frontend +node -e "const p=require('./package.json');p.overrides=p.overrides||{};p.overrides['webworkify-webpack']='2.1.3';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2));" +rm -f package-lock.json +$STD npm install --no-audit --progress=false +$STD npm run build +msg_ok "Configured Dispatcharr" + +msg_info "Configuring Nginx" +cat </etc/nginx/sites-available/dispatcharr.conf +server { + listen 9191; + server_name _; + client_max_body_size 100M; + + location /assets/ { + alias /opt/dispatcharr/frontend/dist/assets/; + expires 30d; + add_header Cache-Control "public, immutable"; + + types { + text/javascript js; + text/css css; + image/png png; + image/svg+xml svg svgz; + font/woff2 woff2; + font/woff woff; + font/ttf ttf; + } + } + + location /static/ { + alias /opt/dispatcharr/static/; + expires 30d; + add_header Cache-Control "public, immutable"; + } + + location /media/ { + alias /opt/dispatcharr/media/; + } + + location /ws/ { + proxy_pass http://127.0.0.1:8001; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } + + location / { + include proxy_params; + proxy_pass http://127.0.0.1:5656; + } +} +EOF +ln -sf /etc/nginx/sites-available/dispatcharr.conf /etc/nginx/sites-enabled/dispatcharr.conf +rm -f /etc/nginx/sites-enabled/default +systemctl restart nginx +msg_ok "Configured Nginx" + +msg_info "Creating Services" +cat <<'EOF' >/opt/dispatcharr/start-uwsgi.sh +#!/usr/bin/env bash +cd /opt/dispatcharr +set -a +source .env +set +a +exec .venv/bin/uwsgi \ + --chdir=/opt/dispatcharr \ + --module=dispatcharr.wsgi:application \ + --master \ + --workers=4 \ + --gevent=400 \ + --http=0.0.0.0:5656 \ + --http-keepalive=1 \ + --http-timeout=600 \ + --socket-timeout=600 \ + --buffer-size=65536 \ + --post-buffering=4096 \ + --lazy-apps \ + --thunder-lock \ + --die-on-term \ + --vacuum +EOF +chmod +x /opt/dispatcharr/start-uwsgi.sh + +cat <<'EOF' >/opt/dispatcharr/start-celery.sh +#!/usr/bin/env bash +cd /opt/dispatcharr +set -a +source .env +set +a +exec uv run celery -A dispatcharr worker -l info -c 4 +EOF +chmod +x /opt/dispatcharr/start-celery.sh + +cat <<'EOF' >/opt/dispatcharr/start-celerybeat.sh +#!/usr/bin/env bash +cd /opt/dispatcharr +set -a +source .env +set +a +exec uv run celery -A dispatcharr beat -l info +EOF +chmod +x /opt/dispatcharr/start-celerybeat.sh + +cat <<'EOF' >/opt/dispatcharr/start-daphne.sh +#!/usr/bin/env bash +cd /opt/dispatcharr +set -a +source .env +set +a +exec uv run daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application +EOF +chmod +x /opt/dispatcharr/start-daphne.sh + +cat </etc/systemd/system/dispatcharr.service +[Unit] +Description=Dispatcharr Web Server +After=network.target postgresql.service redis-server.service + +[Service] +Type=simple +WorkingDirectory=/opt/dispatcharr +ExecStart=/opt/dispatcharr/start-uwsgi.sh +Restart=on-failure +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/dispatcharr-celery.service +[Unit] +Description=Dispatcharr Celery Worker +After=network.target redis-server.service +Requires=dispatcharr.service + +[Service] +Type=simple +WorkingDirectory=/opt/dispatcharr +ExecStart=/opt/dispatcharr/start-celery.sh +Restart=on-failure +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/dispatcharr-celerybeat.service +[Unit] +Description=Dispatcharr Celery Beat Scheduler +After=network.target redis-server.service +Requires=dispatcharr.service + +[Service] +Type=simple +WorkingDirectory=/opt/dispatcharr +ExecStart=/opt/dispatcharr/start-celerybeat.sh +Restart=on-failure +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/dispatcharr-daphne.service +[Unit] +Description=Dispatcharr WebSocket Server (Daphne) +After=network.target +Requires=dispatcharr.service + +[Service] +Type=simple +WorkingDirectory=/opt/dispatcharr +ExecStart=/opt/dispatcharr/start-daphne.sh +Restart=on-failure +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now dispatcharr dispatcharr-celery dispatcharr-celerybeat dispatcharr-daphne +msg_ok "Created Services" + +motd_ssh +customize +cleanup_lxc