- Introduced two new plugins: `jakarta-prayer-time-parser-for-ntfy` for formatting prayer times as ntfy Markdown, and `jakarta-prayer-time-today-and-tomorrow` for fetching prayer times from Kemenag for today and tomorrow. - Enhanced `ntfy.js` to support improved Markdown header handling and added a utility function for Markdown configuration validation. - Updated plugin metadata and descriptions for clarity on functionality and usage. - Implemented robust error handling and logging for better debugging and user feedback.
166 lines
4.3 KiB
JavaScript
166 lines
4.3 KiB
JavaScript
const PRAYERS = [
|
|
["imsak", "Imsak"],
|
|
["subuh", "Subuh"],
|
|
["terbit", "Terbit"],
|
|
["dhuha", "Dhuha"],
|
|
["dzuhur", "Dzuhur"],
|
|
["ashar", "Ashar"],
|
|
["maghrib", "Maghrib"],
|
|
["isya", "Isya"],
|
|
];
|
|
|
|
function passContext(ctx) {
|
|
if (ctx?.context != null && typeof ctx.context === "object" && !Array.isArray(ctx.context)) {
|
|
return { ...ctx.context };
|
|
}
|
|
return {};
|
|
}
|
|
|
|
function unwrapScalar(value) {
|
|
if (value == null) return "";
|
|
if (typeof value === "string") return value.trim();
|
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
return "";
|
|
}
|
|
|
|
function requireDay(day, label) {
|
|
if (day == null || typeof day !== "object" || Array.isArray(day)) {
|
|
throw new Error(
|
|
`parser: missing ${label} prayer-time data (run plugin/jakarta-prayer-time-today-and-tomorrow first)`,
|
|
);
|
|
}
|
|
return day;
|
|
}
|
|
|
|
function dayCaption(day, fallbackDate) {
|
|
const tanggal = unwrapScalar(day.tanggal);
|
|
if (tanggal) return tanggal;
|
|
return unwrapScalar(fallbackDate);
|
|
}
|
|
|
|
function formatDayTable(heading, day) {
|
|
const lines = [
|
|
`### ${heading}`,
|
|
"",
|
|
"| Prayer | Time |",
|
|
"| --- | --- |",
|
|
];
|
|
for (const [key, label] of PRAYERS) {
|
|
const time = unwrapScalar(day[key]) || "—";
|
|
lines.push(`| ${label} | ${time} |`);
|
|
}
|
|
return lines.join("\n");
|
|
}
|
|
|
|
async function parsePrayerTimesForNtfy(ctx) {
|
|
const data = ctx?.data && typeof ctx.data === "object" ? ctx.data : {};
|
|
const today = requireDay(data.today, "today");
|
|
const tomorrow = requireDay(data.tomorrow, "tomorrow");
|
|
const location = unwrapScalar(ctx.config?.location) || "Jakarta";
|
|
|
|
const todayCaption = dayCaption(today, data.todayDate);
|
|
const tomorrowCaption = dayCaption(tomorrow, data.tomorrowDate);
|
|
|
|
const todayHeading = todayCaption ? `Today — ${todayCaption}` : "Today";
|
|
const tomorrowHeading = tomorrowCaption
|
|
? `Tomorrow — ${tomorrowCaption}`
|
|
: "Tomorrow";
|
|
|
|
const message = [
|
|
formatDayTable(todayHeading, today),
|
|
"",
|
|
"---",
|
|
"",
|
|
formatDayTable(tomorrowHeading, tomorrow),
|
|
].join("\n");
|
|
|
|
const title = todayCaption
|
|
? `Prayer Times (${location}): ${todayCaption}`
|
|
: `Prayer Times (${location})`;
|
|
|
|
log.info(
|
|
{ location, todayCaption, tomorrowCaption },
|
|
"jakarta-prayer-time-parser-for-ntfy: formatted",
|
|
);
|
|
|
|
const output = { ok: true, title, message };
|
|
return { output, context: { ...passContext(ctx), ...output } };
|
|
}
|
|
|
|
parsePrayerTimesForNtfy.meta = {
|
|
description:
|
|
"Format today/tomorrow prayer times as ntfy Markdown (headings + tables). Set ntfy.js config.markdown to true.",
|
|
previewConfigKey: "location",
|
|
tags: ["ntfy", "Markdown", "Prayer Times"],
|
|
config: {
|
|
location: {
|
|
type: "string",
|
|
default: "Jakarta",
|
|
description: "City name used in the ntfy title",
|
|
},
|
|
},
|
|
input: {
|
|
today: {
|
|
type: "any",
|
|
required: true,
|
|
description: "Today's prayer-time record from the fetcher",
|
|
},
|
|
tomorrow: {
|
|
type: "any",
|
|
required: true,
|
|
description: "Tomorrow's prayer-time record from the fetcher",
|
|
},
|
|
todayDate: {
|
|
type: "string",
|
|
required: false,
|
|
description: "YYYY-MM-DD fallback when today.tanggal is missing",
|
|
},
|
|
tomorrowDate: {
|
|
type: "string",
|
|
required: false,
|
|
description: "YYYY-MM-DD fallback when tomorrow.tanggal is missing",
|
|
},
|
|
},
|
|
output: {
|
|
ok: { type: "boolean" },
|
|
title: { type: "string", description: "ntfy Title header" },
|
|
message: { type: "string", description: "Markdown body (headings + tables)" },
|
|
},
|
|
context: {
|
|
ok: { type: "boolean" },
|
|
title: { type: "string" },
|
|
message: { type: "string" },
|
|
},
|
|
example: {
|
|
data: {
|
|
todayDate: "2026-08-30",
|
|
tomorrowDate: "2026-08-31",
|
|
today: {
|
|
tanggal: "Minggu, 30/08/2026",
|
|
imsak: "04:32",
|
|
subuh: "04:42",
|
|
terbit: "05:57",
|
|
dhuha: "06:26",
|
|
dzuhur: "11:58",
|
|
ashar: "15:18",
|
|
maghrib: "17:58",
|
|
isya: "19:08",
|
|
},
|
|
tomorrow: {
|
|
tanggal: "Senin, 31/08/2026",
|
|
imsak: "04:32",
|
|
subuh: "04:42",
|
|
terbit: "05:57",
|
|
dhuha: "06:26",
|
|
dzuhur: "11:58",
|
|
ashar: "15:17",
|
|
maghrib: "17:58",
|
|
isya: "19:08",
|
|
},
|
|
},
|
|
config: { location: "Jakarta" },
|
|
},
|
|
};
|
|
|
|
export default parsePrayerTimesForNtfy;
|