Greasy Fork is available in English.

ScoreSaber BeatSaver Link

Adds a link to BeatSaver map on ScoreSaber and Hitbloq leaderboard pages

// ==UserScript==
// @name        ScoreSaber BeatSaver Link
// @namespace   forked_bytes
// @match       https://scoresaber.com/*
// @match       https://hitbloq.com/leaderboard/*
// @grant       none
// @version     1.1.3
// @author      forked_bytes
// @license     0BSD
// @description Adds a link to BeatSaver map on ScoreSaber and Hitbloq leaderboard pages
// ==/UserScript==

const beatsaverLink = document.createElement("a");
const beatmaps = {};

setInterval(async function() {
  if (beatsaverLink.isConnected || !location.pathname.startsWith("/leaderboard/")) return;
  const prefix = "web+bsmap://";
  const download = document.querySelector(`a[href^="${prefix}"]`);
  const hash = download?.href.substring(prefix.length);
  if (!hash) return;

  if (location.hostname === "hitbloq.com") {
    const id = download.parentNode.textContent.match(/\b([a-f0-9]{1,8})\b/)?.[1];
    if (id) {
      download.parentNode.replaceChild(getLink(id), download.parentNode.childNodes[3]);
      return;
    }
  }

  if (!beatmaps[hash]) {
    beatmaps[hash] = fetch("https://api.beatsaver.com/maps/hash/" + hash).then(r => r.json());
  }

  const beatmap = await beatmaps[hash];
  if (beatmap?.id) {
    download.parentNode?.parentNode?.appendChild(getLink(beatmap.id));
  }
}, 500);

function getLink(id) {
  beatsaverLink.href = "https://beatsaver.com/maps/" + id;
  beatsaverLink.innerHTML = `<img alt="!bsr" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEUAAADAAGe6AGm9AGrmAILnAIHbAHv/+/3/4vL/4fH/s97/sd3/kc//j87/esX/TbP/FJz/A5X/AJD9AI/M2IS5AAAAB3RSTlMAJSkrvsHAP6LsMgAAAF9JREFUeNpVz1kOgCAMRVEmiwNCofvfq8TGV+kX5yZA6nQiUXS/8ZtI8ovHkM0v1mJGgVGieZYUHMHcKgshtHPPpc8QkpYr57vPK9+jfLy2b5pZSy1qFFajJIGxftDTA2/CCDAL30DlAAAAAElFTkSuQmCC"> ${id}`;
  return beatsaverLink;
}