Skip to content

feat: Give the user the option to specify an image proxy for Discord RPC - #2152

Open
Quinnca77 wants to merge 19 commits into
jeffvli:developmentfrom
Quinnca77:image-proxy
Open

Quinnca77 wants to merge 19 commits into
jeffvli:developmentfrom
Quinnca77:image-proxy

Conversation

@Quinnca77

Copy link
Copy Markdown

What does this fix?

I personally use Navidrome, and embed my cover arts directly into the files. I then instruct Navidrome to use these embeds as the first priority for viewing the cover art, rather than the associated album image. This does not interface well with Feishin Discord RPC, as Feishin asks for the album image directly on the album id. Rather than doing this, we can do the following:

  1. Use getCoverArt endpoint on music server
  2. Get image and send it to an image proxy
  3. Image proxy sends back a link pointing to the image resource, which is accessible from the internet
  4. Send link to Discord RPC

This feature works out of the box if Image proxy is selected for the server type, and the link https://uguu.se/upload is given.

Verification steps

  • I have ran linting.
  • Checked for myself with a song on Navidrome of which the embedded cover art is different from the album cover art that this works. Tested with uguu.se.

Things I'm not too sure about

  • How the image proxy returns the image link can differ per service, and this is not configurable at the moment.
  • The way the configuration is changed for Serve discord images from server and its text.

Additional notes

I would like to say that I have been enjoying Feishin a lot and do not plan to return to any other platform after experiencing this one. Thank you all for making such a great app!
Second, this is my first open-source contribution. I do not have much experience working in big codebases like these. Feel free to let me know what I could've done better :)

@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
feishin Ready Ready Preview, Comment Jul 25, 2026 11:52pm

@Quinnca77

Copy link
Copy Markdown
Author

I discarded the renamed fields in different locales as I felt this change was unwarranted

Comment thread src/main/features/core/discord-rpc/index.ts Outdated
@Quinnca77

Copy link
Copy Markdown
Author

The upload is now more configurable :)
I added the above bullet points as configuration options that only appear when the user has selected to use an image proxy for Discord RPC.

@Quinnca77
Quinnca77 requested a review from jeffvli July 15, 2026 17:38
@jeffvli

jeffvli commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Unfortunately even with the three configuration options it's still too rigid. I did a quick analysis (using AI) to determine what formats other image hosts expect for the uploader.

I think the proper approach here would be to do what I mentioned in my previous comment:

The other option is to specifically add pre-configured file share hosts (e.g. imgur, uguu.se, etc) and interface it so that they can be plugged into the same interface.

You would create an interface which accepts an uploader callback as well as a group of custom settings which are depicted as an object but parsed to the interface.


Works (or should) with current config

Host Config Notes
uguu.se (default) URL https://uguu.se/upload, field files[], path files.0.url Designed for this
Self-hosted uguu / pomf clones Same pattern if response is JSON with a URL field Best bet for “bring your own”
ImgBB URL https://api.imgbb.com/1/upload?key=YOUR_KEY, field image, path data.url (or data.display_url) Key in query string avoids needing an extra form field
tmpfiles.org URL https://tmpfiles.org/api/v1/upload, field file, path data.url Upload works, but response URL is often a viewer page (tmpfiles.org/...), not a direct image URL Discord may want

Does not work without extending the client

Host Blocker
catbox.moe Needs extra form field reqtype=fileupload; response is plain text URL, not JSON
litterbox.catbox.moe Needs reqtype + time; plain text response
0x0.st Multipart file is fine, but response is plain text, not JSON
Pixeldrain Upload can be multipart file, but JSON returns an id, not a full URL — you’d need a URL template like https://pixeldrain.com/api/file/{id}
Imgur Needs Authorization: Client-ID … header
Freeimage.host (Chevereto-style) Needs at least key + action=upload as extra fields (unless those can live entirely in the query string — not guaranteed)
transfer.sh / similar Often PUT with raw body, not multipart POST

