Compare commits
7 Commits
backup0808
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b35739db12 | |||
| a27c122070 | |||
| 3670988ae8 | |||
| f3c27ae563 | |||
| 28fe33a355 | |||
| 410f266ca6 | |||
| 65364bc889 |
@@ -4,7 +4,7 @@ WORKDIR /app
|
|||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
COPY grepodata.py .
|
COPY grepodata.py goldeval.py notify.py .
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
CMD ["python", "grepodata.py"]
|
CMD ["python", "grepodata.py"]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Grepolis Data Sender (Deep Scan v6.7 — Toolbar Pause Button + Soft Refresh & Full Stats)
|
// @name Grepolis Data Sender (Deep Scan v6.8 — Toolbar Pause Button + Window Reopen & Full Stats)
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 6.7
|
// @version 6.8
|
||||||
// @description Sends town stats, extracts Premium Exchange title, and soft-refreshes tab every 30s via Marketplace building click. Includes pause/resume button in top toolbar.
|
// @description Sends town stats, extracts Premium Exchange title, and refreshes tab every 30s by closing and reopening Marketplace. Includes pause/resume button in top toolbar.
|
||||||
// @author Dimitrios
|
// @author Dimitrios
|
||||||
// @match https://*.grepolis.com/game/*
|
// @match https://*.grepolis.com/game/*
|
||||||
// @grant unsafeWindow
|
// @grant unsafeWindow
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
console.log("💰 DeepScan v6.7 loaded — Soft refresh + Toolbar pause button + full stats");
|
console.log("💰 DeepScan v6.8 loaded — Toolbar pause button + window reopen + full stats");
|
||||||
|
|
||||||
const uw = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
|
const uw = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
|
||||||
let latestBasicPayload = null;
|
let latestBasicPayload = null;
|
||||||
@@ -155,7 +155,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🏛️ Soft refresh: click building and switch tab
|
// ❎ Close all Marketplace windows
|
||||||
|
function forceCloseMarketplaceWindows() {
|
||||||
|
const marketWindows = document.querySelectorAll(".classic_window.market");
|
||||||
|
|
||||||
|
marketWindows.forEach(win => {
|
||||||
|
const closeBtn = win.querySelector(".buttons_container .btn_wnd.close");
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.click();
|
||||||
|
console.log("❎ Clicked close button for Marketplace window:", win.id);
|
||||||
|
} else {
|
||||||
|
console.warn("⚠️ Close button not found in window:", win.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🏛️ Refresh Premium Exchange tab by closing and reopening
|
||||||
function refreshGoldWindow() {
|
function refreshGoldWindow() {
|
||||||
if (paused) {
|
if (paused) {
|
||||||
console.log("⏸️ DeepScan is paused — skipping refresh");
|
console.log("⏸️ DeepScan is paused — skipping refresh");
|
||||||
@@ -163,31 +178,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const marketArea = document.querySelector("area#building_main_area_market");
|
forceCloseMarketplaceWindows();
|
||||||
if (marketArea) {
|
|
||||||
marketArea.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
||||||
console.log("🏛️ Clicked Marketplace area to trigger Premium Exchange");
|
|
||||||
|
|
||||||
// Wait 1.5s and switch to Sell tab
|
setTimeout(() => {
|
||||||
setTimeout(() => {
|
const marketArea = document.querySelector("area#building_main_area_market");
|
||||||
const newWin = Array.from(document.querySelectorAll(".classic_window.market"))
|
if (marketArea) {
|
||||||
.find(win => win.querySelector("#premium_exchange"));
|
marketArea.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||||
|
console.log("🏛️ Clicked Marketplace area to reopen Premium Exchange");
|
||||||
|
|
||||||
if (newWin) {
|
setTimeout(() => {
|
||||||
const sellTab = newWin.querySelector(".gp_page_caption.js-page-caption-1");
|
const newWin = Array.from(document.querySelectorAll(".classic_window.market"))
|
||||||
if (sellTab) {
|
.find(win => win.querySelector("#premium_exchange"));
|
||||||
sellTab.click();
|
|
||||||
console.log("🔁 Switched to Premium Exchange Sell tab");
|
if (newWin) {
|
||||||
|
const sellTab = newWin.querySelector(".gp_page_caption.js-page-caption-1");
|
||||||
|
if (sellTab) {
|
||||||
|
sellTab.click();
|
||||||
|
console.log("🔁 Switched to Premium Exchange Sell tab");
|
||||||
|
} else {
|
||||||
|
console.warn("⚠️ Sell tab not found in reopened window");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn("⚠️ Sell tab not found in window");
|
console.warn("❌ Premium Exchange window not found after reopening");
|
||||||
}
|
}
|
||||||
} else {
|
}, 1500);
|
||||||
console.warn("❌ Premium Exchange window not found after click");
|
} else {
|
||||||
}
|
console.warn("❌ Marketplace area not found — cannot reopen Premium Exchange");
|
||||||
}, 1500);
|
}
|
||||||
} else {
|
}, 5000);
|
||||||
console.warn("❌ Marketplace area not found — cannot trigger Premium Exchange");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("💥 Error in refreshGoldWindow:", err);
|
console.error("💥 Error in refreshGoldWindow:", err);
|
||||||
}
|
}
|
||||||
@@ -196,14 +214,14 @@
|
|||||||
// 🔁 Main loop
|
// 🔁 Main loop
|
||||||
function runDataCycle() {
|
function runDataCycle() {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
console.log("🕒 Data cycle tick — soft refresh + send stats");
|
console.log("🕒 Data cycle tick — close/reopen + send stats");
|
||||||
refreshGoldWindow();
|
refreshGoldWindow();
|
||||||
setTimeout(sendBasicStats, 3000);
|
setTimeout(sendBasicStats, 7000); // after reopen + tab switch
|
||||||
}, 30000);
|
}, 30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
console.log("🚀 DeepScan v6.5 booting up...");
|
console.log("🚀 DeepScan v6.8 booting up...");
|
||||||
runDataCycle();
|
runDataCycle();
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
30
goldeval.py
Normal file
30
goldeval.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
from notify import hooknotify
|
||||||
|
|
||||||
|
def goldeval(player_file):
|
||||||
|
"""Evaluate gold market surplus and send alerts if needed."""
|
||||||
|
if not os.path.exists(player_file):
|
||||||
|
print(f"❌ File not found: {player_file}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(player_file, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
title = data.get("gold_market_title", "Unknown Title")
|
||||||
|
timestamp = data.get("server_received_at", "Unknown Time")
|
||||||
|
market = data.get("gold_market", {})
|
||||||
|
|
||||||
|
for resource in ["wood", "stone", "iron"]:
|
||||||
|
res_data = market.get(resource, {})
|
||||||
|
current = int(res_data.get("current", "0").replace(",", ""))
|
||||||
|
max_val = int(res_data.get("max", "0").replace(",", ""))
|
||||||
|
surplus = max_val - current
|
||||||
|
|
||||||
|
if surplus > 1000:
|
||||||
|
print(f"📢 Surplus detected: {resource} = {surplus}")
|
||||||
|
hooknotify(timestamp, title, resource, surplus)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("💥 Error in goldeval:", e)
|
||||||
46
grepodata.py
46
grepodata.py
@@ -1,9 +1,9 @@
|
|||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
from datetime import datetime # ✅ minimal timestamp support
|
from datetime import datetime
|
||||||
|
from goldeval import goldeval # ⬅️ Add this at the top
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
@@ -25,6 +25,45 @@ def save_payload_as_player_file(payload):
|
|||||||
print(f"📝 Payload saved to {filename}")
|
print(f"📝 Payload saved to {filename}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("❌ Failed to save payload:", e)
|
print("❌ Failed to save payload:", e)
|
||||||
|
goldeval(filename)
|
||||||
|
|
||||||
|
def append_prices_log(payload):
|
||||||
|
"""Append resource prices and market title to prices.txt in CSV format with timestamp."""
|
||||||
|
try:
|
||||||
|
market = payload.get("gold_market")
|
||||||
|
title = payload.get("gold_market_title", "").strip()
|
||||||
|
|
||||||
|
# Skip if title is missing, empty, or placeholder
|
||||||
|
if not title or title.lower() in ["unknown title", "n/a", "null"]:
|
||||||
|
print("⏭️ Skipping log: Missing or placeholder title")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Skip if market is missing
|
||||||
|
if not market:
|
||||||
|
print("⏭️ Skipping log: Missing market data")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Extract and sanitize values
|
||||||
|
wood = market.get("wood", {}).get("current", "").replace(",", "")
|
||||||
|
stone = market.get("stone", {}).get("current", "").replace(",", "")
|
||||||
|
iron = market.get("iron", {}).get("current", "").replace(",", "")
|
||||||
|
|
||||||
|
# Skip if all values are missing or zero
|
||||||
|
if not wood or not stone or not iron or (wood == "0" and stone == "0" and iron == "0"):
|
||||||
|
print("⏭️ Skipping log: Market values are empty or zero")
|
||||||
|
return
|
||||||
|
|
||||||
|
timestamp = datetime.now().isoformat()
|
||||||
|
safe_title = title.replace('"', "'")
|
||||||
|
|
||||||
|
line = f'{timestamp},{wood},{stone},{iron},"{safe_title}"\n'
|
||||||
|
|
||||||
|
with open("prices.txt", "a", encoding="utf-8") as f:
|
||||||
|
f.write(line)
|
||||||
|
|
||||||
|
print("📈 Appended to prices.txt:", line.strip())
|
||||||
|
except Exception as log_err:
|
||||||
|
print("⚠️ Failed to log to prices.txt:", log_err)
|
||||||
|
|
||||||
@app.route('/api/grepolis-data', methods=['POST'])
|
@app.route('/api/grepolis-data', methods=['POST'])
|
||||||
def receive_data():
|
def receive_data():
|
||||||
@@ -34,10 +73,11 @@ def receive_data():
|
|||||||
payload = request.get_json(force=True)
|
payload = request.get_json(force=True)
|
||||||
print("✅ Parsed JSON:", payload)
|
print("✅ Parsed JSON:", payload)
|
||||||
|
|
||||||
# Inject server-side timestamp (system time)
|
# Inject server-side timestamp
|
||||||
payload["server_received_at"] = datetime.now().isoformat()
|
payload["server_received_at"] = datetime.now().isoformat()
|
||||||
|
|
||||||
save_payload_as_player_file(payload)
|
save_payload_as_player_file(payload)
|
||||||
|
append_prices_log(payload)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"status": "success",
|
"status": "success",
|
||||||
|
|||||||
23
notify.py
Normal file
23
notify.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
# ✅ Your Discord webhook URL
|
||||||
|
WEBHOOK_URL2 = "https://discord.com/api/webhooks/847569410839150662/lJo0y5aah72zj-ML-9jMMAEPzD5M0gafC4xUe2d5HlKZaW0Z187wjCW912fmJqV5c74a"
|
||||||
|
WEBHOOK_URL = "https://discord.com/api/webhooks/1403835326509744211/OjqbGjCvwAEDfWSqAU-YVcqcgsT4d9U84oEM4a89Ec7Jsi5GO_jIg8zl9nwB9KDB0gmr"
|
||||||
|
|
||||||
|
def hooknotify(server_time, title, resource, surplus):
|
||||||
|
"""Send Discord notification with surplus info."""
|
||||||
|
message = (
|
||||||
|
"```yaml\n"
|
||||||
|
f"{server_time} | {title} | {resource} surplus: {surplus}\n"
|
||||||
|
"```"
|
||||||
|
)
|
||||||
|
data = { "content": message }
|
||||||
|
try:
|
||||||
|
response = requests.post(WEBHOOK_URL2, json=data)
|
||||||
|
response = requests.post(WEBHOOK_URL, json=data)
|
||||||
|
if response.status_code == 204:
|
||||||
|
print(f"📨 Notification sent for {resource}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ Failed to send notification: {response.status_code}")
|
||||||
|
except Exception as e:
|
||||||
|
print("❌ Error sending notification:", e)
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
Flask==3.0.3
|
Flask==3.0.3
|
||||||
flask-cors==4.0.0
|
flask-cors==4.0.0
|
||||||
|
requests
|
||||||
Reference in New Issue
Block a user