-
Notifications
You must be signed in to change notification settings - Fork 1.7k
add: show YTM user pfp / name in Discord RPC #4103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -48,6 +48,11 @@ export class DiscordService { | |||||||||||
|
|
||||||||||||
| mainWindow: Electron.BrowserWindow; | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Stores the logged-in YouTube Music user information. | ||||||||||||
| */ | ||||||||||||
| private youtubeUser: { name: string; avatar: string } | null = null; | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Initializes the Discord service with configuration and main window reference. | ||||||||||||
| * Sets up RPC event listeners. | ||||||||||||
|
|
@@ -71,6 +76,10 @@ export class DiscordService { | |||||||||||
|
|
||||||||||||
| this.rpc.on('ready', () => { | ||||||||||||
| this.ready = true; | ||||||||||||
| // Fetch YouTube Music user info after connecting if enabled | ||||||||||||
| if (this.config?.showYouTubeUser) { | ||||||||||||
| this.fetchYouTubeUserInfo(); | ||||||||||||
| } | ||||||||||||
| if (this.lastSongInfo && this.config) { | ||||||||||||
| this.updateActivity(this.lastSongInfo); | ||||||||||||
| } | ||||||||||||
|
|
@@ -107,6 +116,8 @@ export class DiscordService { | |||||||||||
| largeImageText: songInfo.album | ||||||||||||
| ? truncateString(songInfo.album, 128) | ||||||||||||
| : undefined, | ||||||||||||
| smallImageKey: config.showYouTubeUser ? this.getYouTubeUserAvatar() : undefined, | ||||||||||||
| smallImageText: config.showYouTubeUser ? this.getYouTubeUserName() : undefined, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Suggested change
|
||||||||||||
| buttons: buildDiscordButtons(config, songInfo), | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
|
|
@@ -280,6 +291,11 @@ export class DiscordService { | |||||||||||
| // Cache the latest song info | ||||||||||||
| this.timerManager.clear(TimerKey.ClearActivity); | ||||||||||||
|
|
||||||||||||
| // Fetch YouTube user info if not already available and feature is enabled | ||||||||||||
| if (!this.youtubeUser && this.config?.showYouTubeUser) { | ||||||||||||
| this.fetchYouTubeUserInfo(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if (!this.rpc || !this.ready) { | ||||||||||||
| // skip update if not ready | ||||||||||||
| return; | ||||||||||||
|
|
@@ -400,6 +416,101 @@ export class DiscordService { | |||||||||||
| return this.rpc.isConnected && this.ready; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
|
Comment on lines
+419
to
+420
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Suggested change
|
||||||||||||
| * Fetches the YouTube Music user avatar and name from the page. | ||||||||||||
| * This method opens the settings menu to access the username. | ||||||||||||
| */ | ||||||||||||
| private async fetchYouTubeUserInfo(): Promise<void> { | ||||||||||||
| try { | ||||||||||||
| const result = await this.mainWindow.webContents.executeJavaScript(` | ||||||||||||
| (async function() { | ||||||||||||
| try { | ||||||||||||
| // Find avatar first - this is always visible | ||||||||||||
| const accountButton = document.querySelector('ytmusic-settings-button img#img') | ||||||||||||
| || document.querySelector('ytmusic-settings-button yt-img-shadow img') | ||||||||||||
| || document.querySelector('ytmusic-settings-button img'); | ||||||||||||
|
|
||||||||||||
| let avatar = null; | ||||||||||||
| if (accountButton) { | ||||||||||||
| avatar = accountButton.src || accountButton.getAttribute('src'); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Now get the username by clicking the settings button | ||||||||||||
| const settingsButton = document.querySelector('ytmusic-settings-button button') | ||||||||||||
| || document.querySelector('ytmusic-settings-button tp-yt-paper-icon-button'); | ||||||||||||
|
|
||||||||||||
| let name = 'Pear Desktop User'; | ||||||||||||
|
|
||||||||||||
| if (settingsButton) { | ||||||||||||
| // Click to open the menu | ||||||||||||
| settingsButton.click(); | ||||||||||||
|
|
||||||||||||
| // Wait for the menu to appear (check multiple times) | ||||||||||||
| for (let i = 0; i < 20; i++) { | ||||||||||||
| await new Promise(resolve => setTimeout(resolve, 50)); | ||||||||||||
|
|
||||||||||||
| const accountNameElement = document.querySelector('ytd-active-account-header-renderer #account-name') | ||||||||||||
| || document.querySelector('yt-formatted-string#account-name'); | ||||||||||||
|
|
||||||||||||
| if (accountNameElement) { | ||||||||||||
| name = accountNameElement.textContent?.trim() | ||||||||||||
| || accountNameElement.getAttribute('title') | ||||||||||||
| || name; | ||||||||||||
| break; | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Close the menu by pressing Escape | ||||||||||||
| document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', keyCode: 27 })); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if (avatar) { | ||||||||||||
| return { avatar, name }; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return null; | ||||||||||||
| } catch (e) { | ||||||||||||
| console.error('Failed to fetch YouTube user info:', e); | ||||||||||||
| return null; | ||||||||||||
| } | ||||||||||||
| })(); | ||||||||||||
| `); | ||||||||||||
|
Comment on lines
+426
to
+478
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-assignment> reported by reviewdog 🐶 |
||||||||||||
|
|
||||||||||||
| if (result && result.avatar) { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-member-access> reported by reviewdog 🐶 |
||||||||||||
| this.youtubeUser = { | ||||||||||||
| name: result.name, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-assignment> reported by reviewdog 🐶
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-member-access> reported by reviewdog 🐶 |
||||||||||||
| avatar: result.avatar, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-assignment> reported by reviewdog 🐶
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-member-access> reported by reviewdog 🐶 |
||||||||||||
| }; | ||||||||||||
| console.log(LoggerPrefix, `Fetched YouTube user: ${result.name}`); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-member-access> reported by reviewdog 🐶 |
||||||||||||
| console.log(LoggerPrefix, `Fetched Avatar URL: ${result.avatar}`); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <@typescript-eslint/no-unsafe-member-access> reported by reviewdog 🐶 |
||||||||||||
| } else { | ||||||||||||
| console.log(LoggerPrefix, 'Could not fetch YouTube user info - retrying in 5 seconds'); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Suggested change
|
||||||||||||
| // Retry after a delay if enabled | ||||||||||||
| if (this.config?.showYouTubeUser) { | ||||||||||||
| setTimeout(() => this.fetchYouTubeUserInfo(), 5000); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| } catch (err) { | ||||||||||||
| console.error(LoggerPrefix, 'Failed to fetch YouTube user info:', err); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Get the YouTube user's avatar URL for use in rich presence. | ||||||||||||
| * @returns The avatar URL or undefined if not available | ||||||||||||
| */ | ||||||||||||
| private getYouTubeUserAvatar(): string | undefined { | ||||||||||||
| return this.youtubeUser?.avatar ?? undefined; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Get the YouTube user's name for use in rich presence. | ||||||||||||
| * @returns The username or undefined if not available | ||||||||||||
| */ | ||||||||||||
| private getYouTubeUserName(): string | undefined { | ||||||||||||
| return this.youtubeUser?.name ?? undefined; | ||||||||||||
| } | ||||||||||||
| /** | ||||||||||||
| * Cleans up resources: disconnects RPC, clears all timers, and clears callbacks. | ||||||||||||
| * Should be called when the plugin stops or the application quits. | ||||||||||||
|
|
@@ -408,4 +519,4 @@ export class DiscordService { | |||||||||||
| this.disconnect(); | ||||||||||||
| this.refreshCallbacks = []; | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Suggested change
|
||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -39,6 +39,12 @@ export type DiscordPluginConfig = { | |||||
| * Controls which field is displayed in the Discord status text | ||||||
| */ | ||||||
| statusDisplayType: (typeof StatusDisplayType)[keyof typeof StatusDisplayType]; | ||||||
| /** | ||||||
| * Show YouTube Music user avatar and username in Discord Rich Presence | ||||||
| * | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Suggested change
|
||||||
| * @default true | ||||||
| */ | ||||||
| showYouTubeUser: boolean; | ||||||
| }; | ||||||
|
|
||||||
| export default createPlugin({ | ||||||
|
|
@@ -54,6 +60,7 @@ export default createPlugin({ | |||||
| hideGitHubButton: false, | ||||||
| hideDurationLeft: false, | ||||||
| statusDisplayType: StatusDisplayType.Details, | ||||||
| showYouTubeUser: true, | ||||||
| } as DiscordPluginConfig, | ||||||
| menu: onMenu, | ||||||
| backend, | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Replace
·?·this.getYouTubeUserAvatar()with⏎········?·this.getYouTubeUserAvatar()⏎·······