<!-- ===== 🔥 HIVEHUB DASHBOARD FINAL FIX ===== -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.hivehub-grid{
margin-top:50px;
display:grid;
grid-template-columns: repeat(auto-fit,minmax(420px,1fr));
gap:25px;
}
.hivehub-card{
background:#1e1e2f;
border-radius:12px;
padding:20px;
border:1px solid rgba(255,255,255,0.05);
}
.hivehub-title{
font-size:14px;
color:#aaa;
}
.hivehub-value{
font-size:26px;
font-weight:bold;
color:#fff;
margin-bottom:10px;
}
</style>
<div class="hivehub-grid">
<div class="hivehub-card">
<div class="hivehub-title">Hive Power</div>
<div class="hivehub-value" id="hpValue">...</div>
<canvas id="hpChart"></canvas>
</div>
<div class="hivehub-card">
<div class="hivehub-title">HP Delta</div>
<div class="hivehub-value" id="hpDeltaValue">...</div>
<canvas id="hpDeltaChart"></canvas>
</div>
<div class="hivehub-card">
<div class="hivehub-title">Author Rewards</div>
<div class="hivehub-value" id="authorValue">...</div>
<canvas id="authorChart"></canvas>
</div>
<div class="hivehub-card">
<div class="hivehub-title">Curation Rewards</div>
<div class="hivehub-value" id="curationValue">...</div>
<canvas id="curationChart"></canvas>
</div>
</div>
<script>
async function loadHiveHubExact() {
try {
const username = localStorage.getItem('hive_account') || '<?php echo VOTER_ACCOUNT; ?>';
// ===== GLOBAL PROPS =====
const propsRes = await fetch('https://api.hive.blog', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
jsonrpc:"2.0",
method:"condenser_api.get_dynamic_global_properties",
params:[],
id:1
})
});
const props = (await propsRes.json()).result;
const total_vesting_fund = parseFloat(props.total_vesting_fund_hive);
const total_vesting_shares = parseFloat(props.total_vesting_shares);
function vestsToHP(vests){
return (vests * total_vesting_fund) / total_vesting_shares;
}
// ===== ACCOUNT =====
const accRes = await fetch('https://api.hive.blog', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
jsonrpc:"2.0",
method:"condenser_api.get_accounts",
params:[[username]],
id:1
})
});
const accData = await accRes.json();
if (!accData.result || !accData.result[0]) return;
const acc = accData.result[0];
const totalVests =
parseFloat(acc.vesting_shares) +
parseFloat(acc.received_vesting_shares) -
parseFloat(acc.delegated_vesting_shares);
const currentHP = vestsToHP(totalVests);
document.getElementById('hpValue').innerText = currentHP.toFixed(0) + " HP";
// ===== HISTORY =====
const histRes = await fetch('https://api.hive.blog', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
jsonrpc:"2.0",
method:"account_history_api.get_account_history",
params:{ account: username, start:-1, limit:1000 },
id:1
})
});
const histData = await histRes.json();
if (!histData.result) return;
const history = histData.result.history;
let days = 30;
let now = Date.now();
let hpDelta = {};
let author = {};
let curation = {};
for(let i=0;i<days;i++){
let d = new Date(now - i*86400000).toISOString().slice(0,10);
hpDelta[d] = 0;
author[d] = 0;
curation[d] = 0;
}
history.forEach(e=>{
const op = e[1].op;
const ts = new Date(e[1].timestamp).getTime();
const day = new Date(ts).toISOString().slice(0,10);
if(!(day in hpDelta)) return;
// ===== CURATION =====
if(op[0]==="curation_reward"){
let vests = parseFloat(op[1].reward);
let hp = vestsToHP(vests);
if (!isNaN(hp)) {
curation[day]+=hp;
hpDelta[day]+=hp;
}
}
// ===== AUTHOR =====
if(op[0]==="author_reward"){
let total = 0;
if(op[1].hbd_payout) total += parseFloat(op[1].hbd_payout);
if(op[1].hive_payout) total += parseFloat(op[1].hive_payout);
if (!isNaN(total)) author[day]+=total;
}
// ===== POWER UP =====
if(op[0]==="transfer_to_vesting"){
let amount = parseFloat(op[1].amount);
if (!isNaN(amount)) hpDelta[day]+=amount;
}
// ===== POWER DOWN =====
if(op[0]==="fill_vesting_withdraw"){
let amount = parseFloat(op[1].withdrawn);
if (!isNaN(amount)) hpDelta[day]-=amount;
}
});
let labels = Object.keys(hpDelta).reverse();
let cumulative = currentHP;
let hpData = [];
labels.forEach(d=>{
cumulative -= hpDelta[d];
hpData.push(cumulative);
});
hpData.reverse();
// ===== VALUES =====
document.getElementById('hpDeltaValue').innerText =
Object.values(hpDelta).reduce((a,b)=>a+b,0).toFixed(0)+" HP";
document.getElementById('authorValue').innerText =
Object.values(author).reduce((a,b)=>a+b,0).toFixed(2)+" HBD";
document.getElementById('curationValue').innerText =
Object.values(curation).reduce((a,b)=>a+b,0).toFixed(2)+" HP";
const baseOptions = {
responsive:true,
plugins:{legend:{display:false}},
scales:{
x:{ticks:{color:'#777'}},
y:{ticks:{color:'#777'}}
}
};
new Chart(hpChart,{
type:'line',
data:{labels,datasets:[{data:hpData,borderColor:'#00ff88',tension:0.3}]},
options:baseOptions
});
new Chart(hpDeltaChart,{
type:'bar',
data:{labels,datasets:[{data:Object.values(hpDelta).reverse(),backgroundColor:'#00ff8855'}]},
options:baseOptions
});
new Chart(authorChart,{
type:'bar',
data:{labels,datasets:[{data:Object.values(author).reverse(),backgroundColor:'#00d4ff88'}]},
options:baseOptions
});
new Chart(curationChart,{
type:'bar',
data:{labels,datasets:[{data:Object.values(curation).reverse(),backgroundColor:'#00ff8888'}]},
options:baseOptions
});
} catch (e) {
console.error("🔥 HiveHub error:", e);
}
}
document.addEventListener('DOMContentLoaded', loadHiveHubExact);
</script>

