From 938da40a45370162eaf7aeb91446b06a327cbd13 Mon Sep 17 00:00:00 2001 From: Quinta0 <0pietroquintavalle0@gmail.com> Date: Tue, 7 Jul 2026 13:58:45 +0200 Subject: [PATCH] fixed duplicates and slskd crashes, implemented autoheal if containers hangs --- README.md | 49 ++++++++++++++++++++++++---------- docker-compose.yml | 66 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index b41ac43..04654d4 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ No Spotify. No YouTube Music. No ads. Just your music, your server, your rules. | **Pangolin** | Reverse proxy — exposes Navidrome securely to the internet | | **Gluetun** | VPN gateway container — all Soulseek traffic exits via ProtonVPN | | **slskd** | Soulseek client — searches and downloads music from the P2P network | +| **autoheal** | Watches slskd/gluetun health status and force-restarts them if they hang | | **Explo** | Discovery engine — connects ListenBrainz recommendations to slskd | | **ListenBrainz** | Open-source scrobbler + recommendation engine | | **Last.fm** | Secondary scrobbler for stats and social features | @@ -55,7 +56,7 @@ No Spotify. No YouTube Music. No ads. Just your music, your server, your rules. │ └── slskd.yml ← slskd config (copy from repo) └── explo/ ├── .env ← Explo config (copy from .env.example) - └── docker-compose.yml ← Full stack compose file (copy from repo) + └── config/ ← Explo's playlist cache + cover art (auto-populated, must persist) /mnt/user/data/media/music/ ├── incomplete/ ← In-progress downloads (Navidrome ignores these) @@ -99,7 +100,7 @@ Fill in your ListenBrainz username, Navidrome URL/credentials, and slskd API key ### 3. Create required folders ```bash -mkdir -p /mnt/user/appdata/{gluetun,slskd,explo} +mkdir -p /mnt/user/appdata/{gluetun,slskd,explo/config} mkdir -p /mnt/user/data/media/music/{explo,incomplete} ``` @@ -134,21 +135,15 @@ Add these environment variables in the Navidrome container template: | `ND_LASTFM_ENABLED` | `true` | | `ND_SCANSCHEDULE` | `1m` | -### 7. Set up automation via Unraid User Scripts +### 7. Start Explo and autoheal -Install the **User Scripts** plugin from Community Apps, then add two scripts: - -**Weekly Exploration** — Cron: `15 0 * * 2` ```bash -#!/bin/bash -docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-weekly +docker compose up -d explo autoheal ``` -**Daily Jams** — Cron: `15 0 * * *` -```bash -#!/bin/bash -docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-daily -``` +Unlike the rest of the stack, Explo doesn't need any external scheduler (no Unraid User Scripts, no cron). It runs continuously and schedules Weekly Exploration and Daily Jams itself via `WEEKLY_EXPLORATION_SCHEDULE` / `DAILY_JAMS_SCHEDULE` in `docker-compose.yml`, and `EXECUTE_ON_START=false` means restarting or updating the container never triggers an extra, out-of-schedule run. This is what keeps it from downloading the same week twice — see [Troubleshooting](#troubleshooting) below for the full explanation. + +`autoheal` also just runs continuously in the background; it watches slskd and gluetun and restarts either one automatically if Docker marks it unhealthy. --- @@ -176,6 +171,32 @@ You discover new music 🎵 --- +## Troubleshooting + +### slskd hangs and needs a manual restart every ~24h + +This was almost always one of two things, both addressed in the current compose file: + +- **slskd itself getting stuck** (memory pressure / stuck transfers) — fixed by pinning `slskd/slskd:0.25.1`, which bundles a round of upstream fixes for stuck and failing transfers. +- **gluetun's tunnel silently hanging** — since slskd runs inside gluetun's network namespace, a frozen gluetun looks identical to a frozen slskd. Fixed by pinning `qmcgaw/gluetun:v3.41.1`, which resolves a healthcheck race condition that could make gluetun hang completely. + +Both containers already ship a Docker healthcheck, but **Docker does not restart a container just because it's unhealthy** — that gap is why a manual restart was needed. The new `autoheal` service closes it: it watches both containers (via the `autoheal=true` label) and force-restarts whichever one goes unhealthy, with no manual intervention. + +If slskd still misbehaves after this, check `docker ps` for its health status and `docker logs slskd`/`docker logs gluetun` before restarting manually. + +### Weekly Exploration downloaded multiple times + +The old setup ran two one-shot `explo-weekly` / `explo-daily` containers (`restart: "no"`, `EXECUTE_ON_START=true`) that were triggered by an external Unraid User Scripts cron. That design had two compounding problems: + +1. Every container restart (a host reboot, a Docker update, the scheduler firing slightly out of sync) re-ran Explo immediately because of `EXECUTE_ON_START=true`, regardless of whether that week's playlist already existed. +2. Explo's playlist cache had nowhere to persist between runs (no `/opt/explo/config` volume), so each fresh container had no memory of "I already built this week's playlist" and would build it again. + +The current compose runs a single, always-on `explo` container with its own internal cron (`WEEKLY_EXPLORATION_SCHEDULE` / `DAILY_JAMS_SCHEDULE`), `EXECUTE_ON_START=false`, and a persistent `/opt/explo/config` volume, plus the newer `v1.1.0` image which includes further upstream fixes for scheduled-job bugs. Together this means Explo only ever runs on its own schedule, and remembers what it already did across restarts. + +**One-time cleanup:** this fix prevents *future* duplicates, but it won't retroactively merge the duplicate `Weekly-Exploration-2026-WeekXX` playlists already sitting in Navidrome. Delete the extras once, manually, from the Navidrome UI (or via its API) — new runs going forward should stay to one playlist per period. + +--- + ## Tips - **ListenBrainz needs time** — it takes a few weeks of scrobbling before Weekly Exploration playlists are generated. Speed this up by importing your Google Takeout YouTube Music watch history via [ytm-extractor](https://community.metabrainz.org/t/ytm-extractor-import-youtube-music-listens-to-listenbrainz/707619). @@ -189,4 +210,4 @@ You discover new music 🎵 ## License -MIT — do whatever you want with it. +MIT — do whatever you want with it. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 67776bf..0db86ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,6 @@ services: - gluetun: - image: qmcgaw/gluetun:latest + image: qmcgaw/gluetun:v3.41.1 container_name: gluetun cap_add: - NET_ADMIN @@ -14,14 +13,20 @@ services: - WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES} - SERVER_COUNTRIES=${VPN_COUNTRY:-Switzerland} - TZ=${TZ:-Europe/Zurich} + - VPN_PORT_FORWARDING=${VPN_PORT_FORWARDING:-off} + - VPN_PORT_FORWARDING_PROVIDER=protonvpn + - PORT_FORWARD_ONLY=${VPN_PORT_FORWARDING:-off} + - VPN_PORT_FORWARDING_STATUS_FILE=/gluetun/forwarded_port ports: - 5030:5030 + - 8000:8000 volumes: - ${APPDATA_PATH}/gluetun:/gluetun restart: unless-stopped - + labels: + - autoheal=true slskd: - image: slskd/slskd:latest + image: slskd/slskd:0.25.1 container_name: slskd network_mode: "service:gluetun" depends_on: @@ -34,27 +39,48 @@ services: - ${MUSIC_PATH}:/downloads - ${MUSIC_PATH}:/music:ro restart: unless-stopped - - explo-weekly: - image: ghcr.io/lumepart/explo:latest - container_name: explo-weekly + labels: + - autoheal=true + autoheal: + image: willfarrell/autoheal:latest + container_name: autoheal + restart: unless-stopped environment: - - EXECUTE_ON_START=true + - AUTOHEAL_CONTAINER_LABEL=autoheal + - AUTOHEAL_INTERVAL=30 + - AUTOHEAL_START_PERIOD=120 + - AUTOHEAL_DEFAULT_STOP_TIMEOUT=30 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + explo: + image: ghcr.io/lumepart/explo:v1.1.0 + container_name: explo + environment: + - TZ=${TZ:-Europe/Zurich} + - WEB_UI=false + - EXECUTE_ON_START=false + - WEEKLY_EXPLORATION_SCHEDULE=15 0 * * 2 - WEEKLY_EXPLORATION_FLAGS=--playlist=weekly-exploration --persist + - WEEKLY_JAMS_SCHEDULE=30 0 * * 1 + - WEEKLY_JAMS_FLAGS=--playlist=weekly-jams --persist + - DAILY_JAMS_SCHEDULE=15 1 * * * + - DAILY_JAMS_FLAGS=--playlist=daily-jams --persist volumes: - ${APPDATA_PATH}/explo/.env:/opt/explo/.env + - ${APPDATA_PATH}/explo/config:/opt/explo/config - ${MUSIC_PATH}/explo:/data - ${MUSIC_PATH}:/slskd - restart: "no" - - explo-daily: - image: ghcr.io/lumepart/explo:latest - container_name: explo-daily + restart: unless-stopped + lidarr: + image: lscr.io/linuxserver/lidarr:latest + container_name: lidarr environment: - - EXECUTE_ON_START=true - - DAILY_JAMS_FLAGS=--playlist=daily-jams --download-mode=skip + - PUID=${PUID:-99} + - PGID=${PGID:-100} + - TZ=${TZ:-Europe/Zurich} volumes: - - ${APPDATA_PATH}/explo/.env:/opt/explo/.env - - ${MUSIC_PATH}/explo:/data - - ${MUSIC_PATH}:/slskd - restart: "no" + - ${APPDATA_PATH}/lidarr:/config + - ${MUSIC_PATH}:/music + ports: + - 8686:8686 + restart: unless-stopped \ No newline at end of file