userscripts/leetray/LeetRay.user.js

192 lines
5.1 KiB
JavaScript

// ==UserScript==
// @name LeetRay
// @namespace http://tampermonkey.net/
// @version 2023-01-05T01:00:39+05:30
// @description Take beautiful screenshots of your code in Leetcode instantly with Ray.so
// @updateURL https://git.sangeeth.dev/x/userscripts/raw/branch/main/leetray/LeetRay.user.js
// @downloadURL https://git.sangeeth.dev/x/userscripts/raw/branch/main/leetray/LeetRay.user.js
// @author Sangeeth Sudheer
// @match https://leetcode.com/problems/*
// @match https://www.leetcode.com/problems/*
// @match https://www.ray.so/*
// @match https://ray.so/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=leetcode.com
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// @grant GM_log
// @grant GM_getTab
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @grant unsafeWindow
// @grant window.close
// @grant window.focus
// ==/UserScript==
(function () {
"use strict";
let uwindow = unsafeWindow;
function isLeetcode() {
return location.hostname === "leetcode.com";
}
function isRayso() {
return location.hostname === "www.ray.so";
}
function waitForRaysoLoad() {
return new Promise((resolve) => {
let id = GM_addValueChangeListener("leetray.rayso.loaded", () => {
resolve();
GM_removeValueChangeListener(id);
});
});
}
function waitForRaysoExit() {
return new Promise((resolve) => {
let id = GM_addValueChangeListener("leetray.rayso.exit", () => {
resolve();
GM_removeValueChangeListener(id);
});
});
}
async function waitTillFocused() {
return new Promise((resolve) => {
setTimeout(function check() {
if (document.visibilityState === "visible") {
resolve();
} else {
setTimeout(check, 500);
}
}, 500);
});
}
function debug(stuff) {
GM_log(`LeetRay DEBUG ${stuff}`);
}
function error(stuff) {
GM_log(`LeetRay ERROR ${stuff}`);
}
async function isClipboardAllowedForRobots() {
try {
await navigator.clipboard.writeText("");
return true;
} catch (e) {
error(e);
return false;
}
}
function leetcodeMain() {
const menu_command_id = GM_registerMenuCommand(
"Copy screenshot",
async function (event) {
if (!uwindow.monaco?.editor) {
error("monaco.editor not found");
return;
}
const monacoEditorEl = document.querySelector(
".monaco-editor[data-uri]"
);
const editorKey = monacoEditorEl.dataset.uri;
const monacoModel = uwindow.monaco.editor.getModel(editorKey);
const colors = {
rust: "sunset",
python: "raindrop",
python3: "raindrop",
cpp: "midnight",
scala: "sunset",
javascript: "sunset",
typescript: "raindrop",
};
const sourceCode = monacoModel.getValue();
debug("Source code value from editor:");
debug(sourceCode);
const language =
monacoModel._languageId === "python3"
? "python"
: monacoModel._languageId;
const title = uwindow.__NEXT_DATA__.query.slug;
const raysoURL = new URL("https://www.ray.so");
raysoURL.hash = "__leetray";
raysoURL.searchParams.append("code", btoa(sourceCode));
raysoURL.searchParams.append("title", title);
raysoURL.searchParams.append("padding", 16);
language && raysoURL.searchParams.append("language", language);
language && raysoURL.searchParams.append("colors", colors[language]);
debug(`Opening URL: ${raysoURL.toString()}`, {
active: true,
setParent: true,
});
const handler = GM_openInTab(raysoURL.toString());
await waitForRaysoLoad();
GM_setValue("leetray.screenshot", Date.now());
await waitForRaysoExit();
if (GM_getValue("leetray.clip")) {
window.focus();
}
handler.onclose = () => {
alert("Copied screenshot");
};
},
"s"
);
}
async function raysoCopyScreenshot() {
debug("Copying screenshot");
document.querySelector("#app div.setting.export a:nth-child(3)").click();
// TODO: flaky mostly
await new Promise((resolve) => setTimeout(resolve, 1000));
}
function raysoMain() {
GM_setValue("leetray.rayso.loaded", Date.now());
let id = GM_addValueChangeListener("leetray.screenshot", async () => {
window.focus();
await waitTillFocused();
const cbAllowed = await isClipboardAllowedForRobots();
await raysoCopyScreenshot();
GM_removeValueChangeListener(id);
GM_setValue("leetray.rayso.exit", Date.now());
GM_setValue("leetray.clip", cbAllowed);
if (cbAllowed) {
uwindow.close();
}
});
}
debug("Starting");
if (isLeetcode()) {
leetcodeMain();
} else if (isRayso()) {
raysoMain();
}
})();