Last active
September 17, 2022 19:51
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==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