Greasy Fork

Greasy Fork is available in English.

Steam创意工坊饥荒mod下载工具

在创意工坊中注入一个MOD下载按钮,用于下载MOD

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Steam创意工坊饥荒mod下载工具
// @namespace      http://greasyfork.icu/users/3128
// @version      1.9.4
// @description    在创意工坊中注入一个MOD下载按钮,用于下载MOD
// @author       极品小猫
// @include      https://steamcommunity.com/sharedfiles/filedetails/*
// @include      https://steamcommunity.com/id/*/myworkshopfiles/*
// @include      https://steamcommunity.com/id/*/myworkshopfiles?*
// @match        https://t.vvwall.com/*
// @connect       5.5w.pw
// @connect       steamworkshopdownloader.io
// @grant        GM_setClipboard
// @grant        GM_addStyle
// @grant        GM_download
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';
    let webHost=location.host, webPath=location.pathname;

    if(webHost=='steamcommunity.com') {
        let modDownloadStart, HostID=[3,2,1]; //mod 下载开始标记,防止重复请求下载
        if(webPath.search('myworkshopfiles')>-1) {
            GM_addStyle(`.download_Mod, .general_btn {text-align:center;}`)
            document.querySelectorAll('[id^="Subscription"]').forEach(function(e, i){
                console.log(i, e, e.id);
                let mid=e.id.replace(/^[^\d]+/i,''),
                    actionsCtn=e.querySelector('.actionsCtn');

                let down_A=document.createElement('a');
                down_A.className="download_Mod";
                down_A.target='_blank';
                down_A.textContent='下载 MOD';

                let down_span=document.createElement('span');
                down_span.className='general_btn';
                down_span.style.width='70px';
                down_span.appendChild(down_A);

                actionsCtn.appendChild(down_span);

                down_A.addEventListener('click', function(){
                    ModDownloadAjax(mid);
                    jQuery(this).html('<img src="https://community.cloudflare.steamstatic.com/public/images/login/throbber.gif" style="height:20px;vertical-align:middle;">');
                });
            });
        } else { //workshop详细页
            let down_A=document.createElement('a');
            //down_A.href="https://t.vvwall.com/#"+publishedfileid;
            down_A.id="download_Mod";
            down_A.target='_blank';
            down_A.textContent='下载 MOD';
            let down_span=document.createElement('span');
            down_span.className='general_btn share tooltip';
            down_span.id="download_ModBtn"
            down_span.appendChild(down_A);
            GM_addStyle('#download_Mod {line-height:30px;}')

            document.querySelector('#ItemControls').appendChild(down_span);
            let modTags=document.querySelector('span.workshopTagsTitle~a[href*="version"]');
            let modVersion=modTags?modTags.textContent.trim().replace('version:','v'):'';
            document.querySelector('#download_ModBtn').addEventListener('click', function(e){
                if(modDownloadStart) return false;
                ModDownloadAjax(publishedfileid, modVersion);
                jQuery(this).html('<img src="https://community.cloudflare.steamstatic.com/public/images/login/throbber.gif" style="height:20px;vertical-align:middle;">');
                //jQuery('<img src="https://community.cloudflare.steamstatic.com/public/images/login/throbber.gif" style="height:20px;vertical-align:middle;">').appendTo(this);
                //jQuery(this).replaceWith('<img src="https://community.cloudflare.steamstatic.com/public/images/login/throbber.gif" style="height:20px;vertical-align:middle;">');
            });
        }
        /*
        let down_A=$('<a>').text('下载MOD'),
            downBtn=$('<span class="general_btn report tooltip" data-tooltip-text="下载MOD">').append(down_A);
*/
        function ModDownloadAjax(mid, target){
            modDownloadStart=true; //标记 mod 下载线程已开始
            mid=Number(mid);
            let _HostID = HostID.shift();
            console.log(mid, [mid], JSON.stringify(mid), _HostID);

            GM_xmlhttpRequest({
                url:'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/details/file',
                method: 'post',
                timeout : 5000,
                data: JSON.stringify([mid]),
                responseType : 'json',
                headers : {
                    'content-type' : 'application/x-www-form-urlencoded',
                },
                onTimeout : function(e){
                    console.log(e);
                    modDownloadStart=false;
                    jQuery('#download_ModBtn').html('请求超时,请重试');
                },
                abort : function(e){
                    console.log('请求已取消')
                },
                onload: function(e){
                    console.log(e, e.response);
                    let modData, downloadTitle;
                    switch(e.status) {
                        case 200:
                            modData=e.response[0];
                            modData.tags.forEach(function(item){
                                if(/version:/i.test(item.tag)) {
                                    let modVersion=item.tag.trim().replace('version:','v');
                                    downloadTitle="[workshop-"+mid+"]"+modData.title+(modVersion?" "+modVersion:"")+".zip";
                                }
                            });

                            if(!modData.file_url) {
                                GM_xmlhttpRequest({
                                    url:'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/download/request',
                                    method: 'post',
                                    data : JSON.stringify({"publishedFileId": mid,"collectionId":null,"extract":true,"hidden":false,"direct":false,"autodownload":true}),
                                    responseType : 'json',
                                    headers : {
                                        'content-type' : 'application/x-www-form-urlencoded',
                                    },
                                    onload: function(re){
                                        console.log(re, re.response, 'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/download/transmit?uuid='+re.response.uuid);

                                        GM_xmlhttpRequest({
                                            url : 'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/download/status',
                                            method: 'post',
                                            data : JSON.stringify({"uuids": re.response.uuid}),
                                            responseType : 'json',
                                            headers : {
                                                'content-type' : 'application/x-www-form-urlencoded',
                                            },
                                            onload: function(se){
                                                console.log(se);
                                                GM_xmlhttpRequest({
                                                    url:'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/download/transmit?uuid='+re.response.uuid,
                                                    method: 'get',
                                                    headers : {
                                                        'content-type' : 'application/x-www-form-urlencoded',
                                                    },
                                                    onload : function(de){
                                                        console.log('下载开始', de);
                                                        GM_download({
                                                            url: 'https://backend-0'+_HostID + '-prd.steamworkshopdownloader.io/api/download/transmit?uuid='+re.response.uuid,
                                                            name: downloadTitle,
                                                            saveAs : true,
                                                        });
                                                    }
                                                });
                                                jQuery('#download_ModBtn').html('MOD 请求成功');
                                            }
                                        })
                                    }
                                });
                            } else {
                                //直链下载
                                modData.tags.forEach(function(item){
                                    if(/version:/i.test(item.tag)) {
                                        let modVersion=item.tag.trim().replace('version:','v');
                                        downloadTitle="[workshop-"+mid+"]"+modData.title+(modVersion?" "+modVersion:"")+".zip";
                                    }
                                });

                                GM_download({
                                    url: modData.file_url,
                                    name: downloadTitle,
                                    saveAs : true,
                                });
                                jQuery(target).html('直链MOD 请求成功');
                            }

                            break;
                        default :
                            jQuery('#download_ModBtn').text('请求失败 ' + e.status);
                    }
                    /*
                    let data=e.response, downloadTitle="[workshop-"+mid+"]"+data.title+(modVersion?" "+modVersion:"")+".zip";
                    GM_download({
                        url: data.url,
                        name: downloadTitle,
                        saveAs : true,
                    });
                    */
                },
                onerror: function(e){
                    console.error('error', e);
                }
            });

            /* API 已失效
            GM_xmlhttpRequest({
                url:'https://5.5w.pw/api?mid='+mid,
                method: 'get',
                responseType : 'json',
                onload: function(e){
                    console.log(e);
                    let data=e.response, downloadTitle="[workshop-"+mid+"]"+data.title+(modVersion?" "+modVersion:"")+".zip";
                    GM_download({
                        url: data.url,
                        name: downloadTitle,
                        saveAs : true,
                    });
                },
                onerror: function(e){
                    console.error('error', e);
                }
            });

            */
        }
    } else if(webHost=='t.vvwall.com') {
        GM_addStyle(`
input[name="mid"]{
padding: 0 10px;
}
`);
        $('button.starts').click(function(){
            addMObserver('#des', function(){
                console.log($('code#des').text());
                $('code#des').html(markdown.toHTML($('code#des').text()));
            });
        });
        let workshop_A=$('<a id="workshop">').text('创意工坊');
        let dlbtn=$('#dlbtn').removeAttr('onclick target').click(function(e){
            let inputText=$('input[name="mid"]').val().trim(),
                id=getUrlParam('id', inputText, inputText),
                modTitle=$('#modtitle').text().trim(),
                downloadTitle="[workshop-"+id+"]"+modTitle+".zip";
            workshop_A.attr({'href':'https://steamcommunity.com/sharedfiles/filedetails/?id='+id});

            GM_download({
                url: e.href,
                name: downloadTitle,
                saveAs : true,
            });
            e.preventDefault(); //阻止默认动作
            e.stopPropagation(); //阻止冒泡
        });
        $('.downloadbox').prepend(dlbtn);
        dlbtn.after(workshop_A);
    }

        if(location.hash) {
            $('input[name="mid"]').val(location.hash.replace('#',''));
            $('button.starts').click();
        }
    // Your code here...
    function addMObserver(selector, callback, Kill, option) {
        var watch = document.querySelector(selector);

        if (!watch) {
            return;
        }
        console.warn('watch:', watch, selector);
        var observer = new MutationObserver(function(mutations){
            console.log('mutations:', mutations);
            var nodeAdded = mutations.some(function(x){
                console.log(x);
                return x.addedNodes.length > 0;
            });
            console.log(nodeAdded);
            if (nodeAdded) {
                console.log(mutations, observer);
                callback(mutations, observer);
                if(Kill) {
                    console.log('停止'+selector+'的监控');
                    observer.disconnect();
                }
            }
        });
        observer.observe(watch, option||{childList: true, subtree: true});//
    }

    function getUrlParam(name, url, option, newVal) {//筛选参数,url 参数为数字时
        var search = url ? url.replace(/^.+\?/,'') : location.search;
        //网址传递的参数提取,如果传入了url参数则使用传入的参数,否则使用当前页面的网址参数
        var reg = new RegExp("(?:^|&)(" + name + ")=([^&]*)(?:&|$)", "i");		//正则筛选参数
        var str = search.replace(/^\?/,'').match(reg);

        console.log(str, option);

        if (str !== null) {
            switch(option) {
                case 0:
                    return unescape(str[0]);		//所筛选的完整参数串
                case 1:
                    return unescape(str[1]);		//所筛选的参数名
                case 2:
                    return unescape(str[2]);		//所筛选的参数值
                case 'new':
                    return url.replace(str[1]+'='+str[2], str[1]+'='+newVal);
                default:
                    return unescape(str[2]);        //默认返回参数值
            }
        } else if(!str && option) {
            return option;
        } else {
            return null;
        }
    }
})();