您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Collect information from BillyCon pages and send it to a remote server for further analysis
// ==UserScript== // @name BvS BillyCon Analyser // @namespace TheSpy // @description Collect information from BillyCon pages and send it to a remote server for further analysis // @version 1.12 // @history 1.12 New domain - animecubedgaming.com - Channel28 // @history 1.11 Now https compatible (Updated by Channel28) // @history 1.10 Added grant permissions (Updated by Channel28) // @history 1.09 Fixed: DOM issue (temporary fix) // @history 1.08 Fixed: Free Time to Wander was not detected // @history 1.07 Updated: Changed wander parsing from Regex to XPath // @history 1.06 Updated: Quick fix to wanders with level up // @history 1.05 Updated: Deals save modifiers now // @history 1.04 Fixed: In some cases the script didn't parse information correctly; added protection and debug information // @history 1.03 Added: Saving wander events // @history 1.02 Added: Save day/hour along with the deal // @history 1.02 Fixed: Owned cosplay sets don't send the (owned!) post-fix anymore // @history 1.01 Fixed: Hot cosplay sets don't send the (Hot!) post-fix anymore // @history 1.00 Initial release (credits: north made the cosplay part, I added the deal part) // @include http*://*animecubed.com/billy/bvs/billycon-character.html // @include http*://*animecubed.com/billy/bvs/billycon.html // @include http*://*animecubedgaming.com/billy/bvs/billycon-character.html // @include http*://*animecubedgaming.com/billy/bvs/billycon.html // @grant GM_addStyle // @grant GM_xmlhttpRequest // ==/UserScript== /*************************************************************** * DOM Storage Wrapper Class * * Public members: * ctor({"session"|"local"}[, <namespace>]) * setItem(<key>, <value>) * getItem(<key>, <default value>) * removeItem(<key>) * keys() ***************************************************************/ function Storage(type, namespace) { var object = this; if(typeof(type) != "string") type = "session"; switch(type) { case "local": { object.storage = localStorage; } break; case "session": { object.storage = sessionStorage; } break; default: { object.storage = sessionStorage; } break; } if (!namespace || (typeof(namespace) != "string" && typeof(namespace) != "number")) namespace = "ScriptStorage"; object.namespace = [namespace, "."].join(""); object.setItem = function(key, value) { try { object.storage.setItem(escape([object.namespace, key].join("")), uneval(value)); } catch(e) { } } object.getItem = function(key, defaultValue) { try { var value = object.storage.getItem(escape([object.namespace, key].join(""))); if(value) return eval(value); else return defaultValue; } catch(e) { return defaultValue; } } object.removeItem = function(key) { try { object.storage.removeItem(escape([object.namespace, key].join(""))); } catch(e) { } } object.keys = function() { var array = []; var i = 0; do { try { var key = unescape(object.storage.key(i++)); if(key.indexOf(object.namespace) == 0 && object.storage.getItem(key)) array.push(key.slice(object.namespace.length)); } catch(e) { break; } } while(true); return array; } } // UI (credits: http://userscripts.org/users/dtkarlsson) function Window(id, storage) { var my = this; my.id = id; my.offsetX = 0; my.offsetY = 0; my.moving = false; my.element = document.createElement("div"); my.elementContainer = document.createElement("div"); // Window dragging events my.drag = function(event) { if (my.moving) { my.elementContainer.style.left = (event.clientX - my.offsetX)+'px'; my.elementContainer.style.top = (event.clientY - my.offsetY)+'px'; event.preventDefault(); } } my.stopDrag = function(event) { if (my.moving) { my.moving = false; var x = parseInt(my.elementContainer.style.left); var y = parseInt(my.elementContainer.style.top); if(x < 0) x = 0; if(y < 0) y = 0; storage.setItem(my.id + ".coord.x", x); storage.setItem(my.id + ".coord.y", y); my.elementContainer.style.opacity = 1; my.elementContainer.removeEventListener('mouseup', my.stopDrag, true); my.elementContainer.removeEventListener('mousemove', my.drag, true); } } my.startDrag = function(event) { if (event.button != 0) { my.moving = false; return; } my.offsetX = event.clientX - parseInt(my.elementContainer.style.left); my.offsetY = event.clientY - parseInt(my.elementContainer.style.top); my.moving = true; my.elementContainer.style.opacity = 0.75; event.preventDefault(); my.elementContainer.addEventListener('mouseup', my.stopDrag, true); my.elementContainer.addEventListener('mousemove', my.drag, true); } my.elementContainer.id = id; my.elementContainer.className = "drag"; document.body.appendChild(my.elementContainer); my.elementContainer.appendChild(my.element); my.elementContainer.addEventListener('mousedown', my.startDrag, true); if (storage.getItem(my.id + ".coord.x")) my.elementContainer.style.left = storage.getItem(my.id + ".coord.x") + "px"; else my.elementContainer.style.left = "6px"; if (storage.getItem(my.id + ".coord.y")) my.elementContainer.style.top = storage.getItem(my.id + ".coord.y") + "px"; else my.elementContainer.style.top = "6px"; } function FloatingAnalyser() { var my = this; my.window = new Window("BvSDataAnalyser", analyserSettings); GM_addStyle("#BvSDataAnalyser {border: 2px solid #00FF00; position: fixed; z-index: 100; font-size: 12px; font-family: courier new; color: #00FF00; background-color: black; padding: 6px; text-align: left; min-height: 16px; cursor: move;} #BvSDataAnalyser div div {border: 2px solid #00FF00; margin-top: 6px;}"); my.addText = function(text) { if(my.window.element.innerHTML.length > 0) my.window.element.innerHTML = [my.window.element.innerHTML, text].join("<br/>"); else my.window.element.innerHTML = text; } my.setText = function(text) { my.window.element.innerHTML = text; } } var analyserSettings = new Storage("local", "BvSBillyConAnalyser"); var analyserWindow; // StripString(string) function StripString(string) { string = string.replace(/^\s+/g, ""); string = string.replace(/\s+$/g, ""); string = string.replace(/\s+/g, " "); return string; } // PlayerName() function PlayerName() { try { return document.evaluate("//input[@name='player' and @type='hidden']", document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.value; } catch (e) { return "none"; } } // BillyConTime() function BillyConTime() { var o = new Object; o.day = "???"; o.hour = "???"; try { var snapTime = document.evaluate("//table[@class='constats']/tbody/tr[2]/td[position() > 5 and position() < 8]/b", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if(snapTime.snapshotLength == 2 && (/\d+ AM/i.test(snapTime.snapshotItem(1).textContent) || /Noon/i.test(snapTime.snapshotItem(1).textContent) || /\d+ PM/i.test(snapTime.snapshotItem(1).textContent) || /Midnight/i.test(snapTime.snapshotItem(1).textContent) || /LATE/i.test(snapTime.snapshotItem(1).textContent))) { o.day = snapTime.snapshotItem(0).textContent; o.hour = snapTime.snapshotItem(1).textContent; } } catch(e) { o.day = "???"; o.hour = "???"; } return o; } // QueryServer(arguments) function QueryServer(arguments, type) { try { arguments = [arguments, "version=1.07"].join("&"); GM_xmlhttpRequest({ method: "POST", url: ["http://bvs.ecansol.com/billyconanalyser/", type, "/"].join(""), headers: { "User-Agent": "Mozilla/5.0", "Accept": "text/xml", "Content-type": "application/x-www-form-urlencoded" }, data: encodeURI(arguments), onerror: function(response) { analyserWindow.setText(["<b>Error:</b> ", response.status].join("")); }, onload: function(response) { try { analyserWindow.setText(response.responseText); } catch(e) { alert(e); } } }); } catch(e) { alert(e); } } // BillyConDealsAnalyser(snap) function BillyConDealsAnalyser(snap) { try { var arguments = new Array(); var billyConTime = BillyConTime(); for(var i = 0; i < snap.snapshotLength; i++) { var match = snap.snapshotItem(i).textContent.replace(/\s+\(owned!\)/i, "").match(/^(.*) (\d+)M\n\(([^\)]+)\)/i); if(match && match[1] && match[2] && match[3]) { arguments.push(["deals[", i, "][name]=", encodeURIComponent(StripString(match[1]))].join("")); arguments.push(["deals[", i, "][monies]=", match[2]].join("")); arguments.push(["deals[", i, "][desc]=", encodeURIComponent(StripString(match[3]))].join("")); arguments.push(["deals[", i, "][day]=", StripString(billyConTime.day)].join("")); arguments.push(["deals[", i, "][hour]=", StripString(billyConTime.hour)].join("")); } } var snapDealModifiers = document.evaluate("//table[contains(translate(@bgcolor, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'111188')]/tbody/tr/td/font/i[contains(.,'Deal Modifiers')]/text()[last()]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if(snapDealModifiers.snapshotLength == 1) arguments.push(["modifiers=", StripString(snapDealModifiers.snapshotItem(0).nodeValue)].join("")); arguments.push(["contributor=", PlayerName()].join("")); QueryServer(arguments.join("&"), "deals"); } catch(e) { alert(e); } } // BillyConWanderAnalyser(snap) function BillyConWanderAnalyser(snap) { try { var arguments = new Array(); var billyConTime = BillyConTime(); var event = ""; var description = ""; var modifiers = ""; var ttw = 0; var extra = []; try { event = document.evaluate("./text()", snap.snapshotItem(0), null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.nodeValue; } catch(e) {} try { description = document.evaluate("./i/text()", snap.snapshotItem(0), null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.nodeValue; } catch(e) {} try { modifiers = document.evaluate("./font/b/text()", snap.snapshotItem(0), null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.nodeValue; } catch(e) {} try { var snapExtra = document.evaluate("./font[2]//text()", snap.snapshotItem(0), null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for(var i = 0; i < snapExtra.snapshotLength; i++) { extra.push(snapExtra.snapshotItem(i).nodeValue); } } catch(e) {} try { var snapTTW = document.evaluate("./i/b[contains(.,'Time to Wander!')]", snap.snapshotItem(0), null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if(snapTTW.snapshotLength > 0) ttw = 1; } catch(e) {} if(event.length > 0) { if(!modifiers) modifiers = ""; arguments.push(["event=", encodeURIComponent(StripString(event))].join("")); arguments.push(["description=", encodeURIComponent(StripString(description))].join("")); arguments.push(["modifiers=", encodeURIComponent(StripString(modifiers))].join("")); arguments.push(["ttw=", ttw].join("")); arguments.push(["extra=", encodeURIComponent(StripString(extra.join(" ")))].join("")); arguments.push(["day=", StripString(billyConTime.day)].join("")); arguments.push(["hour=", StripString(billyConTime.hour)].join("")); } arguments.push(["contributor=", PlayerName()].join("")); QueryServer(arguments.join("&"), "wander"); } catch(e) { alert(e); } } // BillyConCosplayAnalyser() function BillyConCosplayAnalyser() { try { var arguments = new Array(); var name, stats; var snap = document.evaluate("//table[@width='80%']//table/tbody/tr[position()>1]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for(var i = 0; i < snap.snapshotLength; i += 2) { name = snap.snapshotItem(i).textContent.replace(/\s+\(Hot!\)/i, ""); stats = snap.snapshotItem(i+1).textContent.replace(/\?{3}/g, "0").match(/(\d+d\d+[+-]\d+|\d+d\d+|0)/g); if(stats.length == 4) { var type = ["head", "body", "prop", "combo"]; for(var j = 0; j < 4; j++) { if(stats[j] != "0") { var match = stats[j].match(/(\d+)d(\d+)([+-]\d+)?/i); arguments.push(["cosplay[", StripString(name), "][", type[j], "][r]=", match[1]].join("")); arguments.push(["cosplay[", StripString(name), "][", type[j], "][d]=", match[2]].join("")); arguments.push(["cosplay[", StripString(name), "][", type[j], "][b]=", match[3]].join("")); } } } } arguments.push(["contributor=", PlayerName()].join("")); QueryServer(arguments.join("&"), "cosplay"); } catch(e) { alert(e); } } if(/animecubed.com.billy.bvs.billycon.html/i.test(location.href)) { var snap = document.evaluate("//form[@name='condroom']/table/tbody/tr/td/label", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if(snap.snapshotLength > 0) { analyserWindow = new FloatingAnalyser(); analyserWindow.setText("<blink>Loading...</blink>"); var billyConDealsAnalyser = new BillyConDealsAnalyser(snap); } var snap = document.evaluate("//table/tbody/tr/td/b[contains(.,'Wandering Encounter')]/..", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if(snap.snapshotLength > 0) { analyserWindow = new FloatingAnalyser(); analyserWindow.setText("<blink>Loading...</blink>"); var billyConWanderAnalyser = new BillyConWanderAnalyser(snap); } } if(/animecubed.com.billy.bvs.billycon.character.html/i.test(location.href)) { analyserWindow = new FloatingAnalyser(); analyserWindow.setText("<blink>Loading...</blink>"); var billyConCosplayAnalyser = new BillyConCosplayAnalyser(); }