17-07-2024, 13:24
(This post was last modified: 17-07-2024, 13:31 by Lord DciBelia.)
Automated Report Sorting
Code:
javascript:const DEBUG = false;
const scriptConfig = {
scriptData: {
prefix: 'automateReports',
name: 'Automate Reports',
version: 'v1.0.0',
author: 'Chase',
authorUrl: '',
helpLink: '',
},
allowedMarkets: [],
allowedScreens: ['report'],
allowedModes: ['all'],
isDebug: DEBUG,
enableCountApi: true,
};
let playerDatabase = {};
const extractUnitData = (doc, tableId) => {
const table = doc.getElementById(tableId);
if (!table) return null;
const rows = table.querySelectorAll('tr');
const unitTypes = Array.from(rows[0].querySelectorAll('td img')).map(img => img.title.toLowerCase().replace(/ /g, '_'));
const quantities = Array.from(rows[1].querySelectorAll('td')).slice(1).map(td => parseInt(td.textContent, 10) || 0);
const unitsData = {};
unitTypes.forEach((unitType, index) => {
unitsData[unitType] = quantities[index];
});
return unitsData;
};
const extractUnitsOutsideVillage = (doc) => {
const thElements = doc.querySelectorAll('th');
for (let th of thElements) {
if (th.textContent.trim() === 'Units outside village:') {
const table = th.parentElement.nextElementSibling.querySelector('table');
if (!table) return null;
const rows = table.querySelectorAll('tr');
const unitTypes = Array.from(rows[0].querySelectorAll('th img')).map(img => img.title.toLowerCase().replace(/ /g, '_'));
const quantities = Array.from(rows[1].querySelectorAll('td')).map(td => parseInt(td.textContent, 10) || 0);
const unitsData = {};
unitTypes.forEach((unitType, index) => {
unitsData[unitType] = quantities[index];
});
return unitsData;
}
}
return null;
};
const fetchReportData = async (url, retryCount = 3) => {
if (!url.startsWith('http')) {
console.error(`Invalid URL: ${url}`);
return null;
}
try {
const response = await fetch(url);
if (!response.ok) {
if (response.status === 520 && retryCount > 0) {
console.warn(`Encountered 520 error, retrying... (${3 - retryCount + 1})`);
await new Promise(res => setTimeout(res, 2000));
return fetchReportData(url, retryCount - 1);
}
throw new Error(`HTTP error! Status: ${response.status}`);
}
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'text/html');
const findPlayerData = (label) => {
const thElements = doc.querySelectorAll('th');
for (let th of thElements) {
if (th.textContent.trim() === label) {
const playerLink = th.nextElementSibling.querySelector('a[href*="screen=info_player"]');
const villageLink = th.closest('table').querySelector('a[href*="screen=info_village"]');
const playerName = playerLink ? playerLink.textContent.trim() : 'Unknown';
const villageCoords = villageLink ? villageLink.textContent.trim().match(/\d+\|\d+/)[0] : 'Unknown';
return { playerName, villageCoords };
}
}
return null;
};
const attacker = findPlayerData('Attacker:');
const defender = findPlayerData('Defender:');
const attackerUnits = extractUnitData(doc, 'attack_info_att_units');
const defenderUnits = extractUnitData(doc, 'attack_info_def_units');
const unitsOutside = extractUnitsOutsideVillage(doc);
return {
attacker: { ...attacker, units: attackerUnits },
defender: { ...defender, units: defenderUnits },
unitsOutside,
reportPageLink: url,
};
} catch (error) {
console.error('Error fetching report data:', error);
return null;
}
};
const classifyUnits = (units, unitsOutside) => {
const offensiveUnits = ['axe', 'light_cavalry'];
const defensiveUnits = ['spear', 'sword', 'heavy_cavalry'];
let offensiveCount = 0;
let defensiveCount = 0;
const countUnits = (units) => {
if (!units) return;
for (const [unitType, count] of Object.entries(units)) {
if (offensiveUnits.includes(unitType)) {
offensiveCount += count;
} else if (defensiveUnits.includes(unitType)) {
defensiveCount += count;
}
}
};
countUnits(units);
countUnits(unitsOutside);
if (offensiveCount > defensiveCount) {
return 'offensive';
} else if (defensiveCount > offensiveCount) {
return 'defensive';
} else {
return 'unknown';
}
};
const countVillages = () => {
for (const playerName in playerDatabase) {
const playerData = playerDatabase[playerName];
let offensiveCount = 0;
let defensiveCount = 0;
for (const villageCoords in playerData.villages) {
const villageData = playerData.villages[villageCoords];
if (villageData.classification === 'offensive') {
offensiveCount++;
} else if (villageData.classification === 'defensive') {
defensiveCount++;
}
}
playerData.offensiveCount = offensiveCount;
playerData.defensiveCount = defensiveCount;
}
};
const processReports = async () => {
const reportLinks = document.querySelectorAll('a[href*="view="]');
const validReportLinks = Array.from(reportLinks).filter(link => link.href.startsWith('http'));
const reportPromises = validReportLinks.map(async (link) => {
const reportPageLink = link.href;
const reportData = await fetchReportData(reportPageLink);
if (reportData) {
const { attacker, defender, unitsOutside } = reportData;
if (attacker && attacker.units) {
const classification = classifyUnits(attacker.units, unitsOutside);
if (!playerDatabase[attacker.playerName]) {
playerDatabase[attacker.playerName] = { villages: {} };
}
playerDatabase[attacker.playerName].villages[attacker.villageCoords] = {
classification,
reportLink: reportPageLink,
units: attacker.units,
unitsOutside,
};
}
if (defender && defender.units) {
const classification = classifyUnits(defender.units, unitsOutside);
if (!playerDatabase[defender.playerName]) {
playerDatabase[defender.playerName] = { villages: {} };
}
playerDatabase[defender.playerName].villages[defender.villageCoords] = {
classification,
reportLink: reportPageLink,
units: defender.units,
unitsOutside,
};
}
}
});
await Promise.all(reportPromises);
countVillages();
updatePlayerList();
};
const generateNotebookEntry = () => {
let notebookEntry = '';
Object.keys(playerDatabase).forEach(playerName => {
const playerData = playerDatabase[playerName];
notebookEntry += `[player]${playerName}[/player]\n`;
const villages = [];
Object.keys(playerData.villages).forEach(villageCoords => {
const villageData = playerData.villages[villageCoords];
const classification = villageData.classification === 'offensive' ? '[color=#ae0e0e]OFFENSIVE[/color]' : '[color=#0e0eae]DEFENSE[/color]';
villages.push(`[village]${villageCoords}[/village] - ${classification}`);
});
notebookEntry += villages.join('\n') + '\n\n';
});
return notebookEntry;
};
const copyNotebookEntryToClipboard = () => {
const notebookEntry = generateNotebookEntry();
const tempTextArea = document.createElement('textarea');
tempTextArea.value = notebookEntry;
document.body.appendChild(tempTextArea);
tempTextArea.select();
document.execCommand('copy');
document.body.removeChild(tempTextArea);
alert('Notebook entry copied to clipboard!');
};
const updatePlayerList = () => {
const playerListContainer = document.querySelector('#playerListContainer');
playerListContainer.innerHTML = '';
for (const playerName in playerDatabase) {
const playerData = playerDatabase[playerName];
const playerButton = document.createElement('button');
playerButton.textContent = `${playerName} (O: ${playerData.offensiveCount}, D: ${playerData.defensiveCount})`;
playerButton.onclick = () => showPlayerData(playerName);
playerListContainer.appendChild(playerButton);
}
};
const showPlayerData = (playerName) => {
const playerData = playerDatabase[playerName];
const offensiveVillages = [];
const defensiveVillages = [];
for (const villageCoords in playerData.villages) {
const villageData = playerData.villages[villageCoords];
if (villageData.classification === 'offensive') {
offensiveVillages.push(villageCoords);
} else if (villageData.classification === 'defensive') {
defensiveVillages.push(villageCoords);
}
}
const offensiveCount = playerData.offensiveCount || 0;
const defensiveCount = playerData.defensiveCount || 0;
const popupContent = `
<div>
<h3>${playerName}</h3>
<p>Total Offensive Villages: ${offensiveCount}</p>
<p>Total Defensive Villages: ${defensiveCount}</p>
<textarea id="offensiveCoords" rows="10" cols="60">${offensiveVillages.join('\n')}</textarea>
<button onclick="copyToClipboard('offensiveCoords')">Copy Offensive Coordinates</button>
<textarea id="defensiveCoords" rows="10" cols="60">${defensiveVillages.join('\n')} </textarea>
<button onclick="copyToClipboard('defensiveCoords')">Copy Defensive Coordinates</button>
</div>
`;
const popup = window.open('', 'Player Data', 'width=800,height=600,scrollbars=yes');
popup.document.write(popupContent);
popup.document.close();
};
const copyToClipboard = (elementId) => {
const textarea = document.getElementById(elementId);
textarea.select();
document.execCommand('copy');
alert('Coordinates copied to clipboard!');
};
const exportData = () => {
const dataStr = JSON.stringify(playerDatabase, null, 2);
const dataBlob = new Blob([dataStr], { type: 'application/json' });
const url = URL.createObjectURL(dataBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'playerDatabase.json';
a.click();
URL.revokeObjectURL(url);
};
const viewData = () => {
const popup = window.open('', 'Player Data', 'width=800,height=600,scrollbars=yes');
const dataStr = JSON.stringify(playerDatabase, null, 2);
popup.document.write('<pre>' + dataStr + '</pre>');
popup.document.close();
};
const isValidScreen = location.search.includes('screen=report');
const isValidMode = location.search.includes('mode=all');
if (isValidScreen && isValidMode) {
const content = `
<div class="ra-mb15">
<a href="javascript:void(0);" id="raProcessReportsBtn" class="btn">Automate Reports</a>
<a href="javascript:void(0);" id="raCopyNotebookEntryBtn" class="btn">Copy to Clipboard</a>
<a href="javascript:void(0);" id="raExportDataBtn" class="btn">Export Data</a>
<a href="javascript:void(0);" id="raViewDataBtn" class="btn">View Data</a>
</div>
<div id="playerListContainer" class="ra-mb15"></div>
`;
const widget = document.createElement('div');
widget.innerHTML = content;
const contentValue = document.getElementById('content_value');
contentValue.insertBefore(widget, contentValue.firstChild);
document.querySelector('#raProcessReportsBtn').addEventListener('click', processReports);
document.querySelector('#raCopyNotebookEntryBtn').addEventListener('click', copyNotebookEntryToClipboard);
document.querySelector('#raExportDataBtn').addEventListener('click', exportData);
document.querySelector('#raViewDataBtn').addEventListener('click', viewData);
} else {
console.log('Redirecting...');
location.href = 'https://w1.infernal-wars.com/game.php?village=21&screen=report&mode=all';
}