Adds a button on Facebook Event pages to download the event as an .ics file
// ==UserScript==
// @name Facebook Event → Download ICS
// @namespace https://djpanaflex.com/
// @version 1.0
// @description Adds a button on Facebook Event pages to download the event as an .ics file
// @match https://www.facebook.com/events/*
// @match https://m.facebook.com/events/*
// @grant none
// @license none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// Extract the numeric event ID from the URL path (/events/123456789012345/)
function getEventIdFromPath() {
const parts = location.pathname.split('/').filter(Boolean);
const idx = parts.indexOf('events');
if (idx !== -1 && parts[idx + 1]) {
const candidate = parts[idx + 1].replace(/\D+/g, ''); // keep digits only
if (candidate.length >= 9) return candidate; // FB event IDs are long
}
return null;
}
function buildIcsUrl(eventId) {
return `https://www.facebook.com/events/ical/export/?eid=${eventId}`;
}
// Create a small floating button (robust against FB DOM churn)
function injectButton(icsUrl) {
// Avoid duplicates
if (document.getElementById('fb-ics-download-btn')) return;
const btn = document.createElement('a');
btn.id = 'fb-ics-download-btn';
btn.href = icsUrl;
btn.target = '_blank';
btn.rel = 'noopener';
btn.textContent = 'Download ICS';
Object.assign(btn.style, {
position: 'fixed',
right: '16px',
bottom: '16px',
zIndex: 999999,
padding: '10px 14px',
borderRadius: '999px',
background: '#1877f2',
color: '#fff',
fontSize: '14px',
fontWeight: '600',
textDecoration: 'none',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
fontFamily: 'system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Arial, sans-serif',
});
btn.onmouseenter = () => (btn.style.filter = 'brightness(1.1)');
btn.onmouseleave = () => (btn.style.filter = 'none');
document.body.appendChild(btn);
}
// Because FB is SPA-ish, observe URL changes and (re)inject when on an event
let lastEventId = null;
function tryInject() {
const eid = getEventIdFromPath();
if (!eid) return;
if (eid === lastEventId && document.getElementById('fb-ics-download-btn')) return;
lastEventId = eid;
injectButton(buildIcsUrl(eid));
}
// Initial run
tryInject();
// Re-run on navigation changes
const pushState = history.pushState;
history.pushState = function () {
const ret = pushState.apply(this, arguments);
setTimeout(tryInject, 300);
return ret;
};
window.addEventListener('popstate', () => setTimeout(tryInject, 300));
// Also poll a bit, in case of dynamic loads
let tries = 0;
const iv = setInterval(() => {
tryInject();
if (++tries > 20) clearInterval(iv); // stop after a few seconds
}, 500);
})();