您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Download mod via skymods.ru and modsbase.com directly from steam workshop
当前为
// ==UserScript== // @name Steam Workshop Downloader (Skymods/Modsbase) // @namespace http://tampermonkey.net/ // @version 0.0.5 // @description Download mod via skymods.ru and modsbase.com directly from steam workshop // @author Skrylor - Maintainer // @author Namkazt ( [email protected] ) - Original Author // @match https://steamcommunity.com/sharedfiles/filedetails/* // @match https://steamcommunity.com/workshop/filedetails/* // @match https://steamcommunity.com/workshop/browse/* // @connect smods.ru // @connect modsbase.com // @run-at document-end // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js // @require http://code.jquery.com/jquery-3.6.0.min.js // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_notification // @grant GM_download // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @license MIT // ==/UserScript== function createElementFromHTML(htmlString) { var div = document.createElement("div"); div.innerHTML = htmlString.trim(); return div.firstChild; } function getAppId() { return document.querySelector(".apphub_OtherSiteInfo a").getAttribute('data-appid'); } function isCitiesSkylines() { return ( document.querySelector(".apphub_HeaderTop .apphub_AppName").innerText === "Cities: Skylines" ); } function isCV6() { return ( document.querySelector(".apphub_HeaderTop .apphub_AppName").innerText === "Sid Meier's Civilization VI" ); } function isCollectionPage() { const collectionsLink = document.querySelector('a[href*="/workshop/browse/?section=collections"]'); return collectionsLink !== null; // Returns true if the link is found } function getDownloadId(downloadUrl) { console.log("----------- parsing download url: " + downloadUrl); var regex = /\/[^\/]*\//gm; var m; var downloadId = ""; while ((m = regex.exec(downloadUrl)) !== null) { if (m.index === regex.lastIndex) { regex.lastIndex++; } if (m.index > 6) { downloadId = m[0].substr(1, m[0].length - 2); } } return downloadId; } function getDownloadLinkFromModsBase(downloadId, referer, callback) { const formData = new FormData(); formData.append("op", "download2"); formData.append("id", downloadId); formData.append("rand", ""); formData.append("referer", ""); formData.append("method_free", ""); formData.append("method_premium", ""); GM_xmlhttpRequest({ method: "POST", url: "https://modsbase.com/", headers: { "Content-Type": "application/x-www-form-urlencoded", "Referer": referer, }, data: new URLSearchParams(formData).toString(), onload: function(response) { if (response.status === 200) { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, "text/html"); const downloadLinkElement = doc.querySelector('.download-details a'); if (downloadLinkElement) { const directDownloadLink = downloadLinkElement.href; callback(null, directDownloadLink); } else { callback("Download link not found in response", null); } } else { callback(`Request failed with status ${response.status}`, null); } }, onerror: function(error) { callback(`Request error: ${error.statusText}`, null); } }); } function searchForMod(id, callback) { var appId = getAppId(); var url = "http://catalogue.smods.ru/?s=" + id + "&app=" + appId; console.log("----------- URL: " + url); GM_xmlhttpRequest({ anonymous: true, method: "GET", url: url, headers: { "Referer": "http://catalogue.smods.ru" }, onload: function(e) { doc = new DOMParser().parseFromString(e.responseText, "text/html"); if (doc.getElementsByClassName("post-inner").length > 0) { var downloadUrl = doc.querySelector(".post-inner .skymods-excerpt-btn").href; var downloadId = getDownloadId(downloadUrl); if (downloadId != undefined || downloadId != null || downloadId != "") { console.log("----------- download id: " + downloadId); var rDateStr = doc.querySelector(".post-inner .skymods-item-date").innerText; var updated = moment(rDateStr, "DD MMM at HH:mm YYYY").format( "DD MMM, YYYY" ); let titleElement = doc.querySelector(".post-inner h2 a"); let title = titleElement ? titleElement.textContent.trim() : "Unknown Mod Title"; callback(true, downloadId, downloadUrl, updated, title); } else { callback(false, downloadId, downloadUrl, ""); } } else { callback(false, downloadId, downloadUrl, ""); } }, onerror: function(error) { console.error("Request failed:", error); callback(false, null, null, "Error fetching mod info"); } }); } function gotoRequestPage(id) { var url = "https://steamcommunity.com/sharedfiles/filedetails/?id=" + id; if (isCitiesSkylines()) { window.open('https://docs.google.com/forms/d/e/1FAIpQLSdXlq9OAWVwX5lRLNvpkMSmpKbEDY50Bl-UU3f6P7OBI2Ny3Q/viewform?c=0&w=1&entry.417177883=' + url, '_blank'); } else { window.open('https://docs.google.com/forms/d/e/1FAIpQLSe7MisYbKNUlTXBcSR2clHxpwaoo0HiZ3zWto0osemubdDP1g/viewform?entry.417177883=' + url, '_blank'); } } function changeButtonGradient(btn, color1, color2) { var gradient = "linear-gradient(42deg, #" + color1 + " 35%, #" + color2 + " 65%)"; btn.style.background = gradient; btn.querySelector("#DownloadTxt").style.background = gradient; } function searchForDownloadLink(btn, downloadId, downloadUrl, modTitle) { let textNode = btn.querySelector("#DownloadTxt"); let spinner = btn.querySelector(".loading-spinner"); spinner.style.display = "inline-block"; textNode.style.opacity = 0; btn.classList.add('loading'); getDownloadLinkFromModsBase(downloadId, downloadUrl, function(err, directDownloadLink) { spinner.style.display = "none"; textNode.style.opacity = 1; btn.classList.remove('loading'); if (err) { console.error(err); textNode.innerText = "Failed to get link"; return; } textNode.innerText = "Downloading..."; spinner.style.display = "inline-block"; textNode.style.opacity = 0; let fileName = modTitle.replace(/[^a-zA-Z0-9_.-]/g, '_') + ".zip"; fileName = fileName.substring(0, 250); GM_download({ url: directDownloadLink, name: fileName, onload: function() { spinner.style.display = "none"; textNode.style.opacity = 1; textNode.innerHTML = "Downloaded!"; }, onerror: function(error) { spinner.style.display = "none"; textNode.style.opacity = 1; console.error("Download error:", error); textNode.innerText = "Download Failed"; } }); }); } var DOWNLOAD_BTN_TEMPLATE = ` <button id="DownloadBtn" class="steam-button"> <span id="DownloadTxt">Download</span> <span class="loading-spinner" style="display: none;"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="8" cy="8" r="7" stroke="#fff" stroke-width="2" style="animation: rotate 1s linear infinite;"/> </svg> </span> </button> `; GM_addStyle(` .steam-button { background-color: #7cb342; border: none; color: white; padding: 6px 12px; border-radius: 4px; cursor: pointer; text-decoration: none; font-weight: bold; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; transition: background-color 0.2s ease, transform 0.1s ease; display: inline-block; position: relative; } .steam-button:hover { background-color: #669933; transform: scale(1.02); } .steam-button.loading #DownloadTxt { opacity: 0; transition: opacity 0.2s ease; } .steam-button.loading .loading-spinner { display: inline-block; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .steam-button .loading-spinner svg { animation: rotate 1s linear infinite; } .steam-button.not-available { background-color: #d32f2f; } .steam-button.not-available:hover { background-color: #c62828; } .game_area_purchase_game > div { height: 30px; /* Replace 30px with the actual height of the Subscribe button */ display: flex; align-items: center; } .game_area_purchase_game > div > a#SubscribeItemBtn + button.steam-button { margin-left: -10px; /* Adjust this value as needed for left alignment */ margin-right: 0; /* Ensure no right margin */ } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .steam-button.loading { opacity: 0.7; pointer-events: none; } `); function init() { $(document).ready(function() { if (window.location.href.indexOf("appid=") >= 0) { console.log("----------- Workshop browser page"); var itemList = document.querySelectorAll(".workshopItemPreviewHolder"); for (var item of itemList) { var itemDownloadId = item.id.replace("sharedfile_", ""); var btnNode = createElementFromHTML(DOWNLOAD_BTN_TEMPLATE); searchForMod(itemDownloadId, (function() { var workshopId = itemDownloadId; var btn = btnNode; var textNode = btn.querySelector("#DownloadTxt"); textNode.innerText = "Checking for mod"; return function(found, downloadId, downloadUrl, updated, modTitle) { if (found) { textNode.innerText = "Download - " + updated; btn.addEventListener("click", function() { searchForDownloadLink(btn, downloadId, downloadUrl, modTitle); }); } else { textNode.innerText = "Not Available (REQUEST)"; btn.classList.add("not-available"); btn.addEventListener("click", function() { gotoRequestPage(workshopId); }); } }; })() ); var subscriptionControls = item.parentNode.querySelector('.subscriptionControls'); if (subscriptionControls) subscriptionControls.appendChild(btnNode); } } else if (isCollectionPage()) { console.log("----------- Collection page"); var itemList = document.querySelectorAll(".collectionItem"); for (var item of itemList) { var itemDownloadId = item.id.replace("sharedfile_", ""); var btnNode = createElementFromHTML(DOWNLOAD_BTN_TEMPLATE); searchForMod(itemDownloadId, (function() { var workshopId = itemDownloadId; var btn = btnNode; var textNode = btn.querySelector("#DownloadTxt"); textNode.innerText = "Checking for mod"; return function(found, downloadId, downloadUrl, updated, modTitle) { if (found) { textNode.innerText = "Download - " + updated; btn.addEventListener("click", function() { searchForDownloadLink(btn, downloadId, downloadUrl, modTitle); }); } else { textNode.innerText = "Not Available (REQUEST)"; btn.classList.add("not-available"); btn.addEventListener("click", function() { gotoRequestPage(workshopId); }); } }; })() ); var subscriptionControls = item.querySelector('.subscriptionControls'); if (subscriptionControls) subscriptionControls.appendChild(btnNode); } } else { console.log("----------- Single item page"); var publishedfileid = window.location.href.match(/id=(\d+)/)[1]; var btnNode = createElementFromHTML(DOWNLOAD_BTN_TEMPLATE); var textNode = btnNode.querySelector("#DownloadTxt"); textNode.innerText = "Checking for mod"; searchForMod(publishedfileid, function( found, downloadId, downloadUrl, updated, modTitle ) { if (found) { textNode.innerText = "Download - " + updated; btnNode.addEventListener("click", function() { searchForDownloadLink(btnNode, downloadId, downloadUrl, modTitle); }); } else { textNode.innerText = "Not Available (REQUEST)"; btnNode.classList.add("not-available"); btnNode.addEventListener("click", function() { gotoRequestPage(publishedfileid); }); } }); const subscribeButton = document.getElementById("SubscribeItemBtn"); if (subscribeButton) { subscribeButton.parentNode.insertBefore(btnNode, subscribeButton.nextSibling); } else { // Fallback if Subscribe button not found (e.g., due to Steam layout changes): const subscriptionControls = document.querySelector('.subscriptionControls'); if (subscriptionControls) { subscriptionControls.classList.add('single-item-controls'); // Add a unique class subscriptionControls.insertBefore(btnNode, subscribeButton.nextSibling); // insertBefore, as before } else { console.error("Neither Subscribe button nor Subscription Controls found. Appending to body."); document.body.appendChild(btnNode); } } } console.log("----------- Init successfully"); }); } (function() { "use strict"; init(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址