NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name GuildTimersOnMain // @namespace GuildTimersOnMain // @version 0.3.4.1 // @homepage https://greasyfork.org/ru/scripts/437040 // @description Таймеры для гильдии охотников, наёмников, воров и лидеров на home.php // @author Komdosh // @include *://*.heroeswm.ru/home.php* // @include *://*.heroeswm.ru/map.php* // @include *://*.heroeswm.ru/mercenary_guild.php* // @include *://*.heroeswm.ru/leader_guild.php* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; const GUILDS_INFO_MERCENARY = 'GUILDS_INFO_MERCENARY'; const GUILDS_INFO_HUNTER = 'GUILDS_INFO_HUNTER'; const GUILDS_INFO_LEADER = 'GUILDS_INFO_LEADER'; const GUILDS_INFO_THIEF = 'GUILDS_INFO_THIEF'; if (/map.php/.test(location.href)) { const hunterInfo = getWithExpiry(GUILDS_INFO_HUNTER); if (hunterInfo != null && hunterInfo === '-1') { localStorage.removeItem(GUILDS_INFO_HUNTER); } const thiefInfo = getWithExpiry(GUILDS_INFO_THIEF); if (thiefInfo != null && thiefInfo === '-1') { localStorage.removeItem(GUILDS_INFO_THIEF); } return; } else if (/leader_guild.php/.test(location.href)) { const leaderInfo = getWithExpiry(GUILDS_INFO_LEADER); if (leaderInfo != null && leaderInfo === '-1') { localStorage.removeItem(GUILDS_INFO_LEADER); } return; } localStorage.removeItem(GUILDS_INFO_MERCENARY); const isThiefsAvailable = parseInt(Array.from(document.querySelectorAll('.home_guild_text')) .find(el => el.innerText === 'Воров').parentElement.querySelector('.home_text_exp').innerText) > 0; const userInfo = getUserInfo(); const guildsInfoDiv = document.createElement('div'); guildsInfoDiv.className += "home_container_block"; guildsInfoDiv.style = "align-items: left;"; const guildsInfoHeader = document.createElement('div'); guildsInfoHeader.className += "global_container_block_header global_a_hover"; guildsInfoHeader.innerHTML = 'Таймеры'; guildsInfoDiv.append(guildsInfoHeader); const guildsInfoContentDiv = document.createElement('div'); guildsInfoContentDiv.className += "home_inside_margins global_a_hover"; guildsInfoDiv.append(guildsInfoContentDiv); const workerGuild = document.querySelector(".home_work_block"); workerGuild.before(guildsInfoDiv); const loading = document.createElement('span'); loading.innerText = 'Данные обновляются...'; guildsInfoContentDiv.append(loading); requestHunterInfo(); requestMercenaryInfo(); if (isThiefsAvailable) { requestThiefInfo(userInfo.id); } requestLeadersInfo(); //*************************************************************************** function requestLeadersInfo() { request('leader', 'Новое задание через ', "/leader_guild.php", GUILDS_INFO_LEADER, 'ГЛ', '<a href="leader_guild.php" style="text-decoration:underline">Все цели обнаружены</a>', 'Требуется лидер', (respDoc, timerDiv) => { const nextTime = respDoc.querySelector('#next_lg'); if (nextTime == null) { return 0; } const script = nextTime.parentElement.getElementsByTagName('script')[0]; const scriptDeltaText = script.text.match(/Delta2 = (\d+)/); if (scriptDeltaText == null) { return 0; } else { return parseInt(scriptDeltaText[1]); } }); } //*************************************************************************** function requestHunterInfo() { request('hunter', 'Охота будет доступна через ', "/map.php", GUILDS_INFO_HUNTER, 'ГО', '<a href="map.php" style="text-decoration:underline">Новая охота</a>', 'Охотники зовут на помощь', (respDoc, timerDiv) => { const script = document.querySelector('#map_right_block_inside').getElementsByTagName('script')[0]; const scriptDeltaText = script.text.match(/MapHunterDelta = (\d+)/); if (scriptDeltaText == null) { return 0; } else { return parseInt(scriptDeltaText[1]); } }); } //*************************************************************************** function requestMercenaryInfo() { request('mercenary', 'Новое задание через ', "/mercenary_guild.php", GUILDS_INFO_MERCENARY, 'ГН', '<a href="mercenary_guild.php" style="text-decoration:underline">Новое задание</a>', 'Наёмникам требуется герой!', (respDoc, timerDiv) => { const taskMessageDiv = respDoc.querySelector('table:not([align="center"])').querySelector('table:not([align="center"], [class="wbwhite"])'); if (taskMessageDiv == null) { return 0; } else { const taskMessage = taskMessageDiv.querySelector('td').innerText; const timeRemaining = taskMessage.includes('через') ? (parseInt(taskMessage.split('через ')[1].split(' ')[0]) + 1) * 60 : 0; return timeRemaining; } }); } //*************************************************************************** function requestThiefInfo(userId) { request('thief', 'Новое задание через ', `/pl_warlog.php?id=${userId}`, GUILDS_INFO_THIEF, 'ГВ', '<a href="map.php" style="text-decoration:underline">Новая засада</a>', 'Воры замышляют новое нападение!', (respDoc, timerDiv) => { const battles = respDoc.querySelectorAll('div[class="global_a_hover"]'); let nextTime = 1000 * 60 * 60; if (isPremium()) { nextTime *= 0.7; } for (const battle of battles) { if (/<b>\u041A\u0430\u0440\u0430\u0432\u0430\u043D/.test(battle.innerHTML)) { // Караван выигран let battleDate = battle.innerHTML.split('>')[1].split('<')[0]; const battleDateSplit = battleDate.split('-'); battleDate = battleDateSplit[1] + '-' + battleDateSplit[0] + '-' + battleDateSplit[2]; const thiefDateTime = new Date(battleDate); return Math.floor(((thiefDateTime.getTime() + nextTime) - Date.now()) / 1000); } } return 0; }); } function request(domId, taskHtml, link, localStorageName, notifyMeLinkName, newTaskInstantlyDom, notifyText, processor) { const timerDiv = document.createElement('div'); timerDiv.id = domId; guildsInfoContentDiv.append(timerDiv); const expiration = getWithExpiry(localStorageName); const notifyMeLink = document.createElement('a'); notifyMeLink.style = 'cursor: pointer'; let isNotify = localStorage.getItem(`${localStorageName}_SETTINGS`) === 'true'; notifyMeLink.innerHTML = isNotify ? `<b>${notifyMeLinkName}</b>: ` : `${notifyMeLinkName}: `; notifyMeLink.onclick = () => { isNotify = !isNotify; toggleNotification(isNotify, notifyMeLink, notifyMeLinkName); localStorage.setItem(`${localStorageName}_SETTINGS`, isNotify); }; const wrapper = document.createElement('span'); wrapper.append(notifyMeLink); if (expiration != null) { if (loading != null) { loading.remove(); } if (expiration === '-1') { timerDiv.append(createElementFromTextAndAppend(wrapper, newTaskInstantlyDom)); return; } toggleNotification(isNotify, notifyMeLink, notifyMeLinkName); const delay = Math.floor((expiration - Date.now()) / 1000); initTimer(delay, timerDiv, createElementFromTextAndAppend(wrapper, taskHtml), () => { timerFinished(isNotify, notifyText, timerDiv, newTaskInstantlyDom); }); return; } const xhr = new XMLHttpRequest(); xhr.open('GET', encodeURI(link)); xhr.overrideMimeType('text/xml; charset=windows-1251'); xhr.onload = function () { if (xhr.status === 200) { const div = document.createElement('div'); div.id = 'kom-' + domId; div.style.display = 'none'; div.innerHTML = xhr.responseText; document.getElementsByTagName('body')[0].appendChild(div); const respDoc = document.getElementById('kom-' + domId); if (loading != null) { loading.remove(); } const delta = processor(respDoc, timerDiv); if (delta > 0) { const expiration = Date.now() + delta * 1000; setWithExpiry(localStorageName, expiration, expiration); toggleNotification(isNotify, notifyMeLink, notifyMeLinkName); initTimer(delta, timerDiv, createElementFromTextAndAppend(wrapper, taskHtml), () => { timerFinished(isNotify, notifyText, timerDiv, newTaskInstantlyDom); }); } else { setWithExpiry(localStorageName, '-1', Date.now() + 60 * 60 * 1000); timerDiv.append(createElementFromTextAndAppend(wrapper, newTaskInstantlyDom)); } respDoc.remove(); } else { console.log('Request failed. Returned status of ' + xhr.status); } }; xhr.send(); } //*************************************************************************** function setWithExpiry(key, value, expirationTime) { const item = { value: value, expiry: expirationTime, } localStorage.setItem(key, JSON.stringify(item)) } //*************************************************************************** function getWithExpiry(key) { const itemStr = localStorage.getItem(key) // if the item doesn't exist, return null if (!itemStr) { return null; } const item = JSON.parse(itemStr) const now = new Date() // compare the expiry time of the item with the current time if (now.getTime() > item.expiry) { // If the item is expired, delete the item from storage // and return null localStorage.removeItem(key) return null } return item.value } //*************************************************************************** function initTimer(Delta, timerDiv, html, onTimeEnd) { const timeSpan = document.createElement('span'); html.append(timeSpan); function print_time(t) { if (t < 0) t = 0; const min = Math.floor(t / 60); const sec = t % 60; let s = ''; if (min) s = min + ' ' + 'мин. '; s = s + sec + ' ' + 'с. '; timeSpan.innerText = ' ' + s; if (timerDiv.firstChild != null) { timerDiv.replaceChild(html, timerDiv.firstChild); } else { timerDiv.append(html); } } const Refresh = () => { if (Timer >= 0) clearTimeout(Timer); Delta = Delta - 1; print_time(Delta); if (Delta >= 0) { Timer = setTimeout(Refresh, 1000); } else { onTimeEnd(); } } let Timer = setTimeout(Refresh, 1000); print_time(Delta); } //******************* function getUserInfo() { const infoLink = document.querySelector('center>a[href^=pl_info]'); if (infoLink) { const infoLinkValues = infoLink.href.split("id="); return { id: infoLinkValues[infoLinkValues.length - 1], name: infoLink.innerText }; } else { //console.error("Error: infoLink is null"); return { id: "", name: "" }; } } //******************* function isPremium() { return document.querySelector('a[href="shop.php?cat=potions#vip"]') != null; } //*************************************************************************** function toggleNotification(isNotify, notifyMeLink, notifyMeLinkName) { if (isNotify) { notifyMeLink.innerHTML = `<b>${notifyMeLinkName}</b>: `; notifyMeLink.title = 'Уведомление: включено'; } else { notifyMeLink.innerHTML = `${notifyMeLinkName}: `; notifyMeLink.title = 'Уведомление: выключено'; } } //*************************************************************************** function createElementFromTextAndAppend(wrapper, html) { const span = document.createElement('span'); span.innerHTML = html.trim(); wrapper.append(span); return wrapper; } //*************************************************************************** function timerFinished(isNotify, notifyText, timerDiv, finishedHtml) { if (isNotify) { notifyAfter(notifyText); } const span = document.createElement('span'); span.innerHTML = finishedHtml.trim(); timerDiv = timerDiv.lastChild; let child = timerDiv.lastChild; while (timerDiv.children.length > 1) { timerDiv.removeChild(child); child = timerDiv.lastChild; } timerDiv.append(span); } //*************************************************************************** function notifyAfter(text) { var notify = alert; const cancellation = setTimeout(() => { notify(text); }, 1000); Notification.requestPermission().then((permission) => { if (permission === 'granted') { notify = (t) => new Notification(t); } }); return cancellation; } })();