Skip to content

Commit 26fa1f8

Browse files
committed
fix(discord-rpc, scrobbler): Align artist and title with the last.fm's de facto standard
- Display only the main artist. - Display the title in its original language without romanization. - fix #3358 - fix #3641
1 parent 555817e commit 26fa1f8

File tree

10 files changed

+61
-39
lines changed

10 files changed

+61
-39
lines changed

src/i18n/resources/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@
758758
"token": "Enter ListenBrainz user token"
759759
},
760760
"scrobble-alternative-title": "Use alternative titles",
761+
"scrobble-alternative-artist": "Use alternative artists",
761762
"scrobble-other-media": "Scrobble other media"
762763
},
763764
"name": "Scrobbler",

src/plugins/discord/constants.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,3 @@ export enum TimerKey {
2323
UpdateTimeout = 'updateTimeout', // Timer for throttled activity updates
2424
DiscordConnectRetry = 'discordConnectRetry', // Timer for Discord connection retries
2525
}
26-
27-
/**
28-
* An enum for Discord's activity.status_display_type field, governing which field of the activity should be used after
29-
* "Listening to..." in the user's Discord status.
30-
*/
31-
export const DiscordStatusDisplayType = {
32-
YOUTUBE_MUSIC: 0,
33-
ARTIST: 1,
34-
TITLE: 2,
35-
} as const;

