Skip to content

Instantly share code, notes, and snippets.

@Boettner-eric
Last active March 3, 2025 20:07
Show Gist options
  • Save Boettner-eric/41cabaa207ba4d257478f1d9a7985db2 to your computer and use it in GitHub Desktop.
Save Boettner-eric/41cabaa207ba4d257478f1d9a7985db2 to your computer and use it in GitHub Desktop.
Obsidian google calendar template
const fs = require("fs").promises;
const path = require("path");
const TOKEN_PATH = "path to google token files";
async function calendar() {
try {
const files = await fs.readdir(TOKEN_PATH);
const tokenFiles = files.filter((file) => file.endsWith(".json"));
if (tokenFiles.length === 0) {
console.log("No token files found in directory");
return "";
}
const allEvents = [];
for (const file of tokenFiles) {
const filePath = path.join(TOKEN_PATH, file);
const accessToken = await getAccessToken(filePath);
if (accessToken) {
const events = await listEvents(accessToken);
if (events) {
allEvents.push(...events);
}
}
}
return format_events(allEvents);
} catch (error) {
console.error("Error reading calendar events:", error);
return "";
}
}
function format_time(date) {
return `${date.getHours()}:${String(date.getMinutes()).padStart(2, "0")}`;
}
async function listEvents(accessToken) {
const today = new Date();
const tomorrow = new Date();
tomorrow.setHours(23, 59, 59, 999);
const params = new URLSearchParams({
calendarId: "primary",
timeMin: today.toISOString(),
timeMax: tomorrow.toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: "startTime",
});
const data = await fetch({
url: `https://www.googleapis.com/calendar/v3/calendars/primary/events?${params.toString()}`,
method: "GET",
headers: { authorization: accessToken },
});
const events = data.items;
if (!events || events.length === 0) {
console.log("No upcoming events found.");
return [];
}
return events;
}
function format_events(events) {
return events.reduce((acc, event) => {
const startTime = new Date(event.start.dateTime || event.start.date);
startTime.toLocaleTimeString("en-US", { timeZone: "America/Los_Angeles" });
return acc + `- ${event.summary} @ ${format_time(startTime)}\n`;
}, "");
}
async function getAccessToken(path) {
try {
const content = await fs.readFile(path);
const credentials = JSON.parse(content);
const resp = await fetch({
url: "https://oauth2.googleapis.com/token",
method: "POST",
contentType: "application/x-www-form-urlencoded",
body: new URLSearchParams({
client_id: credentials.client_id,
client_secret: credentials.client_secret,
refresh_token: credentials.refresh_token,
grant_type: "refresh_token",
}).toString(),
});
const { access_token, _expires_in, _id_token, _scope, token_type } = resp;
return token_type + " " + access_token;
} catch (err) {
console.log(err);
return null;
}
}
async function fetch(request) {
try {
const response = await requestUrl(request);
if (response.status != 200) {
throw new Error(`Response status: ${response.status}`);
}
return response.json;
} catch (error) {
console.error(error.message);
}
}
module.exports = calendar;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment