Add a button to export When2Meet availability data as CSV
// ==UserScript==
// @name When2Meet CSV Exporter
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Add a button to export When2Meet availability data as CSV
// @author Tyler Bletsch
// @match https://www.when2meet.com/*
// @grant none
// @license MIT
// ==/UserScript==
/* reverse engineering notes:
Here are the important global variables kept by when2meet:
The strings of people names:
PeopleNames (Array): [ "Abdul", … ]
An array of slots, where each entry is an array of people IDs:
AvailableAtSlot (Array): [ [ 115436591, 115438675, 115448517, … ], … ]
The actual time of each timeslot reffered to in AvailableAtSlot, as unix timestamps:
TimeOfSlot (Array): [ 1736780400, 1736781300, … ]
An array of the people ID numbers used in AvailableAtSlot, ordered in a manner correlated to PeopleNames:
PeopleIDs (Array): [ 115660081, 115436591, … ]
The currently selected timezone:
timezone (string): "America/New_York"
These are consumed by make_csv() below.
*/
(function () {
'use strict';
// Wait until the page is fully loaded
window.addEventListener('load', () => {
// Check if the make_csv function exists
console.log("Export CSV button is being added...");
function make_csv() {
let csv = "time ("+timezone+")," + PeopleNames.join(",") + "\n";
// Iterate through each time slot
for (let i = 0; i < TimeOfSlot.length; i++) {
//const time = new Date(TimeOfSlot[i] * 1000).toISOString(); // Convert UNIX timestamp to ISO string
//const time = new Date(TimeOfSlot[i] * 1000).toISOString().replace("T", " ").split(".")[0];
const time = new Date(TimeOfSlot[i] * 1000).toLocaleString("en-US", {
timeZone: timezone, // timezone is a global from when2meet
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
}).replace(",", "");
const availablePeople = new Set(AvailableAtSlot[i]); // Set of people IDs available at this time slot
// Create a row with "o" for available people
const row = [time];
for (let personID of PeopleIDs) {
row.push(availablePeople.has(personID) ? "o" : "");
}
csv += row.join(",") + "\n";
}
return csv;
}
// Create the "Export CSV" button floating in the lower right of the screen
const button = document.createElement('button');
button.innerText = 'Tampermonkey: Export CSV';
button.style.position = 'fixed';
button.style.bottom = '20px';
button.style.right = '20px';
button.style.padding = '12px 24px';
button.style.fontSize = '16px';
button.style.fontWeight = 'bold';
button.style.backgroundColor = '#007bff';
button.style.color = '#fff';
button.style.border = '2px solid #0056b3';
button.style.borderRadius = '8px';
button.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.5)';
button.style.cursor = 'pointer';
button.style.transition = 'all 0.2s ease';
button.style.zIndex = '1000';
// Add a click event to generate and download the CSV
button.addEventListener('click', () => {
try {
const csv = make_csv(); // Call the make_csv() function
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
// Create a temporary <a> element to trigger the download
const link = document.createElement('a');
link.href = url;
link.download = 'when2meet_export.csv';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Revoke the blob URL
URL.revokeObjectURL(url);
} catch (error) {
console.error("Error generating CSV:", error);
alert("Failed to generate CSV. Check the console for details.");
}
});
// Add the button to the page
document.body.appendChild(button);
});
})();