add custom last.fm api credential support

This commit is contained in:
Eduard Prigoana 2026-02-09 11:44:38 +00:00
parent 61551c2218
commit 19baee21aa
4 changed files with 218 additions and 2 deletions

View file

@ -2620,6 +2620,65 @@
<span class="slider"></span>
</label>
</div>
<div class="setting-item" id="lastfm-custom-creds-toggle-setting" style="display: none">
<div class="info">
<span class="label">Use Custom API Credentials</span>
<span class="description">Use your own Last.fm API key and secret</span>
</div>
<label class="toggle-switch">
<input type="checkbox" id="lastfm-custom-creds-toggle" />
<span class="slider"></span>
</label>
</div>
<div class="setting-item" id="lastfm-custom-creds-setting" style="display: none">
<div class="info" style="flex: 1; min-width: 0">
<span class="label">Custom API Credentials</span>
<div style="display: flex; flex-direction: column; gap: 8px; margin-top: 8px">
<input
type="text"
id="lastfm-custom-api-key"
placeholder="API Key"
style="
padding: 8px;
border-radius: 4px;
border: 1px solid var(--border);
background: var(--background);
color: var(--foreground);
"
/>
<input
type="password"
id="lastfm-custom-api-secret"
placeholder="API Secret"
style="
padding: 8px;
border-radius: 4px;
border: 1px solid var(--border);
background: var(--background);
color: var(--foreground);
"
/>
<div style="display: flex; gap: 8px; margin-top: 4px">
<button
id="lastfm-save-custom-creds"
class="btn-secondary"
style="padding: 6px 12px; font-size: 0.85rem"
>
Save Credentials
</button>
<button
id="lastfm-clear-custom-creds"
class="btn-secondary danger"
style="padding: 6px 12px; font-size: 0.85rem; display: none"
>
Clear
</button>
</div>
</div>
</div>
</div>
</div>
<div class="settings-group">

View file

