192 lines
5.1 KiB
JavaScript
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();
|
|
}
|
|
})();
|