feat: Allow scrobbling using alternative song titles (#3093)

This commit is contained in:
Yumeo
2025-03-15 18:42:58 +01:00
committed by GitHub
parent 2d86d26701
commit bcdd24d74b
6 changed files with 38 additions and 5 deletions

View File

@ -671,7 +671,8 @@
"listenbrainz": { "listenbrainz": {
"token": "Enter ListenBrainz user token" "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", "name": "Scrobbler",
"prompt": { "prompt": {

View File

@ -12,6 +12,12 @@ export interface ScrobblerPluginConfig {
* @default true * @default true
*/ */
scrobbleOtherMedia: boolean; scrobbleOtherMedia: boolean;
/**
* Use alternative titles for scrobbling (Useful for non-roman song titles)
*
* @default false
*/
alternativeTitles: boolean;
scrobblers: { scrobblers: {
lastfm: { lastfm: {
/** /**
@ -71,6 +77,7 @@ export interface ScrobblerPluginConfig {
export const defaultConfig: ScrobblerPluginConfig = { export const defaultConfig: ScrobblerPluginConfig = {
enabled: false, enabled: false,
scrobbleOtherMedia: true, scrobbleOtherMedia: true,
alternativeTitles: false,
scrobblers: { scrobblers: {
lastfm: { lastfm: {
enabled: false, enabled: false,

View File

@ -96,6 +96,15 @@ export const onMenu = async ({
setConfig(config); 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', label: 'Last.fm',
submenu: [ submenu: [

View File

@ -127,8 +127,13 @@ export class LastFmScrobbler extends ScrobblerBase {
await this.createSession(config, setConfig); await this.createSession(config, setConfig);
} }
const title =
config.alternativeTitles && songInfo.alternativeTitle !== undefined
? songInfo.alternativeTitle
: songInfo.title;
const postData: LastFmSongData = { const postData: LastFmSongData = {
track: songInfo.title, track: title,
duration: songInfo.songDuration, duration: songInfo.songDuration,
artist: songInfo.artist, artist: songInfo.artist,
...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video ...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video

View File

@ -48,7 +48,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
return; return;
} }
const body = createRequestBody('playing_now', songInfo); const body = createRequestBody('playing_now', songInfo, config);
submitListen(body, config); submitListen(body, config);
} }
@ -64,7 +64,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
return; return;
} }
const body = createRequestBody('single', songInfo); const body = createRequestBody('single', songInfo, config);
body.payload[0].listened_at = Math.trunc(Date.now() / 1000); body.payload[0].listened_at = Math.trunc(Date.now() / 1000);
submitListen(body, config); submitListen(body, config);
@ -74,10 +74,16 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
function createRequestBody( function createRequestBody(
listenType: string, listenType: string,
songInfo: SongInfo, songInfo: SongInfo,
config: ScrobblerPluginConfig,
): ListenbrainzRequestBody { ): ListenbrainzRequestBody {
const title =
config.alternativeTitles && songInfo.alternativeTitle !== undefined
? songInfo.alternativeTitle
: songInfo.title;
const trackMetadata = { const trackMetadata = {
artist_name: songInfo.artist, artist_name: songInfo.artist,
track_name: songInfo.title, track_name: title,
release_name: songInfo.album ?? undefined, release_name: songInfo.album ?? undefined,
additional_info: { additional_info: {
media_player: 'YouTube Music Desktop App', media_player: 'YouTube Music Desktop App',

View File

@ -28,6 +28,7 @@ export enum MediaType {
export interface SongInfo { export interface SongInfo {
title: string; title: string;
alternativeTitle?: string;
artist: string; artist: string;
views: number; views: number;
uploadDate?: string; uploadDate?: string;
@ -68,6 +69,7 @@ const handleData = async (
// Fill songInfo with empty values // Fill songInfo with empty values
const songInfo: SongInfo = { const songInfo: SongInfo = {
title: '', title: '',
alternativeTitle: '',
artist: '', artist: '',
views: 0, views: 0,
uploadDate: '', uploadDate: '',
@ -91,6 +93,9 @@ const handleData = async (
new URL(microformat.urlCanonical).searchParams.get('list') ?? ''; new URL(microformat.urlCanonical).searchParams.get('list') ?? '';
// Used for options.resumeOnStart // Used for options.resumeOnStart
config.set('url', microformat.urlCanonical); config.set('url', microformat.urlCanonical);
songInfo.alternativeTitle = microformat.linkAlternates.find(
(link) => link.title,
)?.title;
} }
const { videoDetails } = data; const { videoDetails } = data;