@Quinnca77

Copy link
Copy Markdown
Author

So you'd like me to provide some pre-defined working settings for different image hosts. That's okay, but which image hosts would you like me to implement then? Your first table depicts the hosts that already work with the current implementation.

I could then show different config settings per selected image host, depending on what they need. For example, for litterbox.catbox.moe we could give the user the option to configure the time field, and pick a default setting if they choose not to configure it.

@jeffvli

jeffvli commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Just implement your preferred host to start (uguu.se).

I could then show different config settings per selected image host, depending on what they need. For example, for litterbox.catbox.moe we could give the user the option to configure the time field, and pick a default setting if they choose not to configure it.

Exactly.

@Quinnca77

Copy link
Copy Markdown
Author

I won't have a lot of time the coming days so it'll take a while for me to implement, but when I do I'll also include litterbox.catbox.moe as a PoC.

Thank you for the quick review :)

@Quinnca77

Copy link
Copy Markdown
Author

I implemented interfaces for litterbox.catbox.moe and uguu.se. They each specify their own defaults. I kept the URL as a user config item because I felt that users should have the option to point it somewhere else, for example at their own APIs that conform to the same spec. The URLs for each image proxy have their defaults point to the URL you'd expect, so users can simply choose an image proxy while not configuring anything, and it should work for them.

Adding another image proxy should be as easy as exposing the user-configurable config items in Feishin UI, defining its interface, passing the user config items through IPC and implementing its upload function where it uses the config items.

Could you review the code once more? If you have any questions, feel free to ask me through my Discord at the same username.

Comment thread src/i18n/locales/en.json
Comment on lines +890 to +891
"discordServerType_uguu": "uguu.se",
"discordServerType_litterbox": "litterbox.catbox.moe",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URLs do not need a translation string.

Comment on lines +307 to +325
{
control: (
<TextInput
onChange={(e) => {
setSettings({
discord: {
litterboxTime: e.currentTarget.value,
},
});
}}
value={settings.litterboxTime}
/>
),
description: t('setting.discordLitterboxTimeField', {
context: 'description',
}),
isHidden: !isElectron() || settings.serverType !== DiscordServerType.LITTERBOX,
title: t('setting.discordLitterboxTimeField'),
},

@jeffvli jeffvli Aug 13, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not allow specific settings like this as it adds additional overhead especially if additional uploaders are added in the future each with their own specific settings.

I would prefer you refactor this into a JSON setting and input which allows the user to free-form a settings config (JSON) with a link to external documentation added to the repo docs as markdown for each uploader.

Formatted as <uploader>_<setting>, you could then add an infinite number of settings that could then be passed to the uploader to parse and perform actions on. Now we can add specific settings per uploader without having to add settings UI and translation strings to each one.

{
  "litterbox_time": "72h"
}

clientId: '1165957668758900787',
displayType: DiscordDisplayType.FEISHIN,
enabled: false,
imageProxyServerLink: 'https://uguu.se/upload',

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They each specify their own defaults. I kept the URL as a user config item because I felt that users should have the option to point it somewhere else, for example at their own APIs that conform to the same spec. The URLs for each image proxy have their defaults point to the URL you'd expect, so users can simply choose an image proxy while not configuring anything, and it should work for them.

From what you said, this is treated as an override? In this case shouldn't the default setting be empty?

Comment on lines +301 to +317
case DiscordServerType.LITTERBOX:
if (
!['1h', '12h', '24h', '72h'].includes(
discordSettings.litterboxTime,
)
) {
config = {};
break;
}
config = {
time: discordSettings.litterboxTime as LitterboxImageProxyConfig['time'],
};
break;
case DiscordServerType.UGUU: {
config = {};
break;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the JSON settings change, the raw config should be passed to the uploader which handles parsing and consuming the config rather than at the discord rpc hook level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants