Update Grepolis_Data_Sender.js
This commit is contained in:
@@ -1,97 +1,179 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Grepolis Data Sender (Deep Scan Edition)
|
// @name Grepolis Data Sender (Deep Scan v4.8 — Fixed Town ID)
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 3.1
|
// @version 4.8
|
||||||
// @description Full diagnostics + HTTPS endpoint for secure data transmission
|
// @description Sends town stats and merges marketplace offers into correct town (robust ID detection)
|
||||||
// @author Dimitrios
|
// @author Dimitrios
|
||||||
// @match https://*.grepolis.com/game/*
|
// @match https://*.grepolis.com/game/*
|
||||||
// @grant unsafeWindow
|
// @grant unsafeWindow
|
||||||
|
// @updateURL https://your-gitea-domain.com/dimitrios/grepolis-scripts/raw/branch-name/Grepolis-Data-Sender.user.js
|
||||||
|
// @downloadURL https://your-gitea-domain.com/dimitrios/grepolis-scripts/raw/branch-name/Grepolis-Data-Sender.user.js
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
console.log("🔍 [DeepScan] Initializing Grepolis data sender...");
|
console.log("🧠 DeepScan v4.8 initialized...");
|
||||||
const uw = typeof unsafeWindow !== "undefined"
|
|
||||||
? (console.log("✅ [DeepScan] unsafeWindow available"), unsafeWindow)
|
|
||||||
: typeof wrappedJSObject !== "undefined"
|
|
||||||
? (console.log("✅ [DeepScan] wrappedJSObject fallback"), wrappedJSObject)
|
|
||||||
: (console.log("⚠️ [DeepScan] Using default window"), window);
|
|
||||||
|
|
||||||
function collectAndSendData() {
|
const uw = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
|
||||||
|
let latestBasicPayload = null;
|
||||||
|
|
||||||
|
// 🔄 Send town snapshot and cache
|
||||||
|
function sendBasicStats() {
|
||||||
try {
|
try {
|
||||||
console.log("🚀 [DeepScan] Collecting town data...");
|
const towns = uw.ITowns?.towns || {};
|
||||||
|
|
||||||
const player = uw.Game?.player_name || "unknown";
|
const player = uw.Game?.player_name || "unknown";
|
||||||
const player_id = uw.Game?.player_id || "unknown";
|
const player_id = uw.Game?.player_id || "unknown";
|
||||||
const towns = uw.ITowns?.towns || {};
|
|
||||||
const townEntries = Object.values(towns);
|
|
||||||
console.log(`📊 [DeepScan] Found ${townEntries.length} towns in ITowns.towns`);
|
|
||||||
|
|
||||||
if (townEntries.length === 0) {
|
const stats = Object.values(towns).map(town => {
|
||||||
console.warn("⚠️ [DeepScan] Town data structure is present but empty");
|
const res = town.resources();
|
||||||
return;
|
const buildings = town.buildings()?.attributes ?? {};
|
||||||
}
|
const marketLevel = typeof town.getMarketplaceLevel === "function"
|
||||||
|
? town.getMarketplaceLevel()
|
||||||
|
: buildings.market || null;
|
||||||
|
|
||||||
const stats = townEntries.map(town => {
|
return {
|
||||||
try {
|
town_id: town.id,
|
||||||
const resources = town.resources();
|
town_name: town.name,
|
||||||
const buildings = town.buildings()?.attributes ?? {};
|
wood: res.wood,
|
||||||
return {
|
stone: res.stone,
|
||||||
town_id: town.id,
|
iron: res.iron,
|
||||||
town_name: town.name,
|
population: res.population,
|
||||||
wood: resources.wood,
|
points: town.getPoints(),
|
||||||
stone: resources.stone,
|
buildings,
|
||||||
iron: resources.iron,
|
market: { level: marketLevel }
|
||||||
population: resources.population,
|
};
|
||||||
points: town.getPoints(),
|
});
|
||||||
buildings: buildings
|
|
||||||
};
|
|
||||||
} catch (innerErr) {
|
|
||||||
console.error("💥 [DeepScan] Error in town parsing:", innerErr);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
const payload = {
|
latestBasicPayload = {
|
||||||
|
type: "basic",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
player,
|
player,
|
||||||
player_id,
|
player_id,
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
towns: stats
|
towns: stats
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("📤 [DeepScan] Dispatching payload to grepo.haunter-pets.top:", payload);
|
|
||||||
|
|
||||||
fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
|
fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(latestBasicPayload)
|
||||||
})
|
})
|
||||||
.then(r => r.text())
|
.then(res => res.text())
|
||||||
.then(txt => console.log("✅ [DeepScan] Server response:", txt))
|
.then(txt => console.log("✅ Basic stats sent:", txt))
|
||||||
.catch(err => console.error("❌ [DeepScan] Data send failed:", err));
|
.catch(err => console.error("❌ Failed to send basic stats:", err));
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("💥 [DeepScan] Fatal error:", e);
|
console.error("💥 Error collecting basic stats:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitUntilDataReady() {
|
// 📄 Parse marketplace trade offers
|
||||||
console.log("🕰️ [DeepScan] Checking if town data is ready...");
|
function parseMarketOffers() {
|
||||||
const townsObj = uw.ITowns?.towns;
|
const rows = document.querySelectorAll(".js-tutorial-market-offers-table tbody tr");
|
||||||
|
const offers = [];
|
||||||
|
|
||||||
if (townsObj && Object.keys(townsObj).length > 0) {
|
rows.forEach(row => {
|
||||||
console.log("🎯 [DeepScan] Towns are ready — beginning dispatch");
|
const cells = row.querySelectorAll("td");
|
||||||
collectAndSendData();
|
if (cells.length < 10) return;
|
||||||
setInterval(collectAndSendData, 30000);
|
|
||||||
|
const extractType = (td) => {
|
||||||
|
const icon = td.querySelector("span");
|
||||||
|
if (!icon) return "";
|
||||||
|
if (icon.classList.contains("market_wood_icon")) return "wood";
|
||||||
|
if (icon.classList.contains("market_stone_icon")) return "stone";
|
||||||
|
if (icon.classList.contains("market_iron_icon")) return "iron";
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
offers.push({
|
||||||
|
offer_id: row.dataset.offerId || null,
|
||||||
|
give_type: extractType(cells[0]),
|
||||||
|
give_amount: cells[1]?.textContent.trim() || "",
|
||||||
|
get_amount: cells[4]?.textContent.trim() || "",
|
||||||
|
get_type: extractType(cells[5]),
|
||||||
|
duration: cells[7]?.textContent.trim() || "",
|
||||||
|
player: cells[8]?.querySelector(".gp_player_link")?.textContent.trim() || "unknown"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🧬 Merge trades into correct town object
|
||||||
|
function sendMergedMarketStats() {
|
||||||
|
try {
|
||||||
|
const offers = parseMarketOffers();
|
||||||
|
if (offers.length === 0) {
|
||||||
|
console.warn("⚠️ No marketplace offers detected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const townId =
|
||||||
|
uw.Game?.townId ||
|
||||||
|
uw.ITowns?.getCurrentTown()?.id ||
|
||||||
|
uw.current_town_id ||
|
||||||
|
"unknown";
|
||||||
|
|
||||||
|
console.log("🏙️ Active Town ID:", townId);
|
||||||
|
console.log("📋 Available Town IDs:", latestBasicPayload?.towns?.map(t => t.town_id));
|
||||||
|
|
||||||
|
if (!latestBasicPayload || !latestBasicPayload.towns) {
|
||||||
|
console.warn("🚫 Basic stats not yet initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const town = latestBasicPayload.towns.find(t => String(t.town_id) === String(townId));
|
||||||
|
if (!town) {
|
||||||
|
console.warn(`🧭 No matching town found for ID ${townId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
town.market.offers = offers;
|
||||||
|
latestBasicPayload.timestamp = new Date().toISOString();
|
||||||
|
|
||||||
|
fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(latestBasicPayload)
|
||||||
|
})
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(txt => console.log("✅ Merged trades sent:", txt))
|
||||||
|
.catch(err => console.error("❌ Failed to send merged data:", err));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("💥 Error during marketplace merge:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👁️ Watch for marketplace panel opening
|
||||||
|
function monitorMarketplace() {
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
const panel = document.querySelector('.marketplace.all_offers');
|
||||||
|
if (panel && panel.offsetParent !== null) {
|
||||||
|
console.log("👁️ Marketplace opened — merging trades");
|
||||||
|
observer.disconnect();
|
||||||
|
sendMergedMarketStats();
|
||||||
|
setInterval(sendMergedMarketStats, 30000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🕓 Start script after town data is ready
|
||||||
|
function waitForTowns() {
|
||||||
|
const towns = uw.ITowns?.towns;
|
||||||
|
if (towns && Object.keys(towns).length > 0) {
|
||||||
|
console.log("🧭 Towns ready — starting DeepScan");
|
||||||
|
sendBasicStats();
|
||||||
|
setInterval(sendBasicStats, 30000);
|
||||||
|
monitorMarketplace();
|
||||||
} else {
|
} else {
|
||||||
console.log("⏳ [DeepScan] Towns not ready yet — retrying in 1s");
|
console.log("⏳ Waiting for town data...");
|
||||||
setTimeout(waitUntilDataReady, 1000);
|
setTimeout(waitForTowns, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
console.log("🌐 [DeepScan] Window loaded — monitoring town readiness");
|
console.log("🚀 Game page loaded — DeepScan v4.8 booting...");
|
||||||
waitUntilDataReady();
|
waitForTowns();
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user