Skip to content

Instantly share code, notes, and snippets.

@sorah
Last active December 2, 2025 17:23
Show Gist options
  • Select an option

  • Save sorah/fc1ecae203dbdb45bdd50496e8488454 to your computer and use it in GitHub Desktop.

Select an option

Save sorah/fc1ecae203dbdb45bdd50496e8488454 to your computer and use it in GitHub Desktop.
reinvent25-rainfocus-calendar-more-data.user.js

user script for re:Invent 2025 event portal to improve its calendar by:

  • show code, type and venue on the calendar directly
  • highlight sessions where isn't a breakout session and you have no reserved seat

Confirmed working with Tampermonkey.

before

image

after

image
// ==UserScript==
// @name reinvent2025 calendar show session data
// @namespace http://tampermonkey.net/
// @version 2025-12-01
// @author sorah
// @match https://registration.awsevents.com/flow/awsevents/reinvent2025/calendar/page/calendar
// @icon https://www.google.com/s2/favicons?sz=64&domain=awsevents.com
// @grant none
// ==/UserScript==
(function () {
"use strict";
let myData = null;
let sessions = null;
const getSessions = (data) => {
const newSessions = [];
const mapSession = (s) => {
if (!s.times) {
console.warn("no times", s);
return null;
}
if (s.times?.length > 1) console.warn("multiple times", s);
const time = s.times[0];
const retval = {
sessionID: s.sessionID,
code: s.code,
title: s.title,
time,
date: time.daySort,
startTime: time.startTimeFormatted.replace(/^0(\d):/, "$1:"),
endTime: time.endTimeFormatted.replace(/^0(\d):/, "$1:"),
type: s.attributevalues?.find((a) => a.attribute == "Type")?.value,
venue: s.attributevalues?.find((a) => a.attribute == "Venue")?.value,
};
retval.matcher = new RegExp(
`^${retval.startTime} - ${retval.endTime}[^:]+: ${RegExp.escape(
retval.title
)}`
);
return retval;
};
data.mySchedule?.forEach((s) => {
if (s.type !== "Enrolled") return;
newSessions.push(mapSession(s));
});
data.sessionInterests?.forEach((s) => {
newSessions.push(mapSession(s));
});
return newSessions.filter((s) => s);
};
const startObserver = () => {
const action = (session, el) => {
const sub =
el.querySelector(".srh-session-meta") || document.createElement("div");
sub.innerHTML = "";
sub.classList.add("srh-session-meta");
[session.code, session.type, `@ ${session.venue}`].forEach((t) => {
const p = document.createElement("p");
p.appendChild(document.createTextNode(t));
sub.appendChild(p);
});
el.querySelector(".rbc-event-content")?.appendChild(sub);
if (!el.classList.contains("enrolled")) {
if (session.type !== "Breakout session") {
el.style.backgroundColor = "#6f6191";
} else {
el.style.backgroundColor = null;
}
} else {
el.style.backgroundColor = null;
}
};
const remove = (el) => {
el.querySelectorAll(".srh-session-meta").forEach((e) => e.remove());
el.style.backgroundColor = null;
};
const check = (el) => {
if (!sessions) return;
if (!el.classList.contains("schedule-calendar-session")) {
remove(el);
return;
}
const daySlot = el.closest(".rbc-day-slot");
if (!daySlot) return;
const m = daySlot
.querySelector("button.rbc-time-slot")
?.dataset.test?.match(/\d{4}\d{2}\d{2}/);
if (!m) return;
const date = m[0];
const session = sessions.find((s) => {
const mt = s.matcher.test(el.title);
const md = s.date === date;
return mt && md;
});
if (!session) {
console.warn({ date, el });
remove(el);
return;
}
action(session, el);
};
const observer2 = new window.MutationObserver(function (set) {
set.forEach((mutation) => {
if (mutation.target.nodeType == 3) {
const node = mutation.target.parentElement;
const sessionEl = node.classList.contains("schedule-calendar-session")
? node
: node.closest(".schedule-calendar-session");
if (sessionEl) check(sessionEl);
}
});
});
const observer = new window.MutationObserver(function (set) {
set.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType == 1) {
const sessionEls = node.classList.contains(
"schedule-calendar-session"
)
? [node]
: Array.from(node.querySelectorAll(".schedule-calendar-session"));
sessionEls.forEach((el) => {
check(el);
observer2.observe(el, {
childList: true,
subtree: true,
characterData: true,
});
});
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
document
.querySelectorAll(".schedule-calendar-session")
.forEach((x) => check(x));
};
const getMyData = () => {
const authToken = window.authToken;
const apiProfileId = window.widget?.apiToken;
const widgetId = window.widget?.widgetId;
const domain = window.vanityDomains?.events;
if (!authToken || !apiProfileId || !widgetId || !domain) {
setTimeout(getMyData, 500);
return;
}
fetch(`https://${domain}/api/myData`, {
method: "post",
body: null,
credentials: "include",
headers: {
rfapiprofileid: apiProfileId,
rfauthtoken: authToken,
rfwidgetid: widgetId,
},
})
.then((r) => r.json())
.then((j) => {
myData = j;
sessions = getSessions(j);
startObserver();
});
};
setTimeout(getMyData, 500);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment