Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
cc2f411
Fix admin client sending no X-Plex-Token
Gabriel-Lewis Aug 19, 2026
56fc672
Fix "Save each run as new playlist" toggle never saving
Gabriel-Lewis Aug 19, 2026
c5af338
Merge pull request #1 from Gabriel-Lewis/fix/replace-playlist-toggle
Gabriel-Lewis Aug 19, 2026
b4f3b8a
Add opt-in album downloads for slskd
Gabriel-Lewis Aug 29, 2026
22386aa
Merge pull request #4 from Gabriel-Lewis/feat/slskd-album
Gabriel-Lewis Aug 29, 2026
ac4a6f7
Scope the session cookie to the instance
Gabriel-Lewis Aug 29, 2026
5aeff08
Check response body close in session tests
Gabriel-Lewis Aug 30, 2026
c5c935e
Merge pull request #5 from Gabriel-Lewis/fix/instance-scoped-session-…
Gabriel-Lewis Aug 30, 2026
6007c2e
Expose slskd album mode in the setup wizard
Gabriel-Lewis Aug 30, 2026
6b654d1
Merge pull request #6 from Gabriel-Lewis/feat/album-mode-ui
Gabriel-Lewis Aug 30, 2026
b7a5fa8
Keep migrating a release until its files arrive
Gabriel-Lewis Aug 30, 2026
71e43c5
Don't lose a playlist to one failed status poll
Gabriel-Lewis Aug 30, 2026
4510b49
Time out a run that never finishes
Gabriel-Lewis Aug 30, 2026
2ab6273
Stop a scheduled run from overlapping itself
Gabriel-Lewis Aug 30, 2026
dba64ab
Merge pull request #7 from Gabriel-Lewis/fix/album-sibling-migration
Gabriel-Lewis Aug 30, 2026
0d5e770
Merge pull request #8 from Gabriel-Lewis/fix/monitor-poll-resilience
Gabriel-Lewis Aug 30, 2026
4b077b4
Merge pull request #10 from Gabriel-Lewis/fix/run-timeout
Gabriel-Lewis Aug 30, 2026
138e331
Merge pull request #11 from Gabriel-Lewis/fix/cron-overlap
Gabriel-Lewis Aug 30, 2026
5a9f071
Let a playlist build from local files only
Gabriel-Lewis Aug 30, 2026
575ade5
Merge pull request #12 from Gabriel-Lewis/feat/per-playlist-local-only
Gabriel-Lewis Aug 30, 2026
5a887e1
Don't send a delete when there is no playlist to delete
Gabriel-Lewis Aug 30, 2026
46818c1
Merge pull request #13 from Gabriel-Lewis/fix/plex-delete-no-playlist
Gabriel-Lewis Aug 30, 2026
d62010d
Add a ceiling to the slskd quality filters
Gabriel-Lewis Aug 30, 2026
5fc96cd
Merge pull request #14 from Gabriel-Lewis/feat/quality-range
Gabriel-Lewis Aug 30, 2026
1f6b496
Restore the size preference onto dev
Gabriel-Lewis Aug 30, 2026
208ae98
Merge pull request #17 from Gabriel-Lewis/fix/restore-size-preference
Gabriel-Lewis Aug 30, 2026
4fcd518
Restore the release preference onto dev
Gabriel-Lewis Aug 30, 2026
ab4b6ca
Merge pull request #18 from Gabriel-Lewis/fix/restore-release-preference
Gabriel-Lewis Aug 30, 2026
a0a870e
Prefer the original release in album mode
Gabriel-Lewis Aug 30, 2026
9889df5
Assert wizard defaults against the written value, not the sample comment
Gabriel-Lewis Aug 30, 2026
9d0c0b8
Merge pull request #19 from Gabriel-Lewis/feat/prefer-original-release
Gabriel-Lewis Aug 30, 2026
cf3d144
Take the album's shape from its release group, not one matched release
Gabriel-Lewis Aug 30, 2026
c69d981
Merge pull request #20 from Gabriel-Lewis/feat/release-group-consensus
Gabriel-Lewis Aug 30, 2026
d1aa6f1
Merge upstream LumePart/Explo dev (v1.2 pre-release) into fork
Gabriel-Lewis Sep 19, 2026
f2c84e4
Merge pull request #21 from Gabriel-Lewis/merge/upstream-v1.2
Gabriel-Lewis Sep 24, 2026
46d8f00
Download each album once per run in album mode
Gabriel-Lewis Sep 24, 2026
9b49b4a
Merge pull request #24 from Gabriel-Lewis/fix/album-dedupe
Gabriel-Lewis Sep 24, 2026
85a8802
Add bug tracking TODO list
Gabriel-Lewis Oct 19, 2026
9194681
Add per-provider fallback threshold for download services
Gabriel-Lewis Oct 19, 2026
92a561e
Note PR #25 and stale-branch cleanup in tracker
Gabriel-Lewis Oct 19, 2026
e1d6575
Merge pull request #25 from Gabriel-Lewis/feat/download-provider-fall…
Gabriel-Lewis Oct 19, 2026
95b2228
Fix staticcheck QF1001 in monitor deadline check
Gabriel-Lewis Oct 19, 2026
c85aaaf
Fix session race crashing the app under concurrent requests
Gabriel-Lewis Oct 19, 2026
88bac9b
Fix Lidarr album cache race and nil dereference
Gabriel-Lewis Oct 19, 2026
51474f7
Fix custom playlists being wiped by concurrent saves
Gabriel-Lewis Oct 20, 2026
1b16855
Fix panic on ListenBrainz recordings with no artists
Gabriel-Lewis Oct 20, 2026
8c7fbf1
Error clearly on an unknown DISCOVERY_SERVICE instead of panicking
Gabriel-Lewis Oct 20, 2026
1d957aa
Return an error instead of panicking on an empty Plex library response
Gabriel-Lewis Oct 20, 2026
8b4d1c3
Stop file moves from erasing the destination song
Gabriel-Lewis Oct 20, 2026
95d8455
Serialize settings saves and write .env atomically
Gabriel-Lewis Oct 20, 2026
65d43d2
Mask API keys however they are spelled in the settings view
Gabriel-Lewis Oct 20, 2026
526fb4b
Stop legacy CRON_SCHEDULE from disabling all scheduling
Gabriel-Lewis Oct 20, 2026
63d5cf3
Keep draining run output past very long lines
Gabriel-Lewis Oct 20, 2026
8ac653e
Bound remote fetches with timeouts and size caps
Gabriel-Lewis Oct 20, 2026
6f831aa
Close the run log instead of the pipe on rejected runs
Gabriel-Lewis Oct 20, 2026
1287887
Only mark a track present after its move succeeds
Gabriel-Lewis Oct 20, 2026
a19fa89
Skip unmatched tracks when creating Subsonic playlists
Gabriel-Lewis Oct 20, 2026
39bff7b
Resolve the real Jellyfin user instead of sending the API key
Gabriel-Lewis Oct 20, 2026
020c66d
Actually delete Emby playlists instead of silently keeping them
Gabriel-Lewis Oct 20, 2026
c27927f
Marshal Jellyfin/Emby playlist bodies instead of fmt-printing them
Gabriel-Lewis Oct 20, 2026
decf51d
Stop MPD playlists doubling on every re-run
Gabriel-Lewis Oct 20, 2026
7045dcb
Run the opened tracklist's own replace flag from its card
Gabriel-Lewis Oct 20, 2026
ab7c991
Tag each song with its own disc and track number
Gabriel-Lewis Oct 20, 2026
ae5f305
Skip empty metadata keys when building ffmpeg tags
Gabriel-Lewis Oct 20, 2026
5da4767
Proceed without cover art when the cover download fails
Gabriel-Lewis Oct 20, 2026
52f6bce
Retry mutating requests once on a stale CSRF token
Gabriel-Lewis Oct 20, 2026
76d5ea6
Show an error screen instead of a blank page on startup failure
Gabriel-Lewis Oct 20, 2026
77a2b56
Register the path-templates route with its leading slash
Gabriel-Lewis Oct 20, 2026
65e2c31
Lock Docker-configured wizard fields in step 2
Gabriel-Lewis Oct 20, 2026
872957f
Gate playlist refreshes on the freshly loaded fetch time
Gabriel-Lewis Oct 20, 2026
fcddbc1
Record per-issue local branches for all 30 bug fixes
Gabriel-Lewis Oct 20, 2026
3d25a06
Merge pull request #26 from Gabriel-Lewis/fix/bug-01-session-race
Gabriel-Lewis Oct 20, 2026
b1156c4
Merge pull request #27 from Gabriel-Lewis/fix/bug-02-lidarr-cache-race
Gabriel-Lewis Oct 20, 2026
a4b45f5
Merge pull request #28 from Gabriel-Lewis/fix/bug-03-empty-artist-panic
Gabriel-Lewis Oct 20, 2026
9118db3
Merge pull request #29 from Gabriel-Lewis/fix/bug-04-config-typo-panic
Gabriel-Lewis Oct 20, 2026
7cc36b0
Merge pull request #30 from Gabriel-Lewis/fix/bug-05-plex-library-panic
Gabriel-Lewis Oct 20, 2026
b59db5f
Merge pull request #31 from Gabriel-Lewis/fix/bug-06-custom-playlists…
Gabriel-Lewis Oct 20, 2026
b20eee1
Merge pull request #32 from Gabriel-Lewis/fix/bug-07-file-move-erases…
Gabriel-Lewis Oct 20, 2026
6793ecb
Merge pull request #33 from Gabriel-Lewis/fix/bug-08-settings-save-race
Gabriel-Lewis Oct 20, 2026
0902c74
Reject line breaks in settings written to .env
Gabriel-Lewis Oct 20, 2026
f5580ec
Merge pull request #34 from Gabriel-Lewis/fix/bug-09-env-injection
Gabriel-Lewis Oct 20, 2026
0f76801
Merge pull request #35 from Gabriel-Lewis/fix/bug-10-sensitive-key-mask
Gabriel-Lewis Oct 20, 2026
c0a96db
Merge pull request #36 from Gabriel-Lewis/fix/bug-11-move-before-present
Gabriel-Lewis Oct 20, 2026
9759448
Merge pull request #37 from Gabriel-Lewis/fix/bug-12-subsonic-missing…
Gabriel-Lewis Oct 20, 2026
c996123
Merge pull request #38 from Gabriel-Lewis/fix/bug-13-jellyfin-userid
Gabriel-Lewis Oct 20, 2026
8bd28a7
Merge pull request #39 from Gabriel-Lewis/fix/bug-14-emby-delete-noop
Gabriel-Lewis Oct 20, 2026
3a25e1b
Merge pull request #40 from Gabriel-Lewis/fix/bug-15-playlist-json-es…
Gabriel-Lewis Oct 20, 2026
d84db8d
Merge pull request #41 from Gabriel-Lewis/fix/bug-16-mpd-append
Gabriel-Lewis Oct 20, 2026
fb79791
Merge pull request #42 from Gabriel-Lewis/fix/bug-17-tracklist-replac…
Gabriel-Lewis Oct 20, 2026
d601f1f
Merge pull request #43 from Gabriel-Lewis/fix/bug-19-long-log-line
Gabriel-Lewis Oct 20, 2026
3151f26
Merge pull request #44 from Gabriel-Lewis/fix/bug-20-http-timeouts
Gabriel-Lewis Oct 20, 2026
7f7fc18
Merge pull request #45 from Gabriel-Lewis/fix/bug-21-rejected-run-leak
Gabriel-Lewis Oct 20, 2026
42c5605
Merge pull request #46 from Gabriel-Lewis/fix/bug-22-track-number
Gabriel-Lewis Oct 20, 2026
35be863
Merge pull request #48 from Gabriel-Lewis/fix/bug-24-metadata-empty-keys
Gabriel-Lewis Oct 20, 2026
f0dad45
Merge pull request #49 from Gabriel-Lewis/fix/bug-25-cover-failure
Gabriel-Lewis Oct 20, 2026
a98b2fd
Merge pull request #50 from Gabriel-Lewis/fix/bug-26-csrf-retry
Gabriel-Lewis Oct 20, 2026
7d3fe34
Merge pull request #51 from Gabriel-Lewis/fix/bug-27-startup-blank-page
Gabriel-Lewis Oct 20, 2026
101a3e4
Merge pull request #52 from Gabriel-Lewis/fix/bug-28-path-templates-r…
Gabriel-Lewis Oct 20, 2026
760c926
Merge pull request #53 from Gabriel-Lewis/fix/bug-29-wizard-env-lock
Gabriel-Lewis Oct 20, 2026
f92a6e3
Merge pull request #54 from Gabriel-Lewis/fix/bug-30-legacy-cron-sche…
Gabriel-Lewis Oct 20, 2026
d6903a2
Merge pull request #55 from Gabriel-Lewis/fix/bug-31-weekly-refresh
Gabriel-Lewis Oct 20, 2026
fbd364d
Keep recommendation order when building tracks from recordings
Gabriel-Lewis Oct 20, 2026
93d3fed
Merge pull request #47 from Gabriel-Lewis/fix/bug-23-playlist-order
Gabriel-Lewis Oct 20, 2026
452a55e
Prefer multi-file releases over single-file strays in album selection
Gabriel-Lewis Oct 21, 2026
70894c8
Exclude oversized dumps from the strict album selection pass
Gabriel-Lewis Oct 21, 2026
784ea91
Default RELEASE_PREFERENCE to smaller in album mode
Gabriel-Lewis Oct 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ WORKDIR /opt/explo/

