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();
|
var token = await _spotifyClient.GetWebAccessTokenAsync();
|
||||||
if (!string.IsNullOrEmpty(token))
|
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();
|
var (success, userId, displayName) = await _spotifyClient.GetCurrentUserAsync();
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@@ -85,10 +85,10 @@ public class AdminController : ControllerBase
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Token is valid but /me endpoint failed - still consider it authenticated
|
// Token is valid but /me endpoint failed - this is normal for TOTP tokens
|
||||||
// (the token being non-anonymous is the real indicator)
|
// which don't have user-read-private scope. Playlists still work fine.
|
||||||
spotifyAuthStatus = "authenticated";
|
spotifyAuthStatus = "authenticated";
|
||||||
spotifyUser = "(profile not accessible)";
|
spotifyUser = "(working - profile scope not available)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -498,6 +498,36 @@ public class AdminController : ControllerBase
|
|||||||
return Ok(new { message = "Cache cleared", filesDeleted = clearedFiles });
|
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)
|
private static string MaskValue(string? value, int showLast = 0)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value)) return "(not set)";
|
if (string.IsNullOrEmpty(value)) return "(not set)";
|
||||||
|
|||||||
@@ -532,7 +532,6 @@
|
|||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Spotify ID</th>
|
<th>Spotify ID</th>
|
||||||
<th>Tracks</th>
|
<th>Tracks</th>
|
||||||
<th>Position</th>
|
|
||||||
<th>Cache Age</th>
|
<th>Cache Age</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -685,13 +684,6 @@
|
|||||||
<label>Spotify Playlist ID</label>
|
<label>Spotify Playlist ID</label>
|
||||||
<input type="text" id="new-playlist-id" placeholder="Get from Spotify Import plugin">
|
<input type="text" id="new-playlist-id" placeholder="Get from Spotify Import plugin">
|
||||||
</div>
|
</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">
|
<div class="modal-actions">
|
||||||
<button onclick="closeModal('add-playlist-modal')">Cancel</button>
|
<button onclick="closeModal('add-playlist-modal')">Cancel</button>
|
||||||
<button class="primary" onclick="addPlaylist()">Add Playlist</button>
|
<button class="primary" onclick="addPlaylist()">Add Playlist</button>
|
||||||
@@ -774,8 +766,13 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Format cookie age with color coding
|
// Format cookie age with color coding
|
||||||
function formatCookieAge(setDateStr) {
|
function formatCookieAge(setDateStr, hasCookie = false) {
|
||||||
if (!setDateStr) return { text: 'Unknown age', class: 'warning', detail: 'Set the cookie to start tracking its age' };
|
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 setDate = new Date(setDateStr);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@@ -804,6 +801,20 @@
|
|||||||
return { text, class: status, detail };
|
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
|
// API calls
|
||||||
async function fetchStatus() {
|
async function fetchStatus() {
|
||||||
try {
|
try {
|
||||||
@@ -847,8 +858,14 @@
|
|||||||
|
|
||||||
// Update cookie age display
|
// Update cookie age display
|
||||||
if (cookieAgeEl) {
|
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>`;
|
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) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch status:', error);
|
console.error('Failed to fetch status:', error);
|
||||||
@@ -873,7 +890,6 @@
|
|||||||
<td><strong>${escapeHtml(p.name)}</strong></td>
|
<td><strong>${escapeHtml(p.name)}</strong></td>
|
||||||
<td style="font-family:monospace;font-size:0.85rem;color:var(--text-secondary);">${p.id || '-'}</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 class="track-count">${p.trackCount || 0}</td>
|
||||||
<td>${p.localTracksPosition}</td>
|
|
||||||
<td class="cache-age">${p.cacheAge || '-'}</td>
|
<td class="cache-age">${p.cacheAge || '-'}</td>
|
||||||
<td>
|
<td>
|
||||||
<button onclick="viewTracks('${escapeHtml(p.name)}')">View</button>
|
<button onclick="viewTracks('${escapeHtml(p.name)}')">View</button>
|
||||||
@@ -901,7 +917,8 @@
|
|||||||
// Cookie age in config tab
|
// Cookie age in config tab
|
||||||
const configCookieAge = document.getElementById('config-cookie-age');
|
const configCookieAge = document.getElementById('config-cookie-age');
|
||||||
if (configCookieAge) {
|
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}`;
|
configCookieAge.innerHTML = `<span class="${age.class}">${age.text}</span> - ${age.detail}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,14 +980,12 @@
|
|||||||
function openAddPlaylist() {
|
function openAddPlaylist() {
|
||||||
document.getElementById('new-playlist-name').value = '';
|
document.getElementById('new-playlist-name').value = '';
|
||||||
document.getElementById('new-playlist-id').value = '';
|
document.getElementById('new-playlist-id').value = '';
|
||||||
document.getElementById('new-playlist-position').value = 'first';
|
|
||||||
openModal('add-playlist-modal');
|
openModal('add-playlist-modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addPlaylist() {
|
async function addPlaylist() {
|
||||||
const name = document.getElementById('new-playlist-name').value.trim();
|
const name = document.getElementById('new-playlist-name').value.trim();
|
||||||
const id = document.getElementById('new-playlist-id').value.trim();
|
const id = document.getElementById('new-playlist-id').value.trim();
|
||||||
const position = document.getElementById('new-playlist-position').value;
|
|
||||||
|
|
||||||
if (!name || !id) {
|
if (!name || !id) {
|
||||||
showToast('Name and ID are required', 'error');
|
showToast('Name and ID are required', 'error');
|
||||||
@@ -981,7 +996,7 @@
|
|||||||
const res = await fetch('/api/admin/playlists', {
|
const res = await fetch('/api/admin/playlists', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ name, spotifyId: id, localTracksPosition: position })
|
body: JSON.stringify({ name, spotifyId: id })
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|||||||
Reference in New Issue
Block a user