Refactor MBID lookup and add loving functionality

This commit is contained in:
.vlad 2026-03-27 17:26:35 +03:00 committed by GitHub
parent c0589f6d3f
commit 27c2a7b092
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,6 +8,7 @@ export class ListenBrainzScrobbler {
this.scrobbleThreshold = 0; this.scrobbleThreshold = 0;
this.hasScrobbled = false; this.hasScrobbled = false;
this.isScrobbling = false; this.isScrobbling = false;
this.isLoving = false;
} }
getApiUrl() { getApiUrl() {
@ -69,33 +70,38 @@ export class ListenBrainzScrobbler {
payload.additional_info.is_local = true; payload.additional_info.is_local = true;
} }
if (track.mbids) {
if (track.mbids.recording_mbid) {
payload.additional_info.recording_mbid = track.mbids.recording_mbid;
}
if (track.mbids.release_mbid) {
payload.additional_info.release_mbid = track.mbids.release_mbid;
}
if (track.mbids.artist_mbids) {
payload.additional_info.artist_mbids = track.mbids.artist_mbids;
}
}
return payload; return payload;
} }
async _lookupRecordingMbid(track) { async _lookupMbids(track) {
let artistName = 'Unknown Artist'; if (track.mbids) return track.mbids;
if (track.artist?.name) { let with_album = true;
artistName = track.artist.name; const metadata = this._getMetadata(track);
} else if (typeof track.artist === 'string') { if (!metadata || !metadata.artist_name || !metadata.track_name) return null;
artistName = track.artist;
} else if (track.artists && track.artists.length > 0) {
const first = track.artists[0];
artistName = typeof first === 'string' ? first : first.name || 'Unknown Artist';
}
artistName = artistName
.split(/\s*[&]\s*|\s+feat\.?\s*|\s+ft\.?\s*|\s+featuring\s+|\s+with\s+|\s+x\s+/i)[0]
.trim();
const trackName = track.cleanTitle || track.title;
if (!artistName || !trackName) return null;
try { try {
const apiUrl = this.getApiUrl(); const apiUrl = this.getApiUrl();
const params = new URLSearchParams({ const params = new URLSearchParams({
recording_name: trackName, recording_name: metadata.track_name,
artist_name: artistName, artist_name: metadata.artist_name,
}); });
if (track.album?.title) {
params.append('release_name', track.album.title);
}
const response = await fetch(`${apiUrl}/1/metadata/lookup/?${params}`, { const response = await fetch(`${apiUrl}/1/metadata/lookup/?${params}`, {
method: 'GET', method: 'GET',
headers: { headers: {
@ -104,14 +110,35 @@ export class ListenBrainzScrobbler {
}); });
if (!response.ok) { if (!response.ok) {
console.warn(`[ListenBrainz] MBID lookup failed: ${response.status}`); console.warn(`[ListenBrainz] MBID lookup failed, trying without album`);
return null; with_album = false;
const params = new URLSearchParams({
recording_name: metadata.track_name,
artist_name: metadata.artist_name,
});
const response = await fetch(`${apiUrl}/1/metadata/lookup/?${params}`, {
method: 'GET',
headers: {
Authorization: `Token ${this.getToken()}`,
},
});
if (!response.ok) {
console.warn(`[ListenBrainz] MBID lookup failed: ${response.status}`);
return null;
}
} }
const data = await response.json(); const data = await response.json();
if (data?.recording_mbid) { if (data?.recording_mbid) {
track.mbids = {
recording_mbid: data.recording_mbid,
artist_mbids: data.artist_mbids,
};
if (with_album) {
track.mbids.release_mbid = data.release_mbid;
}
console.log(`[ListenBrainz] Found MBID: ${data.recording_mbid}`); console.log(`[ListenBrainz] Found MBID: ${data.recording_mbid}`);
return data.recording_mbid; return track.mbids;
} }
console.warn('[ListenBrainz] No recording_mbid found in lookup response'); console.warn('[ListenBrainz] No recording_mbid found in lookup response');
} catch (error) { } catch (error) {
@ -122,7 +149,7 @@ export class ListenBrainzScrobbler {
async submitListen(listenType, track, timestamp = null) { async submitListen(listenType, track, timestamp = null) {
if (!this.isEnabled()) return; if (!this.isEnabled()) return;
await this._lookupMbids(track);
const metadata = this._getMetadata(track); const metadata = this._getMetadata(track);
if (!metadata) return; if (!metadata) return;
@ -157,7 +184,9 @@ export class ListenBrainzScrobbler {
throw new Error(`ListenBrainz API Error ${response.status}: ${text}`); throw new Error(`ListenBrainz API Error ${response.status}: ${text}`);
} }
console.log(`[ListenBrainz] Submitted ${listenType}: ${metadata.track_name}`); console.log(
`[ListenBrainz] Submitted ${listenType}: ${metadata.track_name} ${metadata.artist_name} ${metadata.release_name}`
);
} catch (error) { } catch (error) {
console.error('[ListenBrainz] Submission failed:', error); console.error('[ListenBrainz] Submission failed:', error);
} }
@ -171,7 +200,6 @@ export class ListenBrainzScrobbler {
this.hasScrobbled = false; this.hasScrobbled = false;
} }
this.clearScrobbleTimer(); this.clearScrobbleTimer();
await this.submitListen('playing_now', track); await this.submitListen('playing_now', track);
const scrobblePercentage = lastFMStorage.getScrobblePercentage() / 100; const scrobblePercentage = lastFMStorage.getScrobblePercentage() / 100;
@ -221,11 +249,13 @@ export class ListenBrainzScrobbler {
} }
async loveTrack(track) { async loveTrack(track) {
if (!this.isEnabled()) return; if (!this.isEnabled() || this.isLoving) return;
this.isLoving = true;
try { try {
const apiUrl = this.getApiUrl(); const apiUrl = this.getApiUrl();
const mbid = await this._lookupRecordingMbid(track); const mbids = await this._lookupMbids(track);
const mbid = mbids?.recording_mbid;
if (mbid) { if (mbid) {
const response = await fetch(`${apiUrl}/1/feedback/recording-feedback`, { const response = await fetch(`${apiUrl}/1/feedback/recording-feedback`, {
@ -251,6 +281,8 @@ export class ListenBrainzScrobbler {
} }
} catch (error) { } catch (error) {
console.error('[ListenBrainz] Failed to love track:', error); console.error('[ListenBrainz] Failed to love track:', error);
} finally {
this.isLoving = false;
} }
} }
} }