# Copy entrypoint, binary, python helper
COPY ./docker/start.sh /start.sh
COPY ./docker/explo-run.sh /explo-run.sh
COPY --from=builder /app/explo .
COPY src/downloader/youtube_music/search_ytmusic.py .


RUN chmod +x /start.sh ./explo
RUN chmod +x /start.sh /explo-run.sh ./explo


ENV WEB_ADDR=":7288"
Expand Down
311 changes: 311 additions & 0 deletions TODO.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ services:
# Web UI credentials (optional)
#- UI_USERNAME=
#- UI_PASSWORD=
# Session cookie name. Defaults to explo_session_<port> from WEB_ADDR, so
# that instances on one host do not overwrite each other's login. Only set
# this if several instances share a host AND port behind a reverse proxy.
#- UI_COOKIE_NAME=

# [Legacy] Schedules are managed through the web UI.
# These can still be set here for backwards compatibility — they will take precedence over the UI.
Expand Down
46 changes: 46 additions & 0 deletions docker/explo-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/sh
# Run one scheduled Explo job under a lock of its own.
#
# crond starts a job on schedule whether or not the last one finished, and a run
# can outlast its own interval -- downloads are slow. Two copies of the same job
# then race on the same playlist. The lock makes the second one stand down.
#
# The lock is per job, not global: a long weekly-exploration must not cancel
# weekly-jams, since skipping a different playlist entirely is worse than
# running the two at once.
#
# Usage: explo-run.sh <job-name> <command> [args...]

