mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Fix web UI config persistence and cookie age tracking
- Add SPOTIFY_API_SESSION_COOKIE_SET_DATE to docker-compose.yml env mapping - Mount .env file in container for web UI to update - Add SessionCookieSetDate loading in Program.cs - Improve .env update logic with better error handling and logging - Auto-initialize cookie date when cookie exists but date not set - Simplify local vs external track detection in Jellyfin playlists - Enhanced Spotify playlist ID parsing (supports ID, URI, and URL formats) - Better UI clarity: renamed tabs to 'Link Playlists' and 'Active Playlists'
This commit is contained in:
@@ -493,8 +493,8 @@
|
||||
|
||||
<div class="tabs">
|
||||
<div class="tab active" data-tab="dashboard">Dashboard</div>
|
||||
<div class="tab" data-tab="jellyfin-playlists">Jellyfin Playlists</div>
|
||||
<div class="tab" data-tab="playlists">Configured Playlists</div>
|
||||
<div class="tab" data-tab="jellyfin-playlists">Link Playlists</div>
|
||||
<div class="tab" data-tab="playlists">Active Playlists</div>
|
||||
<div class="tab" data-tab="config">Configuration</div>
|
||||
</div>
|
||||
|
||||
@@ -554,18 +554,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jellyfin Playlists Tab -->
|
||||
<!-- Link Playlists Tab -->
|
||||
<div class="tab-content" id="tab-jellyfin-playlists">
|
||||
<div class="card">
|
||||
<h2>
|
||||
Jellyfin Playlists
|
||||
Link Jellyfin Playlists to Spotify
|
||||
<div class="actions">
|
||||
<button onclick="fetchJellyfinPlaylists()">Refresh</button>
|
||||
</div>
|
||||
</h2>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 16px;">
|
||||
Link Jellyfin playlists to Spotify playlists to fill in missing tracks.
|
||||
Select a user and/or library to filter playlists.
|
||||
Connect your Jellyfin playlists to Spotify playlists. Allstarr will automatically fill in missing tracks from Spotify using your preferred music service (SquidWTF/Deezer/Qobuz).
|
||||
<br><strong>Tip:</strong> Use the sp_dc cookie method for best results - it's simpler and more reliable.
|
||||
</p>
|
||||
|
||||
<div style="display: flex; gap: 16px; margin-bottom: 16px; flex-wrap: wrap;">
|
||||
@@ -599,16 +599,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playlists Tab -->
|
||||
<!-- Active Playlists Tab -->
|
||||
<div class="tab-content" id="tab-playlists">
|
||||
<div class="card">
|
||||
<h2>
|
||||
Configured Playlists
|
||||
Active Spotify Playlists
|
||||
<div class="actions">
|
||||
<button onclick="refreshPlaylists()">Refresh All</button>
|
||||
<button class="primary" onclick="openAddPlaylist()">Add Playlist</button>
|
||||
</div>
|
||||
</h2>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 12px;">
|
||||
These are the Spotify playlists currently being monitored and filled with tracks from your music service.
|
||||
</p>
|
||||
<table class="playlist-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -812,8 +814,7 @@
|
||||
<div class="modal-content">
|
||||
<h3>Link to Spotify Playlist</h3>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 16px;">
|
||||
Enter the Spotify playlist ID to link with this Jellyfin playlist.
|
||||
Allstarr will fill in missing tracks from Spotify.
|
||||
Enter the Spotify playlist ID or URL. Allstarr will automatically download missing tracks from your configured music service.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label>Jellyfin Playlist</label>
|
||||
@@ -821,9 +822,11 @@
|
||||
<input type="hidden" id="link-jellyfin-id">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Spotify Playlist ID</label>
|
||||
<input type="text" id="link-spotify-id" placeholder="e.g., 37i9dQZF1DX0XUsuxWHRQd">
|
||||
<small style="color: var(--text-secondary);">Get this from Spotify URL or Spotify Import plugin</small>
|
||||
<label>Spotify Playlist ID or URL</label>
|
||||
<input type="text" id="link-spotify-id" placeholder="37i9dQZF1DXcBWIGoYBM5M or spotify:playlist:... or full URL">
|
||||
<small style="color: var(--text-secondary); display: block; margin-top: 4px;">
|
||||
Accepts: <code>37i9dQZF1DXcBWIGoYBM5M</code>, <code>spotify:playlist:37i9dQZF1DXcBWIGoYBM5M</code>, or full Spotify URL
|
||||
</small>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('link-playlist-modal')">Cancel</button>
|
||||
@@ -884,9 +887,9 @@
|
||||
function formatCookieAge(setDateStr, hasCookie = false) {
|
||||
if (!setDateStr) {
|
||||
if (hasCookie) {
|
||||
return { text: 'Unknown age', class: 'warning', detail: 'Initializing tracking...', needsInit: true };
|
||||
return { text: 'Unknown age', class: 'warning', detail: 'Cookie date not tracked', needsInit: true };
|
||||
}
|
||||
return { text: 'No cookie', class: '', detail: '' };
|
||||
return { text: 'No cookie', class: '', detail: '', needsInit: false };
|
||||
}
|
||||
|
||||
const setDate = new Date(setDateStr);
|
||||
@@ -913,7 +916,7 @@
|
||||
else if (remaining > 0) detail = 'Cookie may expire soon!';
|
||||
else detail = 'Cookie may have expired - update if having issues';
|
||||
|
||||
return { text, class: status, detail };
|
||||
return { text, class: status, detail, needsInit: false };
|
||||
}
|
||||
|
||||
// Initialize cookie date if cookie exists but date is not set
|
||||
@@ -921,9 +924,15 @@
|
||||
try {
|
||||
const res = await fetch('/api/admin/config/init-cookie-date', { method: 'POST' });
|
||||
if (res.ok) {
|
||||
console.log('Cookie date initialized successfully');
|
||||
// Refresh status after initialization
|
||||
fetchStatus();
|
||||
fetchConfig();
|
||||
setTimeout(() => {
|
||||
fetchStatus();
|
||||
fetchConfig();
|
||||
}, 500);
|
||||
} else {
|
||||
const data = await res.json();
|
||||
console.log('Cookie date init response:', data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to init cookie date:', error);
|
||||
@@ -974,6 +983,7 @@
|
||||
|
||||
// Auto-init cookie date if cookie exists but date is not set
|
||||
if (age.needsInit) {
|
||||
console.log('Cookie exists but date not set, initializing...');
|
||||
initCookieDate();
|
||||
}
|
||||
}
|
||||
@@ -1145,12 +1155,23 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract ID from URL if pasted
|
||||
// Extract ID from various Spotify formats:
|
||||
// - spotify:playlist:37i9dQZF1DXcBWIGoYBM5M
|
||||
// - https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M
|
||||
// - 37i9dQZF1DXcBWIGoYBM5M
|
||||
let cleanSpotifyId = spotifyId;
|
||||
if (spotifyId.includes('spotify.com/playlist/')) {
|
||||
|
||||
// Handle spotify: URI format
|
||||
if (spotifyId.startsWith('spotify:playlist:')) {
|
||||
cleanSpotifyId = spotifyId.replace('spotify:playlist:', '');
|
||||
}
|
||||
// Handle URL format
|
||||
else if (spotifyId.includes('spotify.com/playlist/')) {
|
||||
const match = spotifyId.match(/playlist\/([a-zA-Z0-9]+)/);
|
||||
if (match) cleanSpotifyId = match[1];
|
||||
}
|
||||
// Remove any query parameters or trailing slashes
|
||||
cleanSpotifyId = cleanSpotifyId.split('?')[0].split('#')[0].replace(/\/$/, '');
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/admin/jellyfin/playlists/${encodeURIComponent(jellyfinId)}/link`, {
|
||||
|
||||
Reference in New Issue
Block a user