diff --git a/app/client/modules/notifications/components/create-notification-form.tsx b/app/client/modules/notifications/components/create-notification-form.tsx
index 712baaa..79b4353 100644
--- a/app/client/modules/notifications/components/create-notification-form.tsx
+++ b/app/client/modules/notifications/components/create-notification-form.tsx
@@ -64,6 +64,12 @@ const defaultValuesForType = {
topic: "",
priority: "default" as const,
},
+ pushover: {
+ type: "pushover" as const,
+ userKey: "",
+ apiToken: "",
+ priority: 0,
+ },
custom: {
type: "custom" as const,
shoutrrrUrl: "",
@@ -141,6 +147,7 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
Discord
Gotify
Ntfy
+ Pushover
Custom (Shoutrrr URL)
@@ -490,6 +497,80 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
>
)}
+ {watchedType === "pushover" && (
+ <>
+ (
+
+ User Key
+
+
+
+ Your Pushover user key from the dashboard.
+
+
+ )}
+ />
+ (
+
+ API Token
+
+
+
+ Application API token from your Pushover application.
+
+
+ )}
+ />
+ (
+
+ Devices (Optional)
+
+
+
+ Comma-separated list of device names. Leave empty for all devices.
+
+
+ )}
+ />
+ (
+
+ Priority
+
+ Message priority level.
+
+
+ )}
+ />
+ >
+ )}
+
{watchedType === "custom" && (
Shoutrrr documentation
- for supported services and URL formats.
+ for supported services and URL formats.
diff --git a/app/client/modules/notifications/routes/notifications.tsx b/app/client/modules/notifications/routes/notifications.tsx
index 546c888..f4497c6 100644
--- a/app/client/modules/notifications/routes/notifications.tsx
+++ b/app/client/modules/notifications/routes/notifications.tsx
@@ -101,6 +101,7 @@ export default function Notifications({ loaderData }: Route.ComponentProps) {
Discord
Gotify
Ntfy
+ Pushover
Custom
diff --git a/app/schemas/notifications.ts b/app/schemas/notifications.ts
index da20d15..998675c 100644
--- a/app/schemas/notifications.ts
+++ b/app/schemas/notifications.ts
@@ -6,6 +6,7 @@ export const NOTIFICATION_TYPES = {
discord: "discord",
gotify: "gotify",
ntfy: "ntfy",
+ pushover: "pushover",
custom: "custom",
} as const;
@@ -52,6 +53,14 @@ export const ntfyNotificationConfigSchema = type({
priority: "'max' | 'high' | 'default' | 'low' | 'min'",
});
+export const pushoverNotificationConfigSchema = type({
+ type: "'pushover'",
+ userKey: "string",
+ apiToken: "string",
+ devices: "string?",
+ priority: "-1 | 0 | 1",
+});
+
export const customNotificationConfigSchema = type({
type: "'custom'",
shoutrrrUrl: "string",
@@ -62,6 +71,7 @@ export const notificationConfigSchema = emailNotificationConfigSchema
.or(discordNotificationConfigSchema)
.or(gotifyNotificationConfigSchema)
.or(ntfyNotificationConfigSchema)
+ .or(pushoverNotificationConfigSchema)
.or(customNotificationConfigSchema);
export type NotificationConfig = typeof notificationConfigSchema.infer;
diff --git a/app/server/modules/notifications/builders/index.ts b/app/server/modules/notifications/builders/index.ts
index ffe84c3..a6e125c 100644
--- a/app/server/modules/notifications/builders/index.ts
+++ b/app/server/modules/notifications/builders/index.ts
@@ -4,6 +4,7 @@ import { buildSlackShoutrrrUrl } from "./slack";
import { buildDiscordShoutrrrUrl } from "./discord";
import { buildGotifyShoutrrrUrl } from "./gotify";
import { buildNtfyShoutrrrUrl } from "./ntfy";
+import { buildPushoverShoutrrrUrl } from "./pushover";
import { buildCustomShoutrrrUrl } from "./custom";
export function buildShoutrrrUrl(config: NotificationConfig): string {
@@ -18,6 +19,8 @@ export function buildShoutrrrUrl(config: NotificationConfig): string {
return buildGotifyShoutrrrUrl(config);
case "ntfy":
return buildNtfyShoutrrrUrl(config);
+ case "pushover":
+ return buildPushoverShoutrrrUrl(config);
case "custom":
return buildCustomShoutrrrUrl(config);
default: {
diff --git a/app/server/modules/notifications/builders/pushover.ts b/app/server/modules/notifications/builders/pushover.ts
new file mode 100644
index 0000000..5f735a0
--- /dev/null
+++ b/app/server/modules/notifications/builders/pushover.ts
@@ -0,0 +1,24 @@
+import type { NotificationConfig } from "~/schemas/notifications";
+
+export function buildPushoverShoutrrrUrl(
+ config: Extract,
+): string {
+ const params = new URLSearchParams();
+
+ if (config.devices) {
+ params.append("devices", config.devices);
+ }
+
+ if (config.priority !== undefined) {
+ params.append("priority", config.priority.toString());
+ }
+
+ const queryString = params.toString();
+ let shoutrrrUrl = `pushover://shoutrrr:${config.apiToken}@${config.userKey}/`;
+
+ if (queryString) {
+ shoutrrrUrl += `?${queryString}`;
+ }
+
+ return shoutrrrUrl;
+}
diff --git a/app/server/modules/notifications/notifications.service.ts b/app/server/modules/notifications/notifications.service.ts
index 16d6806..8b7d311 100644
--- a/app/server/modules/notifications/notifications.service.ts
+++ b/app/server/modules/notifications/notifications.service.ts
@@ -60,6 +60,11 @@ async function encryptSensitiveFields(config: NotificationConfig): Promise