Compare commits
No commits in common. "b92808a6378f88b1ae2764bdfd34959d1a4ca8ba" and "f08db49f0b6960960d295009c38979878ccb60ed" have entirely different histories.
b92808a637
...
f08db49f0b
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.7.193",
|
"version": "1.7.192",
|
||||||
"description": "Desktop downloader",
|
"description": "Desktop downloader",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@ -108,7 +108,6 @@ export function defaultSettings(): AppSettings {
|
|||||||
confirmDeleteSelection: true,
|
confirmDeleteSelection: true,
|
||||||
backupIncludeDownloads: false,
|
backupIncludeDownloads: false,
|
||||||
notifyUrl: "",
|
notifyUrl: "",
|
||||||
notifyMention: "",
|
|
||||||
notifyOnPackageCompleted: false,
|
notifyOnPackageCompleted: false,
|
||||||
notifyOnPackageFailed: false,
|
notifyOnPackageFailed: false,
|
||||||
notifyOnRunFinished: false,
|
notifyOnRunFinished: false,
|
||||||
|
|||||||
@ -10497,8 +10497,7 @@ export class DownloadManager extends EventEmitter {
|
|||||||
this.notifiedPackages.add(pkg.id);
|
this.notifiedPackages.add(pkg.id);
|
||||||
void sendNotification(url, {
|
void sendNotification(url, {
|
||||||
title: kind === "completed" ? "✅ Paket fertig" : "❌ Paket fehlgeschlagen",
|
title: kind === "completed" ? "✅ Paket fertig" : "❌ Paket fehlgeschlagen",
|
||||||
message: `${pkg.name}\n${detail}`,
|
message: `${pkg.name}\n${detail}`
|
||||||
mention: this.settings.notifyMention
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12122,8 +12121,7 @@ export class DownloadManager extends EventEmitter {
|
|||||||
if (this.settings.notifyOnRunFinished && total > 0) {
|
if (this.settings.notifyOnRunFinished && total > 0) {
|
||||||
void sendNotification(this.settings.notifyUrl, {
|
void sendNotification(this.settings.notifyUrl, {
|
||||||
title: failed > 0 ? "⚠️ Durchlauf beendet" : "🏁 Durchlauf beendet",
|
title: failed > 0 ? "⚠️ Durchlauf beendet" : "🏁 Durchlauf beendet",
|
||||||
message: `${success}/${total} erfolgreich, ${failed} fehlgeschlagen, ${cancelled} abgebrochen\nDauer ${duration}s, Durchschnitt ${humanSize(avgSpeed)}/s`,
|
message: `${success}/${total} erfolgreich, ${failed} fehlgeschlagen, ${cancelled} abgebrochen\nDauer ${duration}s, Durchschnitt ${humanSize(avgSpeed)}/s`
|
||||||
mention: this.settings.notifyMention
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.runItemIds.clear();
|
this.runItemIds.clear();
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { logger } from "./logger";
|
|||||||
export interface NotifyPayload {
|
export interface NotifyPayload {
|
||||||
title: string;
|
title: string;
|
||||||
message: string;
|
message: string;
|
||||||
mention?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NOTIFY_TIMEOUT_MS = 5000;
|
const NOTIFY_TIMEOUT_MS = 5000;
|
||||||
@ -13,22 +12,8 @@ export function isNotifyUrlValid(url: string): boolean {
|
|||||||
return /^https?:\/\/\S+$/i.test(String(url || "").trim());
|
return /^https?:\/\/\S+$/i.test(String(url || "").trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accepts a bare Discord user ID (wrapped as <@id> so it actually pings),
|
|
||||||
// @everyone/@here, or an already-formed <@...>/<@&...> mention as-is.
|
|
||||||
export function normalizeDiscordMention(raw: string): string {
|
|
||||||
const text = String(raw || "").trim();
|
|
||||||
if (!text) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (/^\d{5,}$/.test(text)) {
|
|
||||||
return `<@${text}>`;
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildNotifyRequest(url: string, payload: NotifyPayload): { url: string; init: RequestInit } {
|
export function buildNotifyRequest(url: string, payload: NotifyPayload): { url: string; init: RequestInit } {
|
||||||
const mention = normalizeDiscordMention(payload.mention || "");
|
const content = `**${payload.title}**\n${payload.message}`.slice(0, 2000);
|
||||||
const content = `${mention ? `${mention} ` : ""}**${payload.title}**\n${payload.message}`.slice(0, 2000);
|
|
||||||
return {
|
return {
|
||||||
url: String(url || "").trim(),
|
url: String(url || "").trim(),
|
||||||
init: {
|
init: {
|
||||||
|
|||||||
@ -460,7 +460,6 @@ export function normalizeSettings(settings: AppSettings): AppSettings {
|
|||||||
confirmDeleteSelection: settings.confirmDeleteSelection !== undefined ? Boolean(settings.confirmDeleteSelection) : defaults.confirmDeleteSelection,
|
confirmDeleteSelection: settings.confirmDeleteSelection !== undefined ? Boolean(settings.confirmDeleteSelection) : defaults.confirmDeleteSelection,
|
||||||
backupIncludeDownloads: settings.backupIncludeDownloads !== undefined ? Boolean(settings.backupIncludeDownloads) : defaults.backupIncludeDownloads,
|
backupIncludeDownloads: settings.backupIncludeDownloads !== undefined ? Boolean(settings.backupIncludeDownloads) : defaults.backupIncludeDownloads,
|
||||||
notifyUrl: asText(settings.notifyUrl) || defaults.notifyUrl,
|
notifyUrl: asText(settings.notifyUrl) || defaults.notifyUrl,
|
||||||
notifyMention: asText(settings.notifyMention) || defaults.notifyMention,
|
|
||||||
notifyOnPackageCompleted: settings.notifyOnPackageCompleted !== undefined ? Boolean(settings.notifyOnPackageCompleted) : defaults.notifyOnPackageCompleted,
|
notifyOnPackageCompleted: settings.notifyOnPackageCompleted !== undefined ? Boolean(settings.notifyOnPackageCompleted) : defaults.notifyOnPackageCompleted,
|
||||||
notifyOnPackageFailed: settings.notifyOnPackageFailed !== undefined ? Boolean(settings.notifyOnPackageFailed) : defaults.notifyOnPackageFailed,
|
notifyOnPackageFailed: settings.notifyOnPackageFailed !== undefined ? Boolean(settings.notifyOnPackageFailed) : defaults.notifyOnPackageFailed,
|
||||||
notifyOnRunFinished: settings.notifyOnRunFinished !== undefined ? Boolean(settings.notifyOnRunFinished) : defaults.notifyOnRunFinished,
|
notifyOnRunFinished: settings.notifyOnRunFinished !== undefined ? Boolean(settings.notifyOnRunFinished) : defaults.notifyOnRunFinished,
|
||||||
|
|||||||
@ -853,7 +853,7 @@ const emptySnapshot = (): UiSnapshot => ({
|
|||||||
maxParallel: 4, maxParallelExtract: 2, extractCpuPriority: "high", retryLimit: 0, speedLimitEnabled: false, speedLimitKbps: 0, speedLimitMode: "global",
|
maxParallel: 4, maxParallelExtract: 2, extractCpuPriority: "high", retryLimit: 0, speedLimitEnabled: false, speedLimitKbps: 0, speedLimitMode: "global",
|
||||||
updateRepo: "", autoUpdateCheck: true, clipboardWatch: false, minimizeToTray: false,
|
updateRepo: "", autoUpdateCheck: true, clipboardWatch: false, minimizeToTray: false,
|
||||||
theme: "dark", collapseNewPackages: true, historyRetentionMode: "permanent", autoSortPackagesByProgress: true, autoSkipExtracted: false, hideExtractedItems: true, confirmDeleteSelection: true, backupIncludeDownloads: false,
|
theme: "dark", collapseNewPackages: true, historyRetentionMode: "permanent", autoSortPackagesByProgress: true, autoSkipExtracted: false, hideExtractedItems: true, confirmDeleteSelection: true, backupIncludeDownloads: false,
|
||||||
notifyUrl: "", notifyMention: "", notifyOnPackageCompleted: false, notifyOnPackageFailed: false, notifyOnRunFinished: false,
|
notifyUrl: "", notifyOnPackageCompleted: false, notifyOnPackageFailed: false, notifyOnRunFinished: false,
|
||||||
accountListShowDetailedDebridLinkKeys: false,
|
accountListShowDetailedDebridLinkKeys: false,
|
||||||
bandwidthSchedules: [], totalDownloadedAllTime: 0, totalCompletedFilesAllTime: 0, totalRuntimeAllTimeMs: 0,
|
bandwidthSchedules: [], totalDownloadedAllTime: 0, totalCompletedFilesAllTime: 0, totalRuntimeAllTimeMs: 0,
|
||||||
columnOrder: ["name", "size", "progress", "hoster", "account", "prio", "status", "speed"],
|
columnOrder: ["name", "size", "progress", "hoster", "account", "prio", "status", "speed"],
|
||||||
@ -4960,9 +4960,6 @@ export function App(): ReactElement {
|
|||||||
<label>Webhook-URL (Discord)</label>
|
<label>Webhook-URL (Discord)</label>
|
||||||
<input value={settingsDraft.notifyUrl} placeholder="https://discord.com/api/webhooks/..." onChange={(e) => setText("notifyUrl", e.target.value)} />
|
<input value={settingsDraft.notifyUrl} placeholder="https://discord.com/api/webhooks/..." onChange={(e) => setText("notifyUrl", e.target.value)} />
|
||||||
<div className="hint">In Discord: Servereinstellungen → Integrationen → Webhooks → Neuer Webhook → URL kopieren und hier eintragen. Die gewählten Ereignisse landen als Nachricht im Kanal.</div>
|
<div className="hint">In Discord: Servereinstellungen → Integrationen → Webhooks → Neuer Webhook → URL kopieren und hier eintragen. Die gewählten Ereignisse landen als Nachricht im Kanal.</div>
|
||||||
<label>Discord-Ping (optional)</label>
|
|
||||||
<input value={settingsDraft.notifyMention} placeholder="Deine User-ID, @everyone oder @here" onChange={(e) => setText("notifyMention", e.target.value)} />
|
|
||||||
<div className="hint">Wird jeder Nachricht vorangestellt, damit Discord dich pingt. Eigene ID: Discord-Einstellungen → Erweitert → Entwicklermodus an, dann Rechtsklick auf deinen Namen → "User-ID kopieren" und die Zahl hier eintragen.</div>
|
|
||||||
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnPackageCompleted} onChange={(e) => setBool("notifyOnPackageCompleted", e.target.checked)} /> Benachrichtigen wenn ein Paket fertig ist</label>
|
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnPackageCompleted} onChange={(e) => setBool("notifyOnPackageCompleted", e.target.checked)} /> Benachrichtigen wenn ein Paket fertig ist</label>
|
||||||
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnPackageFailed} onChange={(e) => setBool("notifyOnPackageFailed", e.target.checked)} /> Benachrichtigen wenn ein Paket fehlschlägt</label>
|
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnPackageFailed} onChange={(e) => setBool("notifyOnPackageFailed", e.target.checked)} /> Benachrichtigen wenn ein Paket fehlschlägt</label>
|
||||||
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnRunFinished} onChange={(e) => setBool("notifyOnRunFinished", e.target.checked)} /> Benachrichtigen wenn der Durchlauf beendet ist</label>
|
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.notifyOnRunFinished} onChange={(e) => setBool("notifyOnRunFinished", e.target.checked)} /> Benachrichtigen wenn der Durchlauf beendet ist</label>
|
||||||
|
|||||||
@ -133,7 +133,6 @@ export interface AppSettings {
|
|||||||
confirmDeleteSelection: boolean;
|
confirmDeleteSelection: boolean;
|
||||||
backupIncludeDownloads: boolean;
|
backupIncludeDownloads: boolean;
|
||||||
notifyUrl: string;
|
notifyUrl: string;
|
||||||
notifyMention: string;
|
|
||||||
notifyOnPackageCompleted: boolean;
|
notifyOnPackageCompleted: boolean;
|
||||||
notifyOnPackageFailed: boolean;
|
notifyOnPackageFailed: boolean;
|
||||||
notifyOnRunFinished: boolean;
|
notifyOnRunFinished: boolean;
|
||||||
|
|||||||
@ -1,22 +1,5 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import { buildNotifyRequest, isNotifyUrlValid, normalizeDiscordMention, sendNotification } from "../src/main/notify";
|
import { buildNotifyRequest, isNotifyUrlValid, sendNotification } from "../src/main/notify";
|
||||||
|
|
||||||
describe("normalizeDiscordMention", () => {
|
|
||||||
it("wraps a bare user ID as a pinging mention", () => {
|
|
||||||
expect(normalizeDiscordMention("123456789012345678")).toBe("<@123456789012345678>");
|
|
||||||
expect(normalizeDiscordMention(" 987654321 ")).toBe("<@987654321>");
|
|
||||||
});
|
|
||||||
it("passes @everyone/@here and formed mentions through", () => {
|
|
||||||
expect(normalizeDiscordMention("@everyone")).toBe("@everyone");
|
|
||||||
expect(normalizeDiscordMention("@here")).toBe("@here");
|
|
||||||
expect(normalizeDiscordMention("<@123456789>")).toBe("<@123456789>");
|
|
||||||
expect(normalizeDiscordMention("<@&111222333>")).toBe("<@&111222333>");
|
|
||||||
});
|
|
||||||
it("returns empty for empty input", () => {
|
|
||||||
expect(normalizeDiscordMention("")).toBe("");
|
|
||||||
expect(normalizeDiscordMention(" ")).toBe("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("isNotifyUrlValid", () => {
|
describe("isNotifyUrlValid", () => {
|
||||||
it("accepts http/https URLs", () => {
|
it("accepts http/https URLs", () => {
|
||||||
@ -47,16 +30,6 @@ describe("buildNotifyRequest", () => {
|
|||||||
const body = JSON.parse(String(req.init.body));
|
const body = JSON.parse(String(req.init.body));
|
||||||
expect(body.content.length).toBe(2000);
|
expect(body.content.length).toBe(2000);
|
||||||
});
|
});
|
||||||
it("prepends the mention so Discord pings (bare ID gets wrapped)", () => {
|
|
||||||
const req = buildNotifyRequest("https://discord.com/api/webhooks/123/abc", { title: "T", message: "M", mention: "123456789012345678" });
|
|
||||||
const body = JSON.parse(String(req.init.body));
|
|
||||||
expect(body.content).toBe("<@123456789012345678> **T**\nM");
|
|
||||||
});
|
|
||||||
it("sends no mention prefix when the field is empty", () => {
|
|
||||||
const req = buildNotifyRequest("https://discord.com/api/webhooks/123/abc", { title: "T", message: "M", mention: "" });
|
|
||||||
const body = JSON.parse(String(req.init.body));
|
|
||||||
expect(body.content).toBe("**T**\nM");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("sendNotification", () => {
|
describe("sendNotification", () => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user