From 0185f161a0ada241c941f9e8598754a3d80f2693 Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Mon, 29 Dec 2025 23:14:57 +0100 Subject: [PATCH] new: option to love tracks on last.fm --- index.html | 11 +++++++++++ js/app.js | 2 +- js/events.js | 14 +++++++++----- js/lastfm.js | 16 ++++++++++++++++ js/settings.js | 9 +++++++++ js/storage.js | 13 +++++++++++++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 0d50570..030e327 100644 --- a/index.html +++ b/index.html @@ -339,6 +339,17 @@ + +
diff --git a/js/app.js b/js/app.js index d1b8f59..17452af 100644 --- a/js/app.js +++ b/js/app.js @@ -196,7 +196,7 @@ document.addEventListener('DOMContentLoaded', async () => { initializeSettings(scrobbler, player, api, ui); initializePlayerEvents(player, audioPlayer, scrobbler, ui); - initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'), lyricsManager, ui); + initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'), lyricsManager, ui, scrobbler); initializeUIInteractions(player, api); initializeKeyboardShortcuts(player, audioPlayer, lyricsPanel); diff --git a/js/events.js b/js/events.js index afe457e..3a698d8 100644 --- a/js/events.js +++ b/js/events.js @@ -316,7 +316,7 @@ function initializeSmoothSliders(audioPlayer, player) { }); } -export async function handleTrackAction(action, item, player, api, lyricsManager, type = 'track', ui = null) { +export async function handleTrackAction(action, item, player, api, lyricsManager, type = 'track', ui = null, scrobbler = null) { if (!item) return; if (action === 'add-to-queue') { @@ -357,6 +357,10 @@ export async function handleTrackAction(action, item, player, api, lyricsManager const added = await db.toggleFavorite(type, item); syncManager.syncLibraryItem(type, item, added); + if (added && type === 'track' && scrobbler && lastFMStorage.isEnabled() && lastFMStorage.shouldLoveOnLike()) { + scrobbler.loveTrack(item); + } + // Update all instances of this item's like button on the page const id = type === 'playlist' ? item.uuid : item.id; const selector = type === 'track' @@ -429,7 +433,7 @@ export async function handleTrackAction(action, item, player, api, lyricsManager } } -export function initializeTrackInteractions(player, api, mainContent, contextMenu, lyricsManager, ui) { +export function initializeTrackInteractions(player, api, mainContent, contextMenu, lyricsManager, ui, scrobbler) { let contextTrack = null; mainContent.addEventListener('click', async e => { @@ -462,7 +466,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen } if (item) { - await handleTrackAction(action, item, player, api, lyricsManager, type, ui); + await handleTrackAction(action, item, player, api, lyricsManager, type, ui, scrobbler); } return; } @@ -539,7 +543,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen e.stopPropagation(); const action = e.target.dataset.action; if (action && contextTrack) { - await handleTrackAction(action, contextTrack, player, api, lyricsManager, 'track', ui); + await handleTrackAction(action, contextTrack, player, api, lyricsManager, 'track', ui, scrobbler); } contextMenu.style.display = 'none'; }); @@ -575,7 +579,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen nowPlayingLikeBtn.addEventListener('click', async (e) => { e.stopPropagation(); if (player.currentTrack) { - await handleTrackAction('toggle-like', player.currentTrack, player, api, lyricsManager, 'track', ui); + await handleTrackAction('toggle-like', player.currentTrack, player, api, lyricsManager, 'track', ui, scrobbler); } }); } diff --git a/js/lastfm.js b/js/lastfm.js index 1e1e10b..02e299a 100644 --- a/js/lastfm.js +++ b/js/lastfm.js @@ -232,6 +232,22 @@ export class LastFMScrobbler { } } + async loveTrack(track) { + if (!this.isAuthenticated()) return; + + try { + const params = { + artist: track.artist?.name || 'Unknown Artist', + track: track.title + }; + + await this.makeRequest('track.love', params, true); + console.log('Loved track on Last.fm:', track.title); + } catch (error) { + console.error('Failed to love track on Last.fm:', error); + } + } + onTrackChange(track) { if (!this.isAuthenticated()) return; this.updateNowPlaying(track); diff --git a/js/settings.js b/js/settings.js index 9074a97..656a184 100644 --- a/js/settings.js +++ b/js/settings.js @@ -14,6 +14,8 @@ export function initializeSettings(scrobbler, player, api, ui) { const lastfmStatus = document.getElementById('lastfm-status'); const lastfmToggle = document.getElementById('lastfm-toggle'); const lastfmToggleSetting = document.getElementById('lastfm-toggle-setting'); + const lastfmLoveToggle = document.getElementById('lastfm-love-toggle'); + const lastfmLoveSetting = document.getElementById('lastfm-love-setting'); function updateLastFMUI() { if (scrobbler.isAuthenticated()) { @@ -21,12 +23,15 @@ export function initializeSettings(scrobbler, player, api, ui) { lastfmConnectBtn.textContent = 'Disconnect'; lastfmConnectBtn.classList.add('danger'); lastfmToggleSetting.style.display = 'flex'; + lastfmLoveSetting.style.display = 'flex'; lastfmToggle.checked = lastFMStorage.isEnabled(); + lastfmLoveToggle.checked = lastFMStorage.shouldLoveOnLike(); } 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'; } } @@ -104,6 +109,10 @@ export function initializeSettings(scrobbler, player, api, ui) { lastFMStorage.setEnabled(e.target.checked); }); + lastfmLoveToggle?.addEventListener('change', (e) => { + lastFMStorage.setLoveOnLike(e.target.checked); + }); + // Theme picker const themePicker = document.getElementById('theme-picker'); const currentTheme = themeManager.getTheme(); diff --git a/js/storage.js b/js/storage.js index 975feda..c90ca93 100644 --- a/js/storage.js +++ b/js/storage.js @@ -293,6 +293,7 @@ export const themeManager = { export const lastFMStorage = { STORAGE_KEY: 'lastfm-enabled', + LOVE_ON_LIKE_KEY: 'lastfm-love-on-like', isEnabled() { try { @@ -304,6 +305,18 @@ export const lastFMStorage = { setEnabled(enabled) { localStorage.setItem(this.STORAGE_KEY, enabled ? 'true' : 'false'); + }, + + shouldLoveOnLike() { + try { + return localStorage.getItem(this.LOVE_ON_LIKE_KEY) === 'true'; + } catch (e) { + return false; + } + }, + + setLoveOnLike(enabled) { + localStorage.setItem(this.LOVE_ON_LIKE_KEY, enabled ? 'true' : 'false'); } };