diff --git a/index.html b/index.html
index c95f425..478ade4 100644
--- a/index.html
+++ b/index.html
@@ -360,100 +360,146 @@ function getFiltered() {
.sort((a, b) => (b.points||0) - (a.points||0));
}
- });
+function render() {
+ const list = getFiltered();
+ const tb = document.getElementById('tbody');
+ const ml = document.getElementById('mlist');
+ tb.innerHTML = ""; ml.innerHTML = "";
- const online = allServers.filter(d => d.status === "online" || d.status === "OK").length;
- document.getElementById('s-online').textContent = online;
- document.getElementById('s-total').textContent = allServers.length;
- const top = getFiltered()[0];
- document.getElementById('s-block').textContent = top ? fmt(top.last_block) : '—';
+ if (!list.length) {
+ tb.innerHTML = '
| No servers found. |
';
}
- async function fetchData() {
- const chain = getChain();
- const params = new URLSearchParams({ page: 0, limit: 100 });
- if (!withTor) params.append("onion", "no");
- try {
- const response = await fetch(`/data/${chain}?${params}`);
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
- const obj = await response.json();
- allServers = Object.entries(obj).map(([key, s]) => ({ id: key, ...s }));
- render();
- } catch (err) {
- console.error('Fetch error:', err);
- allServers = [];
- render();
- }
- }
+ list.forEach((d, i) => {
+ const rank = i + 1;
+ const st = d.status === "online" || d.status === "OK"
+ ? 'Online'
+ : 'Offline';
+ const weLink = `/weinfo/${d.chain||getChain()}/${d.id}`;
- document.getElementById('onion').addEventListener('change', e => {
- withTor = e.target.checked;
- fetchData();
+ tb.insertAdjacentHTML('beforeend', `
+
+ | ${rank} |
+ ${DOMPurify.sanitize(d.url)} |
+ ${DOMPurify.sanitize(d.info||'—')} |
+ ${fmt(d.base_fee)} |
+ ${DOMPurify.sanitize(d.version||'—')} |
+ ${fmt(d.balance)} |
+ ${st} |
+ ${fmt(d.last_block)} |
+ ${d.count_win != null ? d.count_win : '—'} |
+ ${fmt(d.points)} |
+
`);
+
+ ml.insertAdjacentHTML('beforeend', `
+
+
+
+
Score${fmt(d.points)}
+
Wins${d.count_win != null ? d.count_win : '—'}
+
Fee${fmt(d.base_fee)} sat
+
Balance${fmt(d.balance)}
+
Version${DOMPurify.sanitize(d.version||'—')}
+
Height${fmt(d.last_block)}
+
+
`);
});
- document.getElementById('filter').addEventListener('input', e => {
- q = e.target.value;
+ const online = allServers.filter(d => d.status === "online" || d.status === "OK").length;
+ document.getElementById('s-online').textContent = online;
+ document.getElementById('s-total').textContent = allServers.length;
+ const top = getFiltered()[0];
+ document.getElementById('s-block').textContent = top ? fmt(top.last_block) : '—';
+}
+
+async function fetchData() {
+ const chain = getChain();
+ const params = new URLSearchParams({ page: 0, limit: 100 });
+ if (!withTor) params.append("onion", "no");
+ try {
+ const response = await fetch(`/data/${chain}?${params}`);
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
+ const obj = await response.json();
+ allServers = Object.entries(obj).map(([key, s]) => ({ id: key, ...s }));
render();
- });
+ } catch (err) {
+ console.error('Fetch error:', err);
+ allServers = [];
+ render();
+ }
+}
- document.getElementById('chainSeg').addEventListener('click', e => {
- const b = e.target.closest('button');
- if (!b) return;
- [...e.currentTarget.children].forEach(x => x.setAttribute('aria-pressed', 'false'));
- b.setAttribute('aria-pressed', 'true');
- fetchData();
- });
+document.getElementById('onion').addEventListener('change', e => {
+ withTor = e.target.checked;
+ fetchData();
+});
- document.getElementById('submit').addEventListener('click', async () => {
- const urlInput = document.getElementById('url');
- let url = urlInput.value.trim();
- if (!url) return;
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
- url = 'https://' + url;
- urlInput.value = url;
- }
- const chain = getChain();
- try {
- const response = await fetch('/data', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ url, chain })
- });
- const result = await response.json();
- const inv = document.getElementById('invoice');
- if (!response.ok) {
- document.getElementById('iv-status').className = 'err-line';
- document.getElementById('iv-status').textContent = 'Error: ' + (result.message || result.error || JSON.stringify(result));
- inv.classList.add('show');
- document.getElementById('qrcode').innerHTML = '';
- return;
- }
- document.getElementById('iv-status').className = 'ok-line';
- document.getElementById('iv-status').textContent = '✓ Server added. Pay the invoice to complete.';
- document.getElementById('iv-min').textContent = (result.min_amount || '50,000') + ' sats';
- document.getElementById('iv-chain').textContent = result.chain || chain;
- document.getElementById('iv-addr').textContent = result.address || '—';
- document.getElementById('iv-balance').textContent = result.balance != null ? fmt(result.balance) : '—';
- document.getElementById('iv-status2').textContent = result.status || '—';
- const invoiceuri = `bitcoin:${result.address}?label=BAL&message=Order+For+url+%26+${encodeURIComponent(url)}`;
- const qrEl = document.getElementById('qrcode');
- qrEl.innerHTML = '';
- new QRCode(qrEl, invoiceuri);
- inv.classList.add('show');
- inv.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
- } catch (err) {
+document.getElementById('filter').addEventListener('input', e => {
+ q = e.target.value;
+ render();
+});
+
+document.getElementById('chainSeg').addEventListener('click', e => {
+ const b = e.target.closest('button');
+ if (!b) return;
+ [...e.currentTarget.children].forEach(x => x.setAttribute('aria-pressed', 'false'));
+ b.setAttribute('aria-pressed', 'true');
+ fetchData();
+});
+
+document.getElementById('submit').addEventListener('click', async () => {
+ const urlInput = document.getElementById('url');
+ let url = urlInput.value.trim();
+ if (!url) return;
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
+ url = 'https://' + url;
+ urlInput.value = url;
+ }
+ const chain = getChain();
+ try {
+ const response = await fetch('/data', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ url, chain })
+ });
+ const result = await response.json();
+ const inv = document.getElementById('invoice');
+ if (!response.ok) {
document.getElementById('iv-status').className = 'err-line';
- document.getElementById('iv-status').textContent = 'Network error. Please try again.';
- document.getElementById('invoice').classList.add('show');
+ document.getElementById('iv-status').textContent = 'Error: ' + (result.message || result.error || JSON.stringify(result));
+ inv.classList.add('show');
document.getElementById('qrcode').innerHTML = '';
+ return;
}
- });
+ document.getElementById('iv-status').className = 'ok-line';
+ document.getElementById('iv-status').textContent = '✓ Server added. Pay the invoice to complete.';
+ document.getElementById('iv-min').textContent = (result.min_amount || '50,000') + ' sats';
+ document.getElementById('iv-chain').textContent = result.chain || chain;
+ document.getElementById('iv-addr').textContent = result.address || '—';
+ document.getElementById('iv-balance').textContent = result.balance != null ? fmt(result.balance) : '—';
+ document.getElementById('iv-status2').textContent = result.status || '—';
+ const invoiceuri = `bitcoin:${result.address}?label=BAL&message=Order+For+url+%26+${encodeURIComponent(url)}`;
+ const qrEl = document.getElementById('qrcode');
+ qrEl.innerHTML = '';
+ new QRCode(qrEl, invoiceuri);
+ inv.classList.add('show');
+ inv.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ } catch (err) {
+ document.getElementById('iv-status').className = 'err-line';
+ document.getElementById('iv-status').textContent = 'Network error. Please try again.';
+ document.getElementById('invoice').classList.add('show');
+ document.getElementById('qrcode').innerHTML = '';
+ }
+});
- (function init() {
- const blob = new Blob([JSON.stringify(allServers, null, 2)], { type: 'application/json' });
- document.getElementById('download').href = URL.createObjectURL(blob);
- fetchData();
- })();
+(function init() {
+ const blob = new Blob([JSON.stringify(allServers, null, 2)], { type: 'application/json' });
+ document.getElementById('download').href = URL.createObjectURL(blob);
+ fetchData();
+})();