From b7a8cca387fdbc1c2fb265b5f2d4b594479e012b Mon Sep 17 00:00:00 2001 From: undirectlookable Date: Mon, 25 May 2026 16:42:25 +0800 Subject: [PATCH] feat(notifications): add Bark push support Add Bark as a supported Apprise notification protocol. Supported URL formats: - bark://bark_key uses the official Bark server at https://api.day.app/ - bark://host/bark_key uses a custom Bark server over HTTP - barks://host/bark_key uses a custom Bark server over HTTPS Bark notifications are sent with POST JSON payloads containing the device key, title, and body. The notification settings modal now lists Bark examples in the Apprise URL placeholder and support text. --- src/lib/server/notifications.ts | 63 +++++++++++++++++++ .../notifications/NotificationModal.svelte | 5 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/lib/server/notifications.ts b/src/lib/server/notifications.ts index d9b5b98..c651bfc 100644 --- a/src/lib/server/notifications.ts +++ b/src/lib/server/notifications.ts @@ -129,6 +129,9 @@ async function sendToAppriseUrl(url: string, payload: NotificationPayload): Prom case 'ntfy': case 'ntfys': return await sendNtfy(url, payload); + case 'bark': + case 'barks': + return await sendBark(url, payload); case 'pushover': return await sendPushover(url, payload); case 'json': @@ -435,6 +438,66 @@ async function sendNtfy(appriseUrl: string, payload: NotificationPayload): Promi } } +// Bark +async function sendBark(appriseUrl: string, payload: NotificationPayload): Promise { + // Supported formats: + // bark://device_key (official api.day.app server) + // bark://host/device_key (custom server over HTTP) + // barks://host/device_key (custom server over HTTPS) + const isSecure = appriseUrl.startsWith('barks'); + const path = appriseUrl.replace(/^barks?:\/\//, ''); + + let url: string; + let deviceKey: string; + + if (!path.includes('/')) { + if (!path) { + return { success: false, error: 'Invalid Bark URL format. Expected: bark://device_key, bark://host/device_key, or barks://host/device_key' }; + } + url = 'https://api.day.app/push'; + deviceKey = path; + } else { + const parts = path.split('/'); + if (parts.length !== 2) { + return { success: false, error: 'Invalid Bark URL format. Expected: bark://device_key, bark://host/device_key, or barks://host/device_key' }; + } + const [host, key] = parts; + deviceKey = key; + if (!host || !deviceKey) { + return { success: false, error: 'Invalid Bark URL format. Expected: bark://device_key, bark://host/device_key, or barks://host/device_key' }; + } + url = `${isSecure ? 'https' : 'http'}://${host}/push`; + } + + const titleWithEnv = payload.environmentName ? `${payload.title} [${payload.environmentName}]` : payload.title; + const body: Record = { + device_key: deviceKey, + title: titleWithEnv, + body: payload.message + }; + + if (payload.type === 'error') { + body.level = 'timeSensitive'; + } + + try { + const response = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + + if (!response.ok) { + const text = await response.text().catch(() => ''); + return { success: false, error: `Bark error ${response.status}: ${text || response.statusText}` }; + } + await drainResponse(response); + return { success: true }; + } catch (error) { + return { success: false, error: `Bark connection failed: ${error instanceof Error ? error.message : String(error)}` }; + } +} + // Pushover async function sendPushover(appriseUrl: string, payload: NotificationPayload): Promise { // pushover://user_key/api_token diff --git a/src/routes/settings/notifications/NotificationModal.svelte b/src/routes/settings/notifications/NotificationModal.svelte index e29e997..e176d06 100644 --- a/src/routes/settings/notifications/NotificationModal.svelte +++ b/src/routes/settings/notifications/NotificationModal.svelte @@ -427,11 +427,14 @@ ntfy://host/topic?auth=base64token&priority=3 ntfys://host/topic?auth=base64token pushover://user_key/api_token workflows://hostname/workflow/signature +bark://bark_key +bark://host/bark_key +barks://host/bark_key jsons://hostname/webhook/path" class="flex min-h-[220px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" >

- Supports Gotify (gotify:// or gotifys:// for HTTPS), Discord, Slack, Mattermost (mmost:// or mmosts://), Telegram, ntfy, Pushover, Workflows (for e.g. Microsoft Teams), and generic JSON webhooks. + Supports Gotify (gotify:// or gotifys:// for HTTPS), Discord, Slack, Mattermost (mmost:// or mmosts://), Telegram, ntfy, Bark, Pushover, Workflows (for e.g. Microsoft Teams), and generic JSON webhooks.