From 2b4cd35cf7e198c9e6d88f426534295edb49848f Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Mon, 9 Feb 2026 13:15:04 -0500 Subject: [PATCH] feat: add per-playlist cron sync schedules Each playlist now has its own cron schedule for syncing with Spotify. Default is 0 8 * * 1 (Monday 8 AM). Removed global MatchingIntervalHours in favor of per-playlist scheduling. --- allstarr/Controllers/AdminController.cs | 19 ++++++++---- .../Models/Settings/SpotifyImportSettings.cs | 8 +++++ allstarr/wwwroot/index.html | 30 ++++++++++++++++++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/allstarr/Controllers/AdminController.cs b/allstarr/Controllers/AdminController.cs index ff6f970..6da2235 100644 --- a/allstarr/Controllers/AdminController.cs +++ b/allstarr/Controllers/AdminController.cs @@ -2274,12 +2274,19 @@ public class AdminController : ControllerBase Name = request.Name, Id = request.SpotifyPlaylistId, JellyfinId = jellyfinPlaylistId, - LocalTracksPosition = LocalTracksPosition.First // Use Spotify order + LocalTracksPosition = LocalTracksPosition.First, // Use Spotify order + SyncSchedule = request.SyncSchedule ?? "0 8 * * 1" // Default to Monday 8 AM }); - // Convert to JSON format for env var: [["Name","SpotifyId","JellyfinId","first|last"],...] + // Convert to JSON format for env var: [["Name","SpotifyId","JellyfinId","first|last","cronSchedule"],...] var playlistsJson = JsonSerializer.Serialize( - currentPlaylists.Select(p => new[] { p.Name, p.Id, p.JellyfinId, p.LocalTracksPosition.ToString().ToLower() }).ToArray() + currentPlaylists.Select(p => new[] { + p.Name, + p.Id, + p.JellyfinId, + p.LocalTracksPosition.ToString().ToLower(), + p.SyncSchedule ?? "0 8 * * 1" + }).ToArray() ); // Update .env file @@ -2335,7 +2342,7 @@ public class AdminController : ControllerBase return playlists; } - // Parse JSON array format: [["Name","SpotifyId","JellyfinId","first|last"],...] + // Parse JSON array format: [["Name","SpotifyId","JellyfinId","first|last","cronSchedule"],...] var playlistArrays = JsonSerializer.Deserialize(value); if (playlistArrays != null) { @@ -2351,7 +2358,8 @@ public class AdminController : ControllerBase LocalTracksPosition = arr.Length >= 4 && arr[3].Trim().Equals("last", StringComparison.OrdinalIgnoreCase) ? LocalTracksPosition.Last - : LocalTracksPosition.First + : LocalTracksPosition.First, + SyncSchedule = arr.Length >= 5 ? arr[4].Trim() : "0 8 * * 1" }); } } @@ -3406,6 +3414,7 @@ public class LinkPlaylistRequest { public string Name { get; set; } = string.Empty; public string SpotifyPlaylistId { get; set; } = string.Empty; + public string SyncSchedule { get; set; } = "0 8 * * 1"; // Default: 8 AM every Monday } /// diff --git a/allstarr/Models/Settings/SpotifyImportSettings.cs b/allstarr/Models/Settings/SpotifyImportSettings.cs index aa810c0..48956b9 100644 --- a/allstarr/Models/Settings/SpotifyImportSettings.cs +++ b/allstarr/Models/Settings/SpotifyImportSettings.cs @@ -45,6 +45,14 @@ public class SpotifyPlaylistConfig /// Where to position local tracks: "first" or "last" /// public LocalTracksPosition LocalTracksPosition { get; set; } = LocalTracksPosition.First; + + /// + /// Cron schedule for syncing this playlist with Spotify + /// Format: minute hour day month dayofweek + /// Example: "0 8 * * 1" = 8 AM every Monday + /// Default: "0 8 * * 1" (weekly on Monday at 8 AM) + /// + public string SyncSchedule { get; set; } = "0 8 * * 1"; } /// diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html index f525c5b..1a3ce1e 100644 --- a/allstarr/wwwroot/index.html +++ b/allstarr/wwwroot/index.html @@ -1254,6 +1254,17 @@ + +
+ + + + Cron format: minute hour day month dayofweek
+ Default: 0 8 * * 1 = 8 AM every Monday
+ Examples: 0 6 * * * = daily at 6 AM, 0 20 * * 5 = Fridays at 8 PM +
+
+