mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Remove LocalTracksPosition UI, auto-init cookie date tracking
- Removed LocalTracksPosition from playlist table (uses Spotify order now) - Removed LocalTracksPosition from add playlist modal and JS - Added /api/admin/config/init-cookie-date endpoint to auto-set date - Cookie date auto-initializes when cookie exists but date is unknown - Improved user display message when profile scope unavailable - TOTP tokens work for playlists but don't have user-read-private scope
This commit is contained in:
@@ -76,7 +76,7 @@ public class AdminController : ControllerBase
|
||||
var token = await _spotifyClient.GetWebAccessTokenAsync();
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
// Try to get user info (may fail even with valid token)
|
||||
// Try to get user info (may fail even with valid token due to scope limitations)
|
||||
var (success, userId, displayName) = await _spotifyClient.GetCurrentUserAsync();
|
||||
if (success)
|
||||
{
|
||||
@@ -85,10 +85,10 @@ public class AdminController : ControllerBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// Token is valid but /me endpoint failed - still consider it authenticated
|
||||
// (the token being non-anonymous is the real indicator)
|
||||
// Token is valid but /me endpoint failed - this is normal for TOTP tokens
|
||||
// which don't have user-read-private scope. Playlists still work fine.
|
||||
spotifyAuthStatus = "authenticated";
|
||||
spotifyUser = "(profile not accessible)";
|
||||
spotifyUser = "(working - profile scope not available)";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -498,6 +498,36 @@ public class AdminController : ControllerBase
|
||||
return Ok(new { message = "Cache cleared", filesDeleted = clearedFiles });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize cookie date to current date if cookie exists but date is not set
|
||||
/// </summary>
|
||||
[HttpPost("config/init-cookie-date")]
|
||||
public async Task<IActionResult> InitCookieDate()
|
||||
{
|
||||
// Only init if cookie exists but date is not set
|
||||
if (string.IsNullOrEmpty(_spotifyApiSettings.SessionCookie))
|
||||
{
|
||||
return BadRequest(new { error = "No cookie set" });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_spotifyApiSettings.SessionCookieSetDate))
|
||||
{
|
||||
return Ok(new { message = "Cookie date already set", date = _spotifyApiSettings.SessionCookieSetDate });
|
||||
}
|
||||
|
||||
_logger.LogInformation("Initializing cookie date to current date (cookie existed without date tracking)");
|
||||
|
||||
var updateRequest = new ConfigUpdateRequest
|
||||
{
|
||||
Updates = new Dictionary<string, string>
|
||||
{
|
||||
["SPOTIFY_API_SESSION_COOKIE_SET_DATE"] = DateTime.UtcNow.ToString("o")
|
||||
}
|
||||
};
|
||||
|
||||
return await UpdateConfig(updateRequest);
|
||||
}
|
||||
|
||||
private static string MaskValue(string? value, int showLast = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return "(not set)";
|
||||
|
||||
@@ -532,7 +532,6 @@
|
||||
<th>Name</th>
|
||||
<th>Spotify ID</th>
|
||||
<th>Tracks</th>
|
||||
<th>Position</th>
|
||||
<th>Cache Age</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
@@ -685,13 +684,6 @@
|
||||
<label>Spotify Playlist ID</label>
|
||||
<input type="text" id="new-playlist-id" placeholder="Get from Spotify Import plugin">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Local Tracks Position</label>
|
||||
<select id="new-playlist-position">
|
||||
<option value="first">First (local tracks shown before Spotify tracks)</option>
|
||||
<option value="last">Last (Spotify tracks shown first)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('add-playlist-modal')">Cancel</button>
|
||||
<button class="primary" onclick="addPlaylist()">Add Playlist</button>
|
||||
@@ -774,8 +766,13 @@
|
||||
});
|
||||
|
||||
// Format cookie age with color coding
|
||||
function formatCookieAge(setDateStr) {
|
||||
if (!setDateStr) return { text: 'Unknown age', class: 'warning', detail: 'Set the cookie to start tracking its age' };
|
||||
function formatCookieAge(setDateStr, hasCookie = false) {
|
||||
if (!setDateStr) {
|
||||
if (hasCookie) {
|
||||
return { text: 'Unknown age', class: 'warning', detail: 'Initializing tracking...', needsInit: true };
|
||||
}
|
||||
return { text: 'No cookie', class: '', detail: '' };
|
||||
}
|
||||
|
||||
const setDate = new Date(setDateStr);
|
||||
const now = new Date();
|
||||
@@ -804,6 +801,20 @@
|
||||
return { text, class: status, detail };
|
||||
}
|
||||
|
||||
// Initialize cookie date if cookie exists but date is not set
|
||||
async function initCookieDate() {
|
||||
try {
|
||||
const res = await fetch('/api/admin/config/init-cookie-date', { method: 'POST' });
|
||||
if (res.ok) {
|
||||
// Refresh status after initialization
|
||||
fetchStatus();
|
||||
fetchConfig();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to init cookie date:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// API calls
|
||||
async function fetchStatus() {
|
||||
try {
|
||||
@@ -847,8 +858,14 @@
|
||||
|
||||
// Update cookie age display
|
||||
if (cookieAgeEl) {
|
||||
const age = formatCookieAge(data.spotify.cookieSetDate);
|
||||
const hasCookie = data.spotify.hasCookie;
|
||||
const age = formatCookieAge(data.spotify.cookieSetDate, hasCookie);
|
||||
cookieAgeEl.innerHTML = `<span class="${age.class}">${age.text}</span><br><small style="color:var(--text-secondary)">${age.detail}</small>`;
|
||||
|
||||
// Auto-init cookie date if cookie exists but date is not set
|
||||
if (age.needsInit) {
|
||||
initCookieDate();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch status:', error);
|
||||
@@ -873,7 +890,6 @@
|
||||
<td><strong>${escapeHtml(p.name)}</strong></td>
|
||||
<td style="font-family:monospace;font-size:0.85rem;color:var(--text-secondary);">${p.id || '-'}</td>
|
||||
<td class="track-count">${p.trackCount || 0}</td>
|
||||
<td>${p.localTracksPosition}</td>
|
||||
<td class="cache-age">${p.cacheAge || '-'}</td>
|
||||
<td>
|
||||
<button onclick="viewTracks('${escapeHtml(p.name)}')">View</button>
|
||||
@@ -901,7 +917,8 @@
|
||||
// Cookie age in config tab
|
||||
const configCookieAge = document.getElementById('config-cookie-age');
|
||||
if (configCookieAge) {
|
||||
const age = formatCookieAge(data.spotifyApi.sessionCookieSetDate);
|
||||
const hasCookie = data.spotifyApi.sessionCookie && data.spotifyApi.sessionCookie !== '(not set)';
|
||||
const age = formatCookieAge(data.spotifyApi.sessionCookieSetDate, hasCookie);
|
||||
configCookieAge.innerHTML = `<span class="${age.class}">${age.text}</span> - ${age.detail}`;
|
||||
}
|
||||
|
||||
@@ -963,14 +980,12 @@
|
||||
function openAddPlaylist() {
|
||||
document.getElementById('new-playlist-name').value = '';
|
||||
document.getElementById('new-playlist-id').value = '';
|
||||
document.getElementById('new-playlist-position').value = 'first';
|
||||
openModal('add-playlist-modal');
|
||||
}
|
||||
|
||||
async function addPlaylist() {
|
||||
const name = document.getElementById('new-playlist-name').value.trim();
|
||||
const id = document.getElementById('new-playlist-id').value.trim();
|
||||
const position = document.getElementById('new-playlist-position').value;
|
||||
|
||||
if (!name || !id) {
|
||||
showToast('Name and ID are required', 'error');
|
||||
@@ -981,7 +996,7 @@
|
||||
const res = await fetch('/api/admin/playlists', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, spotifyId: id, localTracksPosition: position })
|
||||
body: JSON.stringify({ name, spotifyId: id })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
Reference in New Issue
Block a user