您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
The primary aim of this script is to identify in what coding language the user has written the code. For v1, I only consider the first result.
当前为
您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
- // ==UserScript==
- // @name Leetcode Contest Language reavealer
- // @namespace http://tampermonkey.net/
- // @version 1.2
- // @description The primary aim of this script is to identify in what coding language the user has written the code. For v1, I only consider the first result.
- // @author Rupesh Dabbir
- // @license MIT
- // @namespace https://github.com/rupeshdabbir
- // @include https://leetcode.com/contest/*/ranking/*
- // @include https://leetcode.com/contest/*
- // @match https://leetcode.com/contest/weekly-contest-*/ranking*/*
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
- (function() {
- let firstLoad = false;
- const pageURLCheckTimer = setInterval(
- function() {
- if (this.lastPathStr !== location.pathname ||
- this.lastQueryStr !== location.search ||
- this.lastPathStr === null ||
- this.lastQueryStr === null
- ) {
- this.lastPathStr = location.pathname;
- this.lastQueryStr = location.search;
- gmMain();
- }
- }, 222
- );
- function gmMain() {
- const isRanking = window.location.pathname.split('ranking').length > 1;
- if (isRanking && !firstLoad) {
- firstLoad = true;
- initMagic();
- }
- }
- function initMagic() {
- /* Promisified Helper method that waits for a particular DOM elem to be loaded */
- const waitFor = (...selectors) => new Promise(resolve => {
- const delay = 500
- const f = () => {
- const elements = selectors.map(selector => document.querySelector(selector))
- if (elements.every(element => element != null)) {
- resolve(elements)
- } else {
- setTimeout(f, delay)
- }
- }
- f()
- })
- /* When Pagination has been clicked */
- waitFor('.pagination').then(([table]) => {
- $('.pagination').click(function() {
- $('.td-lang-data').remove();
- $('.td-my-data').remove();
- $('.rupesh-loader').css('display', 'block');
- setTimeout(() => { // Time for window.location.href to update.
- doAjax();
- }, 1000);
- });
- });
- /*
- * When Table has been loaded, add the language barrier! ;-)
- */
- waitFor('thead > tr').then(([table]) => {
- $('thead > tr').append('<th class="language-bar"> Language</th>');
- addLoader();
- doAjax();
- });
- /*
- * Helper to add Spinner on page.
- * Note: Once this component has been initialized, it'll stay on the page with
- * CSS display being 'none'. Thus, can be re-used without further DOM manipulation.
- * TODO: Refactor and move all the inline styling to CSS class.
- */
- function addLoader() {
- $('tbody > tr').each(function(i) {
- if (i > 0) {
- const img = document.createElement('img');
- img.src = "https://image.ibb.co/bLqPSf/Facebook-1s-200px.gif";
- img.width = "50";
- img.height = "50";
- img.style = "margin-left: 10px";
- img.classList.add("rupesh-loader");
- $('tbody > tr')[i].append(img);
- }
- });
- }
- function getLastUrlPath() {
- let locationLastPart = window.location.pathname
- if (locationLastPart.substring(locationLastPart.length - 1) == "/") {
- locationLastPart = locationLastPart.substring(0, locationLastPart.length - 1);
- }
- locationLastPart = locationLastPart.substr(locationLastPart.lastIndexOf('/') + 1);
- if (isNaN(+locationLastPart)) return "1";
- return +locationLastPart;
- }
- /*
- * @param AJAX with url.
- * @returns JSON that contains ID's that can be further fetched to find Lang metadata.
- */
- function doAjax() {
- const contextSuffix = window.location.href.split('/').filter((val) => val.indexOf('weekly-contest') > -1)[0];
- const page = getLastUrlPath();
- const url = `https://leetcode.com/contest/api/ranking/${contextSuffix}/?pagination=${page}`;
- // console.log("You are on page:", page);
- // console.info("The Url before making req:", url);
- fetch(url)
- .then((resp) => resp.json())
- .then(function(data) {
- //console.log("Ranking API data return", data);
- fetchSubmissionIDS(data);
- });
- }
- function fetchSubmissionIDS(data) {
- const ids = [];
- data.submissions.forEach((submission) => {
- const one = Object.values(submission)[0];
- const id = one.submission_id;
- ids.push(id);
- });
- //console.log("Submission ID's are: ", ids);
- fetchLanguageInfo(ids);
- }
- function doSyncCall(id) {
- const url = 'https://leetcode.com/api/submissions/';
- return new Promise((resolve, reject) => {
- fetch(url + id)
- .then(resp => resp.json())
- .then((data) => resolve(data.lang))
- .catch((err) => resolve('N/A')); // TODO: Maybe retry promise after xx ms?
- // Currently we are resolving the promise && proceeding.
- });
- }
- /*
- * At this point, this function does the following:
- * 1. It takes an array of ID's (leetcode submission ID)
- * 2. Fetch respective metadata from the leetcode submission API.
- * 3. Delegate the results to anther fxn to append to the DOM.
- *
- * Note: This is a promisified function that heavily relies on fetching data in sequence.
- * This is because the appropriate ID needs to be shown the correct language choice.
- * TODO: Further optimization could be fetch everything async and maintain a running ID,
- * And append their respective results to the DOM.
- */
- function fetchLanguageInfo(ids) {
- const languageArr = [];
- ids.reduce((promise, id) => {
- return promise.then((result) => {
- return doSyncCall(id).then(val => {
- languageArr.push(val);
- });
- });
- }, Promise.resolve()).then(() => { // TODDO: Optimize with promise.all/race
- //console.log("Final Language Array: ", languageArr);
- appendLangToDOM(languageArr);
- });
- }
- /*
- * This method is currently deprecated. Thought of making this a helper method for something else.
- */
- function makeCallAndFetchLanguage(id, arr) {
- const url = `https://leetcode.com/api/submissions/${id}`;
- fetch(url)
- .then((resp) => resp.json())
- .then(function(data) {
- //console.log("Language Results", data);
- // Data is a JSON.
- arr.push(Promise.resolve(data.lang));
- });
- }
- /*
- * It does exactly what it sounds like it does ;-)
- */
- function appendLangToDOM(arr) {
- let j = 0;
- // Hide the spinner.
- $('.rupesh-loader').css('display', 'none');
- // Append my submission.
- const myTd = document.createElement('td');
- myTd.innerHTML = "? (hehe)"; // TODO: Make it dynamic.
- myTd.classList.add('td-my-data');
- $('.success').append(myTd);
- $('tbody > tr').each(function(i) {
- if (i > 0) {
- const td = document.createElement('td');
- //console.log("array JAKE", arr[j]);
- td.innerHTML = arr[j];
- td.classList.add('td-lang-data');
- $('tbody > tr')[i].append(td);
- j++;
- }
- });
- }
- }
- })();