From 19baee21aa0faa5c9d30927cac05c7033b31c9ca Mon Sep 17 00:00:00 2001 From: Eduard Prigoana Date: Mon, 9 Feb 2026 11:44:38 +0000 Subject: [PATCH] add custom last.fm api credential support --- index.html | 59 ++++++++++++++++++++++++++++++ js/lastfm.js | 19 ++++++++-- js/settings.js | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ js/storage.js | 45 +++++++++++++++++++++++ 4 files changed, 218 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index d03b941..9fe1391 100644 --- a/index.html +++ b/index.html @@ -2620,6 +2620,65 @@ + + + +
diff --git a/js/lastfm.js b/js/lastfm.js index c30e421..378a2d9 100644 --- a/js/lastfm.js +++ b/js/lastfm.js @@ -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'); diff --git a/js/settings.js b/js/settings.js index 7bc93f5..a4ae68c 100644 --- a/js/settings.js +++ b/js/settings.js @@ -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 // ======================================== diff --git a/js/storage.js b/js/storage.js index 88f79bd..03d84e0 100644 --- a/js/storage.js +++ b/js/storage.js @@ -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 = {