├── .gitignore ├── LICENSE ├── README.md ├── content.js ├── icons ├── Screenshot 2024-02-05 at 6.17.35 PM.png └── leetcode.png ├── manifest.json ├── popup.html ├── popup.js └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | .architect 2 | bootstrap.css 3 | bootstrap.js 4 | bootstrap.json 5 | bootstrap.jsonp 6 | build/ 7 | classic.json 8 | classic.jsonp 9 | ext/ 10 | .DS_STORE 11 | modern.json 12 | modern.jsonp 13 | resources/sass/.sass-cache/ 14 | resources/.arch-internal-preview.css 15 | .arch-internal-preview.css 16 | token.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Faheem 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetHub 2 | A chrome extension which automatically commits your leetcode solution to a predefined repository you connected earlier. 3 | 4 | # V 0.0.2.6 5 | 6 | ### Special Mentions: [Wahaj Javed Alam](https://github.com/WahajJaved20) 7 | 8 | 9 | # Installation Steps 10 | 1. **Download the Zip File from the Github Page** 11 | - Visit the [Github Page](https://github.com/SyedMuhammadFaheem/LeetHub). 12 | - Download the Zip File by clicking on the "Code" button and selecting "Download ZIP." 13 | 14 | 2. **Extract it into any directory in your PC** 15 | - After downloading, extract the contents of the ZIP file into any directory of your choice on your computer. 16 | 17 | 3. **Open your browser (Chrome or Opera GX or Brave)** 18 | - Ensure you have either Google Chrome or Opera GX installed. This extension is designed to work on browsers supporting the Chrome Web Store. 19 | 20 | 4. **Go to Extensions** 21 | - Open your browser and navigate to the Extensions page. 22 | - In Chrome: Click on the three dots in the top-right corner, go to "More tools," and then select "Extensions." 23 | - In Opera GX or Brave: Click on the browser menu, go to "Extensions," and then select "Manage Extensions." 24 | 25 | 5. **Enable Developer Mode in the Top bar** 26 | - Once on the Extensions page, look for a checkbox or toggle named "Developer mode" in the top-right corner. 27 | - Enable Developer Mode. 28 | 29 | 6. **Load the Extension** 30 | - Look for an option to "Load unpacked" or "Load extension" on the Extensions page. 31 | - Click on it and select the directory where you extracted the contents of the ZIP file. 32 | 33 | 7. **Verify Installation** 34 | - The extension should now be visible in your list of installed extensions. 35 | - Ensure it is enabled and working as expected. 36 | 37 | 38 | # Generate Github Personal Access Token 39 | ## Log in to your GitHub Account: 40 | 41 | 1. Open your web browser and go to [GitHub](https://github.com/). 42 | 2. Log in to your GitHub account if you are not already logged in. 43 | 44 | ## Access Personal Access Tokens Settings: 45 | 46 | 1. In the top-right corner of the GitHub page, click on your profile picture, and then click on "Settings." 47 | 48 | ## Go to Developer Settings: 49 | 50 | 1. In the left sidebar, scroll down and click on "Developer settings." 51 | 52 | ## Generate a Token: 53 | 54 | 1. In the Developer settings menu, click on "Personal access tokens. (Fine Grained Tokens)" 55 | 2. Click the "Generate token" button. 56 | 57 | ## Configure Token Settings: 58 | 59 | 1. Provide a name for your token in the "Token name" field. 60 | 2. Select the repo you want to push in. Choose only the permissions necessary (admin, commit statuses, contents). 61 | 62 | ## Generate Token: 63 | 64 | 1. Scroll down and click the "Generate token" button at the bottom of the page. 65 | 66 | ## Copy and Save the Token: 67 | 68 | Once the token is generated, GitHub will display it. Copy the token and save it in a secure location immediately. 69 | 70 | 71 | # How and where to use the extension? 72 | ## After you submitted the solution, go to your specific accepted submission 73 | 74 | 1. The URL would look like this below: 75 | - `https://leetcode.com/submissions/detail/1163743480/` 76 | 77 | ## Enter your GitHub Username, Repository Name, and GitHub Access Token extracted earlier in the extension, and voilà 78 | 79 | 1. Open the extension or application where you need to enter your GitHub details. 80 | 2. Provide your GitHub username in the designated field. 81 | 3. Enter the repository name associated with your solution. 82 | 4. Paste the GitHub access token you extracted earlier into the relevant field. 83 | 5. Click on COMMIT TO GITHUB button. 84 | 85 | ## Voilà! 86 | ![Voilà Image](https://github.com/SyedMuhammadFaheem/LeetHub/blob/fea5afe88b5376a2faca9791270061d1b5261fd2/icons/Screenshot%202024-02-05%20at%206.17.35%E2%80%AFPM.png) 87 | 88 | Your solution would get committed now successfully. 89 | 90 | -------------------------------------------------------------------------------- /content.js: -------------------------------------------------------------------------------- 1 | chrome.storage.local.get(["username", "repo", "token"], function (result) { 2 | const username = result.username; 3 | const repo = result.repo; 4 | const token = result.token; 5 | const questionName = document 6 | .getElementsByTagName("h4")[0] 7 | .textContent.split(" ") 8 | .join(""); 9 | let extensionName = document.getElementById("result_language").innerHTML; 10 | 11 | if (extensionName === "python3") extensionName = ".py"; 12 | else if (extensionName === "python") extensionName = ".py"; 13 | else if (extensionName === "java") extensionName = ".java"; 14 | else if (extensionName === "cpp") extensionName = ".cpp"; 15 | else if (extensionName === "c") extensionName = ".c"; 16 | else if (extensionName === "cs") extensionName = ".cs"; 17 | else if (extensionName === "js") extensionName = ".js"; 18 | else if (extensionName === "ts") extensionName = ".ts"; 19 | else if (extensionName === "php") extensionName = ".php"; 20 | else if (extensionName === "swift") extensionName = ".swift"; 21 | 22 | const fileName = 23 | questionName + extensionName || 24 | "solution.txt" + Math.floor(Math.random() * 100); 25 | 26 | 27 | const COMMIT_MESSAGE = fileName + " " + String(new Date()); 28 | 29 | 30 | const leetCodeSolutionTextarea = 31 | document.getElementsByClassName("ace_content"); 32 | let newContent = ""; 33 | for (let i = 0; i < leetCodeSolutionTextarea.length; i++) { 34 | const element = leetCodeSolutionTextarea[i]; 35 | newContent += element.textContent; 36 | } 37 | for(let i=1;i { 67 | if (response.ok) { 68 | return response.json(); 69 | } else { 70 | fetch(apiUrl, { 71 | method: "PUT", 72 | headers: { 73 | Authorization: `Basic ${credentials}`, 74 | "Content-Type": "application/json", 75 | }, 76 | body: JSON.stringify(fileData), 77 | }).then((response) => { 78 | if (response.ok) window.alert("File Created!"); 79 | else throw new error("Error in creating file!"); 80 | }); 81 | } 82 | }) 83 | .then((data) => { 84 | const sha = data ? data.sha : ''; 85 | if (sha) { 86 | return fetch(apiUrl, { 87 | method: "PUT", 88 | headers: { 89 | Authorization: `Basic ${credentials}`, 90 | "Content-Type": "application/json", 91 | }, 92 | body: JSON.stringify({ 93 | ...fileData, 94 | sha: sha, 95 | }), 96 | }); 97 | } 98 | }) 99 | .then((response) => response ? response.json() : 'No SHA found') 100 | .then((data) => { 101 | if(data!="No SHA found") 102 | window.alert("File Updated!") 103 | }) 104 | .catch((error) => { 105 | console.error("Error:", error); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /icons/Screenshot 2024-02-05 at 6.17.35 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedMuhammadFaheem/LeetHub/1436b1882e87d886712ae31112257c03933a3a61/icons/Screenshot 2024-02-05 at 6.17.35 PM.png -------------------------------------------------------------------------------- /icons/leetcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedMuhammadFaheem/LeetHub/1436b1882e87d886712ae31112257c03933a3a61/icons/leetcode.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "LeetHub", 4 | "version": "0.0.2.6", 5 | "description": "Commit LeetCode solutions to GitHub", 6 | "browser_action": { 7 | "default_icon": { 8 | "128": "icons/leetcode.png" 9 | }, 10 | "default_popup": "popup.html" 11 | }, 12 | "permissions": [ 13 | "activeTab", 14 | "storage" 15 | ], 16 | "icons": { 17 | "128": "icons/leetcode.png" 18 | }, 19 | "content_scripts": [ 20 | { 21 | "matches": ["https://*.leetcode.com/submissions"], 22 | "js": ["content.js"] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LeetHub 6 | 7 | 8 | 9 | 10 |
11 |
12 |

