Mensaar Show Next Day

A userscript that switches to the meal plans for the next day when the canteen has already closed for today

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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;
  }
}