set -u

if [ "$#" -lt 2 ]; then
echo "[explo] usage: explo-run.sh <job-name> <command> [args...]" >&2
exit 2
fi

job="$1"
shift

lock="${EXPLO_LOCK_DIR:-/tmp}/explo-${job}.lock"

# Without flock, run unlocked rather than not at all: an overlapping run is a
# lesser problem than a playlist that never gets built.
if ! command -v flock >/dev/null 2>&1; then
echo "[explo] $job: flock unavailable, running without an overlap guard"
exec "$@"
fi

# Hold the lock on a file descriptor so it is released when this shell exits,
# however it exits. Taking it this way also keeps the exit status unambiguous:
# flock fails here only because the lock is held, never because the job did.
exec 9>"$lock" || {
echo "[explo] $job: couldn't open $lock, running without an overlap guard"
exec "$@"
}

if ! flock -n 9; then
echo "[explo] $job: previous run still in progress, skipping this schedule"
exit 0
fi

exec "$@"
86 changes: 86 additions & 0 deletions docker/explo-run_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/bin/sh
# Tests for explo-run.sh. Run it directly: sh docker/explo-run_test.sh
#
# There is no shell test harness in CI (the pipeline runs golangci-lint only),
# so this is here to be run by hand and to document what the lock guarantees.

