When2Meet CSV Exporter

Add a button to export When2Meet availability data as CSV

  1. // ==UserScript==
  2. // @name When2Meet CSV Exporter
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Add a button to export When2Meet availability data as CSV
  6. // @author Tyler Bletsch
  7. // @match https://www.when2meet.com/*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. /* reverse engineering notes:
  13.  
  14. Here are the important global variables kept by when2meet:
  15.  
  16. The strings of people names:
  17. PeopleNames (Array): [ "Abdul", … ]
  18.  
  19. An array of slots, where each entry is an array of people IDs:
  20. AvailableAtSlot (Array): [ [ 115436591, 115438675, 115448517, … ], … ]
  21.  
  22. The actual time of each timeslot reffered to in AvailableAtSlot, as unix timestamps:
  23. TimeOfSlot (Array): [ 1736780400, 1736781300, … ]
  24.  
  25. An array of the people ID numbers used in AvailableAtSlot, ordered in a manner correlated to PeopleNames:
  26. PeopleIDs (Array): [ 115660081, 115436591, … ]
  27.  
  28. The currently selected timezone:
  29. timezone (string): "America/New_York"
  30.  
  31. These are consumed by make_csv() below.
  32. */
  33.  
  34. (function () {
  35. 'use strict';
  36.  
  37. // Wait until the page is fully loaded
  38. window.addEventListener('load', () => {
  39. // Check if the make_csv function exists
  40. console.log("Export CSV button is being added...");
  41. function make_csv() {
  42. let csv = "time ("+timezone+")," + PeopleNames.join(",") + "\n";
  43.  
  44. // Iterate through each time slot
  45. for (let i = 0; i < TimeOfSlot.length; i++) {
  46. //const time = new Date(TimeOfSlot[i] * 1000).toISOString(); // Convert UNIX timestamp to ISO string
  47. //const time = new Date(TimeOfSlot[i] * 1000).toISOString().replace("T", " ").split(".")[0];
  48. const time = new Date(TimeOfSlot[i] * 1000).toLocaleString("en-US", {
  49. timeZone: timezone, // timezone is a global from when2meet
  50. year: "numeric",
  51. month: "2-digit",
  52. day: "2-digit",
  53. hour: "2-digit",
  54. minute: "2-digit",
  55. second: "2-digit",
  56. hour12: false,
  57. }).replace(",", "");
  58. const availablePeople = new Set(AvailableAtSlot[i]); // Set of people IDs available at this time slot
  59.  
  60. // Create a row with "o" for available people
  61. const row = [time];
  62. for (let personID of PeopleIDs) {
  63. row.push(availablePeople.has(personID) ? "o" : "");
  64. }
  65.  
  66. csv += row.join(",") + "\n";
  67. }
  68. return csv;
  69. }
  70.  
  71. // Create the "Export CSV" button floating in the lower right of the screen
  72. const button = document.createElement('button');
  73. button.innerText = 'Tampermonkey: Export CSV';
  74. button.style.position = 'fixed';
  75. button.style.bottom = '20px';
  76. button.style.right = '20px';
  77. button.style.padding = '12px 24px';
  78. button.style.fontSize = '16px';
  79. button.style.fontWeight = 'bold';
  80. button.style.backgroundColor = '#007bff';
  81. button.style.color = '#fff';
  82. button.style.border = '2px solid #0056b3';
  83. button.style.borderRadius = '8px';
  84. button.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.5)';
  85. button.style.cursor = 'pointer';
  86. button.style.transition = 'all 0.2s ease';
  87. button.style.zIndex = '1000';
  88.  
  89. // Add a click event to generate and download the CSV
  90. button.addEventListener('click', () => {
  91. try {
  92. const csv = make_csv(); // Call the make_csv() function
  93. const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
  94. const url = URL.createObjectURL(blob);
  95.  
  96. // Create a temporary <a> element to trigger the download
  97. const link = document.createElement('a');
  98. link.href = url;
  99. link.download = 'when2meet_export.csv';
  100. link.style.display = 'none';
  101. document.body.appendChild(link);
  102. link.click();
  103. document.body.removeChild(link);
  104.  
  105. // Revoke the blob URL
  106. URL.revokeObjectURL(url);
  107. } catch (error) {
  108. console.error("Error generating CSV:", error);
  109. alert("Failed to generate CSV. Check the console for details.");
  110. }
  111. });
  112.  
  113. // Add the button to the page
  114. document.body.appendChild(button);
  115. });
  116. })();