mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
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.
This commit is contained in:
@@ -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<string[][]>(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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,6 +45,14 @@ public class SpotifyPlaylistConfig
|
||||
/// Where to position local tracks: "first" or "last"
|
||||
/// </summary>
|
||||
public LocalTracksPosition LocalTracksPosition { get; set; } = LocalTracksPosition.First;
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
/// </summary>
|
||||
public string SyncSchedule { get; set; } = "0 8 * * 1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1254,6 +1254,17 @@
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Sync Schedule -->
|
||||
<div class="form-group">
|
||||
<label>Sync Schedule (Cron)</label>
|
||||
<input type="text" id="link-sync-schedule" placeholder="0 8 * * 1" value="0 8 * * 1" style="font-family: monospace;">
|
||||
<small style="color: var(--text-secondary); display: block; margin-top: 4px;">
|
||||
Cron format: <code>minute hour day month dayofweek</code><br>
|
||||
Default: <code>0 8 * * 1</code> = 8 AM every Monday<br>
|
||||
Examples: <code>0 6 * * *</code> = daily at 6 AM, <code>0 20 * * 5</code> = Fridays at 8 PM
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('link-playlist-modal')">Cancel</button>
|
||||
<button class="primary" onclick="linkPlaylist()">Link Playlist</button>
|
||||
@@ -2080,6 +2091,19 @@
|
||||
async function linkPlaylist() {
|
||||
const jellyfinId = document.getElementById('link-jellyfin-id').value;
|
||||
const name = document.getElementById('link-jellyfin-name').value;
|
||||
const syncSchedule = document.getElementById('link-sync-schedule').value.trim();
|
||||
|
||||
// Validate sync schedule (basic cron format check)
|
||||
if (!syncSchedule) {
|
||||
showToast('Sync schedule is required', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const cronParts = syncSchedule.split(/\s+/);
|
||||
if (cronParts.length !== 5) {
|
||||
showToast('Invalid cron format. Expected: minute hour day month dayofweek', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Spotify ID based on current mode
|
||||
let spotifyId = '';
|
||||
@@ -2119,7 +2143,11 @@
|
||||
const res = await fetch(`/api/admin/jellyfin/playlists/${encodeURIComponent(jellyfinId)}/link`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, spotifyPlaylistId: cleanSpotifyId })
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
spotifyPlaylistId: cleanSpotifyId,
|
||||
syncSchedule: syncSchedule
|
||||
})
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
Reference in New Issue
Block a user