Fix: Final working v0.3.12 build with populated function mapping
All checks were successful
Build SilverBullet Plug / build (push) Successful in 23s

This commit is contained in:
2026-02-17 14:44:02 -08:00
parent 188cbf1254
commit 98c3b64659
5 changed files with 91 additions and 53 deletions

View File

@@ -1,8 +1,8 @@
---
name: Library/sstent/icalendar
version: 0.3.11
version: 0.3.12
tags: meta/library
files:
- icalendar.plug.js
---
iCalendar sync plug for SilverBullet.
iCalendar sync plug for SilverBullet.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,7 @@
name: icalendar
version: 0.3.11
version: 0.3.12
author: sstent
index: icalendar.ts
functions:
syncCalendars:
path: icalendar.ts:syncCalendars
@@ -7,8 +9,11 @@ functions:
forceSync:
path: icalendar.ts:forceSync
command: "iCalendar: Force Sync"
clearCache:
path: icalendar.ts:clearCache
command: "iCalendar: Clear Cache"
showVersion:
path: icalendar.ts:showVersion
command: "iCalendar: Show Version"
permissions:
- http
- http

View File

@@ -1,8 +1,8 @@
import { clientStore, config, datastore, editor, index } from "@silverbulletmd/silverbullet/syscalls";
import { convertIcsCalendar } from "https://esm.sh/ts-ics@2.4.0";
import type { IcsCalendar, IcsEvent, IcsDateObjects } from "https://esm.sh/ts-ics@2.4.0";
import type { IcsEvent } from "https://esm.sh/ts-ics@2.4.0";
const VERSION = "0.3.11";
const VERSION = "0.3.12";
const CACHE_KEY = "icalendar:lastSync";
const TIMEZONE_OFFSETS: Record<string, number> = {
@@ -19,46 +19,66 @@ const TIMEZONE_OFFSETS: Record<string, number> = {
"None": 0
};
export async function syncCalendars() {
const rawConfig = await config.get("icalendar", { sources: [] });
let sources: any[] = rawConfig.sources || [];
let tzShift = rawConfig.tzShift || 0;
if (sources.length === 0) return;
await editor.flashNotification("Syncing calendars...", "info");
const allEvents: any[] = [];
for (const source of sources) {
const response = await fetch(source.url);
const text = await response.text();
const calendar = convertIcsCalendar(undefined, text);
if (!calendar.events) continue;
for (const icsEvent of calendar.events) {
const obj = icsEvent.start;
let wallTimeStr = "";
if (obj.local && typeof obj.local.date === "string") wallTimeStr = obj.local.date;
else if (typeof obj.date === "string") wallTimeStr = obj.date;
const baseDate = new Date(wallTimeStr.replace("Z", "") + "Z");
const tzName = obj.local?.timezone || obj.timezone || "UTC";
const sourceOffset = TIMEZONE_OFFSETS[tzName] ?? 0;
const utcMillis = baseDate.getTime() - (sourceOffset * 3600000);
const finalDate = new Date(utcMillis + (tzShift * 3600000));
const pad = (n: number) => String(n).padStart(2, "0");
const localIso = finalDate.getFullYear() + "-" + pad(finalDate.getMonth() + 1) + "-" + pad(finalDate.getDate()) + "T" + pad(finalDate.getHours()) + ":" + pad(finalDate.getMinutes()) + ":" + pad(finalDate.getSeconds());
allEvents.push({
...icsEvent,
start: localIso,
tag: "ical-event",
sourceName: source.name
});
}
async function getSources(): Promise<{ sources: any[], tzShift: number }> {
try {
const rawConfig = await config.get("icalendar", { sources: [] });
const sources = rawConfig.sources || [];
const tzShift = rawConfig.tzShift || 0;
return { sources, tzShift };
} catch (e) {
return { sources: [], tzShift: 0 };
}
}
async function fetchAndParseCalendar(source: any, hourShift = 0): Promise<any[]> {
const response = await fetch(source.url);
if (!response.ok) return [];
const text = await response.text();
const calendar = convertIcsCalendar(undefined, text);
if (!calendar.events) return [];
const events: any[] = [];
for (const icsEvent of calendar.events) {
const obj = icsEvent.start;
let wallTimeStr = "";
if (obj.local && typeof obj.local.date === "string") wallTimeStr = obj.local.date;
else if (typeof obj.date === "string") wallTimeStr = obj.date;
if (!wallTimeStr) continue;
const baseDate = new Date(wallTimeStr.replace("Z", "") + "Z");
const tzName = obj.local?.timezone || obj.timezone || "UTC";
const sourceOffset = TIMEZONE_OFFSETS[tzName] ?? 0;
const utcMillis = baseDate.getTime() - (sourceOffset * 3600000);
const finalDate = new Date(utcMillis + (hourShift * 3600000));
const pad = (n: number) => String(n).padStart(2, "0");
const localIso = finalDate.getFullYear() + "-" + pad(finalDate.getMonth() + 1) + "-" + pad(finalDate.getDate()) + "T" + pad(finalDate.getHours()) + ":" + pad(finalDate.getMinutes()) + ":" + pad(finalDate.getSeconds());
events.push({
...icsEvent,
start: localIso,
tag: "ical-event",
sourceName: source.name
});
}
return events;
}
export async function syncCalendars() {
try {
const { sources, tzShift } = await getSources();
if (sources.length === 0) return;
await editor.flashNotification("Syncing calendars...", "info");
const allEvents: any[] = [];
for (const source of sources) {
const events = await fetchAndParseCalendar(source, tzShift);
allEvents.push(...events);
}
await index.indexObjects("$icalendar", allEvents);
await editor.flashNotification(`Synced ${allEvents.length} events`, "info");
} catch (err) {
console.error("Sync failed:", err);
}
await index.indexObjects("$icalendar", allEvents);
await editor.flashNotification(`Synced ${allEvents.length} events`, "info");
}
export async function forceSync() {
@@ -66,6 +86,19 @@ export async function forceSync() {
await syncCalendars();
}
export async function clearCache() {
if (!await editor.confirm("Clear all calendar events?")) return;
const pageKeys = await datastore.query({ prefix: ["ridx", "$icalendar"] });
const allKeys: any[] = [];
for (const { key } of pageKeys) {
allKeys.push(key);
allKeys.push(["idx", ...key.slice(2), "$icalendar"]);
}
if (allKeys.length > 0) await datastore.batchDel(allKeys);
await clientStore.del(CACHE_KEY);
await editor.flashNotification("Calendar index cleared", "info");
}
export async function showVersion() {
await editor.flashNotification(`iCalendar Plug ${VERSION}`, "info");
}
}