mqtt webhook: nest under jellyfin card, strict enable gating, end-to-end test
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m29s
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m29s
- MqttSection now renders as a nested block inside the Jellyfin ConnSection instead of its own card; ConnSection grew a children slot - when the enable checkbox is off, broker/topic/credentials inputs and the whole plugin setup panel are hidden; only the toggle + a small save button remain - 'Test Connection' became 'Test end-to-end': connects to the broker, subscribes, picks a random scanned movie/episode, asks jellyfin to refresh it, and waits for a matching webhook message. the UI walks through all three steps (broker reachable → jellyfin rescan triggered → webhook received) with per-step success/failure so a broken plugin config is obvious
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Hono } from "hono";
|
||||
import { getAllConfig, getConfig, getDb, getEnvLockedKeys, reseedDefaults, setConfig } from "../db/index";
|
||||
import { getUsers, testConnection as testJellyfin } from "../services/jellyfin";
|
||||
import { getUsers, refreshItem, testConnection as testJellyfin } from "../services/jellyfin";
|
||||
import { getMqttStatus, startMqttClient, testMqttConnection } from "../services/mqtt";
|
||||
import { testConnection as testRadarr } from "../services/radarr";
|
||||
import { getScheduleConfig, type ScheduleConfig, updateScheduleConfig } from "../services/scheduler";
|
||||
@@ -145,7 +145,31 @@ app.post("/mqtt/test", async (c) => {
|
||||
const topic = (body.topic ?? "jellyfin/events").trim() || "jellyfin/events";
|
||||
const password = body.password || getConfig("mqtt_password") || "";
|
||||
|
||||
const result = await testMqttConnection({ url, topic, username: (body.username ?? "").trim(), password }, 15_000);
|
||||
const jellyfinUrl = getConfig("jellyfin_url") ?? "";
|
||||
const jellyfinApiKey = getConfig("jellyfin_api_key") ?? "";
|
||||
const jellyfinUserId = getConfig("jellyfin_user_id") ?? "";
|
||||
const jfCfg = { url: jellyfinUrl, apiKey: jellyfinApiKey, userId: jellyfinUserId };
|
||||
|
||||
const triggerRefresh = async (): Promise<{ itemId: string; itemName: string } | null> => {
|
||||
if (!jellyfinUrl || !jellyfinApiKey) return null;
|
||||
// Grab any scanned movie/episode as the trigger target. Random ordering
|
||||
// so repeated tests don't keep hammering the same item.
|
||||
const row = getDb()
|
||||
.prepare("SELECT jellyfin_id, name FROM media_items WHERE type IN ('Movie', 'Episode') ORDER BY RANDOM() LIMIT 1")
|
||||
.get() as { jellyfin_id: string; name: string } | undefined;
|
||||
if (!row) return null;
|
||||
// Fire-and-poll: refreshItem blocks until Jellyfin finishes, which we
|
||||
// don't want here — the webhook fires during the refresh itself.
|
||||
// Kick it off in the background; the mqtt subscriber catches the event.
|
||||
refreshItem(jfCfg, row.jellyfin_id, 2_000).catch(() => {});
|
||||
return { itemId: row.jellyfin_id, itemName: row.name };
|
||||
};
|
||||
|
||||
const result = await testMqttConnection(
|
||||
{ url, topic, username: (body.username ?? "").trim(), password },
|
||||
triggerRefresh,
|
||||
30_000,
|
||||
);
|
||||
return c.json(result);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user