Skip to content

Commit 2cca64b

Browse files
committed
Update sample env; reorganize
Add PUID/GID support to Docker container Fixup rebase
1 parent 93cd525 commit 2cca64b

File tree

7 files changed

+92
-42
lines changed

7 files changed

+92
-42
lines changed

Dockerfile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ RUN GOOS=linux GOARCH=$TARGETARCH go build -o explo ./src/main/
1212

1313
FROM python:3.12-alpine
1414

15-
# Install runtime deps: libc compat, ffmpeg, yt-dlp, tzdata
15+
# Install runtime deps: libc compat, ffmpeg, yt-dlp, tzdata, shadow for user management, su-exec for user switching
1616
RUN apk add --no-cache \
1717
libc6-compat \
1818
ffmpeg \
1919
yt-dlp \
20-
tzdata
20+
tzdata \
21+
shadow \
22+
su-exec
2123

2224
# Install ytmusicapi in the container
2325
RUN pip install --no-cache-dir ytmusicapi
@@ -33,7 +35,11 @@ COPY src/downloader/youtube_music/search_ytmusic.py .
3335

3436
RUN chmod +x /start.sh ./explo
3537

36-
# Can be defined from compose as well
38+
# Can be defined from compose as well
3739
ENV WEEKLY_EXPLORATION_SCHEDULE="15 0 * * 2"
3840

41+
# Default PUID and PGID
42+
ENV PUID=1000
43+
ENV PGID=1000
44+
3945
CMD ["/start.sh"]

docker-compose.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ services:
1010
# - $PLAYLIST_DIR:$PLAYLIST_DIR # for MPD. Both paths should be as defined in .env (e.g /my/playlists/:/my/playlists/)
1111
environment:
1212
- TZ=UTC # Change this to the timezone set in ListenBrainz (default is UTC)
13+
- PUID=1000 # User ID for file permissions (optional, defaults to 1000)
14+
- PGID=1000 # Group ID for file permissions (optional, defaults to 1000)
1315

1416
- WEEKLY_EXPLORATION_SCHEDULE=15 00 * * 2 # Runs weekly, every Tuesday 15 minutes past midnight
1517
- WEEKLY_EXPLORATION_FLAGS= # Run weekly exploration with default settings

docker/start.sh

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,45 @@
11
#!/bin/sh
2+
3+
# Handle PUID/PGID
4+
if [ "$PUID" != "0" ] && [ "$PGID" != "0" ]; then
5+
echo "[setup] Setting up user with PUID=$PUID and PGID=$PGID"
6+
7+
# Create group if it doesn't exist
8+
if ! getent group explo > /dev/null 2>&1; then
9+
groupadd -g "$PGID" explo
10+
fi
11+
12+
# Create user if it doesn't exist
13+
if ! getent passwd explo > /dev/null 2>&1; then
14+
useradd -u "$PUID" -g "$PGID" -d /opt/explo -s /bin/sh explo
15+
fi
16+
17+
# Ensure explo user owns the working directory and data directory
18+
chown -R explo:explo /opt/explo
19+
[ -d /data ] && chown -R explo:explo /data
20+
21+
# If running as non-root, exec as the explo user
22+
if [ "$(id -u)" = "0" ]; then
23+
exec su-exec explo "$0" "$@"
24+
fi
25+
fi
26+
227
echo "[setup] Initializing cron jobs..."
328

29+
# Determine which user to run cron jobs as
30+
CRON_USER="root"
31+
if [ "$PUID" != "0" ] && [ "$PGID" != "0" ]; then
32+
CRON_USER="explo"
33+
# Create crontab directory for explo user if it doesn't exist
34+
mkdir -p /var/spool/cron/crontabs
35+
touch "/var/spool/cron/crontabs/$CRON_USER"
36+
chown "$CRON_USER:$CRON_USER" "/var/spool/cron/crontabs/$CRON_USER"
37+
fi
38+
439
if [ -n "$CRON_SCHEDULE" ]; then
5-
echo "$CRON_SCHEDULE apk add --upgrade yt-dlp && cd /opt/explo && ./explo >> /proc/1/fd/1 2>&1" > /etc/crontabs/root
6-
chmod 600 /etc/crontabs/root
40+
cmd="apk add --upgrade yt-dlp && cd /opt/explo && ./explo >> /proc/1/fd/1 2>&1"
41+
echo "$CRON_SCHEDULE $cmd" > "/var/spool/cron/crontabs/$CRON_USER"
42+
chmod 600 "/var/spool/cron/crontabs/$CRON_USER"
743
echo "[setup] Registered single CRON_SCHEDULE job: $CRON_SCHEDULE"
844
crond -f -l 2
945
fi
@@ -23,13 +59,13 @@ for var in $(env | grep "_SCHEDULE=" | cut -d= -f1); do
2359
# Default: just run explo if flags are empty
2460
cmd="apk add --upgrade yt-dlp && cd /opt/explo && ./explo $flags >> /proc/1/fd/1 2>&1"
2561

26-
echo "$schedule $cmd" >> /etc/crontabs/root
62+
echo "$schedule $cmd" >> "/var/spool/cron/crontabs/$CRON_USER"
2763
echo "[setup] Registered job: $job"
2864
echo " Schedule: $schedule"
2965
echo " Command : ./explo $flags"
3066
done
3167

32-
chmod 600 /etc/crontabs/root
68+
chmod 600 "/var/spool/cron/crontabs/$CRON_USER"
3369

