// ==UserScript==
// @name 咕咕镇数据采集
// @namespace https://greasyfork.org/users/448113
// @version 1.4.4
// @description 咕咕镇数据采集,目前采集已关闭,兼作助手
// @author paraii
// @match https://www.guguzhen.com/*
// @grant GM_xmlhttpRequest
// @connect www.guguzhen.com
// @run-at document-body
// @license MIT License
// @downloadURL none
// ==/UserScript==
// @connect notes.orga.cat
// @require https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js
// @require https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/js/tooltip.js
// @require https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/js/popover.js
(function() {
'use strict'
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// by zyxboy
//
////////////////////////////////////////////////////////////////////////////////////////////////////
const g_modificationVersion = '2022-05-22 06:30:00';
const g_kfUser = document.getElementsByClassName('icon-user')[0].parentNode.innerText.split(' ')[1];
const g_autoTaskEnabledStorageKey = g_kfUser + '_autoTaskEnabled';
const g_amuletGroupsStorageKey = g_kfUser + '_amulet_groups';
const g_equipmentBGStorageKey = g_kfUser + '_equipment_BG';
const g_beachBGStorageKey = g_kfUser + '_beach_BG';
const g_userDataStorageKeyConfig = [ g_kfUser, g_autoTaskEnabledStorageKey, 'keepcheck', g_amuletGroupsStorageKey,
g_equipmentBGStorageKey, g_beachBGStorageKey, 'beachcheck' ];
const g_userDataStorageKeyExtra = [ 'attribute', 'cardName', 'title', 'over', 'halo_max', 'dataReward' ];
const USER_STORAGE_RESERVED_SEPARATORS = /[:;,|=+*%!#$&?<>{}^`"\\\/\[\]\r\n\t\v\s]/;
const USER_STORAGE_KEY_VALUE_SEPARATOR = ':';
console.log(g_kfUser)
// perform a binary search. array must be sorted, but no matter in ascending or descending order.
// in this manner, you must pass in a proper comparer function for it works properly, aka, if the
// array was sorted in ascending order, then the comparer(a, b) should return a negative value
// while a < b or a positive value while a > b; otherwise, if the array was sorted in descending
// order, then the comparer(a, b) should return a positive value while a < b or a negative value
// while a > b, and in both, if a equals b, the comparer(a, b) should return 0. if you pass nothing
// or null / undefined value as comparer, then you must make sure about that the array was sorted
// in ascending order.
//
// in this particular case, we just want to check whether the array contains the value or not, we
// don't even need to point out the first place where the value appears (if the array actually
// contains the value), so we perform a simplest binary search and return an index (may not the
// first place where the value appears) or a negative value (means value not found) to indicate
// the search result.
function searchElement(array, value, fnComparer) {
if (array?.length > 0) {
fnComparer ??= ((a, b) => a < b ? -1 : (a > b ? 1 : 0));
let li = 0;
let hi = array.length - 1;
while (li <= hi) {
let mi = ((li + hi) >> 1);
let cr = fnComparer(value, array[mi]);
if (cr == 0) {
return mi;
}
else if (cr > 0) {
li = mi + 1;
}
else {
hi = mi - 1;
}
}
}
return -1;
}
// perform a binary insertion. the array and comparer must exactly satisfy as it in the searchElement
// function. this operation behaves sort-stable, aka, the newer inserting element will be inserted
// into the position after any existed equivalent elements.
function insertElement(array, value, fnComparer) {
if (array != null) {
fnComparer ??= ((a, b) => a < b ? -1 : (a > b ? 1 : 0));
let li = 0;
let hi = array.length - 1;
while (li <= hi) {
let mi = ((li + hi) >> 1);
let cr = fnComparer(value, array[mi]);
if (cr >= 0) {
li = mi + 1;
}
else {
hi = mi - 1;
}
}
array.splice(li, 0, value);
return li;
}
return -1;
}
// it's not necessary to have newArray been sorted, but the oldArray must be sorted since we are calling
// searchElement. if there are some values should be ignored in newArray, the comparer(a, b) should be
// implemented as return 0 whenever parameter a equals any of values that should be ignored.
function findNewObjects(newArray, oldArray, fnComparer, findIndices) {
// just in case, i discovered that sometimes if we use array.length directly in for(...) statement
// (either some other statements too), the statement get chances to be executed incorrectly (or just
// console.log can be effected?), don't know why, but we can use a temporary variable to handle this.
let newObjects = [];
let nl = (newArray?.length ?? 0);
for (let i = 0; i < nl; i++) {
if (searchElement(oldArray, newArray[i], fnComparer) < 0) {
newObjects.push(findIndices ? i : newArray[i]);
}
}
return newObjects;
}
// HTTP requests
var g_httpRequests = [];
function httpRequestRegister(request) {
if (request != null) {
g_httpRequests.push(request);
}
}
function httpRequestAbortAll() {
while (g_httpRequests.length > 0) {
g_httpRequests.pop().abort();
}
g_httpRequests = [];
}
function httpRequestClearAll() {
g_httpRequests = [];
}
function objectIdParseNodes(nodes, ids, ignoreEmptyCell) {
for (let node of nodes) {
if (node.className?.endsWith("fyg_mp3")) {
let id = node.getAttribute('onclick')?.match(/\d+/)[0];
if (id != undefined) {
ids.push(id);
}
else if (!ignoreEmptyCell) {
ids.push(-1);
}
}
}
}
const g_postMethod = 'POST'
const g_readUrl = 'https://www.guguzhen.com/fyg_read.php'
const g_postUrl = 'https://www.guguzhen.com/fyg_click.php'
const g_postHeader = { 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8' , 'Cookie' : document.cookie };
const g_networkTimeoutMS = 120 * 1000;
function beginReadObjects(bagIds, storeIds, ignoreEmptyCell, fnFurtherProcess, fnParams) {
if (bagIds != null || storeIds != null) {
let request = GM_xmlhttpRequest({
method: g_postMethod,
url: g_readUrl,
headers: g_postHeader,
data: 'f=7',
onload: response => {
let div = document.createElement('div');
div.innerHTML = response.responseText;
if (bagIds != null) {
objectIdParseNodes(div.children[0].children[1].children, bagIds, ignoreEmptyCell);
}
if (storeIds != null) {
objectIdParseNodes(div.children[1].children[1].children, storeIds, ignoreEmptyCell);
}
if (fnFurtherProcess != null) {
fnFurtherProcess(fnParams);
}
}
});
httpRequestRegister(request);
}
else if (fnFurtherProcess != null) {
fnFurtherProcess(fnParams);
}
}
// we wait the response(s) of the previous batch of request(s) to send another batch of request(s)
// rather than simply send them all within an inside foreach - which could cause too many requests
// to server simultaneously, that can be easily treated as D.D.O.S attack and therefor leads server
// to returns http status 503: Service Temporarily Unavailable
// * caution * the parameter 'objects' is required been sorted by their indices in ascending order
const g_maxConcurrentRequestsCount = 5;
var g_objectMoveRequestsCount = 0;
var g_objectMoveTargetSiteFull = false;
var g_func_puti_data = null;
var g_func_puto_data = null;
function beginMoveObjects(objects, bagToStore, fnFurtherProcess, fnParams) {
if (!g_objectMoveTargetSiteFull && objects?.length > 0) {
g_func_puti_data ??= getPostData(/puti\(id\)\{[\s\S]*\}/m, /data: ".*\+id\+.*"/).slice(7, -1);
g_func_puto_data ??= getPostData(/puto\(id\)\{[\s\S]*\}/m, /data: ".*\+id\+.*"/).slice(7, -1);
let ids = [];
while (ids.length < g_maxConcurrentRequestsCount && objects.length > 0) {
let id = objects.pop();
if (id >= 0) {
ids.push(id);
}
}
if ((g_objectMoveRequestsCount = ids.length) > 0) {
while (ids.length > 0) {
let request = GM_xmlhttpRequest({
method: g_postMethod,
url: g_postUrl,
headers: g_postHeader,
data: (bagToStore ? g_func_puti_data : g_func_puto_data).replace('"+id+"', ids.shift()),
onload: response => {
if (response.responseText != 'ok') {
g_objectMoveTargetSiteFull = true;
}
if (--g_objectMoveRequestsCount == 0) {
beginMoveObjects(objects, bagToStore, fnFurtherProcess, fnParams);
}
}
});
httpRequestRegister(request);
}
return;
}
}
g_objectMoveTargetSiteFull = false;
if (fnFurtherProcess != null) {
fnFurtherProcess(fnParams);
}
}
// read currently mounted role card and halo informations
// roleInfo = [ roleId, roleName ]
// haloInfo = [ haloPoints, haloSlots, [ haloItem1, haloItem2, … ] ]
function beginReadRoleAndHalo(roleInfo, haloInfo, fnFurtherProcess, fnParams) {
let asyncOperations = 0;
let error = 0;
let requestRole;
let requestHalo;
if (roleInfo != null) {
asyncOperations++;
requestRole = GM_xmlhttpRequest({
method: g_postMethod,
url: g_readUrl,
headers: g_postHeader,
data: 'f=9',
onload: response => {
let div = document.createElement('div');
div.innerHTML = response.responseText;
let role = g_roleMap.get(div.querySelector('div.text-info.fyg_f24.fyg_lh60')?.children[0]?.innerText);
if (role != undefined) {
roleInfo.push(role.id);
roleInfo.push(role.name);
}
asyncOperations--;
},
onerror : err => {
error++;
asyncOperations--;
},
ontimeout : err => {
error++;
asyncOperations--;
}
});
}
if (haloInfo != null) {
asyncOperations++;
requestHalo = GM_xmlhttpRequest({
method: g_postMethod,
url: g_readUrl,
headers: g_postHeader,
data: 'f=5',
onload: response => {
let haloPS = response.responseText.match(/
`;
insertAfter(btn0, btns[i]);
}
}
g_pickingEquipment = false;
}
$(function() {
$('#beach_copy .btn[data-toggle="popover"]').popover();
});
$('#beach_copy .bg-danger.with-padding').css({
'max-width': '200px',
'padding': '5px',
'white-space': 'pre-line',
'word-break': 'break-all'
});
changeBeachStyle('beach_copy');
}
function changeBeachStyle(container)
{
$(`#${container}`).css({
'background-color': beach_BG ? 'black' : 'white'
});
$(`#${container} .popover-content-show`).css({
'background-color': beach_BG ? 'black' : 'white'
});
$(`#${container} .btn-light`).css({
'background-color': beach_BG ? 'black' : 'white'
});
$(`#${container} .popover-title`).css({
'color': beach_BG ? 'black' : 'white'
});
$(`#${container} .pull-right`).css({
'color': beach_BG ? 'black' : 'white'
});
$(`#${container} .bg-danger.with-padding`).css({
'color': beach_BG ? 'black' : 'white'
});
}
//
// by zyxboy
//等待海滩装备加载
let show = setInterval(() => {
if ($('#beachall .btn').length != 0) {
clearInterval(show);
//等待装备读取完成
let pick = setInterval(() => {
if (equipment.length > 0) {
clearInterval(pick);
pickEquipment(equipment);
let beachObserver = new MutationObserver(() => { pickEquipment(equipment); });
beachObserver.observe(document.getElementById('beachall'), { childList: true });
}
}, 500);
}
}, 500);
function copyBeach(beach_copy) {
beach_copy.innerHTML = '';
let nodes = Array.from(document.getElementById('beachall').children).sort(sortBeach);
for (let node of nodes) {
beach_copy.appendChild(node.cloneNode(true));
}
}
function sortBeach(a, b) {
if (a.className != b.className) {
if (a.className == null || !a.className.endsWith('fyg_mp3')) {
return -1;
}
else if (b.className == null || !b.className.endsWith('fyg_mp3')) {
return 1;
}
return (a.className.split(' ')[1] > b.className.split(' ')[1] ? -1 : 1);
}
else if (a == null || !a.className.endsWith('fyg_mp3')) {
return -1;
}
let delta = parseInt(a.innerText.match(/\d+/)[0]) - parseInt(b.innerText.match(/\d+/)[0]);
return (delta != 0 ? -delta : (a.getAttribute('data-original-title') > b.getAttribute('data-original-title') ? -1 : 1));
}
// end by zyxboy
//
}
else if (window.location.pathname == '/fyg_pk.php') {
//
// by zyxboy
let autoTaskEnabled = localStorage.getItem(g_autoTaskEnabledStorageKey);
if (autoTaskEnabled == null) {
autoTaskEnabled = 1;
localStorage.setItem(g_autoTaskEnabledStorageKey, autoTaskEnabled);
}
let autoTaskEnabledSpan = document.createElement('label');
autoTaskEnabledSpan.setAttribute('for','autoTaskEnabledCheckbox');
autoTaskEnabledSpan.style.float = 'right';
autoTaskEnabledSpan.style.color = '#ffffff';
autoTaskEnabledSpan.style.padding = '5px';
autoTaskEnabledSpan.style.cursor = 'pointer';
autoTaskEnabledSpan.innerText = '允许执行自定义任务';
let autoTaskEnabledCheckbox = document.createElement('input');
autoTaskEnabledCheckbox.id = 'autoTaskEnabledCheckbox';
autoTaskEnabledCheckbox.setAttribute('type','checkbox');
autoTaskEnabledCheckbox.style.marginLeft = '5px';
autoTaskEnabledCheckbox.style.marginRight = '10px';
autoTaskEnabledCheckbox.checked = (autoTaskEnabled != 0);
autoTaskEnabledCheckbox.onchange = (() => {
localStorage.setItem(g_autoTaskEnabledStorageKey, autoTaskEnabledCheckbox.checked ? 1 : 0);
window.location.reload();
});
autoTaskEnabledSpan.appendChild(autoTaskEnabledCheckbox);
let p = document.getElementsByClassName('panel panel-primary')[0];
p.insertBefore(autoTaskEnabledSpan, p.children[0]);
if (autoTaskEnabledCheckbox.checked) {
// end by zyxboy
//
let btngroup0 = document.createElement('div');
btngroup0.setAttribute('class', 'action_selector');
btngroup0.innerHTML = `
`;
let btngroup1 = document.createElement('div');
btngroup1.setAttribute('class', 'action_selector');
btngroup1.innerHTML = `
`;
let btngroup2 = document.createElement('div');
btngroup2.setAttribute('class', 'action_selector');
btngroup2.innerHTML = `
`;
let observerBody0 = new MutationObserver(() => {
//observerBody0.disconnect();
if (document.getElementsByClassName('btn-secondary').length == 0) {
let addbtn = setInterval(() => {
let col = document.querySelector("#pklist > div > div.col-md-8");
if (col != null) {
clearInterval(addbtn);
let obtns = document.getElementsByClassName('btn-block dropdown-toggle fyg_lh30');
col.insertBefore(btngroup0, obtns[0]);
col.insertBefore(btngroup1, obtns[1]);
col.insertBefore(btngroup2, obtns[2]);
if (document.getElementsByClassName('btn-outline-secondary').length == 0) {
if (localStorage.getItem('dataReward') == null) {
localStorage.setItem('dataReward', '{"sumShell":"0","sumExp":"0"}');
}
let ok = document.createElement('div');
ok.innerHTML = ``;
col.appendChild(ok);
function gobattle() {
let times = [ 0, 0, 0 ];
let sum = 0;
$(".btn-secondary").each(function(i, e) {
if ($(e).attr("style") != null && $(e).css("background-color") == "rgb(135, 206, 250)") {
let a = parseInt(e.innerText);
let b = $(".btn-group .btn-secondary").index(e);
sum += a;
if (b < 11) {
times[0] = a / 10;
} else if (b >= 11 && b < 32) {
times[1] = a / 5;
} else if (b >= 32) {
times[2] = a / 5;
}
}
});
if (sum <= parseInt(document.getElementsByClassName('fyg_colpz03')[0].innerText)) {
let gox_data = getPostData(/gox\(\)\{[\s\S]*\}/m, /data: ".*"/).slice(7, -1);
let dataReward = JSON.parse(localStorage.getItem('dataReward'));
let sum0 = parseInt(dataReward.sumShell);
let sum1 = parseInt(dataReward.sumExp);
//
// by zyxboy
function parseGainResponse(response)
{
let gainText = '';
if (response.startsWith('
获得了
')) {
let gain;
let sp = '获得';
let regex = /x\s*(\d+)\s*([^<]+)<\/span>/g;
while ((gain = regex.exec(response))?.length == 3) {
gainText += `${sp}${gain[2].trim()}:${gain[1]}`;
sp = ', ';
}
let lvlUp = response.match(/角色 \[ [^\s]+ \] 卡片等级提升!/g);
if (lvlUp?.length > 0) {
lvlUp.forEach((e) => {
gainText += `${sp}${e}`;
sp = ', ';
});
}
}
return gainText;
}
// end by zyxboy
//
function func0(time) {
if (time == 0) {
if (times[0] != 0) {
GM_xmlhttpRequest({
method: g_postMethod,
url: g_readUrl,
headers: g_postHeader,
data: 'f=12',
onload: response => {
let ap = response.responseText.match(/class="fyg_colpz03" style="font-size:32px;font-weight:900;">\d+)[0].match(/>\d+)[0].slice(1, -1);
document.getElementsByClassName('fyg_colpz03')[0].innerText = ap;
let rankp = response.responseText.match(/class="fyg_colpz02" style="font-size:32px;font-weight:900;">\d+%)[0].match(/\d+%/)[0];
document.getElementsByClassName('fyg_colpz02')[0].innerText = rankp;
let div_sum = document.createElement('div');
div_sum.innerText = `贝壳总次数:经验总次数=${sum0}:${sum1}=${(sum0 == 0 || sum1 == 0) ? 'undefined' : (sum0 / sum1).toFixed(4)}`;
dataReward.sumShell = sum0;
dataReward.sumExp = sum1;
localStorage.setItem('dataReward', JSON.stringify(dataReward));
document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_sum);
times[0] = 0;
}
});
}
return;
}
GM_xmlhttpRequest({
method: g_postMethod,
url: g_postUrl,
headers: g_postHeader,
data: gox_data,
onload: response => {
//
// by zyxboy
let gainText = parseGainResponse(response.responseText);
if (gainText.length > 0) {
let div_info = document.createElement('div');
div_info.innerText = gainText;
document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_info);
if (gainText.indexOf('贝壳') != -1) {
sum0 += 1;
}
if (gainText.indexOf('经验') != -1) {
sum1 += 1;
}
func0(time - 1);
} else {
let div_info = document.createElement('div');
div_info.innerText = '段位进度不足或无法识别的应答信息';
document.getElementsByClassName('btn-outline-secondary')[0].parentNode.appendChild(div_info);
func0(0);
}
// end by zyxboy
//
}
});
}
function func1(time) {
if (time == 0) {
times[1] = 0;
return;
}
let observerPk = new MutationObserver((mutationsList, observer) => {
let isPk = 0;
for (let mutation of mutationsList) {
if (mutation.type == 'childList') {
isPk = 1;
}
}
if (isPk) {
observerPk.disconnect();
func1(time - 1);
}
});
observerPk.observe(document.querySelector("#pk_text"), { characterData: true, childList: true });
jgjg(1);
}
function func2(time) {
if (time == 0) {
times[2] = 0;
return;
}
let observerPk = new MutationObserver((mutationsList, observer) => {
let isPk = 0;
for (let mutation of mutationsList) {
if (mutation.type == 'childList') {
isPk = 1;
}
}
if (isPk) {
observerPk.disconnect();
func2(time - 1);
}
});
observerPk.observe(document.querySelector("#pk_text"), { characterData: true, childList: true });
jgjg(2);
}
func0(times[0]);
let waitFor0 = setInterval(() => {
if (times[0] == 0) {
clearInterval(waitFor0);
func1(times[1]);
}
}, 1000);
let waitFor1 = setInterval(() => {
if (times[0] == 0 && times[1] == 0) {
clearInterval(waitFor1);
func2(times[2]);
}
}, 1000);
} else {
alert('体力不足');
}
}
document.getElementsByClassName('btn-outline-secondary')[0].addEventListener('click', gobattle, false);
}
function selector_act() {
var btnNum = $(".btn-group .btn-secondary").index(this);
$(".btn-group .btn-secondary")
.eq(btnNum)
.css("background-color", "rgb(135, 206, 250)")
.siblings(".btn-group .btn-secondary")
.css("background-color", "rgb(255, 255, 255)");
}
let btnselector = document.getElementsByClassName('btn-secondary');
for (let i = 0; i < btnselector.length; i++) {
btnselector[i].addEventListener('click', selector_act, false);
}
}
}, 1000);
}
});
observerBody0.observe(document.getElementsByClassName('panel panel-primary')[0], { childList: true, subtree: true, });
}
let keepCheck = document.createElement('form');
keepCheck.innerHTML =
`
`;
document.getElementsByClassName('panel panel-primary')[1].insertBefore(keepCheck, document.getElementById('pk_text'));
document.querySelector("#keepcheck").addEventListener('click', () => { localStorage.setItem('keepcheck', document.querySelector("#keepcheck").checked) }, false);
document.querySelector("#keepcheck").checked = (localStorage.getItem('keepcheck') == 'true');
let div0_pk_text_more = document.createElement('div');
div0_pk_text_more.setAttribute('id', 'pk_text_more');
div0_pk_text_more.setAttribute('class', 'panel-body');
document.getElementsByClassName('panel panel-primary')[1].appendChild(div0_pk_text_more);
let pkText = document.querySelector("#pk_text").innerHTML;
let observerBody1 = new MutationObserver(() => {
if (document.querySelector("#keepcheck").checked == true) {
document.querySelector("#pk_text_more").innerHTML = pkText + document.querySelector("#pk_text_more").innerHTML;
pkText = document.querySelector("#pk_text").innerHTML;
$('#pk_text_more .btn[data-toggle="tooltip"]').tooltip();
}
});
observerBody1.observe(document.querySelector("#pk_text"), { characterData: true, childList: true });
wishExpireTip();
}
else if (window.location.pathname == '/fyg_wish.php') {
let timer = setInterval(() => {
let wishPoints = parseInt(document.getElementById('xys_dsn')?.innerText);
if (!isNaN(wishPoints)) {
clearInterval(timer);
function getWishPoints() {
let text = 'WISH';
for (let i = 7; i <= 13; i++) {
text += (' ' + (document.getElementById('xyx_' + ('0' + i).slice(-2))?.innerText ?? '0'));
}
return text;
}
unsafeWindow.copyWishPoints = ((a) => {
let acolor = a.style.color;
let astring = a.innerText;
a.style.color = '#c00000';
calcWishPoints.select();
if (document.execCommand('copy')) {
a.innerText = '许愿点设置已复制到剪贴板';
}
else {
a.innerText = '复制失败,这可能是因为浏览器没有剪贴板访问权限,请进行手工复制';
}
setTimeout((() => {
a.style.color = acolor;
a.innerText = astring;
}), 3000);
});
let div = document.createElement('div');
div.className = 'row';
div.innerHTML =
'