Загрузка данных
// ============================================================
// ПОРТОВЫЙ БОТ + РђР’РўРћРљР›РКЕР+ Р РђРЎРЁРРЕННОЕ GUI
// F6 - Вкл/Выкл защиту от админов | F7 - старт/стоп | F8 - запись маршрута | F9 - ТП | F10 - точка | F12 - выгрузка
// ============================================================
// в•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђ
// GUI (взято из stroka_upd, адаптировано под порт)
// в•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђв•ђ
var guiBrowser = null;
var guiHTML = `<!DOCTYPE html>
<html><head><meta charset="utf-8"><style>
*{margin:0;padding:0;box-sizing:border-box;}
html,body{background:transparent;overflow:hidden;font-family:'Segoe UI',sans-serif;user-select:none;}
#panel{position:absolute;left:15px;top:15px;width:340px;
background:linear-gradient(160deg,rgba(15,15,25,0.95),rgba(8,8,18,0.97));
border-radius:12px;border:1px solid rgba(255,255,255,0.08);
box-shadow:0 8px 32px rgba(0,0,0,0.6);overflow:hidden;cursor:move;}
.title{background:linear-gradient(90deg,rgba(0,180,80,0.25),rgba(80,0,200,0.25));
padding:9px 12px;font-size:11px;font-weight:700;text-transform:uppercase;
letter-spacing:1.5px;color:#fff;border-bottom:1px solid rgba(255,255,255,0.07);text-align:center;}
.tabs{display:flex;border-bottom:1px solid rgba(255,255,255,0.06);}
.tab{flex:1;padding:7px 4px;font-size:9px;font-weight:700;text-align:center;
color:rgba(255,255,255,0.35);cursor:pointer;letter-spacing:.5px;text-transform:uppercase;
transition:all .2s;border-bottom:2px solid transparent;}
.tab.active{color:#fff;border-bottom:2px solid #a78bfa;}
.tab:hover{color:rgba(255,255,255,0.7);}
.page{display:none;padding:10px 12px;}.page.active{display:block;}
.row{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
.row:last-child{margin-bottom:0;}
.lbl{font-size:10px;color:rgba(255,255,255,0.45);font-weight:600;text-transform:uppercase;letter-spacing:.4px;}
.val{font-size:11px;font-weight:700;color:#fff;text-align:right;
background:rgba(255,255,255,0.07);padding:2px 8px;border-radius:5px;
max-width:155px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.val.green{background:rgba(0,220,80,0.2);color:#00ff55;}
.val.blue{background:rgba(0,120,255,0.2);color:#4db8ff;}
.val.yellow{background:rgba(255,200,0,0.15);color:#ffe066;}
.val.red{background:rgba(255,50,50,0.2);color:#ff6666;}
.val.orange{background:rgba(255,140,0,0.2);color:#ffaa33;}
.val.purple{background:rgba(167,139,250,0.15);color:#a78bfa;}
.divider{height:1px;background:rgba(255,255,255,0.05);margin:6px 0;}
.stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px;}
.stat-cell{background:rgba(255,255,255,0.04);border-radius:7px;padding:7px 8px;text-align:center;}
.stat-cell .n{font-size:15px;font-weight:800;color:#00ff55;}
.stat-cell .l{font-size:8px;color:rgba(255,255,255,0.35);text-transform:uppercase;margin-top:2px;}
.inp-row{margin-bottom:8px;}
.inp-lbl{font-size:9px;color:rgba(255,255,255,0.45);text-transform:uppercase;letter-spacing:.4px;margin-bottom:4px;}
input[type=number]{width:100%;background:rgba(255,255,255,0.06);
border:1px solid rgba(255,255,255,0.1);border-radius:5px;padding:5px 8px;color:#fff;font-size:11px;outline:none;}
select{width:100%;background:rgba(255,255,255,0.06);
border:1px solid rgba(255,255,255,0.1);border-radius:5px;padding:6px 8px;color:#fff;font-size:11px;outline:none;}
select option{background:#11121d;color:#fff;}
input:focus,select:focus{border-color:rgba(167,139,250,0.5);}
.btn-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:6px;}
.ui-btn{width:100%;padding:7px 6px;border-radius:6px;text-align:center;cursor:pointer;
background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);
color:#fff;font-size:10px;font-weight:700;box-sizing:border-box;}
.ui-btn.green{background:rgba(0,220,80,0.15);border-color:rgba(0,220,80,0.3);color:#00ff55;}
.ui-btn.red{background:rgba(255,50,50,0.15);border-color:rgba(255,50,50,0.3);color:#ff6666;}
.ui-btn.yellow{background:rgba(255,200,0,0.15);border-color:rgba(255,200,0,0.25);color:#ffe066;}
.ui-btn.purple{background:rgba(167,139,250,0.2);border-color:rgba(167,139,250,0.3);color:#a78bfa;}
.hint{font-size:9px;color:rgba(255,255,255,0.35);line-height:1.35;margin-top:5px;}
.route-list{max-height:145px;overflow-y:auto;margin-top:7px;padding-right:2px;}
.route-item{width:100%;padding:7px 8px;margin-bottom:5px;border-radius:6px;cursor:pointer;
background:rgba(255,255,255,0.045);border:1px solid rgba(255,255,255,0.08);
color:rgba(255,255,255,0.74);font-size:10px;font-weight:700;box-sizing:border-box;}
.route-item:hover{background:rgba(255,255,255,0.08);color:#fff;}
.route-item.active{background:rgba(0,120,255,0.18);border-color:rgba(77,184,255,0.45);color:#4db8ff;}
.route-item.recorded{border-color:rgba(255,200,0,0.18);}
.reset-btn{width:100%;margin-top:8px;padding:6px;background:rgba(255,50,50,0.15);
border:1px solid rgba(255,50,50,0.2);color:#ff6666;font-size:10px;font-weight:700;
border-radius:5px;cursor:pointer;text-align:center;letter-spacing:.5px;}
.reset-btn:hover{background:rgba(255,50,50,0.25);}
</style></head><body>
<div id="panel">
<div class="title">⚓ ПОРТОВЫЙ БОТ v2.0</div>
<div class="tabs">
<div class="tab" onclick="showTab('routes',this)">Routes</div>
<div class="tab active" onclick="showTab('info',this)">рџ“Љ Рнфо</div>
<div class="tab" onclick="showTab('stats',this)">📈 Стат</div>
<div class="tab" onclick="showTab('settings',this)">⚙️ Настр</div>
</div>
<div id="page-info" class="page active">
<div class="row"><span class="lbl">Статус бота</span><span id="status" class="val red">Стоит</span></div>
<div class="row"><span class="lbl">Автокликер</span><span id="clicker" class="val red">Выкл</span></div>
<div class="divider"></div>
<div id="bot-btn" onclick="toggleBot()" style="width:100%;padding:8px;margin-bottom:6px;border-radius:7px;text-align:center;cursor:pointer;background:rgba(0,220,80,0.15);border:1px solid rgba(0,220,80,0.3);color:#00ff55;font-size:11px;font-weight:700;letter-spacing:.5px;box-sizing:border-box;">в–¶ Р—РђРџРЈРЎРўРРўР¬ БОТА</div>
<div class="divider"></div>
<div class="row"><span class="lbl">Текущий маршрут</span><span id="route-name" class="val blue">—</span></div>
<div class="row"><span class="lbl">Прогресс</span><span id="route-progress" class="val">—</span></div>
<div class="divider"></div>
<div class="row"><span class="lbl">РђРґРјРёРЅС‹ <40Рј</span><span id="admin-count" class="val green">0</span></div>
<div class="divider"></div>
<div class="row"><span class="lbl">TGK</span><span class="val purple">t.me/leet_community</span></div>
</div>
<div id="page-routes" class="page">
<div class="inp-row">
<div class="inp-lbl">Delivery routes pool</div>
<select id="route-select" onchange="selectRoute()">
<option value="auto">Auto - by state</option>
</select>
<div id="route-list" class="route-list"></div>
<div class="hint">Pickup is fixed. After pickup the bot randomly chooses a built-in or custom delivery route.</div>
</div>
<div class="row"><span class="lbl">Selected</span><span id="selected-route-name" class="val blue">For delete</span></div>
<div class="row"><span class="lbl">Recorded</span><span id="recorded-route-count" class="val yellow">0</span></div>
<div class="row"><span class="lbl">Mode</span><span id="route-reverse-status" class="val purple">Random</span></div>
<div class="divider"></div>
<div class="btn-grid">
<div class="ui-btn green" onclick="toggleBot()">F7 Start/Stop</div>
<div class="ui-btn purple" onclick="clearCustomRoutes()">Clear Custom</div>
<div class="ui-btn yellow record-route-btn" onclick="toggleRouteRecord()">F8 New Delivery</div>
<div class="ui-btn yellow" onclick="forceRoutePoint()">F10 Start/Point</div>
<div class="ui-btn" onclick="refreshRoutes()">Refresh</div>
<div class="ui-btn red" onclick="deleteSelectedRoute()">Delete</div>
</div>
</div>
<div id="page-stats" class="page">
<div class="stat-grid">
<div class="stat-cell"><div class="n" id="s-pk">0</div><div class="l">Обезбол</div></div>
<div class="stat-cell"><div class="n" id="s-earned" style="color:#ffe066;">$0</div><div class="l">Заработано</div></div>
<div class="stat-cell"><div class="n" id="s-pkval" style="color:#a78bfa;">$0</div><div class="l">Цена обезбол</div></div>
<div class="stat-cell"><div class="n" id="s-pkrate">0</div><div class="l">Обезбол / час</div></div>
</div>
<div class="divider"></div>
<div class="row"><span class="lbl">Время сессии</span><span id="s-session" class="val blue">00:00:00</span></div>
<div class="row"><span class="lbl">$ / час</span><span id="s-earnrate" class="val yellow">—</span></div>
<div class="row"><span class="lbl">Шанс обезбола</span><span id="s-chance" class="val">—</span></div>
<div class="divider"></div>
<div class="reset-btn" onclick="resetStats()">🗑 Сбросить статистику</div>
</div>
<div id="page-settings" class="page">
<div class="inp-row">
<div class="inp-lbl">Цена 1 обезбола ($)</div>
<input type="number" id="cfg-pkprice" value="2900" oninput="saveCfg()">
</div>
<div class="inp-row">
<div class="inp-lbl">Стоп при админе</div>
<div id="admin-toggle" onclick="toggleAdminStop()" style="width:100%;padding:6px;border-radius:6px;text-align:center;cursor:pointer;background:rgba(0,220,80,0.15);border:1px solid rgba(0,220,80,0.3);color:#00ff55;font-size:10px;font-weight:700;box-sizing:border-box;">✅ Включено</div>
</div>
<div class="divider"></div>
<div class="inp-row">
<div class="inp-lbl">Телепорт на старт</div>
<div onclick="teleportToStart()" style="width:100%;padding:6px;border-radius:6px;text-align:center;cursor:pointer;background:rgba(167,139,250,0.2);border:1px solid rgba(167,139,250,0.3);color:#a78bfa;font-size:10px;font-weight:700;box-sizing:border-box;">📍 F9 - Телепорт</div>
</div>
<div class="inp-row">
<div class="inp-lbl">Запись маршрута</div>
<div class="record-route-btn" onclick="toggleRouteRecord()" style="width:100%;padding:6px;border-radius:6px;text-align:center;cursor:pointer;background:rgba(255,200,0,0.15);border:1px solid rgba(255,200,0,0.25);color:#ffe066;font-size:10px;font-weight:700;box-sizing:border-box;">⏺ F8 - Начать запись</div>
</div>
</div>
</div>
<script>
var panel = document.getElementById('panel');
var drag = false, ox, oy;
panel.onmousedown = function(e) {
var tag = e.target.tagName;
if (tag === 'INPUT' || tag === 'SELECT' || tag === 'OPTION' || e.target.classList.contains('ui-btn') || e.target.classList.contains('route-item')) return;
drag = true;
ox = e.clientX - panel.getBoundingClientRect().left;
oy = e.clientY - panel.getBoundingClientRect().top;
e.preventDefault();
};
document.onmousemove = function(e) { if (drag) { panel.style.left = (e.clientX - ox) + 'px'; panel.style.top = (e.clientY - oy) + 'px'; } };
document.onmouseup = function() { drag = false; };
function showTab(t, el) {
document.querySelectorAll('.tab').forEach(x => x.classList.remove('active'));
document.querySelectorAll('.page').forEach(x => x.classList.remove('active'));
el.classList.add('active');
document.getElementById('page-'+t).classList.add('active');
}
var settingsRecordBtn = document.querySelector('#page-settings .record-route-btn');
if (settingsRecordBtn && settingsRecordBtn.parentNode) {
settingsRecordBtn.parentNode.style.display = 'none';
}
var CFG = { pkprice: 2900 };
var statsData = { pk: 0, startTime: Date.now() };
var __persistLock = false;
function persistCfg() {
if (__persistLock) return;
try { mp.trigger('gui:saveCfg', JSON.stringify(CFG)); } catch(e) {}
}
function persistStats() {
if (__persistLock) return;
try { mp.trigger('gui:saveStats', JSON.stringify(statsData)); } catch(e) {}
}
function loadPersistedCfg(cfg) {
if (!cfg) return;
__persistLock = true;
try {
var price = parseFloat(cfg.pkprice);
if (!isNaN(price) && price >= 0) CFG.pkprice = price;
var inp = document.getElementById('cfg-pkprice');
if (inp) inp.value = CFG.pkprice;
} catch(e) {}
__persistLock = false;
updateStats();
}
function loadPersistedStats(s) {
if (!s) return;
__persistLock = true;
try {
var pk = parseInt(s.pk, 10);
statsData.pk = !isNaN(pk) && pk >= 0 ? pk : 0;
var st = parseInt(s.startTime, 10);
statsData.startTime = !isNaN(st) && st > 0 ? st : Date.now();
} catch(e2) {}
__persistLock = false;
updateStats();
}
function saveCfg() {
CFG.pkprice = parseFloat(document.getElementById('cfg-pkprice').value) || 0;
updateStats();
persistCfg();
mp.trigger('gui:setPKPrice', CFG.pkprice);
}
function resetStats() {
statsData = { pk: 0, startTime: Date.now() };
updateStats();
persistStats();
mp.trigger('gui:resetStatsClient');
}
function addPK(count) {
statsData.pk += (count || 1);
updateStats();
persistStats();
}
function updateStats() {
var totalMoney = statsData.pk * CFG.pkprice;
var elapsed = (Date.now() - statsData.startTime) / 3600000;
var ratePerHour = elapsed > 0 ? (statsData.pk / elapsed).toFixed(1) : 0;
var earnRate = elapsed > 0 ? Math.round(totalMoney / elapsed) : 0;
var chance = statsData.pk > 0 ? '—' : '—'; // шанс не считаем, т.к. неизвестно кол-во действий
document.getElementById('s-pk').innerText = statsData.pk;
document.getElementById('s-earned').innerText = '$' + totalMoney.toLocaleString();
document.getElementById('s-pkval').innerText = '$' + (statsData.pk * CFG.pkprice).toLocaleString();
document.getElementById('s-pkrate').innerText = ratePerHour + ' / С‡';
document.getElementById('s-earnrate').innerText = earnRate > 0 ? '$' + earnRate + ' / ч' : '—';
document.getElementById('s-chance').innerText = chance;
}
var _adminStopEnabled = true;
function toggleAdminStop() {
_adminStopEnabled = !_adminStopEnabled;
var btn = document.getElementById('admin-toggle');
if (_adminStopEnabled) {
btn.innerText = '✅ Включено';
btn.style.background = 'rgba(0,220,80,0.15)';
btn.style.borderColor = 'rgba(0,220,80,0.3)';
btn.style.color = '#00ff55';
} else {
btn.innerText = '❌ Выключено';
btn.style.background = 'rgba(255,50,50,0.15)';
btn.style.borderColor = 'rgba(255,50,50,0.3)';
btn.style.color = '#ff6666';
}
mp.trigger('gui:setAdminStop', _adminStopEnabled);
}
function teleportToStart() {
mp.trigger('gui:teleportToStart');
}
function toggleBot() {
mp.trigger('gui:toggleBot');
}
function toggleRouteRecord() {
mp.trigger('gui:toggleRouteRecord');
}
function forceRoutePoint() {
mp.trigger('gui:forceRoutePoint');
}
function refreshRoutes() {
mp.trigger('gui:refreshRoutes');
}
function deleteSelectedRoute() {
var sel = document.getElementById('route-select');
if (sel) mp.trigger('gui:deleteRecordedRoute', sel.value);
}
function clearCustomRoutes() {
mp.trigger('gui:clearCustomRoutes');
}
function toggleRouteReverse() {
mp.trigger('gui:toggleRouteReverse');
}
function selectRoute() {
var sel = document.getElementById('route-select');
if (sel) mp.trigger('gui:setRouteSelection', sel.value);
}
function pickRoute(routeId) {
var sel = document.getElementById('route-select');
if (sel) sel.value = routeId;
mp.trigger('gui:setRouteSelection', routeId);
}
function setRouteReverseStatus(enabled) {
var el = document.getElementById('route-reverse-status');
if (!el) return;
el.innerText = 'Random';
el.className = 'val purple';
}
function setRouteOptions(routes, selectedId) {
var sel = document.getElementById('route-select');
var list = document.getElementById('route-list');
if (sel) sel.innerHTML = '';
if (list) list.innerHTML = '';
var recordedCount = 0;
for (var i = 0; i < routes.length; i++) {
if (sel) {
var opt = document.createElement('option');
opt.value = routes[i].id;
opt.textContent = routes[i].name;
sel.appendChild(opt);
}
if (list) {
var item = document.createElement('div');
item.className = 'route-item' + (routes[i].recorded ? ' recorded' : '') + (routes[i].id === (selectedId || 'auto') ? ' active' : '');
item.textContent = routes[i].name;
item.setAttribute('data-route-id', routes[i].id);
item.onclick = function() { pickRoute(this.getAttribute('data-route-id')); };
list.appendChild(item);
}
if (routes[i].recorded) recordedCount++;
}
if (sel) sel.value = selectedId || 'auto';
var selected = null;
for (var j = 0; j < routes.length; j++) {
if (routes[j].id === sel.value) {
selected = routes[j];
break;
}
}
var nameEl = document.getElementById('selected-route-name');
if (nameEl) nameEl.innerText = selected ? selected.name : 'None';
var countEl = document.getElementById('recorded-route-count');
if (countEl) countEl.innerText = recordedCount;
}
function setBotBtn(running) {
var btn = document.getElementById('bot-btn');
if (!btn) return;
if (running) {
btn.innerText = 'вЏ№ РћРЎРўРђРќРћР’РРўР¬ БОТА';
btn.style.background = 'rgba(255,50,50,0.15)';
btn.style.borderColor = 'rgba(255,50,50,0.3)';
btn.style.color = '#ff6666';
} else {
btn.innerText = 'в–¶ Р—РђРџРЈРЎРўРРўР¬ БОТА';
btn.style.background = 'rgba(0,220,80,0.15)';
btn.style.borderColor = 'rgba(0,220,80,0.3)';
btn.style.color = '#00ff55';
}
}
function setClickerStatus(status) {
var el = document.getElementById('clicker');
if (!el) return;
el.innerText = status;
el.className = 'val ' + (status === 'ON' ? 'green' : 'red');
}
function setStatus(status, route, progress) {
var statusEl = document.getElementById('status');
if (statusEl) {
statusEl.innerText = status;
if (status === 'Running') statusEl.className = 'val green';
else if (status === 'AFK') statusEl.className = 'val red';
else statusEl.className = 'val red';
}
var routeEl = document.getElementById('route-name');
if (routeEl) routeEl.innerText = route || '—';
var progEl = document.getElementById('route-progress');
if (progEl) progEl.innerText = progress || '—';
}
function setAdminCount(count) {
var el = document.getElementById('admin-count');
if (!el) return;
el.innerText = count;
el.className = 'val ' + (count > 0 ? 'red' : 'green');
}
function setSessionTime(timeStr) {
var el = document.getElementById('s-session');
if (el) el.innerText = timeStr;
}
function setRouteRecordStatus(active, count) {
var buttons = document.querySelectorAll('.record-route-btn');
if (buttons.length) {
for (var i = 0; i < buttons.length; i++) {
var routeBtn = buttons[i];
if (active) {
routeBtn.innerText = 'F8