Cannot use extenstion on this site!

13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /popup.js: -------------------------------------------------------------------------------- 1 | function saveCredentials(username, repo, token, fileName) { 2 | chrome.storage.local.set({ 3 | username: username, 4 | repo: repo, 5 | token: token, 6 | }); 7 | } 8 | 9 | function loadCredentials() { 10 | chrome.storage.local.get(["username", "repo", "token"], function (result) { 11 | const username = result.username || ""; 12 | const repo = result.repo || ""; 13 | const token = result.token || ""; 14 | 15 | document.getElementById("username").value = username; 16 | document.getElementById("repo").value = repo; 17 | document.getElementById("token").value = token; 18 | }); 19 | } 20 | 21 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 22 | var currentURL = tabs[0].url; 23 | var urlPattern = /^https:\/\/leetcode\.com\/submissions\/detail\/\d*\/?$/; 24 | 25 | console.log(urlPattern.test(currentURL)) 26 | 27 | 28 | 29 | if (urlPattern.test(currentURL)) { 30 | document.getElementById( 31 | "popupContent" 32 | ).innerHTML = ` 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | `; 42 | loadCredentials(); 43 | document 44 | .getElementById("commitButton") 45 | .addEventListener("click", function () { 46 | const username = document.getElementById("username").value; 47 | const repo = document.getElementById("repo").value; 48 | const token = document.getElementById("token").value; 49 | 50 | saveCredentials(username, repo, token); 51 | console.log(username, repo, token); 52 | chrome.tabs.executeScript(tabs[0].id, { file: "content.js" }); 53 | }); 54 | } 55 | 56 | 57 | }); 58 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Arial', sans-serif; 3 | margin: 0; 4 | padding: 0; 5 | background-color: #f4f4f4; 6 | } 7 | 8 | .container { 9 | max-width: 1000px; 10 | margin: 50px auto; 11 | margin-top: 0; 12 | background-color: #fff; 13 | padding: 20px; 14 | border-radius: 8px; 15 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 16 | } 17 | 18 | #popupContent { 19 | width: 120px; 20 | height: 50px; 21 | text-align: center; 22 | color: #3700ff; 23 | } 24 | 25 | .form-container { 26 | margin-top: 20px; 27 | } 28 | 29 | label { 30 | display: block; 31 | margin-bottom: 5px; 32 | font-weight: bold; 33 | } 34 | 35 | input { 36 | width: 100%; 37 | padding: 8px; 38 | margin-bottom: 10px; 39 | box-sizing: border-box; 40 | } 41 | 42 | button { 43 | background-color: #007bff; 44 | color: #fff; 45 | padding: 10px; 46 | border: none; 47 | border-radius: 4px; 48 | cursor: pointer; 49 | } 50 | 51 | button:hover { 52 | background-color: #0056b3; 53 | } 54 | --------------------------------------------------------------------------------