3470
echo "[setup] Starting cron..."
3571
crond -f -l 2

go.sum

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,14 @@ golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+o
5757
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5858
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
5959
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
60-
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
61-
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
60+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
61+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
6262
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
6363
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6464
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6565
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6666
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
6767
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
68-
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
6968
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
7069
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
7170
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=

sample.env

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ YOUTUBE_API_KEY=
6969
# Minimal Bitrate (default: 256)
7070
# MIN_BITRATE=256
7171

72+
# === Lidarr Configuration ===
73+
74+
# LIDARR_API_KEY=
75+
# LIDARR_RETRY=
76+
# LIDARR_DL_ATTEMPTS=
77+
# LIDARR_DIR=
78+
# MIGRATE_DOWNLOADS=
79+
# LIDARR_TIMEOUT=
80+
# LIDARR_SCHEME=
81+
# LIDARR_URL=
82+
7283
# === Metadata / Formatting ===
7384

7485
# Set to true to merge featured artists into title (recommended), false appends them to artist field (default: true)

src/config/config.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,6 @@ type Credentials struct {
5454
Salt string
5555
}
5656

57-
type DiscoveryConfig struct {
58-
Discovery string `env:"DISCOVERY_SERVICE" env-default:"listenbrainz"`
59-
Separator string `env:"FILENAME_SEPARATOR" env-default:" "`
60-
Listenbrainz Listenbrainz
61-
}
62-
63-
type Filters struct {
64-
Extensions []string `env:"EXTENSIONS" env-default:"flac,mp3"`
65-
MinBitDepth int `env:"MIN_BIT_DEPTH" env-default:"8"`
66-
MinBitRate int `env:"MIN_BITRATE" env-default:"256"`
67-
FilterList []string `env:"FILTER_LIST" env-default:"live,remix,instrumental,extended"`
68-
}
69-
7057
type Lidarr struct {
7158
APIKey string `env:"LIDARR_API_KEY"`
7259
Retry int `env:"LIDARR_RETRY" env-default:"5"` // Number of times to check search status before skipping the track
@@ -98,6 +85,13 @@ type DownloadConfig struct {
9885
Services []string `env:"DOWNLOAD_SERVICES" env-default:"youtube"`
9986
}
10087

88+
type Filters struct {
89+
Extensions []string `env:"EXTENSIONS" env-default:"flac,mp3"`
90+
MinBitDepth int `env:"MIN_BIT_DEPTH" env-default:"8"`
91+
MinBitRate int `env:"MIN_BITRATE" env-default:"256"`
92+
FilterList []string `env:"FILTER_LIST" env-default:"live,remix,instrumental,extended"`
93+
}
94+
10195
type Youtube struct {
10296
APIKey string `env:"YOUTUBE_API_KEY"`
10397
FfmpegPath string `env:"FFMPEG_PATH"`
@@ -128,17 +122,19 @@ type SlskdMon struct {
128122
Duration time.Duration `env:"SLSKD_MONITOR_DURATION" env-default:"15m"`
129123
}
130124

125+
type DiscoveryConfig struct {
126+
Discovery string `env:"DISCOVERY_SERVICE" env-default:"listenbrainz"`
127+
Listenbrainz Listenbrainz
128+
}
129+
131130
type Listenbrainz struct {
132131
Discovery string `env:"LISTENBRAINZ_DISCOVERY" env-default:"playlist"`
133132
User string `env:"LISTENBRAINZ_USER"`
134133
ImportPlaylist string
135134
SingleArtist bool `env:"SINGLE_ARTIST" env-default:"true"`
136135
}
137136

138-
func (cfg *Config) ReadEnv() {
139-
}
140-
141-
func ReadEnv() Config {
137+
func ReadEnv() {
142138
var cfg Config
143139

144140
// Try to read from .env file first

src/downloader/lidarr.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,21 @@ func (c Lidarr) findBestAlbumMatch(track *models.Track) (*Album, error) {
301301
return &topMatch, nil
302302
}
303303

304+
func (c Lidarr) getDownloadStatus() (DownloadStatus, error) {
305+
reqParams := "/api/v0/transfers/downloads"
306+
307+
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+reqParams, nil, nil)
308+
if err != nil {
309+
return nil, err
310+
}
311+
312+
var status DownloadStatus
313+
if err := util.ParseResp(body, &status); err != nil {
314+
return nil, err
315+
}
316+
return status, nil
317+
}
318+
304319
func (c Lidarr) MonitorDownloads(tracks []*models.Track) error {
305320
monitorCfg := MonitorConfig{
306321
CheckInterval: 1 * time.Minute,
@@ -322,21 +337,6 @@ func (c Lidarr) MonitorDownloads(tracks []*models.Track) error {
322337
return nil
323338
}
324339

325-
func (c Lidarr) getDownloadStatus() (DownloadStatus, error) {
326-
reqParams := "/api/v0/transfers/downloads"
327-
328-
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+reqParams, nil, nil)
329-
if err != nil {
330-
return nil, err
331-
}
332-
333-
var status DownloadStatus
334-
if err := util.ParseResp(body, &status); err != nil {
335-
return nil, err
336-
}
337-
return status, nil
338-
}
339-
340340
func (c Lidarr) cleanupTrack(track *models.Track, fileID string) {
341341
if err := c.deleteSearch(track.ID); err != nil {
342342
debug.Debug(fmt.Sprintf("[slskd] failed to delete search request: %v", err))

0 commit comments

Comments
 (0)