set -u

script="$(dirname "$0")/explo-run.sh"
lockdir="$(mktemp -d)"
export EXPLO_LOCK_DIR="$lockdir"

failures=0

fail() {
echo "FAIL: $1"
failures=$((failures + 1))
}

pass() {
echo "ok: $1"
}

# A job runs normally when nothing holds its lock.
out="$("$script" solo /bin/echo ran)"
if [ "$out" = "ran" ]; then
pass "runs the command when the lock is free"
else
fail "expected 'ran', got '$out'"
fi

# A second copy of the SAME job stands down instead of racing the first.
"$script" overlap /bin/sleep 2 &
first=$!
sleep 0.3

out="$("$script" overlap /bin/echo ran)"
case "$out" in
*"skipping this schedule"*)
pass "a second copy of the same job skips" ;;
*)
fail "expected the second run to skip, got '$out'" ;;
esac

# Skipping must look like success, or cron mails an error every schedule.
"$script" overlap /bin/echo ran >/dev/null
if [ $? -eq 0 ]; then
pass "a skipped run exits 0"
else
fail "a skipped run exited non-zero"
fi

# A DIFFERENT job must not be blocked: skipping another playlist entirely is
# worse than two runs overlapping.
out="$("$script" other /bin/echo ran)"
if [ "$out" = "ran" ]; then
pass "a different job is not blocked"
else
fail "a different job was blocked, got '$out'"
fi

wait "$first"

# Once the first finishes, the job can run again.
out="$("$script" overlap /bin/echo ran)"
if [ "$out" = "ran" ]; then
pass "the lock is released when the run ends"
else
fail "lock was not released, got '$out'"
fi

# The command's own exit status must reach cron unchanged.
"$script" status /bin/sh -c 'exit 3'
if [ $? -eq 3 ]; then
pass "the command's exit status is passed through"
else
fail "exit status was not passed through"
fi

rm -rf "$lockdir"

if [ "$failures" -ne 0 ]; then
echo "$failures failure(s)"
exit 1
fi
echo "all passed"
17 changes: 13 additions & 4 deletions docker/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,23 @@ if [ -f "$_cfg" ]; then
fi


# $CRON_SHCEDULE was deprecated in v0.11.0, keeping this block for backwards compatibility
# $CRON_SHCEDULE was deprecated in v0.11.0, keeping this block for backwards compatibility.
# Only register the job here: running `crond -f` in the foreground would block
# everything below (per-playlist schedules, EXECUTE_ON_START, the final crond),
# so legacy users silently lost all scheduling.
if [ -n "$CRON_SCHEDULE" ]; then
echo "$CRON_SCHEDULE cd /opt/explo && $RUNNER ./explo --config \"$_cfg\" >> /proc/1/fd/1 2>&1" >> /etc/crontabs/root
echo "$CRON_SCHEDULE cd /opt/explo && /explo-run.sh legacy $RUNNER ./explo --config \"$_cfg\" >> /proc/1/fd/1 2>&1" >> /etc/crontabs/root
chmod 600 /etc/crontabs/root
echo "[setup] Registered single CRON_SCHEDULE job: $CRON_SCHEDULE"
crond -f -l 2
fi

# Loop over all *_SCHEDULE environment variables
for var in $(env | grep "_SCHEDULE=" | cut -d= -f1); do
# CRON_SCHEDULE is registered by the legacy block above; registering it
# again here would run the same job twice.
if [ "$var" = "CRON_SCHEDULE" ]; then
continue
fi
job="${var%_SCHEDULE}" # Job name (e.g WEEKLY_EXPLORATION)
schedule="$(printenv "$var")" # Cron schedule
flags_var="${job}_FLAGS"
Expand All @@ -82,7 +89,9 @@ for var in $(env | grep "_SCHEDULE=" | cut -d= -f1); do
fi

# Default: just run explo if flags are empty
cmd="cd /opt/explo && $RUNNER ./explo --config \"$_cfg\" $flags >> /proc/1/fd/1 2>&1"
# Wrapped so a run that outlasts its own schedule does not get a second copy
# started on top of it. The lock is per job, so other playlists still run.
cmd="cd /opt/explo && /explo-run.sh \"$job\" $RUNNER ./explo --config \"$_cfg\" $flags >> /proc/1/fd/1 2>&1"

