Skip to content

Instantly share code, notes, and snippets.

@panzy
Last active September 17, 2022 19:51
Show Gist options
  • Select an option

  • Save panzy/c126371311dc166a94e611de8f45e63c to your computer and use it in GitHub Desktop.

Select an option

Save panzy/c126371311dc166a94e611de8f45e63c to your computer and use it in GitHub Desktop.
Commit your LeetCode submission to Github! Usage: This is a Tampermonkey script. Open a submission detail page and execute this script from the context menu.
// ==UserScript==
// @name LeetCode to Github
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Commit your LeetCode submission to Github! Usage: Open a submission detail page and execute this script from the context menu.
// @author Zhiyong Pan
// @match https://leetcode.com/submissions/detail/*
// @match https://leetcode.com/contest/*/submissions/detail/*
// @grant none
// @require http://code.jquery.com/jquery-1.12.4.min.js
// @require https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.min.js
// @run-at context-menu
// ==/UserScript==
(function() {
'use strict';
const $ = window.$; // avoid eslint complaining "$ not defined"
// ----------- GitHub configurations -------------
// assume the global variables have been defined by another user script.
const GITHUB_PERSONAL_ACCESS_TOKEN = window.GITHUB_PERSONAL_ACCESS_TOKEN;
const owner = window.GITHUB_OWNER;
const repo = window.GITHUB_REPO;
const author = window.AUTHOR; // used to generate file comment.
// Samples of problme link hrefs:
// /problems/check-if-number-is-a-sum-of-powers-of-three/
// https://leetcode.com/contest/biweekly-contest-47/problems/check-if-number-is-a-sum-of-powers-of-three/
// https://leetcode.com/explore/item/3755 (this is when jumping from daily challenge
let problemLink = $('a.inline-wrap[href*="/problems/"]');
if (problemLink.size() == 0) {
problemLink = $('a[href*="/explore/item/"]');
}
const title = problemLink[0].innerText;
const titleSlug = title.toLowerCase().replace(/[^\da-z ]/g, '').replace(/ +/g, '-');
const submissionId = document.location.href.split('/detail/').pop().split('/').shift(); // https://leetcode.com/submissions/detail/496294093/
const lang = $('#result_language')[0].innerText.toLowerCase();
const code = window.pageData.submissionCode;
const result_progress = $('#result_progress_row').text(); // e.g., "83 / 83 test cases passed, but took too long."
const result_status = $('#status').text(); // e.g., "Status: Time Limit Exceeded"
const result_date = $('#result_date').text(); // e.g., "11 hours, 51 minutes ago"
// extnames[lang] = source code extestion name
const extnames = { [lang]: lang, 'c++': 'cpp', 'c#': 'cs', 'javascript': 'js', 'mysql': 'sql', 'python': 'py', 'python3': 'py', 'ruby': 'rb' };
const commentPrefix = { [lang]: '//', 'bash': '#', 'mysql': '--', 'python': '#', 'python3': '#', 'ruby': '#' };
const filename = prompt('Input desitination filename:', 'Solution_' + submissionId + '.' + extnames[lang]);
if (!filename) {
console.log('cancelled');
return;
}
function queryQuestionFrontendID(titleSlug) {
let postData = {
"operationName": "questionData",
"variables": {
"titleSlug": titleSlug,
},
"query": "query questionData($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n questionId\n questionFrontendId\n}\n}\n"
};
console.log(titleSlug);
return fetch('https://leetcode.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(postData),
}).then(r => {
if (r.ok) {
return r.json().then(j => j.data.question.questionFrontendId);
} else {
throw new Error('Failed to query question frontend ID. HTTP ' + r.status);
}
});
}
queryQuestionFrontendID(titleSlug).then(questionFrontendId => {
const path = 'archives/' + titleSlug.replace(/-/g, '_') + '_' + questionFrontendId + '/' + filename;
let fileComment = commentPrefix[lang] + '\n' +
commentPrefix[lang] + ' ' + questionFrontendId + '. ' + title + '\n' +
commentPrefix[lang] + ' https://leetcode.com/problems/' + titleSlug + '/\n' +
commentPrefix[lang] + ' \n' +
commentPrefix[lang] + ' ' + result_progress + '\t' + result_status + '\n' +
commentPrefix[lang] + ` Runtime: ${window.pageData.runtime} ms\n` +
commentPrefix[lang] + ` Memory Usage: ${Math.round(window.pageData.memory / 1e6 * 10) / 10} MB\n` +
commentPrefix[lang] + ' \n' +
commentPrefix[lang] + ' --\n' +
commentPrefix[lang] + ' Created by ' + author + '\n' +
commentPrefix[lang] + ' Git commit time: ' + new Date().toLocaleString() + '\n' +
commentPrefix[lang] + ' LeetCode submit time: ' + result_date + '\n' +
commentPrefix[lang] + ' Submission detail page: ' + document.location.href + '/\n' +
commentPrefix[lang] + ' Committed with a user script: https://gist.github.com/panzy/c126371311dc166a94e611de8f45e63c\n' +
commentPrefix[lang] + '\n';
console.log(fileComment);
return fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${path}`, {
method: 'PUT',
headers: {
'Accept': 'application/vnd.github.v3+json',
'Authorization': 'token ' + GITHUB_PERSONAL_ACCESS_TOKEN,
},
body: JSON.stringify({
message: `Solved LeetCode problem ${questionFrontendId}. ${title}`,
content: Base64.encode(fileComment + code),
})
}).then(r => {
if (r.ok) {
return r.json().then(j => {
console.log('Committed to: ' + j.content.html_url + '\n\n' + j.commit.sha);
alert('Committed. See Console log for detail');
});
} else if (r.status === 422) {
return r.json().then(j => {
if (j.message === "Invalid request.\n\n\"sha\" wasn't supplied.") { // file exists
alert('This solution was already committed to GitHub before.');
} else {
throw new Error(j.message);
}
});
} else {
alert('Failed to commit. HTTP ' + r.status);
}
});
}).catch(err => {
alert('Failed to commit. ' + err.message);
console.error(err);
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment