A userscript that switches to the meal plans for the next day when the canteen has already closed for today
// ==UserScript==
// @name Mensaar Show Next Day
// @namespace https://github.com/ikelax/userscripts
// @match https://mensaar.de/
// @grant none
// @version 0.4.0
// @author Alexander Ikonomou
// @description A userscript that switches to the meal plans for the next day when the canteen has already closed for today
// @license MIT
// @require https://update.greasyfork.org/scripts/502635/1422102/waitForKeyElements-CoeJoder-fork.js
// @supportURL https://github.com/ikelax/userscripts/issues
// @copyright 2025, Alexander Ikonomou (https://github.com/ikelax)
// @homepageURL https://github.com/ikelax/userscripts
// @homepage https://github.com/ikelax/userscripts
// @contributionURL https://github.com/ikelax/userscripts
// @collaborator ikelax
// @icon https://mensaar.de/img/icon.png
// ==/UserScript==
waitForKeyElements("div.active", switchToNextDay);
function switchToNextDay(activeTab) {
const tabDate = activeTab.innerText;
if (tabDate == undefined) {
return;
}
const canteen = window.location.hash.replace("#/menu/", "");
if (!["sb", "htwcas", "musiksb"].includes(canteen)) {
return;
}
const closingTime = getClosingTime(canteen, tabDate);
if (closingTime === undefined) {
return;
}
const now = new Date();
if (now > closingTime) {
activeTab.nextSibling?.click();
}
}
/***********************************************************
*
* The code below is copied from `utils/getClosingTime.js`.
* If you make any changes to the code, please copy them to
* `utils/getClosingTime.js`.
*
* For the reasons, see commit c47a8305a7a5163d638becc2c169.
*
**********************************************************/
/**
* Converts a German date in the format "Weekday, Day. Month
* Year" to "Day. Month Year", translating the month into
* English.
*
* @param {string} date The date string to convert
* @returns {string | undefined} The converted date string or undefined if the
* date string was not in the expected format
*/
function convertDate(date) {
const germanDate = date.split(", ")[1];
return germanDate
?.replace("Januar", "January")
?.replace("Februar", "February")
?.replace("März", "March")
?.replace("Mai", "May")
?.replace("Juni", "June")
?.replace("Juli", "July")
?.replace("Oktober", "October")
?.replace("Dezember", "December");
}
/**
* Depending on the weekday, the canteens close at different
* times. For the closing times see also the
* {@link https://www.stw-saarland.de/gastro/ page of the Studentenwerk}.
*
* The closing time of the canteen is the closing time of
* the latest counter. For example, for the canteen at the
* Saarland University, this means that it is the closing
* time of the counter for Menü 1 and Menü 2.
*
* `dateString` is expected to be a string in the format
* "Weekday, Day. Month Year" in German.
*
* @param {"sb" | "htwcas" | "musiksb"} canteen The canteen
* @param {string} dateString The date string of the day in
* the specified format
* @returns {Date | undefined} The closing time for the
* `canteen` and the day or undefined if the `dateString`
* was not in the expected format
*/
function getClosingTime(canteen, dateString) {
const convertedDateString = convertDate(dateString);
if (convertedDateString === undefined) {
return;
}
const convertedDate = new Date(convertedDateString);
let closingMinutes = getClosingMinutes(canteen, convertedDate.getDay());
return new Date(
convertedDate.getFullYear(),
convertedDate.getMonth(),
convertedDate.getDate(),
14,
closingMinutes,
);
}
/**
* The function does not check whether `canteen` is one of
* the specified strings.
*
* @param {"sb" | "htwcas" | "musiksb"} canteen The canteen
* @param {number} day The day of the week in the same
* enumeration as the `getDay` property of `Date`
* @returns {0 | 15 | 30} The minutes of the closing time
* for the `canteen` and the day
*/
function getClosingMinutes(canteen, day) {
switch (canteen) {
case "musiksb":
return 0;
case "htwcas":
return 15;
case "sb":
// The canteen closes 15 minutes earlier on Fridays.
return day === 5 ? 15 : 30;
}
}