NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name CurseForge Instant Download // @version 1.0.2 // @description Convenient and instant downloading of Minecraft CurseForge mods. // @author TrevTV, Gustavo6046 <rehermann6046@gmail.com> // @match https://www.curseforge.com/minecraft/mc-mods/*/* // @namespace https://allvvg.xyz // @grant GM_openInTab // @grant window.close // @license MIT // ==/UserScript== (function() { 'use strict'; // Common mod download routine. function openModWithId(baseUrl, modName, id) { console.log(`Opening "${baseUrl}/${modName}/download/${id}/file"...`); // Open download in new tab, for convenience. let newTab = GM_openInTab(`${baseUrl}/${modName}/download/${id}/file`, {insert: true, active: false}); // Now, to undo the mess!... uhhh... // - step 1. get history length let histoLen = window.history.length; // - step 2. close this new tab for the user! :) setTimeout(function() { // don't try to close it before the download is ready! (tested only on Firefox) function finishUp() { // (run after the conclusion of step 2, don't worry) // - step 3. check if histoLen <= 2; if so, close the tab (brand new, thus probably opened as new tab); otherwise just go back let shouldClose = histoLen <= 2; // this statement is only to reduce boilerplate-ish code a little. console.log(`Tab history (length ${histoLen}) is ${shouldClose ? '' : 'not '}empty; ${shouldClose ? 'closing' : 'rewinding'} main tab.`); if (shouldClose) { window.close(); } else { window.history.back(); } } console.log('- download tab already closed:', newTab.closed); if (!newTab.closed) { console.log('Attempting to close download tab...'); let maxCloseAttempts = 60; // 30 seconds until give up let attemptIntv = 3; // 3 attempts per second let _attemptNum = 0; function doAttemptClose() { setTimeout(attemptClose, 1000 / attemptIntv); } function attemptClose() { newTab.close(); console.log(newTab.closed); if (newTab.closed) { console.log('Download tab closed successfully!'); finishUp(); } else if ((maxCloseAttempts -= 1 / attemptIntv) <= 0) { console.warn('Failed to close download tab.'); finishUp(); } else { let barSize = 80; let barPerc = Math.ceil(barSize * _attemptNum / maxCloseAttempts / attemptIntv); console.log(`Attempt #{++_attemptNum} failed... [${'#'.repeat(barPerc) + ' '.repeat(barSize - barPerc)}]`); doAttemptClose(); } } setTimeout(attemptClose, 1500); } else { finishUp(); } }, 200); // - step 4. maximum convenience... // - step 5. ??? // - step 6. profit! } // Set accepted numbers let numbers = /^[0-9]+$/; // Set accepted download URLs let directDownloadPattern = /^.*?\/mc-mods\/.+?\/download\/(\d+)\/file$/; // Set baseUrl, id, oper, and modName let baseUrl = `https://www.curseforge.com/minecraft/mc-mods` let id = ((document.URL).split("/"))[7]; let oper = ((document.URL).split("/"))[6]; let modName = ((document.URL).split("/"))[5]; // Check if ID is actually a number if (oper.toUpperCase() == 'DOWNLOAD') { if (id && id.match(numbers)) { openModWithId(baseUrl, modName, id); } else if (id == null) { console.log(`Finding latest version of mod with name '${modName}'...`); // Find "click here" link let downloadLink = document.querySelector('p.text-sm > a:nth-child(1)'); if (downloadLink == null) { console.warn('Could not find download link in page (link not found by selector query); latest version discovery aborted.') } else { // Extract file ID from link let dlMatch = downloadLink.href.match(directDownloadPattern); if (!dlMatch) { console.warn('Could not find valid download link in page (bad URL); latest version discovery aborted.') } else { // Use file ID to invoke file download routine id = dlMatch[1]; openModWithId(baseUrl, modName, id); } } } else { console.warn(`Invalid ID number for file download: '${id}'`) } } } )();