您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Export display cabinet and bazaar weapon/armor information by clicking button.
当前为
// ==UserScript== // @name easy-market-export-helper // @namespace nodelore.torn.easy-market // @version 1.1 // @description Export display cabinet and bazaar weapon/armor information by clicking button. // @author nodelore[2786679] // @match https://www.torn.com/displaycase.php* // @match https://www.torn.com/bazaar.php* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant GM_getValue // @grant GM.getValue // @grant GM_setValue // @grant GM.setValue // @license MIT // ==/UserScript== (function(){ 'use strict'; //================ Easy-market Configuration ======================= const API = ""; // Insert your API here (PUBLIC level is fine) const STORAGE_KEY = "export_helper_cache"; // You can customize the storage key of local storage //================================================================== const exportMap = {}; let storage; if (GM) { window.GM_getValue = GM.getValue; window.GM_setValue = GM.setValue; window.GM_deleteValue = GM.deleteValue; } const weaponList = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,63,76,98,99,100,108,109,110,111,146,147,170,173,174,175,177,189,217,218,219,223,224,225,227,228,230,231,232,233,234,235,236,237,238,240,241,243,244,245,247,248,249,250,251,252,253,254,255,289,290,291,292,346,359,360,382,387,388,391,393,395,397,398,399,400,401,402,438,439,440,483,484,485,486,487,488,489,490,539,545,546,547,548,549,599,600,604,605,612,613,614,615,632,790,792,805,830,831,832,837,838,839,844,845,846,850,871,874,1053,1055,1056,1152,1153,1154,1155,1156,1157,1158,1159,1231,1255,1257,1296]; const armorList = [32,33,34,49,50,176,178,332,333,334,348,538,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,848,1307,1308,1309,1310,1311,1355,1356,1357,1358,1359]; const filterType = ["Melee", "Secondary", "Primary", "Armor"] const getWeaponInfo = async (armouryID) => { if(storage[armouryID]){ return storage[armouryID]; } else{ const response = await $.ajax({ url: `https://api.torn.com/torn/${armouryID}?selections=itemdetails&key=${API}`, }); const info = response.itemdetails; storage[armouryID] = info; await GM.setValue(STORAGE_KEY, storage); return info; } }; function saveToLocal(result){ const match = /(\d+)/.exec(location.href); if(match){ const uid = match[1]; const blob = new Blob([result], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${uid}_display.txt`; a.style.display = "none"; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); } } function resortExportMap(){ const bonusMap = {}; for(let armouryID in exportMap){ const item = exportMap[armouryID]; let defaultBonus = 'None'; if(item.bonus){ defaultBonus = item.bonus[0].name; } if(!bonusMap[defaultBonus]){ bonusMap[defaultBonus] = []; } bonusMap[defaultBonus].push(item); } return bonusMap; } function exportMapDownload(){ let output = ""; let index = 1; // sort information by bonus const bonusMap = resortExportMap(); for(let bonus in bonusMap){ const bonusList = bonusMap[bonus]; for(let item of bonusList){ const {name, damage, accuracy, armor, quality, bonus, rarity, price} = item; output += `${index}.${name} (`; if(damage){ output += `D: ${damage} A: ${accuracy}`; } else{ output += `A: ${armor}`; } output += `) - `; if(bonus){ for(let b of bonus){ output += `${b.name} ${b.value}|` } } output += `${quality}%` if(rarity != 'None'){ output += ` ${rarity}` } if(price){ output += ` ${parseInt(price).toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 })}`; } output += `\n` index++; } } if(output.length > 0){ saveToLocal(output); } else{ alert("Detect no weapons or armors!") } } function interceptButton(){ let target = $(".info-msg"); if(target.length < 1){ target = $('div.msg'); } if(target.length < 1) return; if(target.find("div.torn-btn").length > 0) { return; } const button = $(` <div class="torn-btn" style="z-index: 1; margin-right: 5px;"> Export Weapon/Armor </div>`); button.click(exportMapDownload); target.append(button); } const handlePercentage = (desc, value) => { const index = desc.indexOf(value); if(desc[index + value.toString().length] === '%'){ return `${value}%` } return value; } const itemType = (itemID)=>{ if(weaponList.indexOf(itemID) !== -1){ return 1; } else if(armorList.indexOf(itemID !== -1)){ return 2; } return -1; } const updateCabinet = async (item)=>{ if(!storage){ storage = await GM.getValue(STORAGE_KEY, {}); return; } if(item.find('top-bonuses').length > 0){ return; } const itemHover = item.find('div.item-hover'); let itemID = itemHover.attr('itemid'); if(!itemID){ return; } itemID = parseInt(itemID); const iType = itemType(itemID); if(iType !== -1){ const armouryID = itemHover.attr('armouryid'); if(armouryID === "0" || exportMap[armouryID]){ return; } const itemdetail = await getWeaponInfo(armouryID); if(itemdetail){ const { name, damage, accuracy, quality, armor, bonuses, rarity } = itemdetail; if(item.find('top-bonuses').length > 0){ return; } const qualityItem = $(`<div class='top-bonuses'>Q:${quality}%</div>`); qualityItem.css({ position: 'absolute', left: '15px', top: '35px', 'z-index': 2, background: '#FFF', 'border-radius': '7px' }); item.append(qualityItem); const exportItem = {}; exportItem['name'] = name; exportItem['quality'] = quality; exportItem['rarity'] = rarity; if(bonuses){ if(!exportItem['bonus']){ exportItem['bonus'] = []; } for(let bonus_id in bonuses){ const bonus_item = bonuses[bonus_id]; const {bonus, value, description} = bonus_item; const valueStr = handlePercentage(description, value); exportItem['bonus'].push({ name: bonus, value: valueStr }); } } // weapon if(iType === 1){ exportItem['damage'] = damage; exportItem['accuracy'] = accuracy; } // armor else if(iType === 2){ exportItem['armor'] = armor; } exportMap[armouryID] = exportItem; interceptButton(); } } } const handleBazaar = (resp)=>{ const bazaarList = resp.list; if(bazaarList){ for(let item of bazaarList){ let {name, armoryID, itemID, accuracy, damage, arm, currentBonuses, quality, rarity, category, price} = item; if(!itemID) continue; itemID = parseInt(itemID); const iType = itemType(itemID); if(filterType.indexOf(category) === -1) continue; if(exportMap[armoryID]) continue; const exportItem = {}; exportItem['name'] = name; exportItem['quality'] = quality; exportItem['price'] = price; rarity = parseInt(rarity); switch(rarity){ case 0: exportItem['rarity'] = 'None'; break; case 1: exportItem['rarity'] = 'Yellow'; break; case 2: exportItem['rarity'] = 'Orange'; break; case 3: exportItem['rarity'] = 'Red'; break; } if(currentBonuses){ if(!exportItem['bonus']){ exportItem['bonus'] = []; } for(let bonus_id in currentBonuses){ const bonus_item = currentBonuses[bonus_id]; const {title, value, desc} = bonus_item; const valueStr = handlePercentage(desc, value); exportItem['bonus'].push({ name: title, value: valueStr }); } } if(iType === 1){ exportItem['damage'] = damage; exportItem['accuracy'] = accuracy; } else if(iType === 2){ exportItem['armor'] = arm; } exportMap[armoryID] = exportItem; interceptButton(); } } } function interceptFetch() { const targetWindow = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window; const origFetch = targetWindow.fetch; targetWindow.fetch = async (...args) => { const rsp = await origFetch(...args); const url = new URL(args[0], location.origin); const params = new URLSearchParams(url.search); // If a request is sent to get bazaarData, we capture and clone it to update the page if (url.pathname === '/bazaar.php' && params.get('sid') === 'bazaarData') { const clonedRsp = rsp.clone(); const resp = await clonedRsp.json(); handleBazaar(resp); } return rsp; }; } waitForKeyElements('ul.display-cabinet li', updateCabinet); if(location.href.startsWith("https://www.torn.com/bazaar.php?userId=")){ interceptFetch(); } })(); function waitForKeyElements( selectorTxt, actionFunction, bWaitOnce, iframeSelector ) { var targetNodes, btargetsFound; if (typeof iframeSelector == "undefined") targetNodes = $(selectorTxt); else targetNodes = $(iframeSelector).contents().find(selectorTxt); if (targetNodes && targetNodes.length > 0) { btargetsFound = true; /*--- Found target node(s). Go through each and act if they are new. */ targetNodes.each(function () { var jThis = $(this); var alreadyFound = jThis.data("alreadyFound") || false; if (!alreadyFound) { //--- Call the payload function. var cancelFound = actionFunction(jThis); if (cancelFound) btargetsFound = false; else jThis.data("alreadyFound", true); } }); } else { btargetsFound = false; } //--- Get the timer-control variable for this selector. var controlObj = waitForKeyElements.controlObj || {}; var controlKey = selectorTxt.replace(/[^\w]/g, "_"); var timeControl = controlObj[controlKey]; //--- Now set or clear the timer as appropriate. if (btargetsFound && bWaitOnce && timeControl) { //--- The only condition where we need to clear the timer. clearInterval(timeControl); delete controlObj[controlKey]; } else { //--- Set a timer, if needed. if (!timeControl) { timeControl = setInterval(function () { waitForKeyElements( selectorTxt, actionFunction, bWaitOnce, iframeSelector ); }, 500); controlObj[controlKey] = timeControl; } } waitForKeyElements.controlObj = controlObj; }