// ==UserScript==
// @name HWM_CommitMultipleTransfers
// @namespace Небылица
// @version 1.25
// @description Отправить несколько переводов золота за раз
// @author Небылица
// @include /^https{0,1}:\/\/((www|qrator)\.heroeswm\.ru|178\.248\.235\.15)\/transfer\.php.*/
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
"use strict";
// Настройки – указание времени ожидания между запросами в мс
var delay = 1000;
//
// Вспомогательные функции
function sendGETRequest(url, mimeType, callback){ // Универсалка для отправки GET-запроса к url с выставлением заданного MIME Type и исполнением функции callback при получении ответа
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
if (typeof mimeType === "string"){
xhr.overrideMimeType(mimeType);
}
if (typeof callback === "function"){
xhr.onreadystatechange = function(){
if (xhr.readyState === 4 && xhr.status === 200){
callback.apply(xhr);
}
};
}
xhr.send();
}
function sendPOSTRequest(url, mimeType, params, callback){ // Универсалка для отправки POST-запроса к url с выставлением заданного MIME Type, параметрами params и исполнением функции callback при получении ответа
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
if (typeof mimeType === "string"){
xhr.overrideMimeType(mimeType);
}
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
if (typeof callback === "function"){
xhr.onreadystatechange = function(){
if (xhr.readyState === 4 && xhr.status === 200){
callback.apply(xhr);
}
};
}
xhr.send(params);
}
function encodeCP1251(text){ // Перекодирует русский текст так, чтобы при отправке запроса не выходили кракозябры (на базе функции из кода Gradient'a)
var result = "",
CP1251toUTF8 = {
"А": "%C0",
"Б": "%C1",
"В": "%C2",
"Г": "%C3",
"Д": "%C4",
"Е": "%C5",
"Ж": "%C6",
"З": "%C7",
"И": "%C8",
"Й": "%C9",
"К": "%CA",
"Л": "%CB",
"М": "%CC",
"Н": "%CD",
"О": "%CE",
"П": "%CF",
"Р": "%D0",
"С": "%D1",
"Т": "%D2",
"У": "%D3",
"Ф": "%D4",
"Х": "%D5",
"Ц": "%D6",
"Ч": "%D7",
"Ш": "%D8",
"Щ": "%D9",
"Ъ": "%DA",
"Ы": "%DB",
"Ь": "%DC",
"Э": "%DD",
"Ю": "%DE",
"Я": "%DF",
"а": "%E0",
"б": "%E1",
"в": "%E2",
"г": "%E3",
"д": "%E4",
"е": "%E5",
"ж": "%E6",
"з": "%E7",
"и": "%E8",
"й": "%E9",
"к": "%EA",
"л": "%EB",
"м": "%EC",
"н": "%ED",
"о": "%EE",
"п": "%EF",
"р": "%F0",
"с": "%F1",
"т": "%F2",
"у": "%F3",
"ф": "%F4",
"х": "%F5",
"ц": "%F6",
"ч": "%F7",
"ш": "%F8",
"щ": "%F9",
"ъ": "%FA",
"ы": "%FB",
"ь": "%FC",
"э": "%FD",
"ю": "%FE",
"я": "%FF",
"Ё": "%A8",
"ё": "%B8",
" ": "%20",
"!": "%21",
"(": "%28",
")": "%29",
"*": "%2A",
"+": "%2B",
",": "%2C",
"-": "%2D",
".": "%2E",
"/": "%2F"
};
var i,
maxI = text.length;
for (i=0;i<maxI;i++){
if (CP1251toUTF8[text[i]] !== undefined){
result += CP1251toUTF8[text[i]];
} else{
result += text[i];
}
}
return result;
}
function isNaturalNumber(n){ // Проверка натуральности числа
n = n.toString();
var n1 = Math.abs(n),
n2 = parseInt(n);
return !isNaN(n1) && n2 === n1 && n1.toString() === n && n1 !== 0;
}
function queryWrapper(nicknames, amounts, descriptions, i, sign, delay, urlAfter, event){ // Обёртка для цикличного отправщика запросов
i++;
if (i < nicknames.length){
sendPOSTRequest("transfer.php",
"text/html; charset=windows-1251",
"nick=" + encodeCP1251(nicknames[i]) + "&gold=" + amounts[i] + "&wood=0&ore=0&mercury=0&sulphur=0&crystal=0&gem=0&desc=" + encodeCP1251(descriptions[i]) + "&sign=" + sign);
event.target.innerHTML = "Отправляем... " + (i+1).toString() + "/" + nicknames.length.toString();
window.setTimeout(function(){queryWrapper(nicknames, amounts, descriptions, i, sign, delay, urlAfter, event);}, delay);
} else{ // закончили отправку, открываем страницу urlAfter
window.open(urlAfter, "_self");
}
}
function getSign(plId){ // Определение sign текущего персонажа
// отправляем запрос к странице магазина с зельями
sendGETRequest("shop.php?cat=potions", "text/html; charset=windows-1251", function(){
// получаем ответ в виде HTML и достаём sign из ссылки на сброс параметров
var parser = new DOMParser(),
responseHTML = parser.parseFromString(this.responseText, "text/html"),
sign = responseHTML.querySelector("a[href^='/shop.php?b=reset_tube&reset=1&cat=potions&sign=']").getAttribute("href").split("sign=")[1];
// записываем его в хранилище
GM_setValue("sign|#" + plId, sign);
});
}
//
// Вывод формы
var transferForm = document.getElementsByName("f")[0].parentNode;
transferForm.innerHTML =
"<br>" +
"<textarea id='nicknames' cols='20' rows='10' placeholder='Ники'></textarea>" +
"<textarea id='amounts' cols='8' rows='10' placeholder='Суммы'></textarea>" +
"<textarea id='descriptions' cols='50' rows='10' placeholder='Подписи'></textarea>" +
"<br>" +
"<form id='mode'>" +
"<input type='radio' name='mode' value='fromtop' checked>Сверху вниз</input>" +
"<br>" +
"<input type='radio' name='mode' value='frombottom'>Снизу вверх</input>" +
"</form>" +
"<button type='button' id='submit'>Отправить</button>";
transferForm.style = "text-align: center;";
// Определение id персонажа и его sign (в случае отсутствия сохранённого значения)
var plId = document.querySelector("li > a[href^='pl_hunter_stat.php']").getAttribute("href").split("id=")[1];
if (GM_getValue("sign|#" + plId) === undefined){
// после исполнения запроса к ключу "sign|#" + plId будет приписан sign, кнопку отправки не следует нажимать ранее
getSign(plId);
}
// Обработка данных формы
var submitButton = document.getElementById("submit");
submitButton.onclick = function(event){
// выключаем для подстраховки дефолтное действие кнопки, ставим ей стили состояния отправки
event.preventDefault();
event.target.innerHTML = "Отправляем...";
event.target.disabled = true;
// берём из хранилища sign персонажа
var sign = GM_getValue("sign|#" + plId);
// вытаскиваем из страницы заполненные поля формы и собираем адрес для перехода после отправки переводов
var nicknames = document.getElementById("nicknames").value.split(/\r?\n/),
amounts = document.getElementById("amounts").value.split(/\r?\n/),
descriptions = document.getElementById("descriptions").value.split(/\r?\n/),
mode = document.querySelector("input[name='mode']:checked").value,
urlAfter = "https://" + location.hostname + "/pl_transfers.php?id=" + plId;
// проверка одинаковости количества строк в полях
if (nicknames.length === amounts.length && amounts.length === descriptions.length){
// проверка того, что все указанные суммы золота – натуральные числа
var amountsCorrect = true,
i,
maxI = amounts.length;
for (i=0;i<maxI;i++){
if (!isNaturalNumber(amounts[i])){
// если встречаем некорректное значение, то прекращаем обработку данных и выбрасываем сообщение об ошибке
event.target.innerHTML = "Отправить";
event.target.disabled = false;
amountsCorrect = false;
alert("Суммы золота для переводов должны быть натуральными числами!");
break;
}
}
// если всё норм, идём дальше
if (amountsCorrect){
// переворачиваем массивы, если выбран вариант "снизу вверх"
if (mode === "frombottom") {
nicknames.reverse();
amounts.reverse();
descriptions.reverse();
}
// делаем POST-запросы по количеству строк в полях и переходим на заданную страницу после
queryWrapper(nicknames, amounts, descriptions, -1, sign, delay, urlAfter, event);
}
} else{ // если кол-во строк не равно, то возвращаем кнопку в прежнее состояние и выбрасываем сообщение об ошибке
event.target.innerHTML = "Отправить";
event.target.disabled = false;
alert("Не совпадает количество строк в полях!");
}
};
})();