Skip to content

Instantly share code, notes, and snippets.

@Roytangrb
Last active May 2, 2023 02:05
Show Gist options
  • Select an option

  • Save Roytangrb/7df5bd7c0321debb9df8e539662b08ea to your computer and use it in GitHub Desktop.

Select an option

Save Roytangrb/7df5bd7c0321debb9df8e539662b08ea to your computer and use it in GitHub Desktop.
Tampermonkey script to save Leetcode question No., name, URL and current code in editor to a download file
// ==UserScript==
// @name Save My Solution
// @namespace https://gist.github.com/Roytangrb/7df5bd7c0321debb9df8e539662b08ea
// @version 2.2
// @updateURL https://gist.githubusercontent.com/Roytangrb/7df5bd7c0321debb9df8e539662b08ea/raw/save-my-solution.js
// @downloadURL https://gist.githubusercontent.com/Roytangrb/7df5bd7c0321debb9df8e539662b08ea/raw/save-my-solution.js
// @description Save Leetcode question No., name, URL and current code in editor to a download file
// @author Roy Tang
// @match https://leetcode.com/problems/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=leetcode.com
// @run-at document-end
// @grant none
// ==/UserScript==
(function () {
"use strict";
var $ = document.querySelector.bind(document);
var $$ = document.querySelectorAll.bind(document);
var BTN_GROUP_DIV_ID = "fj8agdsl344";
var DOWNLOAD_BTN_ID = "fj8agdsl345";
var COPY_TITLE_BTN_ID = "fj8agdsl346";
var TEXT_COLOR = "rgba(239, 241, 246, .75)";
var AUTHOR = "RT";
// To support a new lanuage, add an entry here:
var LANG_SUPPORTED = Object.freeze({
python3: {
commentPrefix: "# ",
extension: ".py",
},
rust: {
commentPrefix: "// ",
extension: ".rs",
},
c: {
commentPrefix: "// ",
extension: ".c",
},
});
function getUrl() {
return window.location.href;
}
function isEditView() {
var url = getUrl();
var r = /^https:\/\/leetcode\.com\/problems\/[^/]*(\/description)?\/?$/;
return r.test(url);
}
function getQuestionTitle() {
return document.title.split(" - ")[0];
}
function getQuestionNumberString() {
const titleEl = Array.from($$("#qd-content span")).find(function (el) {
return (el.textContent + "").includes(".");
});
return !!titleEl ? titleEl.textContent.split(".")[0].trim() : "9999";
}
function getSelectedLanguage() {
return $(
"#qd-content div:nth-child(3) button:first-of-type"
).textContent.toLowerCase();
}
function isLangSupported() {
return LANG_SUPPORTED.hasOwnProperty(getSelectedLanguage());
}
function getFilename() {
var url = getUrl();
var kebabName = url.match(/^.*problems\/([^/]*)\/?.*$/)[1];
var lcNumber = getQuestionNumberString();
var extension = LANG_SUPPORTED[getSelectedLanguage()].extension;
return lcNumber + "-" + kebabName + extension;
}
function getOrCreateBtnGroup() {
var container = $("#" + BTN_GROUP_DIV_ID);
if (container) {
return container;
}
container = document.createElement("div");
container.id = BTN_GROUP_DIV_ID;
container.style.display = "flex";
container.style.position = "absolute";
container.style.top = "15px";
container.style.left = "150px";
container.style.zIndex = "9999";
document.body.appendChild(container);
return container;
}
function createButton(id, innerText) {
var btn = document.createElement("button");
btn.style.marginLeft = "10px";
btn.style.color = TEXT_COLOR;
btn.innerText = innerText;
btn.id = id;
return btn;
}
function insertDownloadBtn() {
var container = getOrCreateBtnGroup();
var btn = createButton(DOWNLOAD_BTN_ID, "Download my code");
container.append(btn);
return btn;
}
function insertCopyTitleBtn() {
var container = getOrCreateBtnGroup();
var btn = createButton(COPY_TITLE_BTN_ID, "Copy title");
container.append(btn);
return btn;
}
function unescapeSlash(contents) {
var replacements = { "\\\\": "\\", "\\n": "\n", '\\"': '"' };
return contents.replace(/\\(\\|n|")/g, function (replace) {
return replacements[replace];
});
}
function getCodeTextFromStorage() {
var prefix = getQuestionNumberString() + "_";
var suffix = getSelectedLanguage() + "_code";
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (key.startsWith(prefix) && key.endsWith(suffix)) {
// unescape multi-line content and remove quotes
return unescapeSlash(localStorage.getItem(key)).slice(1, -1);
}
}
console.warn("Code not found in localStorage");
return "";
}
// Get code lines from dom
function getCodeLinesFromDom() {
var lines = [];
var translates = [
[/\u00a0/g, " "], // replace &nbsp; with single space
[/\u200b/g, ""], // remove zero width space
];
$$(".view-lines .view-line").forEach(function (line) {
lines.push(
translates.reduce(function (str, rule) {
return str.replace(rule[0], rule[1]);
}, line.textContent)
);
});
return lines;
}
function generateFileHeader() {
var commentPrefix = LANG_SUPPORTED[getSelectedLanguage()].commentPrefix;
var lines = [
"Author: " + AUTHOR,
"Date: " + new Date().toISOString(),
"URL: " + getUrl(),
];
return (
lines.reduce(function (s, line) {
return s + commentPrefix + line + "\n";
}, "") + "\n\n"
);
}
function download(filename, url) {
var elm = document.createElement("a");
elm.setAttribute("href", url);
elm.setAttribute("download", filename);
document.body.appendChild(elm);
elm.click();
document.body.removeChild(elm);
setTimeout(function () {
URL.revokeObjectURL(url);
}, 100);
}
function main() {
console.log("Tampermonkey: save my leetcode solution");
if (!isEditView()) {
console.log("not in edit view");
return;
}
var downloadBtn = insertDownloadBtn();
downloadBtn.addEventListener("click", function () {
if (!isLangSupported()) {
alert(
"The selected language is not supported. Please modify the userscript."
);
return;
}
// var codeText = getCodeLinesFromDom().join("\n");
var codeText = getCodeTextFromStorage();
var filename = getFilename();
var file = new File([generateFileHeader() + codeText], filename, {
type: "text/plain",
});
var objUrl = URL.createObjectURL(file);
download(filename, objUrl);
});
var copyTitleBtn = insertCopyTitleBtn();
copyTitleBtn.addEventListener("click", function () {
navigator.clipboard
.writeText(getQuestionTitle())
.then(function () {
copyTitleBtn.innerText = "Copied";
})
.catch(console.error);
});
}
// TODO: on document ready
setTimeout(main, 5000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment