Commit e406085c2350

Vincent Demeester <vincent@sbr.pm>
2026-01-12 15:54:14
fix(music-playlist-dl): add playlists directory and cache path to writable paths
The service was failing with read-only filesystem errors when trying to write playlist files and yt-dlp cache. Fixed by: - Adding playlistsDir to ReadWritePaths (calculated as parent_dir/playlists) - Setting XDG_CACHE_HOME environment variable for yt-dlp cache Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent fad2a9f
Changed files (1)
modules
music-playlist-dl
modules/music-playlist-dl/default.nix
@@ -85,113 +85,125 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
-    # Install the music-playlist-dl tool
-    environment.systemPackages = with pkgs; [
-      music-playlist-dl
-      yt-dlp
-    ];
+  config =
+    let
+      # The script writes playlists to parent_dir(baseDir)/playlists
+      # e.g., if baseDir is /neo/music/mixes, playlists go to /neo/music/playlists
+      playlistsDir = "${dirOf cfg.baseDir}/playlists";
+    in
+    mkIf cfg.enable {
+      # Install the music-playlist-dl tool
+      environment.systemPackages = with pkgs; [
+        music-playlist-dl
+        yt-dlp
+      ];
 
-    # Systemd timer for scheduled downloads
-    systemd.timers.music-playlist-dl = {
-      wantedBy = [ "timers.target" ];
-      timerConfig = {
-        OnCalendar = scheduleToCalendar cfg.schedule;
-        Persistent = true;
-        RandomizedDelaySec = "15m";
+      # Systemd timer for scheduled downloads
+      systemd.timers.music-playlist-dl = {
+        wantedBy = [ "timers.target" ];
+        timerConfig = {
+          OnCalendar = scheduleToCalendar cfg.schedule;
+          Persistent = true;
+          RandomizedDelaySec = "15m";
+        };
       };
-    };
 
-    # Systemd service to run the downloader
-    systemd.services.music-playlist-dl = {
-      description = "Download music podcasts and generate playlists";
-      after = [ "network-online.target" ];
-      wants = [ "network-online.target" ];
+      # Systemd service to run the downloader
+      systemd.services.music-playlist-dl = {
+        description = "Download music podcasts and generate playlists";
+        after = [ "network-online.target" ];
+        wants = [ "network-online.target" ];
 
-      serviceConfig = {
-        Type = "oneshot";
-        User = cfg.user;
-        Group = cfg.group;
+        serviceConfig = {
+          Type = "oneshot";
+          User = cfg.user;
+          Group = cfg.group;
 
-        # Run the downloader command
-        ExecStart = "${pkgs.music-playlist-dl}/bin/music-playlist-dl --config ${cfg.configFile}";
+          # Run the downloader command
+          ExecStart = "${pkgs.music-playlist-dl}/bin/music-playlist-dl --config ${cfg.configFile}";
 
-        # Notifications on success (if enabled)
-        ExecStartPost = mkIf cfg.notification.enable (
-          pkgs.writeShellScript "music-playlist-dl-notify-success" ''
+          # Set cache directory to private temp (yt-dlp needs cache)
+          Environment = [ "XDG_CACHE_HOME=/tmp/cache" ];
+
+          # Notifications on success (if enabled)
+          ExecStartPost = mkIf cfg.notification.enable (
+            pkgs.writeShellScript "music-playlist-dl-notify-success" ''
+              ${
+                if cfg.notification.tokenFile != null then
+                  ''
+                    ${pkgs.curl}/bin/curl \
+                      -H "Authorization: Bearer $(${pkgs.coreutils}/bin/tr -d '\n' < ${cfg.notification.tokenFile})" \
+                      -H "Title: Music Playlist Download Complete" \
+                      -H "Tags: musical_note,headphones" \
+                      -d "Successfully downloaded music podcasts and updated playlists" \
+                      ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
+                  ''
+                else
+                  ''
+                    ${pkgs.curl}/bin/curl \
+                      -H "Title: Music Playlist Download Complete" \
+                      -H "Tags: musical_note,headphones" \
+                      -d "Successfully downloaded music podcasts and updated playlists" \
+                      ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
+                  ''
+              }
+            ''
+          );
+
+          # Ensure base directory exists (playlists dir created by script)
+          ExecStartPre = pkgs.writeShellScript "music-playlist-dl-prepare" ''
+            mkdir -p "${cfg.baseDir}"
+          '';
+
+          # Resource limits
+          Nice = 15;
+          IOSchedulingClass = "idle";
+          CPUSchedulingPolicy = "idle";
+
+          # Security hardening
+          PrivateTmp = true;
+          NoNewPrivileges = true;
+          ProtectSystem = "strict";
+          ProtectHome = "read-only";
+          ReadWritePaths = [
+            cfg.baseDir
+            playlistsDir
+          ];
+        };
+
+        # Notify on failure (if enabled)
+        onFailure = mkIf cfg.notification.enable [ "music-playlist-dl-failure.service" ];
+      };
+
+      # Failure notification service
+      systemd.services.music-playlist-dl-failure = mkIf cfg.notification.enable {
+        description = "Notify on music playlist download failure";
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = pkgs.writeShellScript "music-playlist-dl-notify-failure" ''
             ${
               if cfg.notification.tokenFile != null then
                 ''
                   ${pkgs.curl}/bin/curl \
                     -H "Authorization: Bearer $(${pkgs.coreutils}/bin/tr -d '\n' < ${cfg.notification.tokenFile})" \
-                    -H "Title: Music Playlist Download Complete" \
-                    -H "Tags: musical_note,headphones" \
-                    -d "Successfully downloaded music podcasts and updated playlists" \
+                    -H "Title: Music Playlist Download Failed" \
+                    -H "Priority: high" \
+                    -H "Tags: warning,musical_note" \
+                    -d "Music playlist download failed. Check logs: journalctl -u music-playlist-dl" \
                     ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
                 ''
               else
                 ''
                   ${pkgs.curl}/bin/curl \
-                    -H "Title: Music Playlist Download Complete" \
-                    -H "Tags: musical_note,headphones" \
-                    -d "Successfully downloaded music podcasts and updated playlists" \
+                    -H "Title: Music Playlist Download Failed" \
+                    -H "Priority: high" \
+                    -H "Tags: warning,musical_note" \
+                    -d "Music playlist download failed. Check logs: journalctl -u music-playlist-dl" \
                     ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
                 ''
             }
-          ''
-        );
-
-        # Ensure base directory exists (playlists dir created by script)
-        ExecStartPre = pkgs.writeShellScript "music-playlist-dl-prepare" ''
-          mkdir -p "${cfg.baseDir}"
-        '';
-
-        # Resource limits
-        Nice = 15;
-        IOSchedulingClass = "idle";
-        CPUSchedulingPolicy = "idle";
-
-        # Security hardening
-        PrivateTmp = true;
-        NoNewPrivileges = true;
-        ProtectSystem = "strict";
-        ProtectHome = "read-only";
-        ReadWritePaths = [ cfg.baseDir ];
-      };
-
-      # Notify on failure (if enabled)
-      onFailure = mkIf cfg.notification.enable [ "music-playlist-dl-failure.service" ];
-    };
-
-    # Failure notification service
-    systemd.services.music-playlist-dl-failure = mkIf cfg.notification.enable {
-      description = "Notify on music playlist download failure";
-      serviceConfig = {
-        Type = "oneshot";
-        ExecStart = pkgs.writeShellScript "music-playlist-dl-notify-failure" ''
-          ${
-            if cfg.notification.tokenFile != null then
-              ''
-                ${pkgs.curl}/bin/curl \
-                  -H "Authorization: Bearer $(${pkgs.coreutils}/bin/tr -d '\n' < ${cfg.notification.tokenFile})" \
-                  -H "Title: Music Playlist Download Failed" \
-                  -H "Priority: high" \
-                  -H "Tags: warning,musical_note" \
-                  -d "Music playlist download failed. Check logs: journalctl -u music-playlist-dl" \
-                  ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
-              ''
-            else
-              ''
-                ${pkgs.curl}/bin/curl \
-                  -H "Title: Music Playlist Download Failed" \
-                  -H "Priority: high" \
-                  -H "Tags: warning,musical_note" \
-                  -d "Music playlist download failed. Check logs: journalctl -u music-playlist-dl" \
-                  ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
-              ''
-          }
-        '';
+          '';
+        };
       };
     };
-  };
 }