init
This commit is contained in:
BIN
Logo_nero.ico
Normal file
BIN
Logo_nero.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
Logo_nero.png
Normal file
BIN
Logo_nero.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
93
bal.js
Normal file
93
bal.js
Normal file
@@ -0,0 +1,93 @@
|
||||
var chain = 'bitcoin';
|
||||
var page = 0;
|
||||
var limit = 100;
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has('page')) {
|
||||
page =urlParams.get('page',0);
|
||||
}
|
||||
if (urlParams.has('limit')){
|
||||
limit = urlParams.get('limit',100);
|
||||
}
|
||||
if (urlParams.has('chain')){
|
||||
chain = urlParams.get('chain','bitcoin');
|
||||
}
|
||||
|
||||
|
||||
function get_chain(){
|
||||
var e = document.getElementById('chain')
|
||||
const idx = e.selectedIndex;
|
||||
if (idx == 0){
|
||||
return 'bitcoin';
|
||||
}
|
||||
else if (idx == 1) {
|
||||
return 'testnet';
|
||||
}
|
||||
else if (idx == 2) {
|
||||
return 'regtest';
|
||||
}
|
||||
}
|
||||
function downloadLink(data,options) {
|
||||
const jsonString = JSON.stringify(data);
|
||||
const blob = new Blob([jsonString], { type: 'application/json;charset=utf-8' });
|
||||
|
||||
const urlCreator = URL.createObjectURL(blob);
|
||||
const a = document.getElementById(options.elementName);
|
||||
a.href = urlCreator;
|
||||
a.setAttribute(options.linkText, options.fileName);
|
||||
}
|
||||
|
||||
async function fetchDataAndPopulateTable(url,params,fnPopulateTable,downloadOpt,onError){
|
||||
try {
|
||||
//params.append("page",page);
|
||||
//params.append("limit",limit);
|
||||
//const response = await fetch('/wetime/'+get_chain()+"?"+params.toString());
|
||||
var realurl = url
|
||||
if (params){
|
||||
params.append("page",page);
|
||||
params.append("limit",limit);
|
||||
realurl+="?"+params.toString();
|
||||
}
|
||||
|
||||
const response = await fetch(realurl);
|
||||
if (!response.ok) {
|
||||
console.log("error",response);
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (downloadOpt){
|
||||
downloadLink(data,downloadOpt);
|
||||
}
|
||||
var paginator=fnPopulateTable(data);
|
||||
make_paginator(paginator);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
if (onError){
|
||||
onError(error);
|
||||
}
|
||||
}
|
||||
function createlink(html,dest){
|
||||
const link = document.createElement("a");
|
||||
link.href=dest;
|
||||
link.innerHTML=html
|
||||
return link;
|
||||
}
|
||||
function make_paginator(){
|
||||
document.getElementById("chainth").innerHTML = chain;
|
||||
const pag = document.getElementById("paginator");
|
||||
|
||||
pag.appendChild(document.createTextNode("_"));
|
||||
if (page > 0) {
|
||||
pag.appendChild(createlink("<","?page="+paginator.prev));
|
||||
}
|
||||
else{
|
||||
pag.appendChild(document.createTextNode("<"));
|
||||
}
|
||||
pag.appendChild(document.createTextNode("_"));
|
||||
pag.appendChild(document.createTextNode(page));
|
||||
pag.appendChild(document.createTextNode("_"));
|
||||
pag.appendChild(createlink(">","?page="+paginator.next));
|
||||
}
|
||||
}
|
||||
|
||||
281
index.html
Normal file
281
index.html
Normal file
@@ -0,0 +1,281 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Bal Server List</title>
|
||||
<link rel="icon" href="Logo_nero.ico" type="image/x-icon">
|
||||
<script src="qrcode.min.js"></script>
|
||||
<script src="purify.min.js"></script>
|
||||
<script src="bal.js"></script>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
body>div:first-of-type{
|
||||
text-align:center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<a href="/"><img alt="BAL LOGO" src="/Logo_nero.png"></a>
|
||||
<h1>Bal Server List</h1>
|
||||
<div>
|
||||
<select id="chain" name="chain">
|
||||
<option selected value="bitcoin">Bitcoin</option>
|
||||
<option value="testnet">Testnet</option>
|
||||
<option>Regtest</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="onion">Include tor: </label><input type="checkbox" name="onion" id="onion" value="yes" checked>
|
||||
</div>
|
||||
<div>
|
||||
<a href="" id="download">Download</a>
|
||||
</div>
|
||||
<table id="willexecutors">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Url</th>
|
||||
<th>Info</th>
|
||||
<th>Fees</th>
|
||||
<th>Version</th>
|
||||
<th>Balance</th>
|
||||
<th>Status</th>
|
||||
<th>Height</th>
|
||||
<th>Wins</th>
|
||||
<th>Score</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><!-- --></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<form id="myServer">
|
||||
<input type="text" id="url" name="url" required placeholder="https://bitcoin-after.life:9137">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<div id="result_text"></div>
|
||||
<div>
|
||||
<a id="aqr">
|
||||
<div id="qrcode"></div>
|
||||
</a>
|
||||
</div>
|
||||
<p>Please make sure your server is online before you try to add it</p>
|
||||
<p>Server not online will be removed from this list</p>
|
||||
|
||||
<script>
|
||||
class BalServerList {
|
||||
constructor() {
|
||||
this.chain = 'bitcoin';
|
||||
this.page = 0;
|
||||
this.limit = 100;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.parseUrlParams();
|
||||
this.bindEvents();
|
||||
this.fetchDataAndPopulateTable();
|
||||
}
|
||||
|
||||
parseUrlParams() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
this.page = parseInt(urlParams.get('page')) || 0;
|
||||
this.limit = parseInt(urlParams.get('limit')) || 100;
|
||||
this.chain = urlParams.get('chain') || 'bitcoin';
|
||||
|
||||
const chainSelect = document.getElementById('chain');
|
||||
chainSelect.value = this.chain;
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
document.getElementById('onion').addEventListener('change', () => {
|
||||
this.fetchDataAndPopulateTable();
|
||||
});
|
||||
|
||||
document.getElementById('chain').addEventListener('change', (e) => {
|
||||
this.chain = this.getChain();
|
||||
this.fetchDataAndPopulateTable();
|
||||
});
|
||||
|
||||
document.getElementById('myServer').addEventListener('submit', (e) => {
|
||||
this.handleServerSubmission(e);
|
||||
});
|
||||
}
|
||||
|
||||
async handleServerSubmission(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const urlInput = document.getElementById('url');
|
||||
let url = urlInput.value.trim();
|
||||
|
||||
if (!url) return;
|
||||
|
||||
url = this.formatUrl(url);
|
||||
urlInput.value = url;
|
||||
|
||||
try {
|
||||
const response = await fetch('/data', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, chain: this.chain })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
this.showError(result);
|
||||
} else {
|
||||
this.showSuccess(result, url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Submission error:', error);
|
||||
this.showError('Network error. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
formatUrl(url) {
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
return 'https://' + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
const resultDiv = document.getElementById('result_text');
|
||||
resultDiv.innerHTML = `<p style="color:red">${DOMPurify.sanitize(message)}</p>`;
|
||||
}
|
||||
|
||||
showSuccess(result, url) {
|
||||
const invoiceuri = `bitcoin:${result.address}?label=BAL&message=Order+For+url+%26+${encodeURIComponent(result.url)}`;
|
||||
|
||||
const cleanHtml = DOMPurify.sanitize(`
|
||||
<p style="color:green">${url} successfully added</p>
|
||||
<div>
|
||||
Please Pay this invoice to complete the process:<br/>
|
||||
<b><u>Less than ${result.min_amount} sats are considered donations! if you want your server to be listed you have to send at least ${result.min_amount} sats</u></b><br/>
|
||||
<b>Chain:</b> ${result.chain}<br/>
|
||||
<b>Address:</b> ${result.address}<br/>
|
||||
<b>Balance:</b> ${result.balance}<br/>
|
||||
<b>Status:</b> ${result.status}<br/>
|
||||
</div>
|
||||
`);
|
||||
|
||||
document.getElementById("result_text").innerHTML = cleanHtml;
|
||||
|
||||
// Generate QR code
|
||||
const qrElement = document.getElementById("qrcode");
|
||||
qrElement.innerHTML = "";
|
||||
new QRCode(qrElement, invoiceuri);
|
||||
document.getElementById("aqr").href = invoiceuri;
|
||||
}
|
||||
|
||||
getChain() {
|
||||
const select = document.getElementById('chain');
|
||||
return select.value;
|
||||
}
|
||||
|
||||
async fetchDataAndPopulateTable() {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
page: this.page,
|
||||
limit: this.limit
|
||||
});
|
||||
|
||||
if (!document.getElementById("onion").checked) {
|
||||
params.append("onion", "no");
|
||||
}
|
||||
|
||||
const response = await fetch(`/data/${this.chain}?${params.toString()}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
this.downloadLink(data);
|
||||
this.populateTable(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
this.showTableError();
|
||||
}
|
||||
}
|
||||
|
||||
showTableError() {
|
||||
const tableBody = document.querySelector('#willexecutors tbody');
|
||||
tableBody.innerHTML = '<tr><td colspan="6">Error loading data. Please try again later.</td></tr>';
|
||||
}
|
||||
|
||||
downloadLink(data) {
|
||||
const jsonString = JSON.stringify(data);
|
||||
const blob = new Blob([jsonString], { type: 'application/json;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const downloadLink = document.getElementById('download');
|
||||
downloadLink.href = url;
|
||||
downloadLink.setAttribute('download', 'willexecutors.json');
|
||||
}
|
||||
get_url(id,url){
|
||||
|
||||
}
|
||||
populateTable(willexecutors) {
|
||||
const tableBody = document.querySelector('#willexecutors tbody');
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (Object.keys(willexecutors).length === 0) {
|
||||
tableBody.innerHTML = '<tr><td colspan="9">No servers found</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
Object.entries(willexecutors).forEach(([key, we]) => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
this.appendRawTd(`<a href='/weinfo/${we.chain}/${we.id}'>${we.url}</a>`, row);
|
||||
this.appendTd(we.info || ' ', row);
|
||||
this.appendTd(we.base_fee, row);
|
||||
this.appendTd(we.version, row);
|
||||
this.appendTd(we.balance, row);
|
||||
this.appendTd(we.status, row);
|
||||
this.appendTd(we.last_block, row);
|
||||
this.appendTd(we.count_win, row);
|
||||
this.appendTd(we.points, row);
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
appendTd(content, tr) {
|
||||
const td = document.createElement('td');
|
||||
td.textContent = content;
|
||||
tr.appendChild(td);
|
||||
}
|
||||
appendRawTd(content,tr){
|
||||
const td = document.createElement('td');
|
||||
td.innerHTML = DOMPurify.sanitize(content);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new BalServerList();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
3
purify.min.js
vendored
Normal file
3
purify.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
purify.min.js.map
Normal file
1
purify.min.js.map
Normal file
File diff suppressed because one or more lines are too long
1
qrcode.min.js
vendored
Normal file
1
qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
133
weinfo.html
Normal file
133
weinfo.html
Normal file
@@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-<|begin▁of▁sentence|>8" />
|
||||
<meta name="viewport" content="width=device-w, initial-scale=1.0" />
|
||||
<title>Bal Server List</title>
|
||||
<link rel="icon" href="Logo_nero.ico" type="image/x-icon">
|
||||
<script src="/qrcode.min.js"></script>
|
||||
<script src="/purify.min.js"></script>
|
||||
<script src="/bal.js"></script>
|
||||
</head>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
span{
|
||||
margin-left:10px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div align="center">
|
||||
<a href="/"><img alt="BAL LOGO" src="/Logo_nero.png"></a>
|
||||
<h2 id="wename"> </h2>
|
||||
<h3 id="weinfo"> </h3>
|
||||
<h4 id="wechain"> </h4>
|
||||
</div>
|
||||
<div style="float:left;border:1;margin-right:50px;">
|
||||
<div><span>Version:</span><span id="weversion"> </span></div>
|
||||
<div><span>Fees:</span><span id="wefees"> </span></div>
|
||||
<div><span>Tld:</span><span id="wetld"> </span></div>
|
||||
</div>
|
||||
<div style="float:left;border:1;margin-right:50px;">
|
||||
<div><span>Height:</span><span id="weheight"> </span></div>
|
||||
<div><span>Points:</span><span id="wepoints"> </span></div>
|
||||
<div><span>Win:</span><span id="wewin"> </span></div>
|
||||
</div>
|
||||
<div style="border:1;margin-right:50px;">
|
||||
<div><span>Balance:</span><span id="webalance"> </span></div>
|
||||
<div><span>Status:</span><span id="westatus"> </span></div>
|
||||
<div><span>Last Update:</span><span id="weupdate"> </span></div>
|
||||
</div>
|
||||
<div>
|
||||
<table id="wetimes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan=5><span id="chainth"><!-- --></span>: <span id="paginator"></span></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>height</th>
|
||||
<th>block hash</th>
|
||||
<th>time</th>
|
||||
<th>diff</th>
|
||||
<th>position</th>
|
||||
<th>participants</th>
|
||||
<th>points</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<a href="" id="download">Download</a>
|
||||
<script type="text/javascript">
|
||||
function getWeInfo(){
|
||||
const path = window.location.pathname.split('/').filter(p => p !== '');
|
||||
const we_id = path[2];
|
||||
const chain = path[1];
|
||||
const cdate=new Date().toISOString().replace(/[-:T.Z]/g, '').slice(0, 14);
|
||||
fetchDataAndPopulateTable('/weinfodata/'+chain+"/"+we_id, new URLSearchParams(),(data) => {
|
||||
document.getElementById('wename').innerHTML = DOMPurify.sanitize(data.url);
|
||||
document.getElementById('wechain').innerHTML = DOMPurify.sanitize(data.chain);
|
||||
document.getElementById('weinfo').innerHTML = DOMPurify.sanitize(data.info);
|
||||
document.getElementById('wefees').innerHTML = data.base_fee;
|
||||
document.getElementById('weheight').innerHTML = data.last_block;
|
||||
document.getElementById('wepoints').innerHTML = data.points;
|
||||
document.getElementById('wewin').innerHTML = data.count_win;
|
||||
document.getElementById('wetld').innerHTML = DOMPurify.sanitize(data.tld);
|
||||
document.getElementById('webalance').innerHTML = data.balance;
|
||||
document.getElementById('weversion').innerHTML = data.version;;
|
||||
document.getElementById('westatus').innerHTML = DOMPurify.sanitize(data.status);
|
||||
document.getElementById('weupdate').innerHTML = data.last_update;
|
||||
|
||||
const tableBody = document.querySelector('#wetimes tbody');
|
||||
tableBody.innerHTML ='';
|
||||
Object.entries(data.times).forEach(([key,wetime]) => {
|
||||
const row = document.createElement('tr');
|
||||
const d = new Date(wetime.time/1000);
|
||||
row.innerHTML = `
|
||||
<td>${wetime.blockHeight}</td>
|
||||
<td>${DOMPurify.sanitize(wetime.blockHash)}</td>
|
||||
<td>${d}</td>
|
||||
<td>${wetime.diff/1000000} s</td>
|
||||
<td>${wetime.position+1}</td>
|
||||
<td>${wetime.participants}</td>
|
||||
<td>${wetime.points}</td>
|
||||
`;
|
||||
tableBody.appendChild(row);
|
||||
})
|
||||
var prev=0;
|
||||
var next=0;
|
||||
if (data.times.length > 0){
|
||||
prev = data.times[0].blockHeight+data.times.length;
|
||||
next = data.times[data.times.length-1].blockHeight;
|
||||
if (prev < 0 ){
|
||||
prev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const paginator = {prev:prev,next:next};
|
||||
return paginator;
|
||||
},{elementName:"download",fileName:"weinfo_"+cdate+".json",linkText:"download"})
|
||||
}
|
||||
|
||||
getWeInfo();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user