Fetch Calendar Flight Events
Fetch calendar events pre-filtered for flight-related keywords and patterns
Source Code
import fs from "fs";
import path from "path";
const [yearsBack = "3", outputPath = "session/calendar-flights.json"] =
process.argv.slice(2);
const yearsNum = parseInt(yearsBack) || 3;
// Calculate date range
const endDate = new Date();
const startDate = new Date();
startDate.setFullYear(startDate.getFullYear() - yearsNum);
console.log(`Fetching calendar events from the last ${yearsNum} years...`);
console.log(
`Date range: ${startDate.toISOString().split("T")[0]} to ${endDate.toISOString().split("T")[0]}`
);
try {
// Get user's timezone first
const calRes = await fetch(
"https://www.googleapis.com/calendar/v3/calendars/primary",
{ headers: { Authorization: "Bearer PLACEHOLDER_TOKEN" } }
);
const calData = await calRes.json();
if (calData.error)
throw new Error(`Calendar info failed: ${calData.error.message}`);
const userTimezone = calData.timeZone;
console.log(` User timezone: ${userTimezone}`);
// Fetch all events with pagination
const events = [];
let pageToken = null;
do {
const params = new URLSearchParams({
timeMin: startDate.toISOString(),
timeMax: endDate.toISOString(),
singleEvents: "true",
orderBy: "startTime",
maxResults: "250",
});
if (pageToken) params.set("pageToken", pageToken);
const res = await fetch(
`https://www.googleapis.com/calendar/v3/calendars/primary/events?${params}`,
{ headers: { Authorization: "Bearer PLACEHOLDER_TOKEN" } }
);
const data = await res.json();
if (data.error)
throw new Error(`Events fetch failed: ${data.error.message}`);
events.push(...(data.items || []));
pageToken = data.nextPageToken;
console.log(` Fetched ${events.length} events so far...`);
} while (pageToken);
console.log(`\nTotal events found: ${events.length}`);
// Filter for potential flight-related events
const flightKeywords = [
"flight",
"fly",
"flying",
"airport",
"airline",
"→",
"->",
"depart",
"arrive",
"boarding",
"terminal",
"gate",
"layover",
"connection",
];
// Also look for airport codes (3 uppercase letters)
const airportCodePattern = /\b[A-Z]{3}\b/;
const potentialFlightEvents = events.filter((e) => {
if (e.status === "cancelled") return false;
const title = (e.summary || "").toLowerCase();
const description = (e.description || "").toLowerCase();
const location = (e.location || "").toLowerCase();
const combined = `${title} ${description} ${location}`;
// Check keywords
const hasKeyword = flightKeywords.some((kw) => combined.includes(kw));
// Check for airport codes in original (case-sensitive) text
const originalText = `${e.summary || ""} ${e.description || ""} ${e.location || ""}`;
const hasAirportCode = airportCodePattern.test(originalText);
// Check for arrow patterns suggesting routes
const hasRoute = /\s*[-→>]\s*/.test(e.summary || "");
return hasKeyword || hasAirportCode || hasRoute;
});
console.log(` Potential flight events: ${potentialFlightEvents.length}`);
// Process events for output
const processedEvents = potentialFlightEvents.map((event) => {
const isAllDay = !event.start?.dateTime;
const startTime = event.start?.dateTime || event.start?.date;
const endTime = event.end?.dateTime || event.end?.date;
return {
id: event.id,
title: event.summary || "(No title)",
start: startTime,
end: endTime,
isAllDay,
timezone: event.start?.timeZone || userTimezone,
location: event.location || null,
description: event.description || null,
isRecurring: !!event.recurringEventId,
};
});
// Sort by start time
processedEvents.sort((a, b) => new Date(a.start) - new Date(b.start));
// Compute date range of results
const eventDates = processedEvents
.map((e) => new Date(e.start))
.filter((d) => !isNaN(d.getTime()));
const dateRange =
eventDates.length > 0
? {
oldest: eventDates[0].toISOString().split("T")[0],
newest: eventDates[eventDates.length - 1].toISOString().split("T")[0],
}
: null;
// Ensure output directory exists
const dir = path.dirname(outputPath);
if (dir && dir !== ".") fs.mkdirSync(dir, { recursive: true });
// Build output
const output = {
query: {
start: startDate.toISOString().split("T")[0],
end: endDate.toISOString().split("T")[0],
yearsBack: yearsNum,
},
timezone: userTimezone,
fetchedAt: new Date().toISOString(),
totalEventsScanned: events.length,
count: processedEvents.length,
dateRange,
events: processedEvents,
};
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
console.log(`\n✓ Found ${processedEvents.length} potential flight events`);
console.log(` Written to: ${outputPath}`);
if (dateRange) {
console.log(` Date range: ${dateRange.oldest} to ${dateRange.newest}`);
}
// Log sample titles
if (processedEvents.length > 0) {
console.log(`\n Sample events:`);
processedEvents.slice(0, 5).forEach((e) => {
const date = e.start.split("T")[0];
console.log(` - [${date}] ${e.title.slice(0, 50)}`);
});
}
console.log(
JSON.stringify({
success: true,
outputPath,
totalScanned: events.length,
count: processedEvents.length,
dateRange,
})
);
} catch (error) {
console.error("Error fetching calendar events:", error.message);
throw error;
}