@ -3,8 +3,8 @@ import { lastFMStorage } from './storage.js';
export class LastFMScrobbler {
constructor() {
this.API_KEY = '85214f5abbc730e78770f27784b9bdf7';
this.API_SECRET = '2c2c37fd86739191860db810dd063292';
this.DEFAULT_API_KEY = '85214f5abbc730e78770f27784b9bdf7';
this.DEFAULT_API_SECRET = '2c2c37fd86739191860db810dd063292';
this.API_URL = 'https://ws.audioscrobbler.com/2.0/';
this.sessionKey = null;
@ -15,9 +15,24 @@ export class LastFMScrobbler {
this.hasScrobbled = false;
this.isScrobbling = false;
this.loadCredentials();
this.loadSession();
}
loadCredentials() {
if (lastFMStorage.useCustomCredentials()) {
this.API_KEY = lastFMStorage.getCustomApiKey() || this.DEFAULT_API_KEY;
this.API_SECRET = lastFMStorage.getCustomApiSecret() || this.DEFAULT_API_SECRET;
} else {
this.API_KEY = this.DEFAULT_API_KEY;
this.API_SECRET = this.DEFAULT_API_SECRET;
}
}
reloadCredentials() {
this.loadCredentials();
}
loadSession() {
try {
const session = localStorage.getItem('lastfm-session');

View file

@ -122,6 +122,13 @@ export function initializeSettings(scrobbler, player, api, ui) {
const lastfmToggleSetting = document.getElementById('lastfm-toggle-setting');
const lastfmLoveToggle = document.getElementById('lastfm-love-toggle');
const lastfmLoveSetting = document.getElementById('lastfm-love-setting');
const lastfmCustomCredsToggle = document.getElementById('lastfm-custom-creds-toggle');
const lastfmCustomCredsToggleSetting = document.getElementById('lastfm-custom-creds-toggle-setting');
const lastfmCustomCredsSetting = document.getElementById('lastfm-custom-creds-setting');
const lastfmCustomApiKey = document.getElementById('lastfm-custom-api-key');
const lastfmCustomApiSecret = document.getElementById('lastfm-custom-api-secret');
const lastfmSaveCustomCreds = document.getElementById('lastfm-save-custom-creds');
const lastfmClearCustomCreds = document.getElementById('lastfm-clear-custom-creds');
function updateLastFMUI() {
if (scrobbler.lastfm.isAuthenticated()) {
@ -132,12 +139,30 @@ export function initializeSettings(scrobbler, player, api, ui) {
lastfmLoveSetting.style.display = 'flex';
lastfmToggle.checked = lastFMStorage.isEnabled();
lastfmLoveToggle.checked = lastFMStorage.shouldLoveOnLike();
lastfmCustomCredsToggleSetting.style.display = 'flex';
lastfmCustomCredsToggle.checked = lastFMStorage.useCustomCredentials();
updateCustomCredsUI();
} else {
lastfmStatus.textContent = 'Connect your Last.fm account to scrobble tracks';
lastfmConnectBtn.textContent = 'Connect Last.fm';
lastfmConnectBtn.classList.remove('danger');
lastfmToggleSetting.style.display = 'none';
lastfmLoveSetting.style.display = 'none';
lastfmCustomCredsToggleSetting.style.display = 'none';
lastfmCustomCredsSetting.style.display = 'none';
}
}
function updateCustomCredsUI() {
const useCustom = lastFMStorage.useCustomCredentials();
lastfmCustomCredsSetting.style.display = useCustom ? 'flex' : 'none';
if (useCustom) {
lastfmCustomApiKey.value = lastFMStorage.getCustomApiKey();
lastfmCustomApiSecret.value = lastFMStorage.getCustomApiSecret();
const hasCreds = lastFMStorage.getCustomApiKey() && lastFMStorage.getCustomApiSecret();
lastfmClearCustomCreds.style.display = hasCreds ? 'inline-block' : 'none';
}
}
@ -223,6 +248,78 @@ export function initializeSettings(scrobbler, player, api, ui) {
});
}
// Custom Credentials Toggle
if (lastfmCustomCredsToggle) {
lastfmCustomCredsToggle.addEventListener('change', (e) => {
lastFMStorage.setUseCustomCredentials(e.target.checked);
updateCustomCredsUI();
// Reload credentials in the scrobbler
scrobbler.lastfm.reloadCredentials();
// If credentials are being disabled, clear any existing session
if (!e.target.checked && scrobbler.lastfm.isAuthenticated()) {
scrobbler.lastfm.disconnect();
updateLastFMUI();
alert('Switched to default API credentials. Please reconnect to Last.fm.');
}
});
}
// Save Custom Credentials
if (lastfmSaveCustomCreds) {
lastfmSaveCustomCreds.addEventListener('click', () => {
const apiKey = lastfmCustomApiKey.value.trim();
const apiSecret = lastfmCustomApiSecret.value.trim();
if (!apiKey || !apiSecret) {
alert('Please enter both API Key and API Secret');
return;
}
lastFMStorage.setCustomApiKey(apiKey);
lastFMStorage.setCustomApiSecret(apiSecret);
// Reload credentials
scrobbler.lastfm.reloadCredentials();
updateCustomCredsUI();
alert('Custom API credentials saved! Please reconnect to Last.fm to use them.');
// Disconnect current session if authenticated
if (scrobbler.lastfm.isAuthenticated()) {
scrobbler.lastfm.disconnect();
updateLastFMUI();
}
});
}
// Clear Custom Credentials
if (lastfmClearCustomCreds) {
lastfmClearCustomCreds.addEventListener('click', () => {
if (confirm('Clear custom API credentials?')) {
lastFMStorage.clearCustomCredentials();
lastfmCustomApiKey.value = '';
lastfmCustomApiSecret.value = '';
lastfmCustomCredsToggle.checked = false;
// Reload credentials
scrobbler.lastfm.reloadCredentials();
updateCustomCredsUI();
// Disconnect current session if authenticated
if (scrobbler.lastfm.isAuthenticated()) {
scrobbler.lastfm.disconnect();
updateLastFMUI();
alert(
'Custom credentials cleared. Switched to default API credentials. Please reconnect to Last.fm.'
);
}
}
});
}
// ========================================
// Global Scrobble Settings
// ========================================

View file

@ -282,6 +282,9 @@ export const lastFMStorage = {
STORAGE_KEY: 'lastfm-enabled',
LOVE_ON_LIKE_KEY: 'lastfm-love-on-like',
SCROBBLE_PERCENTAGE_KEY: 'lastfm-scrobble-percentage',
CUSTOM_API_KEY: 'lastfm-custom-api-key',
CUSTOM_API_SECRET: 'lastfm-custom-api-secret',
USE_CUSTOM_CREDENTIALS_KEY: 'lastfm-use-custom-credentials',
isEnabled() {
try {
@ -320,6 +323,48 @@ export const lastFMStorage = {
const validPercentage = Math.max(1, Math.min(100, parseInt(percentage, 10) || 75));
localStorage.setItem(this.SCROBBLE_PERCENTAGE_KEY, validPercentage.toString());
},
useCustomCredentials() {
try {
return localStorage.getItem(this.USE_CUSTOM_CREDENTIALS_KEY) === 'true';
} catch {
return false;
}
},
setUseCustomCredentials(enabled) {
localStorage.setItem(this.USE_CUSTOM_CREDENTIALS_KEY, enabled ? 'true' : 'false');
},
getCustomApiKey() {
try {
return localStorage.getItem(this.CUSTOM_API_KEY) || '';
} catch {
return '';
}
},
setCustomApiKey(key) {
localStorage.setItem(this.CUSTOM_API_KEY, key);
},
getCustomApiSecret() {
try {
return localStorage.getItem(this.CUSTOM_API_SECRET) || '';
} catch {
return '';
}
},
setCustomApiSecret(secret) {
localStorage.setItem(this.CUSTOM_API_SECRET, secret);
},
clearCustomCredentials() {
localStorage.removeItem(this.CUSTOM_API_KEY);
localStorage.removeItem(this.CUSTOM_API_SECRET);
localStorage.removeItem(this.USE_CUSTOM_CREDENTIALS_KEY);
},
};
export const nowPlayingSettings = {