I managed to add a table at the bottom of my code to display a copy-paste of:
https://hivehub.dev/stats/account?username=we-are-ai&category=financial&days=30
My HP
My HP delta
My author reward
My curation reward
I improve it whenever I have time to build a fully automated curation bot .
And I’ll keep you posted if I have other ideas for things to add to the screen, or if you have any.
full code in comment
!HBIT
part 2
...
// ----------- LOGIQUE PRINCIPALE -----------
$account = get_hive_account(VOTER_ACCOUNT);
$current_vp = get_current_vp(VOTER_ACCOUNT);
$posts = get_hive_posts();
$eligible_posts = [];
$debug_logs = [];
foreach ($posts as $p) {
$words = count_words($p['body']);
$vote_weight = get_vote_weight($words);
$user_voted = false;
$reason = "";
}
🤖 Hive Auto Words?>
part 4
...
// ========== AUTO-VOTE INDICATOR ==========
function showAutoVoteIndicator(totalPosts) {
let indicator = document.getElementById('auto-vote-indicator');
if (!indicator) {
indicator = document.createElement('div');
indicator.id = 'auto-vote-indicator';
indicator.style.cssText =
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(18, 18, 48, 0.98); border: 2px solid var(--neon-blue); border-radius: 15px; padding: 30px 40px; z-index: 10000; text-align: center; box-shadow: 0 8px 32px rgba(0, 212, 255, 0.5); animation: pulse-glow 2s infinite;;document.body.appendChild(indicator);
}
let csvContent = "username,post_url\n"; // header CSV
voteSession.history.forEach(vote => {
const username = vote.author.replace('@', '');
const postUrl =
https://peakd.com/@${vote.author}/${vote.permlink};});
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
const now = new Date();
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-');
const filename =
glyph_voters_${timestamp}.csv;link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
console.log(
✅ Exported ${voteSession.history.length} votes with links);}
part 5
...
========== AUTO-VOTE TOGGLE FUNCTION ==========
let autoVotePaused = false;
let autoVoteInterval = null;
function toggleAutoVote() {
autoVotePaused = !autoVotePaused;
const toggleBtn = document.getElementById('autoVoteToggle');
const statusText = document.getElementById('autoVoteStatus');
}
// Modification de startAutoVote pour gérer la pause
window.startAutoVoteOriginal = window.startAutoVote;
window.startAutoVote = async function() {
if (autoVotePaused) return;
await window.startAutoVoteOriginal();
}
// Initialisation
document.addEventListener('DOMContentLoaded', function() {
// Vérifier si l'auto-vote est activé dans la config
if (!) {
const toggleBtn = document.getElementById('autoVoteToggle');
const statusText = document.getElementById('autoVoteStatus');
toggleBtn.textContent = "▶";
statusText.textContent = "DISABLED";
statusText.style.color = "var(--text-secondary)";
toggleBtn.onclick = function() {
alert("Auto-vote is disabled in configuration. Set AUTO_VOTE_ENABLED to true in PHP config.");
};
}
});
part 6
...
// ✅ 1. Neutraliser TOUS les alert() (anti blocage total)
window.alert = function(message) {
console.warn("🚫 Alert bloquée :", message);
};
// ✅ 2. Optionnel : petit toast visuel (non bloquant)
function showToast(msg) {
const div = document.createElement('div');
div.textContent = msg;
div.style =
position: fixed; bottom: 20px; left: 20px; background: #ff2e63; color: white; padding: 10px 15px; border-radius: 8px; z-index: 9999; font-size: 0.8rem; opacity: 0.9; font-family: sans-serif;;document.body.appendChild(div);
setTimeout(() => div.remove(), 3000);
}
// ✅ 3. Hook automatique sur les boutons de vote
document.addEventListener('click', function(e) {
const btn = e.target.closest('button');
if (!btn) return;
});
// ✅ 4. Sécurité globale JS (aucune erreur ne bloque)
window.onerror = function(msg, url, line, col, error) {
console.error("💥 JS Error caught:", msg);
return true; // empêche blocage
};
window.onunhandledrejection = function(event) {
console.error("💥 Promise Error:", event.reason);
};
part 7
...
part 3
...
🔐 Voting Account
// ========== AUTO-VOTE FUNCTION ==========
async function startAutoVote() {
}
...