Skip to content

Add Discord webhook notifications for plugin downloads (#157) - #196

Open
Zoriot wants to merge 1 commit into
OakLoaf:notifierfrom
Zoriot:webhook
Open

Zoriot wants to merge 1 commit into
OakLoaf:notifierfrom
Zoriot:webhook

Conversation

@Zoriot

@Zoriot Zoriot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Implement basic Discord webhook support to send notifications when plugins are successfully downloaded. Uses jdwebhooks 2.0.0 library with Discord's Components V2 API.

Changes:

  • Add jdwebhooks 2.0.0 dependency to common/impl
  • Create DiscordWebhookNotifier class for sending webhook notifications
  • Add discord-webhook configuration section to config.yml (disabled by default)
  • Update ConfigManager to load and reload webhook settings
  • Integrate webhook notifications in UpdateHandler on successful downloads
  • Update UpdaterImpl to initialize and manage webhook notifier lifecycle

Webhook notifications include:

  • Plugin name
  • Version change (old → new)
  • Update type (MAJOR, MINOR, PATCH, etc.)
  • Changelog link (if available)

Infos

Users can enable by setting discord-webhook.enabled to true and providing a webhook-url in config.yml.

Closes #157

  • Config currently does not update automatically
  • This implementation set both Avatar + Users - we could also not set that and use it from the Webhook.
  • Currently it was only implemented for Updates, Update available might be a feature i contribute

AI Disclosure

GitHub Copilot was used for most of the implementation, all code was manually verified & tested on paper. Additional Changes was made to ensure it works correctly.

Implement basic Discord webhook support to send notifications when plugins
are successfully downloaded. Uses jdwebhooks 2.0.0 library with Discord's
Components V2 API.

Changes:
- Add jdwebhooks 2.0.0 dependency to common/impl
- Create DiscordWebhookNotifier class for sending webhook notifications
- Add discord-webhook configuration section to config.yml (disabled by default)
- Update ConfigManager to load and reload webhook settings
- Integrate webhook notifications in UpdateHandler on successful downloads
- Update UpdaterImpl to initialize and manage webhook notifier lifecycle

Webhook notifications include:
- Plugin name
- Version change (old → new)
- Update type (MAJOR, MINOR, PATCH, etc.)
- Changelog link (if available)

Users can enable by setting discord-webhook.enabled to true and providing
a webhook-url in config.yml.

Closes OakLoaf#157

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Zoriot

Zoriot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

@OakLoaf may you do a Review for this one?

@OakLoaf

OakLoaf commented Sep 12, 2026

Copy link
Copy Markdown
Owner

I'm afraid I'm a bit limited on time at the moment, but will try and make some time in the coming weeks to work on, review and merge for v5

@OakLoaf OakLoaf added this to the v5 milestone Sep 15, 2026
@OakLoaf OakLoaf mentioned this pull request Sep 15, 2026
Draft
6 tasks

@OakLoaf OakLoaf left a comment

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.

Thank you very much for this PR, the majority of this looks really good and ready to go, mainly just some nitpick changes.

I've been inspired by this PR to create a notifier system, so this PR will first be merged into the 'notifier' branch which will be later merged into 'v5' following those changes. The main changes from a user perspective will be the configuration but it should allow the ability to create notifications for other platforms in the future.
That doesn't change the direction or scope of this PR, so don't worry about implementing/changing anything other than the things mentioned in the review :)

Comment on lines +53 to +61
Config discordConfig = config.get("discord-webhook");
if (discordConfig != null) {
this.discordWebhookEnabled = discordConfig.getOrElse("enabled", false);
this.discordWebhookUrl = discordConfig.getOrElse("webhook-url", "");
} else {
this.discordWebhookEnabled = false;
this.discordWebhookUrl = "";
}

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 think it would be cleaner to merge discordWebhookEnabled into discordWebhookUrl where the url is null or an empty string if disabled. I don't mind keeping the separate options in the config for convenience and clarity.

try {
Version currentVersion = pluginData.currentVersion();
Optional<Version> latestVersionOpt = pluginData.latestVersion();

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.

Suggested change


try {
Version currentVersion = pluginData.currentVersion();
Optional<Version> latestVersionOpt = pluginData.latestVersion();

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.

To match the rest of the project it should be named latestVersionOptional, or alternatively use the following and do a null check:

Suggested change
Optional<Version> latestVersionOpt = pluginData.latestVersion();
Version latestVersion = pluginData.latestVersion().orElse(null);

Comment on lines +54 to +58
List<ContainerableComponent> components = new ArrayList<>();

components.add(Component.textDisplay("**" + pluginName + " Updated**"));

components.add(Component.textDisplay("**Version:** " + versionString));

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.

We don't need new lines between these lines

Suggested change
List<ContainerableComponent> components = new ArrayList<>();
components.add(Component.textDisplay("**" + pluginName + " Updated**"));
components.add(Component.textDisplay("**Version:** " + versionString));
List<ContainerableComponent> components = new ArrayList<>();
components.add(Component.textDisplay("**" + pluginName + " Updated**"));
components.add(Component.textDisplay("**Version:** " + versionString));

Comment on lines +87 to +90
() -> "Discord webhook returned unsuccessful response. Status code: "
+ statusCode
+ ", response: "
+ response

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.

Could we replace this string formatting with similar to the rest of the project like below, we can then inline this log

Suggested change
() -> "Discord webhook returned unsuccessful response. Status code: "
+ statusCode
+ ", response: "
+ response
() -> "Discord webhook returned unsuccessful response. Status code: %s, response: %s"
.formatted(statusCode, response)

Comment on lines +60 to +63
String versionDiff = pluginData.versionDifference().name();
if (!versionDiff.equals("UNKNOWN")) {
components.add(Component.textDisplay("**Update Type:** " + versionDiff));
}

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.

Suggested change
String versionDiff = pluginData.versionDifference().name();
if (!versionDiff.equals("UNKNOWN")) {
components.add(Component.textDisplay("**Update Type:** " + versionDiff));
}
VersionDifference versionDiff = pluginData.versionDifference();
if (versionDiff != VersionDifference.UNKNOWN)) {
components.add(Component.textDisplay("**Update Type:** " + versionDiff.name()));
}

return config;
}

public DiscordWebhookNotifier discordWebhookNotifier() {

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.

Can we change this to discordWebHookNotifier please.
Additionally, for this method can we return Optional<DiscordWebhookNotifier> and then in places we want to use the notifier we can run #discordWebHookNotifier#ifPresent

}
}

public void close() {

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.

Could we rename this to shutdown to be named similarly to other similar methods in this project


api("io.github.revxrsal:lamp.common:4.0.0-rc.18")
api("com.electronwill.night-config:yaml:3.9.0")
api("io.github.4drian3d:jdwebhooks:2.0.0")

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 don't think we'll need this one outside of this module for the time being so can we set the scope of this to implementation please?

private final List<PluginDataCollector.Factory> collectors;
private final UpdateHandler<T> updateHandler;
private final ConfigManager config;
private DiscordWebhookNotifier discordWebhookNotifier;

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.

Suggested change
private DiscordWebhookNotifier discordWebhookNotifier;
private DiscordWebhookNotifier discordWebHookNotifier;

@OakLoaf
OakLoaf changed the base branch from main to notifier September 15, 2026 21:57
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.

Send Notifications via Discord Webhooks or Bot

2 participants