diff --git a/index.html b/index.html
index d03b941..9fe1391 100644
--- a/index.html
+++ b/index.html
@@ -2620,6 +2620,65 @@
+
+
+
+ Use Custom API Credentials
+ Use your own Last.fm API key and secret
+
+
+
+
+
+
+
Custom API Credentials
+
+
+
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 = {