src/plugins/discord/discord-service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ export class DiscordService {
9999
const activityInfo: SetActivity = {
100100
type: ActivityType.Listening,
101101
statusDisplayType: config.statusDisplayType,
102-
details: truncateString(songInfo.title, 128), // Song title
102+
details: truncateString(songInfo.alternativeTitle ?? songInfo.title, 128), // Song title
103103
detailsUrl: songInfo.url ?? undefined,
104-
state: truncateString(songInfo.artist, 128), // Artist name
104+
state: truncateString(songInfo.tags?.at(0) ?? songInfo.artist, 128), // Artist name
105105
stateUrl: songInfo.artistUrl,
106106
largeImageKey: songInfo.imageSrc ?? undefined,
107107
largeImageText: songInfo.album

src/plugins/discord/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { StatusDisplayType } from 'discord-api-types/v10';
2+
13
import { createPlugin } from '@/utils';
24
import { backend } from './main';
35
import { onMenu } from './menu';
46
import { t } from '@/i18n';
5-
import { DiscordStatusDisplayType } from './constants';
67

78
export type DiscordPluginConfig = {
89
enabled: boolean;
@@ -37,7 +38,7 @@ export type DiscordPluginConfig = {
3738
/**
3839
* Controls which field is displayed in the Discord status text
3940
*/
40-
statusDisplayType: (typeof DiscordStatusDisplayType)[keyof typeof DiscordStatusDisplayType];
41+
statusDisplayType: (typeof StatusDisplayType)[keyof typeof StatusDisplayType];
4142
};
4243

4344
export default createPlugin({
@@ -52,7 +53,7 @@ export default createPlugin({
5253
playOnYouTubeMusic: true,
5354
hideGitHubButton: false,
5455
hideDurationLeft: false,
55-
statusDisplayType: DiscordStatusDisplayType.ARTIST,
56+
statusDisplayType: StatusDisplayType.Details,
5657
} as DiscordPluginConfig,
5758
menu: onMenu,
5859
backend,

src/plugins/discord/menu.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
import prompt from 'custom-electron-prompt';
22

3-
import { discordService } from './main';
3+
import { StatusDisplayType } from 'discord-api-types/v10';
44

5+
import { discordService } from './main';
56
import { singleton } from '@/providers/decorators';
67
import promptOptions from '@/providers/prompt-options';
78
import { setMenuOptions } from '@/config/plugins';
8-
99
import { t } from '@/i18n';
1010

11-
import { DiscordStatusDisplayType } from './constants';
12-
1311
import type { MenuContext } from '@/types/contexts';
1412
import type { DiscordPluginConfig } from './index';
15-
1613
import type { MenuTemplate } from '@/menu';
1714

1815
const registerRefreshOnce = singleton((refreshMenu: () => void) => {
1916
discordService?.registerRefreshCallback(refreshMenu);
2017
});
2118

22-
const DiscordStatusDisplayTypeLabels = {
23-
[DiscordStatusDisplayType.YOUTUBE_MUSIC]:
19+
const DiscordStatusDisplayTypeLabels: Record<StatusDisplayType, string> = {
20+
[StatusDisplayType.Name]:
2421
'plugins.discord.menu.set-status-display-type.submenu.youtube-music',
25-
[DiscordStatusDisplayType.ARTIST]:
22+
[StatusDisplayType.State]:
2623
'plugins.discord.menu.set-status-display-type.submenu.artist',
27-
[DiscordStatusDisplayType.TITLE]:
24+
[StatusDisplayType.Details]:
2825
'plugins.discord.menu.set-status-display-type.submenu.title',
2926
};
3027

@@ -105,18 +102,24 @@ export const onMenu = async ({
105102
},
106103
{
107104
label: t('plugins.discord.menu.set-status-display-type.label'),
108-
submenu: Object.values(DiscordStatusDisplayType).map(
109-
(statusDisplayType) => ({
110-
label: t(DiscordStatusDisplayTypeLabels[statusDisplayType]),
105+
submenu: Object.values(StatusDisplayType)
106+
.filter(
107+
(v) => typeof StatusDisplayType[v as StatusDisplayType] !== 'number',
108+
)
109+
.map((statusDisplayType) => ({
110+
label: t(
111+
DiscordStatusDisplayTypeLabels[
112+
statusDisplayType as StatusDisplayType
113+
],
114+
),
111115
type: 'radio',
112-
checked: config.statusDisplayType == statusDisplayType,
116+
checked: config.statusDisplayType === statusDisplayType,
113117
click() {
114118
setConfig({
115-
statusDisplayType,
119+
statusDisplayType: statusDisplayType as StatusDisplayType,
116120
});
117121
},
118-
}),
119-
),
122+
})),
120123
},
121124
];
122125
};

src/plugins/scrobbler/index.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ export interface ScrobblerPluginConfig {
1313
*/
1414
scrobbleOtherMedia: boolean;
1515
/**
16-
* Use alternative titles for scrobbling (Useful for non-roman song titles)
16+
* Use alternative titles for scrobbling (Useful for non-roman song titles, e.g. (Not) A Devil -> デビルじゃないもん)
1717
*
18-
* @default false
18+
* @default true
1919
*/
2020
alternativeTitles: boolean;
21+
/**
22+
* Use alternative artist for scrobbling (e.g., DECO27 & (or) PinocchioP -> DECO27 / marasy -> まらしぃ)
23+
*
24+
* @default true
25+
*/
26+
alternativeArtist: boolean;
2127
scrobblers: {
2228
lastfm: {
2329
/**
@@ -77,7 +83,8 @@ export interface ScrobblerPluginConfig {
7783
export const defaultConfig: ScrobblerPluginConfig = {
7884
enabled: false,
7985
scrobbleOtherMedia: true,
80-
alternativeTitles: false,
86+
alternativeTitles: true,
87+
alternativeArtist: true,
8188
scrobblers: {
8289
lastfm: {
8390
enabled: false,

src/plugins/scrobbler/menu.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ export const onMenu = async ({
105105
setConfig(config);
106106
},
107107
},
108+
{
109+
label: t('plugins.scrobbler.menu.scrobble-alternative-artist'),
110+
type: 'checkbox',
111+
checked: Boolean(config.alternativeArtist),
112+
click(item) {
113+
config.alternativeArtist = item.checked;
114+
setConfig(config);
115+
},
116+
},
108117
{
109118
label: 'Last.fm',
110119
submenu: [

src/plugins/scrobbler/services/lastfm.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,15 @@ export class LastFmScrobbler extends ScrobblerBase {
132132
? songInfo.alternativeTitle
133133
: songInfo.title;
134134

135+
const artist =
136+
config.alternativeArtist && songInfo.tags?.at(0) !== undefined
137+
? songInfo.tags?.at(0)
138+
: songInfo.artist;
139+
135140
const postData: LastFmSongData = {
136141
track: title,
137142
duration: songInfo.songDuration,
138-
artist: songInfo.artist,
143+
artist: artist,
139144
...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video
140145
api_key: config.scrobblers.lastfm.apiKey,
141146
sk: config.scrobblers.lastfm.sessionKey,

src/plugins/scrobbler/services/listenbrainz.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,13 @@ function createRequestBody(
8181
? songInfo.alternativeTitle
8282
: songInfo.title;
8383

84+
const artist =
85+
config.alternativeArtist && songInfo.tags?.at(0) !== undefined
86+
? songInfo.tags?.at(0)
87+
: songInfo.artist;
88+
8489
const trackMetadata = {
85-
artist_name: songInfo.artist,
90+
artist_name: artist,
8691
track_name: title,
8792
release_name: songInfo.album ?? undefined,
8893
additional_info: {

vite-plugins/plugin-importer.mts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { fileURLToPath } from 'node:url';
33

44
import { globSync } from 'glob';
55
import { Project } from 'ts-morph';
6-
import { Platform } from '../src/types/plugins'
6+
7+
import { Platform } from '../src/types/plugins';
78

89
const kebabToCamel = (text: string) =>
910
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase());
@@ -75,7 +76,7 @@ export const pluginVirtualModuleGenerator = (
7576
}
7677

7778
writer.blankLine();
78-
if (mode === "main" || mode === "preload") {
79+
if (mode === 'main' || mode === 'preload') {
7980
writer.writeLine("import * as is from 'electron-is';");
8081
writer.writeLine('globalThis.electronIs = is;');
8182
}
@@ -137,7 +138,7 @@ export const pluginVirtualModuleGenerator = (
137138
};
138139

139140
function supportsPlatform({ platform }: { platform: string }) {
140-
if (typeof platform !== "number") return true;
141+
if (typeof platform !== 'number') return true;
141142

142143
const is = globalThis.electronIs;
143144

0 commit comments

Comments
 (0)