echo "$schedule $cmd" >> /etc/crontabs/root
echo "[setup] Registered job: $job"
Expand Down
43 changes: 43 additions & 0 deletions sample.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# === Web UI ===
# Web cache limit in MB (cover art, backgrounds) (default: 500)
# WEB_CACHE_MB=500
# Kill a run started from the web UI after this many minutes. Without it a
# wedged run keeps the UI refusing new runs until it is stopped by hand.
# 0 disables the timeout. (default: 240)
# RUN_TIMEOUT=240

# === Discovery Config ===

Expand Down Expand Up @@ -52,6 +56,15 @@ LIBRARY_NAME=
# KEEP_PERMISSIONS=true
# Comma-separated list (no spaces) of download services, in priority order (supported: lidarr,slskd,youtube) (default: youtube)
# DOWNLOAD_SERVICES=youtube
# Time budget (minutes) for a single download service before Explo gives up on it
# and lets the next service in DOWNLOAD_SERVICES try the remaining tracks.
# 0 (default) waits indefinitely. Example chain -- prefer full albums from Lidarr,
# fall back to slskd for anything it hasn't delivered in 15 minutes:
# DOWNLOAD_SERVICES=lidarr,slskd
# LIDARR_FALLBACK_AFTER=15
# SLSKD_FALLBACK_AFTER=10
# LIDARR_FALLBACK_AFTER=0
# SLSKD_FALLBACK_AFTER=0
# Path templating, Options are Artist, Album, TrackName, TrackNumber, File, Ext (eg. "{{Artist}}/{{Album}}/{{File}}")
# PATH_TEMPLATE=""

Expand Down Expand Up @@ -85,6 +98,11 @@ LIBRARY_NAME=
# SLSKD_MIGRATE_DOWNLOADS=false
# Overwrite track metadata when moving file (default: false)
# SLSKD_OVERWRITE_METADATA=false
# Download the whole release the matched file belongs to instead of just the
# recommended track. Only the recommended track is added to the playlist; the
# rest simply land in the library. Off by default -- it multiplies transfer
# volume per recommendation. (default: false)
# SLSKD_ALBUM_MODE=false
# Directory where slskd downloads tracks (default: /slskd/)
# PS! This is only needed on the binary version, in docker it's set through volume mapping
# SLSKD_DIR=/slskd/
Expand All @@ -101,6 +119,31 @@ LIBRARY_NAME=
# MIN_BIT_DEPTH=8
# Minimal Bitrate (default: 256)
# MIN_BITRATE=256
# Highest bitrate in kbps to accept, so a single track cannot arrive as a 138 MB
# WAV. Worked out from file size when a peer reports no bitrate, so it applies
# to files that describe themselves and files that do not. 0 disables the
# ceiling. (default: 0)
# MAX_BITRATE=0
# Which end of the accepted range to reach for first. "none" leaves the order of
# EXTENSIONS deciding, as it always has. "smaller" takes the best lossy file and
# falls back to lossless only when there is none -- note it still prefers a 320
# over a 256, since wanting a small file does not mean wanting a bad one.
# "larger" is the reverse. Ranking only; nothing is rejected. (default: none)
# SIZE_PREFERENCE=none
# Which release album mode takes when several match. "smaller" takes the one
# closest to the album's real track count, so a 21-track deluxe edition does
# not arrive in place of the 11-track album -- note this needs
# ENRICH_TRACK_METADATA, since that is where the real track count comes from,
# and falls back to "fuller" without it. "fuller" takes the most complete
# directory, as it always has. (default: smaller)
# RELEASE_PREFERENCE=smaller
# Trim a release down to the original album before downloading it. Extra discs a
# peer has flattened into one directory are dropped (a real double album is kept
# whole when ENRICH_TRACK_METADATA confirms it), and bonus tracks appended past
# the album's real length are dropped after them. The recommended track is always
# kept, even when it is itself a bonus track. Set to false to take releases
# exactly as the peer shares them. (default: true)
# PREFER_ORIGINAL_RELEASE=true
# Comma-separated (without spaces) keywords to avoid, when filtering slskd results (default: live,remix,instrumental,extended,clean,acapella)
# FILTER_LIST=live,remix,instrumental,extended,clean,acapella

Expand Down
Loading