From f615300e51f6dbf52f81770a72888c4ac213ce49 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Mon, 2 Nov 2026 19:07:54 +0000 Subject: [PATCH 1/9] add pinepods test scripts --- ct/pinepods.sh | 89 +++++++++++++ install/pinepods-install.sh | 256 ++++++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 ct/pinepods.sh create mode 100644 install/pinepods-install.sh diff --git a/ct/pinepods.sh b/ct/pinepods.sh new file mode 100644 index 0000000000..baefaed5fa --- /dev/null +++ b/ct/pinepods.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/main" +_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" +source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: untect +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/madeofpendletonwool/PinePods + +APP="PinePods" +var_tags="${var_tags:-podcast;media}" +var_cpu="${var_cpu:-4}" +var_ram="${var_ram:-4096}" +var_disk="${var_disk:-15}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +#var_arm64="${var_arm64:-no}" # unset = ask the user; set yes/no only when verified +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/pinepods ]]; then + msg_error "No PinePods Installation Found!" + exit + fi + + if check_for_gh_release "yt-dlp" "yt-dlp/yt-dlp"; then + fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" + fi + + if check_for_gh_release "pinepods" "madeofpendletonwool/PinePods"; then + msg_info "Stopping PinePods" + systemctl stop pinepods-gpodder pinepods-api + msg_ok "Stopped PinePods" + + create_backup /opt/pinepods/.env + + setup_go + setup_rust + fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" + CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media certs" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" + + restore_backup + + msg_info "Building PinePods" + $STD rustup target add wasm32-unknown-unknown + cd /opt/pinepods/web + RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release + rm -rf /var/www/html + cp -r /opt/pinepods/web/dist /var/www/html + cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations + cd /opt/pinepods/gpodder-api + CGO_ENABLED=0 $STD go build -ldflags="-s -w" -o /usr/local/bin/gpodder-api ./cmd/server/ + cd /opt/pinepods/rust-api + $STD cargo build --release + cp target/release/pinepods-api /usr/local/bin/pinepods-api + cd /opt/pinepods + $STD uv venv /opt/pinepods/.venv + $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt + rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target + $STD go clean -cache -modcache + cp ~/.pinepods /pinepods/current_version + msg_ok "Built PinePods" + + msg_info "Starting PinePods" + systemctl start pinepods-api pinepods-gpodder + msg_ok "Started PinePods" + 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 "${GATEWAY}${BGN}http://${IP}:8040${CL}" diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh new file mode 100644 index 0000000000..d7915ea316 --- /dev/null +++ b/install/pinepods-install.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Morgan Hickman +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/madeofpendletonwool/PinePods + +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 \ + build-essential \ + pkg-config \ + libssl-dev \ + libmariadb-dev \ + nginx \ + valkey-server +msg_ok "Installed Dependencies" + +PG_VERSION="18" setup_postgresql +PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db +PYTHON_VERSION="3.11" setup_uv +setup_go +setup_rust +setup_ffmpeg +fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" +fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" +fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" + +msg_info "Building PinePods" +$STD rustup target add wasm32-unknown-unknown +cd /opt/pinepods/web +RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release +rm -rf /var/www/html +cp -r /opt/pinepods/web/dist /var/www/html +cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations +cd /opt/pinepods/gpodder-api +CGO_ENABLED=0 $STD go build -ldflags="-s -w" -o /usr/local/bin/gpodder-api ./cmd/server/ +cd /opt/pinepods/rust-api +$STD cargo build --release +cp target/release/pinepods-api /usr/local/bin/pinepods-api +cd /opt/pinepods +$STD uv venv /opt/pinepods/.venv +$STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt +rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target +$STD go clean -cache -modcache +msg_ok "Built PinePods" + +msg_info "Configuring PinePods" +# The API hardcodes these paths, as well as /pinepods/current_version +mkdir -p /opt/pinepods/{downloads,backups,local-media,certs} /pinepods/cache +cp ~/.pinepods /pinepods/current_version +cat </opt/pinepods/.env +DB_TYPE=postgresql +DB_HOST=127.0.0.1 +DB_PORT=5432 +DB_USER=${PG_DB_USER} +DB_PASSWORD=${PG_DB_PASS} +DB_NAME=${PG_DB_NAME} +VALKEY_HOST=127.0.0.1 +VALKEY_PORT=6379 +SEARCH_API_URL=https://search.pinepods.online/api/search +PEOPLE_API_URL=https://people.pinepods.online +HOSTNAME=http://${LOCAL_IP}:8040 +SERVER_URL=http://${LOCAL_IP}:8040 +DEFAULT_LANGUAGE=en +DEBUG_MODE=false +EOF +chmod 600 /opt/pinepods/.env +msg_ok "Configured PinePods" + +msg_info "Configuring Nginx" +cat <<'EOF' >/etc/nginx/sites-available/pinepods +server { + listen 8040; + server_name _; + client_max_body_size 0; + + root /var/www/html; + index index.html; + + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; + + location /rss/ { + rewrite ^/rss/(\d+)(?:/(\d+))?$ /api/feed/$1$2 last; + proxy_pass http://127.0.0.1:8032; + 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; + proxy_set_header Api-Key $arg_api_key; + add_header Content-Type "application/rss+xml; charset=utf-8"; + expires 1h; + add_header Cache-Control "public, no-transform"; + } + + location / { + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + try_files $uri $uri/ /index.html; + } + + location /api { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; + + proxy_pass http://127.0.0.1:8032; + 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; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + location ~ ^/(api/2|auth|subscriptions|devices|updates|episodes|settings|lists|favorites|sync-devices|search|suggestions|toplist|tag|tags|data)/ { + proxy_pass http://127.0.0.1:8042; + 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; + + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + + proxy_read_timeout 300; + proxy_send_timeout 300; + } + + location /api/gpodder { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; + + proxy_pass http://127.0.0.1:8032; + 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; + proxy_read_timeout 1800; + proxy_send_timeout 1800; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Api-Key,Authorization' always; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + location ~ ^/ws/api/(data|tasks)/ { + proxy_pass http://127.0.0.1:8032; + 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; + proxy_read_timeout 86400; + proxy_send_timeout 86400; + } + + location ~* \.wasm$ { + types { + application/wasm wasm; + } + } +} +EOF +nginx_enable_site "pinepods" +msg_ok "Configured Nginx" + +msg_info "Creating Services" +cat </etc/systemd/system/pinepods-api.service +[Unit] +Description=PinePods API +After=network.target postgresql.service valkey-server.service +Requires=postgresql.service valkey-server.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/pinepods +EnvironmentFile=/opt/pinepods/.env +ExecStartPre=/opt/pinepods/.venv/bin/python /opt/pinepods/startup/setup_database_new.py +ExecStart=/usr/local/bin/pinepods-api +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +cat </etc/systemd/system/pinepods-gpodder.service +[Unit] +Description=PinePods gPodder API +After=pinepods-api.service +Requires=pinepods-api.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/pinepods +EnvironmentFile=/opt/pinepods/.env +Environment=SERVER_PORT=8042 +ExecStart=/usr/local/bin/gpodder-api +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now pinepods-api pinepods-gpodder +msg_ok "Created Services" + +motd_ssh +customize +cleanup_lxc From 328f32d5a6a1f1809cb1f69871d95f97cb34bd47 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 09:34:32 +0000 Subject: [PATCH 2/9] Align PinePods scripts with the code-audit checklist Move .env to /opt/pinepods_data so updates need no backup step, pin Python 3.11 in the update path, use the minimal Rust profile, drop directories nothing reads, and add the JSON metadata. Co-Authored-By: Claude Opus 5.5 --- ct/pinepods.sh | 11 ++++----- install/pinepods-install.sh | 16 ++++++------- json/pinepods.json | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 json/pinepods.json diff --git a/ct/pinepods.sh b/ct/pinepods.sh index baefaed5fa..c6b203e70d 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -42,14 +42,11 @@ function update_script() { systemctl stop pinepods-gpodder pinepods-api msg_ok "Stopped PinePods" - create_backup /opt/pinepods/.env - + PYTHON_VERSION="3.11" setup_uv setup_go - setup_rust + RUST_PROFILE="minimal" setup_rust fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" - CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media certs" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" - - restore_backup + CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown @@ -64,7 +61,7 @@ function update_script() { $STD cargo build --release cp target/release/pinepods-api /usr/local/bin/pinepods-api cd /opt/pinepods - $STD uv venv /opt/pinepods/.venv + $STD uv venv --python 3.11 /opt/pinepods/.venv $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target $STD go clean -cache -modcache diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index d7915ea316..3e203cf8d7 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Copyright (c) 2021-2026 community-scripts ORG -# Author: Morgan Hickman +# Author: untect # License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE # Source: https://github.com/madeofpendletonwool/PinePods @@ -27,7 +27,7 @@ PG_VERSION="18" setup_postgresql PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db PYTHON_VERSION="3.11" setup_uv setup_go -setup_rust +RUST_PROFILE="minimal" setup_rust setup_ffmpeg fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" @@ -46,7 +46,7 @@ cd /opt/pinepods/rust-api $STD cargo build --release cp target/release/pinepods-api /usr/local/bin/pinepods-api cd /opt/pinepods -$STD uv venv /opt/pinepods/.venv +$STD uv venv --python 3.11 /opt/pinepods/.venv $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target $STD go clean -cache -modcache @@ -54,9 +54,9 @@ msg_ok "Built PinePods" msg_info "Configuring PinePods" # The API hardcodes these paths, as well as /pinepods/current_version -mkdir -p /opt/pinepods/{downloads,backups,local-media,certs} /pinepods/cache +mkdir -p /opt/pinepods/{downloads,backups,local-media} /opt/pinepods_data /pinepods cp ~/.pinepods /pinepods/current_version -cat </opt/pinepods/.env +cat </opt/pinepods_data/.env DB_TYPE=postgresql DB_HOST=127.0.0.1 DB_PORT=5432 @@ -72,7 +72,7 @@ SERVER_URL=http://${LOCAL_IP}:8040 DEFAULT_LANGUAGE=en DEBUG_MODE=false EOF -chmod 600 /opt/pinepods/.env +chmod 600 /opt/pinepods_data/.env msg_ok "Configured PinePods" msg_info "Configuring Nginx" @@ -220,7 +220,7 @@ Requires=postgresql.service valkey-server.service Type=simple User=root WorkingDirectory=/opt/pinepods -EnvironmentFile=/opt/pinepods/.env +EnvironmentFile=/opt/pinepods_data/.env ExecStartPre=/opt/pinepods/.venv/bin/python /opt/pinepods/startup/setup_database_new.py ExecStart=/usr/local/bin/pinepods-api Restart=on-failure @@ -239,7 +239,7 @@ Requires=pinepods-api.service Type=simple User=root WorkingDirectory=/opt/pinepods -EnvironmentFile=/opt/pinepods/.env +EnvironmentFile=/opt/pinepods_data/.env Environment=SERVER_PORT=8042 ExecStart=/usr/local/bin/gpodder-api Restart=on-failure diff --git a/json/pinepods.json b/json/pinepods.json new file mode 100644 index 0000000000..1714578e52 --- /dev/null +++ b/json/pinepods.json @@ -0,0 +1,45 @@ +{ + "name": "PinePods", + "slug": "pinepods", + "categories": [ + 13 + ], + "date_created": "2026-11-02", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8040, + "documentation": "https://www.pinepods.online/docs/Introduction", + "website": "https://www.pinepods.online/", + "repository": "https://github.com/madeofpendletonwool/PinePods", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/pinepods.webp", + "description": "PinePods is a self-hosted, multi-user podcast server and player. It searches, subscribes to and downloads podcasts and YouTube channels, syncs listening progress across its web, desktop and mobile clients, and works with gPodder-compatible apps.", + "install_methods": [ + { + "type": "default", + "script": "ct/pinepods.sh", + "config_path": "/opt/pinepods_data/.env", + "resources": { + "cpu": 4, + "ram": 4096, + "hdd": 15, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "There is no default account. The first visit to the web UI asks you to create the admin user.", + "type": "info" + }, + { + "text": "HOSTNAME and SERVER_URL in /opt/pinepods_data/.env must match the address you open PinePods at. Change them for a new IP or a reverse proxy, then run systemctl restart pinepods-api.", + "type": "info" + } + ] +} From 0d108304028ce2b1ea02707a9e2e47faa515feab Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 09:41:05 +0000 Subject: [PATCH 3/9] Update PinePods scripts for the 0.9.1 layout 0.9.1 removed the Go gPodder service and serves sync from the Rust API, which broke updates at the gpodder-api build step. Drop the Go build and service, point nginx at the Rust API with upstream's forwarded-host handling, move to Python 3.14, and leave yt-dlp updates to the app. Co-Authored-By: Claude Opus 5.5 --- ct/pinepods.sh | 16 +++------ install/pinepods-install.sh | 71 ++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 52 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index c6b203e70d..f4333bedf9 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -33,17 +33,12 @@ function update_script() { exit fi - if check_for_gh_release "yt-dlp" "yt-dlp/yt-dlp"; then - fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" - fi - if check_for_gh_release "pinepods" "madeofpendletonwool/PinePods"; then msg_info "Stopping PinePods" - systemctl stop pinepods-gpodder pinepods-api + systemctl stop pinepods-api msg_ok "Stopped PinePods" - PYTHON_VERSION="3.11" setup_uv - setup_go + PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" @@ -55,21 +50,18 @@ function update_script() { rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations - cd /opt/pinepods/gpodder-api - CGO_ENABLED=0 $STD go build -ldflags="-s -w" -o /usr/local/bin/gpodder-api ./cmd/server/ cd /opt/pinepods/rust-api $STD cargo build --release cp target/release/pinepods-api /usr/local/bin/pinepods-api cd /opt/pinepods - $STD uv venv --python 3.11 /opt/pinepods/.venv + $STD uv venv --python 3.14 /opt/pinepods/.venv $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target - $STD go clean -cache -modcache cp ~/.pinepods /pinepods/current_version msg_ok "Built PinePods" msg_info "Starting PinePods" - systemctl start pinepods-api pinepods-gpodder + systemctl start pinepods-api msg_ok "Started PinePods" msg_ok "Updated successfully!" fi diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index 3e203cf8d7..0aad764d4a 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -25,8 +25,7 @@ msg_ok "Installed Dependencies" PG_VERSION="18" setup_postgresql PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db -PYTHON_VERSION="3.11" setup_uv -setup_go +PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust setup_ffmpeg fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" @@ -40,16 +39,13 @@ RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations -cd /opt/pinepods/gpodder-api -CGO_ENABLED=0 $STD go build -ldflags="-s -w" -o /usr/local/bin/gpodder-api ./cmd/server/ cd /opt/pinepods/rust-api $STD cargo build --release cp target/release/pinepods-api /usr/local/bin/pinepods-api cd /opt/pinepods -$STD uv venv --python 3.11 /opt/pinepods/.venv +$STD uv venv --python 3.14 /opt/pinepods/.venv $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target -$STD go clean -cache -modcache msg_ok "Built PinePods" msg_info "Configuring PinePods" @@ -77,6 +73,15 @@ msg_ok "Configured PinePods" msg_info "Configuring Nginx" cat <<'EOF' >/etc/nginx/sites-available/pinepods +map $http_x_forwarded_proto $fwd_proto { + default $http_x_forwarded_proto; + '' $scheme; +} +map $http_x_forwarded_host $fwd_host { + default $http_x_forwarded_host; + '' $http_host; +} + server { listen 8040; server_name _; @@ -93,10 +98,11 @@ server { location /rss/ { rewrite ^/rss/(\d+)(?:/(\d+))?$ /api/feed/$1$2 last; proxy_pass http://127.0.0.1:8032; - proxy_set_header Host $host; + proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Host $fwd_host; + proxy_set_header X-Forwarded-Proto $fwd_proto; proxy_set_header Api-Key $arg_api_key; add_header Content-Type "application/rss+xml; charset=utf-8"; expires 1h; @@ -120,10 +126,11 @@ server { add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; proxy_pass http://127.0.0.1:8032; - proxy_set_header Host $host; + proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Host $fwd_host; + proxy_set_header X-Forwarded-Proto $fwd_proto; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*' always; @@ -137,11 +144,12 @@ server { } location ~ ^/(api/2|auth|subscriptions|devices|updates|episodes|settings|lists|favorites|sync-devices|search|suggestions|toplist|tag|tags|data)/ { - proxy_pass http://127.0.0.1:8042; - proxy_set_header Host $host; + proxy_pass http://127.0.0.1:8032; + proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Host $fwd_host; + proxy_set_header X-Forwarded-Proto $fwd_proto; add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT' always; @@ -168,10 +176,11 @@ server { add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; proxy_pass http://127.0.0.1:8032; - proxy_set_header Host $host; + proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Host $fwd_host; + proxy_set_header X-Forwarded-Proto $fwd_proto; proxy_read_timeout 1800; proxy_send_timeout 1800; @@ -186,15 +195,16 @@ server { } } - location ~ ^/ws/api/(data|tasks)/ { + location /ws/api/ { proxy_pass http://127.0.0.1:8032; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; + proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Host $fwd_host; + proxy_set_header X-Forwarded-Proto $fwd_proto; proxy_read_timeout 86400; proxy_send_timeout 86400; } @@ -209,7 +219,7 @@ EOF nginx_enable_site "pinepods" msg_ok "Configured Nginx" -msg_info "Creating Services" +msg_info "Creating Service" cat </etc/systemd/system/pinepods-api.service [Unit] Description=PinePods API @@ -229,27 +239,8 @@ RestartSec=5 [Install] WantedBy=multi-user.target EOF -cat </etc/systemd/system/pinepods-gpodder.service -[Unit] -Description=PinePods gPodder API -After=pinepods-api.service -Requires=pinepods-api.service - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/pinepods -EnvironmentFile=/opt/pinepods_data/.env -Environment=SERVER_PORT=8042 -ExecStart=/usr/local/bin/gpodder-api -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now pinepods-api pinepods-gpodder -msg_ok "Created Services" +systemctl enable -q --now pinepods-api +msg_ok "Created Service" motd_ssh customize From 29f33574624d3316193281b3fedac5b9eb7ddf6a Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 10:24:59 +0000 Subject: [PATCH 4/9] Build PinePods with upstream's pinned trunk version Latest trunk defaults to Tailwind 4, but the PinePods UI targets Tailwind 3. Read the version from the release's dockerfile so builds match upstream without hardcoding it, deploying PinePods first so the file exists. Co-Authored-By: Claude Opus 5.5 --- ct/pinepods.sh | 3 ++- install/pinepods-install.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index f4333bedf9..85795d0d03 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -40,8 +40,9 @@ function update_script() { PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust - fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" + # Upstream's pin, because trunk picks the Tailwind major: newer trunk builds this Tailwind v3 UI with v4 + fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile)" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index 0aad764d4a..9d9f9d324c 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -28,9 +28,10 @@ PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust setup_ffmpeg -fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "latest" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" +# Upstream's pin, because trunk picks the Tailwind major: newer trunk builds this Tailwind v3 UI with v4 +fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile)" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown From 82585c6dad16fe202a3a84218fe4db4548e26045 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 11:48:14 +0000 Subject: [PATCH 5/9] Align PinePods scripts with the BookOrbit layout Rename the service to pinepods now that it is the only one, let slow migrations in ExecStartPre finish with TimeoutStartSec=infinity, give the Python steps their own block, and tidy paths and naming to match. Co-Authored-By: Claude Opus 5.5 --- ct/pinepods.sh | 24 +++++++++++++----------- install/pinepods-install.sh | 23 ++++++++++++++--------- json/pinepods.json | 2 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index 85795d0d03..fdba970d96 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -2,7 +2,6 @@ _CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/main" _cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") - # Copyright (c) 2021-2026 community-scripts ORG # Author: untect # License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE @@ -35,16 +34,17 @@ function update_script() { if check_for_gh_release "pinepods" "madeofpendletonwool/PinePods"; then msg_info "Stopping PinePods" - systemctl stop pinepods-api + systemctl stop pinepods msg_ok "Stopped PinePods" PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" - # Upstream's pin, because trunk picks the Tailwind major: newer trunk builds this Tailwind v3 UI with v4 - fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile)" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" + # Upstream's pin: trunk picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. + TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) + fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" - msg_info "Building PinePods" + msg_info "Rebuilding PinePods" $STD rustup target add wasm32-unknown-unknown cd /opt/pinepods/web RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release @@ -53,16 +53,18 @@ function update_script() { cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations cd /opt/pinepods/rust-api $STD cargo build --release - cp target/release/pinepods-api /usr/local/bin/pinepods-api - cd /opt/pinepods - $STD uv venv --python 3.14 /opt/pinepods/.venv - $STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt + cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target cp ~/.pinepods /pinepods/current_version - msg_ok "Built PinePods" + msg_ok "Rebuilt PinePods" + + msg_info "Updating Python Runtime" + $STD uv venv --python 3.14 /opt/pinepods/.venv + $STD uv pip install --python /opt/pinepods/.venv/bin/python -r /opt/pinepods/requirements.txt + msg_ok "Updated Python Runtime" msg_info "Starting PinePods" - systemctl start pinepods-api + systemctl start pinepods msg_ok "Started PinePods" msg_ok "Updated successfully!" fi diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index 9d9f9d324c..b534eaf41b 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -28,10 +28,12 @@ PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust setup_ffmpeg + fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" -# Upstream's pin, because trunk picks the Tailwind major: newer trunk builds this Tailwind v3 UI with v4 -fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile)" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" +# Upstream's pin: trunk picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. +TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) +fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown @@ -42,13 +44,15 @@ cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations cd /opt/pinepods/rust-api $STD cargo build --release -cp target/release/pinepods-api /usr/local/bin/pinepods-api -cd /opt/pinepods -$STD uv venv --python 3.14 /opt/pinepods/.venv -$STD uv pip install -p /opt/pinepods/.venv/bin/python -r requirements.txt +cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target msg_ok "Built PinePods" +msg_info "Setting up Python Runtime" +$STD uv venv --python 3.14 /opt/pinepods/.venv +$STD uv pip install --python /opt/pinepods/.venv/bin/python -r /opt/pinepods/requirements.txt +msg_ok "Set up Python Runtime" + msg_info "Configuring PinePods" # The API hardcodes these paths, as well as /pinepods/current_version mkdir -p /opt/pinepods/{downloads,backups,local-media} /opt/pinepods_data /pinepods @@ -221,15 +225,16 @@ nginx_enable_site "pinepods" msg_ok "Configured Nginx" msg_info "Creating Service" -cat </etc/systemd/system/pinepods-api.service +cat </etc/systemd/system/pinepods.service [Unit] -Description=PinePods API +Description=PinePods Service After=network.target postgresql.service valkey-server.service Requires=postgresql.service valkey-server.service [Service] Type=simple User=root +TimeoutStartSec=infinity WorkingDirectory=/opt/pinepods EnvironmentFile=/opt/pinepods_data/.env ExecStartPre=/opt/pinepods/.venv/bin/python /opt/pinepods/startup/setup_database_new.py @@ -240,7 +245,7 @@ RestartSec=5 [Install] WantedBy=multi-user.target EOF -systemctl enable -q --now pinepods-api +systemctl enable -q --now pinepods msg_ok "Created Service" motd_ssh diff --git a/json/pinepods.json b/json/pinepods.json index 1714578e52..1f0b17b5fa 100644 --- a/json/pinepods.json +++ b/json/pinepods.json @@ -38,7 +38,7 @@ "type": "info" }, { - "text": "HOSTNAME and SERVER_URL in /opt/pinepods_data/.env must match the address you open PinePods at. Change them for a new IP or a reverse proxy, then run systemctl restart pinepods-api.", + "text": "HOSTNAME and SERVER_URL in /opt/pinepods_data/.env must match the address you open PinePods at. Change them for a new IP or a reverse proxy, then run systemctl restart pinepods.", "type": "info" } ] From 8437c505e1a8db787ef6d665ee78369846cc1c28 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 13:56:11 +0000 Subject: [PATCH 6/9] Read PinePods' Python version from the dockerfile Use the release's dockerfile for the Python version as well as trunk, so a new upstream Python is followed without a script change. Stop with an error if either version can't be read, instead of building with an empty value. Co-Authored-By: Claude Opus 5.5 --- ct/pinepods.sh | 11 ++++++++--- install/pinepods-install.sh | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index fdba970d96..503e76ba96 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -37,11 +37,16 @@ function update_script() { systemctl stop pinepods msg_ok "Stopped PinePods" - PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" - # Upstream's pin: trunk picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. + # Upstream's pins. trunk matters most: it picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. + PYTHON_VERSION=$(sed -n 's/^FROM python:\([0-9.]*\)-.*/\1/p' /opt/pinepods/dockerfile) TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) + if [[ -z "$PYTHON_VERSION" || -z "$TRUNK_VERSION" ]]; then + msg_error "Could not read the Python or trunk version from the PinePods dockerfile" + exit 1 + fi + setup_uv fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" msg_info "Rebuilding PinePods" @@ -59,7 +64,7 @@ function update_script() { msg_ok "Rebuilt PinePods" msg_info "Updating Python Runtime" - $STD uv venv --python 3.14 /opt/pinepods/.venv + $STD uv venv --python "$PYTHON_VERSION" /opt/pinepods/.venv $STD uv pip install --python /opt/pinepods/.venv/bin/python -r /opt/pinepods/requirements.txt msg_ok "Updated Python Runtime" diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index b534eaf41b..7d7faf6d09 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -25,14 +25,19 @@ msg_ok "Installed Dependencies" PG_VERSION="18" setup_postgresql PG_DB_NAME="pinepods_database" PG_DB_USER="pinepods" setup_postgresql_db -PYTHON_VERSION="3.14" setup_uv RUST_PROFILE="minimal" setup_rust setup_ffmpeg fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" -# Upstream's pin: trunk picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. +# Upstream's pins. trunk matters most: it picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. +PYTHON_VERSION=$(sed -n 's/^FROM python:\([0-9.]*\)-.*/\1/p' /opt/pinepods/dockerfile) TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) +if [[ -z "$PYTHON_VERSION" || -z "$TRUNK_VERSION" ]]; then + msg_error "Could not read the Python or trunk version from the PinePods dockerfile" + exit 1 +fi +setup_uv fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" "/usr/local/bin" "trunk-$(arch_resolve "x86_64" "aarch64")-unknown-linux-gnu.tar.gz" msg_info "Building PinePods" @@ -49,7 +54,7 @@ rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/ta msg_ok "Built PinePods" msg_info "Setting up Python Runtime" -$STD uv venv --python 3.14 /opt/pinepods/.venv +$STD uv venv --python "$PYTHON_VERSION" /opt/pinepods/.venv $STD uv pip install --python /opt/pinepods/.venv/bin/python -r /opt/pinepods/requirements.txt msg_ok "Set up Python Runtime" From af9a063e656cf77b821041376d80a2df9e52a1cf Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 18:51:48 +0000 Subject: [PATCH 7/9] Manual review, error checking and verification --- ct/pinepods.sh | 11 +++++------ install/pinepods-install.sh | 7 +++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index 503e76ba96..ddeca90c28 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -3,7 +3,7 @@ _CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/ _cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") # Copyright (c) 2021-2026 community-scripts ORG -# Author: untect +# Author: untect (untect) # License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE # Source: https://github.com/madeofpendletonwool/PinePods @@ -11,10 +11,10 @@ APP="PinePods" var_tags="${var_tags:-podcast;media}" var_cpu="${var_cpu:-4}" var_ram="${var_ram:-4096}" -var_disk="${var_disk:-15}" +var_disk="${var_disk:-10}" var_os="${var_os:-debian}" var_version="${var_version:-13}" -#var_arm64="${var_arm64:-no}" # unset = ask the user; set yes/no only when verified +#var_arm64="${var_arm64:-no}" var_unprivileged="${var_unprivileged:-1}" header_info "$APP" @@ -39,7 +39,6 @@ function update_script() { RUST_PROFILE="minimal" setup_rust CLEAN_INSTALL=1 CLEAN_INSTALL_KEEP="downloads backups local-media" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" - # Upstream's pins. trunk matters most: it picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. PYTHON_VERSION=$(sed -n 's/^FROM python:\([0-9.]*\)-.*/\1/p' /opt/pinepods/dockerfile) TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) if [[ -z "$PYTHON_VERSION" || -z "$TRUNK_VERSION" ]]; then @@ -51,12 +50,12 @@ function update_script() { msg_info "Rebuilding PinePods" $STD rustup target add wasm32-unknown-unknown - cd /opt/pinepods/web + cd /opt/pinepods/web || msg_error "Directory /opt/pinepods/web not found" && exit 1 RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations - cd /opt/pinepods/rust-api + cd /opt/pinepods/rust-api || msg_error "Directory /opt/pinepods/rust-api not found" && exit 1 $STD cargo build --release cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index 7d7faf6d09..43b097a14c 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -30,7 +30,7 @@ setup_ffmpeg fetch_and_deploy_gh_release "yt-dlp" "yt-dlp/yt-dlp" "singlefile" "latest" "/usr/local/bin" "$(arch_resolve "yt-dlp_linux" "yt-dlp_linux_aarch64")" fetch_and_deploy_gh_release "pinepods" "madeofpendletonwool/PinePods" "tarball" -# Upstream's pins. trunk matters most: it picks the Tailwind major, and newer trunk builds this Tailwind v3 UI with v4. + PYTHON_VERSION=$(sed -n 's/^FROM python:\([0-9.]*\)-.*/\1/p' /opt/pinepods/dockerfile) TRUNK_VERSION=$(sed -n 's#.*trunk/releases/download/\(v[0-9.]*\)/.*#\1#p' /opt/pinepods/dockerfile) if [[ -z "$PYTHON_VERSION" || -z "$TRUNK_VERSION" ]]; then @@ -42,12 +42,12 @@ fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown -cd /opt/pinepods/web +cd /opt/pinepods/web || msg_error "Directory /opt/pinepods/web not found" && exit 1 RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations -cd /opt/pinepods/rust-api +cd /opt/pinepods/rust-api || msg_error "Directory /opt/pinepods/rust-api not found" && exit 1 $STD cargo build --release cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target @@ -59,7 +59,6 @@ $STD uv pip install --python /opt/pinepods/.venv/bin/python -r /opt/pinepods/req msg_ok "Set up Python Runtime" msg_info "Configuring PinePods" -# The API hardcodes these paths, as well as /pinepods/current_version mkdir -p /opt/pinepods/{downloads,backups,local-media} /opt/pinepods_data /pinepods cp ~/.pinepods /pinepods/current_version cat </opt/pinepods_data/.env From b17184441ece47a9aad979b4b223c77a5963ddb1 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 18:58:01 +0000 Subject: [PATCH 8/9] Align JSON with default configs in install script --- json/pinepods.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/pinepods.json b/json/pinepods.json index 1f0b17b5fa..044182cc1f 100644 --- a/json/pinepods.json +++ b/json/pinepods.json @@ -13,7 +13,7 @@ "website": "https://www.pinepods.online/", "repository": "https://github.com/madeofpendletonwool/PinePods", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/pinepods.webp", - "description": "PinePods is a self-hosted, multi-user podcast server and player. It searches, subscribes to and downloads podcasts and YouTube channels, syncs listening progress across its web, desktop and mobile clients, and works with gPodder-compatible apps.", + "description": "Pinepods is a complete podcast management system that allows you to play, download, and keep track of podcasts you enjoy. All self hosted and enjoyed on your own server!", "install_methods": [ { "type": "default", @@ -22,7 +22,7 @@ "resources": { "cpu": 4, "ram": 4096, - "hdd": 15, + "hdd": 10, "os": "Debian", "version": "13" } From 0b668868055dfe84475ad11683375cae9ed7ee32 Mon Sep 17 00:00:00 2001 From: Morgan Hickman Date: Wed, 4 Nov 2026 19:15:10 +0000 Subject: [PATCH 9/9] rollback cd guards which are handled by catch_errors --- ct/pinepods.sh | 4 ++-- install/pinepods-install.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ct/pinepods.sh b/ct/pinepods.sh index ddeca90c28..8d028b7653 100644 --- a/ct/pinepods.sh +++ b/ct/pinepods.sh @@ -50,12 +50,12 @@ function update_script() { msg_info "Rebuilding PinePods" $STD rustup target add wasm32-unknown-unknown - cd /opt/pinepods/web || msg_error "Directory /opt/pinepods/web not found" && exit 1 + cd /opt/pinepods/web RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations - cd /opt/pinepods/rust-api || msg_error "Directory /opt/pinepods/rust-api not found" && exit 1 + cd /opt/pinepods/rust-api $STD cargo build --release cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target diff --git a/install/pinepods-install.sh b/install/pinepods-install.sh index 43b097a14c..877dd76dae 100644 --- a/install/pinepods-install.sh +++ b/install/pinepods-install.sh @@ -42,12 +42,12 @@ fetch_and_deploy_gh_release "trunk" "trunk-rs/trunk" "prebuild" "$TRUNK_VERSION" msg_info "Building PinePods" $STD rustup target add wasm32-unknown-unknown -cd /opt/pinepods/web || msg_error "Directory /opt/pinepods/web not found" && exit 1 +cd /opt/pinepods/web RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" $STD trunk build --features server_build --release rm -rf /var/www/html cp -r /opt/pinepods/web/dist /var/www/html cp -r /opt/pinepods/web/src/translations /var/www/html/static/translations -cd /opt/pinepods/rust-api || msg_error "Directory /opt/pinepods/rust-api not found" && exit 1 +cd /opt/pinepods/rust-api $STD cargo build --release cp /opt/pinepods/rust-api/target/release/pinepods-api /usr/local/bin/pinepods-api rm -rf /opt/pinepods/web/target /opt/pinepods/web/dist /opt/pinepods/rust-api/target