From bcdd24d74be2a3b1758598eef01bdf3f45e5d990 Mon Sep 17 00:00:00 2001 From: Yumeo <60485613+Yumeo0@users.noreply.github.com> Date: Sat, 15 Mar 2025 18:42:58 +0100 Subject: [PATCH] feat: Allow scrobbling using alternative song titles (#3093) --- src/i18n/resources/en.json | 3 ++- src/plugins/scrobbler/index.ts | 7 +++++++ src/plugins/scrobbler/menu.ts | 9 +++++++++ src/plugins/scrobbler/services/lastfm.ts | 7 ++++++- src/plugins/scrobbler/services/listenbrainz.ts | 12 +++++++++--- src/providers/song-info.ts | 5 +++++ 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/i18n/resources/en.json b/src/i18n/resources/en.json index 29ca0629..2b15931f 100644 --- a/src/i18n/resources/en.json +++ b/src/i18n/resources/en.json @@ -671,7 +671,8 @@ "listenbrainz": { "token": "Enter ListenBrainz user token" }, - "scrobble-other-media": "Scrobble other media" + "scrobble-other-media": "Scrobble other media", + "scrobble-alternative-title": "Use alternative titles" }, "name": "Scrobbler", "prompt": { diff --git a/src/plugins/scrobbler/index.ts b/src/plugins/scrobbler/index.ts index 678bbd05..ceed9d77 100644 --- a/src/plugins/scrobbler/index.ts +++ b/src/plugins/scrobbler/index.ts @@ -12,6 +12,12 @@ export interface ScrobblerPluginConfig { * @default true */ scrobbleOtherMedia: boolean; + /** + * Use alternative titles for scrobbling (Useful for non-roman song titles) + * + * @default false + */ + alternativeTitles: boolean; scrobblers: { lastfm: { /** @@ -71,6 +77,7 @@ export interface ScrobblerPluginConfig { export const defaultConfig: ScrobblerPluginConfig = { enabled: false, scrobbleOtherMedia: true, + alternativeTitles: false, scrobblers: { lastfm: { enabled: false, diff --git a/src/plugins/scrobbler/menu.ts b/src/plugins/scrobbler/menu.ts index 84c94d70..08a5702d 100644 --- a/src/plugins/scrobbler/menu.ts +++ b/src/plugins/scrobbler/menu.ts @@ -96,6 +96,15 @@ export const onMenu = async ({ setConfig(config); }, }, + { + label: t('plugins.scrobbler.menu.scrobble-alternative-title'), + type: 'checkbox', + checked: Boolean(config.alternativeTitles), + click(item) { + config.alternativeTitles = item.checked; + setConfig(config); + }, + }, { label: 'Last.fm', submenu: [ diff --git a/src/plugins/scrobbler/services/lastfm.ts b/src/plugins/scrobbler/services/lastfm.ts index 525eb0b5..3a6e59b3 100644 --- a/src/plugins/scrobbler/services/lastfm.ts +++ b/src/plugins/scrobbler/services/lastfm.ts @@ -127,8 +127,13 @@ export class LastFmScrobbler extends ScrobblerBase { await this.createSession(config, setConfig); } + const title = + config.alternativeTitles && songInfo.alternativeTitle !== undefined + ? songInfo.alternativeTitle + : songInfo.title; + const postData: LastFmSongData = { - track: songInfo.title, + track: title, duration: songInfo.songDuration, artist: songInfo.artist, ...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video diff --git a/src/plugins/scrobbler/services/listenbrainz.ts b/src/plugins/scrobbler/services/listenbrainz.ts index 405c2e26..56fc4131 100644 --- a/src/plugins/scrobbler/services/listenbrainz.ts +++ b/src/plugins/scrobbler/services/listenbrainz.ts @@ -48,7 +48,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase { return; } - const body = createRequestBody('playing_now', songInfo); + const body = createRequestBody('playing_now', songInfo, config); submitListen(body, config); } @@ -64,7 +64,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase { return; } - const body = createRequestBody('single', songInfo); + const body = createRequestBody('single', songInfo, config); body.payload[0].listened_at = Math.trunc(Date.now() / 1000); submitListen(body, config); @@ -74,10 +74,16 @@ export class ListenbrainzScrobbler extends ScrobblerBase { function createRequestBody( listenType: string, songInfo: SongInfo, + config: ScrobblerPluginConfig, ): ListenbrainzRequestBody { + const title = + config.alternativeTitles && songInfo.alternativeTitle !== undefined + ? songInfo.alternativeTitle + : songInfo.title; + const trackMetadata = { artist_name: songInfo.artist, - track_name: songInfo.title, + track_name: title, release_name: songInfo.album ?? undefined, additional_info: { media_player: 'YouTube Music Desktop App', diff --git a/src/providers/song-info.ts b/src/providers/song-info.ts index 24b10e64..ee8b084f 100644 --- a/src/providers/song-info.ts +++ b/src/providers/song-info.ts @@ -28,6 +28,7 @@ export enum MediaType { export interface SongInfo { title: string; + alternativeTitle?: string; artist: string; views: number; uploadDate?: string; @@ -68,6 +69,7 @@ const handleData = async ( // Fill songInfo with empty values const songInfo: SongInfo = { title: '', + alternativeTitle: '', artist: '', views: 0, uploadDate: '', @@ -91,6 +93,9 @@ const handleData = async ( new URL(microformat.urlCanonical).searchParams.get('list') ?? ''; // Used for options.resumeOnStart config.set('url', microformat.urlCanonical); + songInfo.alternativeTitle = microformat.linkAlternates.find( + (link) => link.title, + )?.title; } const { videoDetails } = data;