forked from GitHubMirrors/silverbullet-icalendar
Load ics sources from Space Config
This commit is contained in:
@@ -23,7 +23,7 @@ icalendar:
|
|||||||
sources:
|
sources:
|
||||||
- url: https://example.com/calendar.ics
|
- url: https://example.com/calendar.ics
|
||||||
# override calName for events from this source, otherwise X-WR-CALNAME is used
|
# override calName for events from this source, otherwise X-WR-CALNAME is used
|
||||||
calName: Example calendar
|
name: Example calendar
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -44,7 +44,6 @@ select summary, description
|
|||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- Load multiple sources from Space Config, instead of SECRETS
|
|
||||||
- Decide which properties should be exposed:
|
- Decide which properties should be exposed:
|
||||||
- Location
|
- Location
|
||||||
- Color?
|
- Color?
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"build": "silverbullet plug:compile -c deno.jsonc caldav.plug.yaml",
|
"build": "silverbullet plug:compile -c deno.jsonc icalendar.plug.yaml",
|
||||||
"watch": "silverbullet plug:compile -c deno.jsonc caldav.plug.yaml -w"
|
"watch": "silverbullet plug:compile -c deno.jsonc icalendar.plug.yaml -w"
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"rules": {
|
"rules": {
|
||||||
|
|||||||
@@ -6,3 +6,21 @@ functions:
|
|||||||
path: ./icalendar.ts:queryEvents
|
path: ./icalendar.ts:queryEvents
|
||||||
events:
|
events:
|
||||||
- query:ical-event
|
- query:ical-event
|
||||||
|
config:
|
||||||
|
schema.config.properties.icalendar:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- sources
|
||||||
|
properties:
|
||||||
|
sources:
|
||||||
|
type: array
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- url
|
||||||
|
properties:
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
|||||||
101
icalendar.ts
101
icalendar.ts
@@ -1,6 +1,5 @@
|
|||||||
import { editor } from "@silverbulletmd/silverbullet/syscalls";
|
import { editor, system } from "@silverbulletmd/silverbullet/syscalls";
|
||||||
import { QueryProviderEvent } from "@silverbulletmd/silverbullet/types";
|
import { QueryProviderEvent } from "@silverbulletmd/silverbullet/types";
|
||||||
import { readYamlPage } from "@silverbulletmd/silverbullet/lib/yaml_page";
|
|
||||||
import { applyQuery } from "@silverbulletmd/silverbullet/lib/query";
|
import { applyQuery } from "@silverbulletmd/silverbullet/lib/query";
|
||||||
import { parseIcsCalendar, type VCalendar } from "ts-ics";
|
import { parseIcsCalendar, type VCalendar } from "ts-ics";
|
||||||
|
|
||||||
@@ -13,36 +12,90 @@ interface Event {
|
|||||||
end: string | undefined;
|
end: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Source {
|
||||||
|
url: string;
|
||||||
|
name: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export async function queryEvents(
|
export async function queryEvents(
|
||||||
{ query }: QueryProviderEvent,
|
{ query }: QueryProviderEvent,
|
||||||
): Promise<any[]> {
|
): Promise<any[]> {
|
||||||
const secrets = await readYamlPage("SECRETS");
|
const events: Event[] = [];
|
||||||
const icsUrl = secrets.icsUrl;
|
|
||||||
const result = await fetch(icsUrl);
|
|
||||||
const icsData = await result.text();
|
|
||||||
const calendarParsed: VCalendar = parseIcsCalendar(icsData);
|
|
||||||
|
|
||||||
if (calendarParsed.events === undefined) {
|
const sources = await getSources();
|
||||||
editor.flashNotification("Did not parse events from iCalendar");
|
for (const source of sources) {
|
||||||
|
const identifier = (source.name === undefined || source.name === "")
|
||||||
|
? source.url
|
||||||
|
: source.name;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await fetch(source.url);
|
||||||
|
const icsData = await result.text();
|
||||||
|
|
||||||
|
const calendarParsed: VCalendar = parseIcsCalendar(icsData);
|
||||||
|
if (calendarParsed.events === undefined) {
|
||||||
|
throw new Error("Didn't parse events from ics data");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(calendarParsed.events[0], null, 2));
|
||||||
|
|
||||||
|
for (const icsEvent of calendarParsed.events) {
|
||||||
|
events.push({
|
||||||
|
summary: icsEvent.summary,
|
||||||
|
description: icsEvent.description,
|
||||||
|
// Mimic properties of pages
|
||||||
|
created: icsEvent.created
|
||||||
|
? localDateString(icsEvent.created.date)
|
||||||
|
: undefined,
|
||||||
|
lastModified: icsEvent.lastModified
|
||||||
|
? localDateString(icsEvent.lastModified.date)
|
||||||
|
: undefined,
|
||||||
|
// Consistent with formats above
|
||||||
|
start: localDateString(icsEvent.start.date),
|
||||||
|
end: icsEvent.end ? localDateString(icsEvent.end.date) : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(
|
||||||
|
`Getting events from ${identifier} failed with:`,
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return applyQuery(query, events, {}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSources(): Promise<Source[]> {
|
||||||
|
const config = await system.getSpaceConfig("icalendar", {});
|
||||||
|
|
||||||
|
if (!config.sources || !Array.isArray(config.sources)) {
|
||||||
|
console.error("Configure icalendar.sources");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const events: Event[] = calendarParsed.events.map((ics) => {
|
const sources = config.sources;
|
||||||
return {
|
|
||||||
summary: ics.summary,
|
|
||||||
description: ics.description,
|
|
||||||
// Mimic properties of pages
|
|
||||||
created: ics.created ? localDateString(ics.created.date) : undefined,
|
|
||||||
lastModified: ics.lastModified
|
|
||||||
? localDateString(ics.lastModified.date)
|
|
||||||
: undefined,
|
|
||||||
// Consistent with formats above
|
|
||||||
start: localDateString(ics.start.date),
|
|
||||||
end: ics.end ? localDateString(ics.end.date) : undefined,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return applyQuery(query, events, {}, {});
|
if (sources.length === 0) {
|
||||||
|
console.error("Empty icalendar.sources");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const validated: Source[] = [];
|
||||||
|
for (const src of sources) {
|
||||||
|
if (typeof src.url !== "string") {
|
||||||
|
console.error(
|
||||||
|
`Invalid iCalendar source`,
|
||||||
|
src,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
validated.push({
|
||||||
|
url: src.url,
|
||||||
|
name: (typeof src.name === "string") ? src.name : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return validated;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from @silverbulletmd/silverbullet/lib/dates.ts which is not exported in the package
|
// Copied from @silverbulletmd/silverbullet/lib/dates.ts which is not exported in the package
|
||||||
|
|||||||
Reference in New Issue
Block a user