RE: Update Bot auto curation
You are viewing a single comment's thread:
part 3
...
(html comment removed: ========== PATCH 2: Account Switcher ========== )
🔐 Voting Account
<div style="display: flex; gap: 10px; align-items: center; margin-bottom: 10px;">
<input
type="text"
id="account-input"
placeholder="Enter Hive username"
style="flex: 1; padding: 10px; background: rgba(18, 18, 48, 0.8); border: 1px solid rgba(178, 0, 255, 0.3); border-radius: 8px; color: var(--text-primary); font-size: 1rem;"
/>
<button
id="connect-btn"
onclick="connectAccount()"
style="padding: 10px 20px; white-space: nowrap;">
🔗 Connect & Validate
</button>
</div>
<div id="account-status" style="display: none; padding: 10px; border-radius: 6px; margin-top: 10px; font-size: 0.9rem;"></div>
</div>
<p><strong>Eligible Posts:</strong> <span style="color: var(--neon-green);"><?php echo count($eligible_posts); ?></span>/<?php echo count($posts); ?></p>
(html comment removed: ========== AFFICHAGE DES RÈGLES DE VOTE ========== )
<div style="margin-top: 20px; padding: 15px; background: rgba(0, 212, 255, 0.05); border-radius: 8px; border: 1px solid rgba(0, 212, 255, 0.2);">
<h3 style="color: var(--neon-blue); margin-bottom: 10px; font-size: 1.1rem;">⚙️ Vote Rules</h3>
<?php foreach ($VOTE_RULES as $min_words => $weight): ?>
<p style="margin: 5px 0; font-size: 0.95rem;">
<span style="color: var(--neon-yellow);">≥ <?php echo $min_words; ?> words</span>
→
<span style="color: var(--neon-green); font-weight: bold;"><?php echo $weight / 100; ?>%</span>
</p>
<?php endforeach; ?>
</div>
</div>
<?php if (count($eligible_posts) > 0): ?>
<div class="card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<h2 style="margin: 0;">✅ Eligible Posts (<?php echo count($eligible_posts); ?>)</h2>
<button onclick="voteAll()" style="padding: 10px 20px;">🚀 Vote All</button>
</div>
<table>
<thead>
<tr>
<th>Author</th>
<th>Title</th>
<th>Words</th>
<th>Weight</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($eligible_posts as $p):
$words = count_words($p['body']);
$vote_weight = get_vote_weight($words);
?>
<tr>
<td>
<a href="https://peakd.com/@<?php echo $p['author']; ?>"
target="_blank"
style="color: var(--neon-blue); text-decoration: none;">
@<?php echo $p['author']; ?>
</a>
</td>
<td>
<a href="https://peakd.com/@<?php echo $p['author']; ?>/<?php echo $p['permlink']; ?>"
target="_blank"
style="color: var(--text-primary); text-decoration: none;">
<?php echo htmlspecialchars(mb_substr($p['title'], 0, 60)) . (mb_strlen($p['title']) > 60 ? '...' : ''); ?>
</a>
</td>
<td><?php echo $words; ?></td>
<td>
<span style="
color: <?php
echo $vote_weight >= 600 ? 'var(--neon-green)' :
($vote_weight >= 500 ? 'var(--neon-yellow)' : 'var(--neon-blue)');
?>;
font-weight: bold;
">
<?php echo $vote_weight / 100; ?>%
</span>
</td>
<td>
<button
class="vote-btn"
onclick="votePost(
'<?php echo addslashes($p['author']); ?>',
'<?php echo addslashes($p['permlink']); ?>',
this,
<?php echo $words; ?>
)">
Vote <?php echo $vote_weight / 100; ?>%
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="card">
<h2>⚠️ No Eligible Posts</h2>
<p style="color: var(--text-secondary);">All posts have already been voted on or don't meet criteria.</p>
</div>
<?php endif; ?>
(html comment removed: ========== PATCH 1: Vote History (AMÉLIORÉ) ========== )
<div id="vote-history" style="
margin-top: 40px;
padding: 30px;
background: linear-gradient(135deg, rgba(18, 18, 48, 0.95), rgba(30, 30, 70, 0.85));
border-radius: 15px;
border: 2px solid var(--neon-purple);
box-shadow: 0 8px 32px rgba(178, 0, 255, 0.3);
">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<h2 style="
font-family: 'Orbitron', sans-serif;
color: var(--neon-purple);
text-shadow: 0 0 10px var(--neon-purple);
margin: 0;
">📊 Vote Session History</h2>
<button onclick="clearVoteHistory()" style="
background: linear-gradient(45deg, #ff0040, #ff6b9d);
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
font-family: 'Orbitron', sans-serif;
" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
🗑️ Clear History
</button>
</div>
<div id="history-list" style="
display: grid;
gap: 15px;
max-height: 500px;
overflow-y: auto;
"></div>
</div>
<script>
// ========== CONFIGURATION ==========
const VOTE_STORAGE_KEY = 'hiveVoteHistory';
const ACCOUNT_STORAGE_KEY = 'hiveVoterAccount';
const VOTE_DELAY = 5000;
const AUTO_REFRESH_DELAY = 900000;
// ========== AUTO-VOTE CONFIG (FROM PHP) ==========
const AUTO_VOTE_ENABLED = <?php echo AUTO_VOTE_ENABLED ? 'true' : 'false'; ?>;
const AUTO_VOTE_DELAY = <?php echo AUTO_VOTE_DELAY; ?>;
const AUTO_REFRESH_AFTER_VOTE = <?php echo AUTO_REFRESH_AFTER_VOTE ? 'true' : 'false'; ?>;
// ========== VOTE RULES (SYNCHRONIZED WITH PHP) ==========
const VOTE_RULES = <?php echo json_encode($VOTE_RULES); ?>;
function calculateVoteWeight(wordCount) {
// Trie les seuils par ordre décroissant
const sortedThresholds = Object.keys(VOTE_RULES)
.map(Number)
.sort((a, b) => b - a);
for (const minWords of sortedThresholds) {
if (wordCount >= minWords) {
return VOTE_RULES[minWords];
}
}
return 0;
}
// ========== VOTE SESSION ==========
let voteSession = {
history: [],
votedPosts: []
};
let autoRefreshTimer = null;
// ========== CONNECT ACCOUNT ==========
function connectAccount() {
const accountInput = document.getElementById('account-input');
const statusDiv = document.getElementById('account-status');
const username = accountInput.value.trim().replace('@', '');
if (!username) {
alert('⚠️ Please enter a username');
return;
}
statusDiv.style.display = 'block';
statusDiv.className = 'status-badge status-loading';
statusDiv.textContent = '⏳ Validating account...';
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
})
})
.then(res => res.json())
.then(data => {
if (data.result && data.result.length > 0) {
localStorage.setItem(ACCOUNT_STORAGE_KEY, username);
document.getElementById('current-account-display').textContent = `@${username}`;
statusDiv.className = 'status-badge status-success';
statusDiv.textContent = `✅ Connected as @${username}`;
console.log(`✅ Account validated: @${username}`);
} else {
statusDiv.className = 'status-badge status-failed';
statusDiv.textContent = '❌ Account not found';
}
})
.catch(err => {
statusDiv.className = 'status-badge status-failed';
statusDiv.textContent = '❌ Connection error';
console.error(err);
});
}
// ========== VOTE FUNCTION ==========
function votePost(author, permlink, button, wordCount) {
const savedAccount = localStorage.getItem(ACCOUNT_STORAGE_KEY) || '<?php echo VOTER_ACCOUNT; ?>';
if (button.disabled) return;
button.disabled = true;
button.textContent = "⏳ Voting...";
// Calculate weight using centralized function
let weight = calculateVoteWeight(wordCount);
console.log(`🗳️ Voting for @${author}/${permlink} with ${weight/100}% (${wordCount} words)`);
hive_keychain.requestVote(
savedAccount,
permlink,
author,
weight,
response => {
if (response.success) {
button.textContent = "✅ Voted";
button.classList.add("voted");
addVoteToSession(author, permlink, weight, true);
updateHistoryDisplay();
console.log(`✅ Successfully voted for @${author}/${permlink}`);
} else {
button.textContent = "❌ Failed";
button.style.background = "linear-gradient(90deg, var(--neon-red), #ff7a18)";
console.error("Vote error:", response.message);
alert(`❌ Vote failed: ${response.message}`);
}
}
);
}
// ========== ADD VOTE TO SESSION ==========
function addVoteToSession(author, permlink, weight, success) {
const voteData = {
author: author,
permlink: permlink,
weight: weight,
success: success,
timestamp: Date.now()
};
voteSession.history.unshift(voteData);
voteSession.votedPosts.push(`${author}/${permlink}`);
localStorage.setItem(VOTE_STORAGE_KEY, JSON.stringify(voteSession));
}
// ========== LOAD VOTE SESSION ==========
function loadVoteSession() {
const stored = localStorage.getItem(VOTE_STORAGE_KEY);
if (stored) {
voteSession = JSON.parse(stored);
updateHistoryDisplay();
}
}
// ========== CLEAR VOTE HISTORY ==========
function clearVoteHistory() {
if (confirm('🗑️ Clear all vote history?')) {
voteSession = { history: [], votedPosts: [] };
localStorage.removeItem(VOTE_STORAGE_KEY);
updateHistoryDisplay();
console.log('✅ Vote history cleared');
}
}
// ========== UPDATE HISTORY DISPLAY ==========
function updateHistoryDisplay() {
const historyList = document.getElementById('history-list');
if (voteSession.history.length === 0) {
historyList.innerHTML = '<p style="text-align: center; color: var(--text-secondary); padding: 20px;">No votes yet in this session</p>';
return;
}
historyList.innerHTML = voteSession.history.map(vote => {
const authorName = `@${vote.author}`;
const postUrl = `https://peakd.com/@${vote.author}/${vote.permlink}`;
const profileUrl = `https://peakd.com/@${vote.author}`;
const avatarUrl = `https://images.hive.blog/u/${vote.author}/avatar`;
const timeAgo = getTimeAgo(vote.timestamp);
return `
<div class="history-item">
<a href="${profileUrl}" target="_blank">
<img src="${avatarUrl}" alt="${authorName}" class="history-avatar"
onerror="this.src='https://images.hive.blog/u/hive.blog/avatar'">
</a>
<div class="history-content">
<a href="${profileUrl}" target="_blank" class="history-author">
${authorName}
</a>
<a href="${postUrl}" target="_blank" class="history-post-link">
🔗 View post on PeakD
</a>
</div>
<div class="history-meta">
<span class="history-weight">💎 ${vote.weight / 100}%</span>
<span class="history-time">${timeAgo}</span>
</div>
</div>
`;
}).join('');
}
function getTimeAgo(timestamp) {
const now = Date.now();
const diffMs = now - timestamp;
const diffMins = Math.floor(diffMs / 60000);
if (diffMins < 1) return 'Just now';
if (diffMins < 60) return `${diffMins}m ago`;
const diffHours = Math.floor(diffMins / 60);
if (diffHours < 24) return `${diffHours}h ago`;
const diffDays = Math.floor(diffHours / 24);
return `${diffDays}d ago`;
}
// ========== AUTO-VOTE FUNCTION ==========
async function startAutoVote() {
const username = localStorage.getItem(ACCOUNT_STORAGE_KEY)
|| '<?php echo VOTER_ACCOUNT; ?>';
// ✅ CHECK VP LIVE AU DÉMARRAGE
const res = 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 data = await res.json();
const liveVP = data?.result?.[0]
? Math.round(data.result[0].voting_power / 100)
: 0;
console.log(`🔋 VP au démarrage : ${liveVP}%`);
if (liveVP < <?php echo MIN_VP_THRESHOLD; ?>) {
console.log("⛔ VP insuffisant, auto-vote annulé");
return;
}
// ✅ TON CODE AUTO-VOTE EXISTANT
const buttons = document.querySelectorAll("button.vote-btn:not([disabled])");
if (buttons.length === 0) {
console.log("✅ No posts to vote");
if (AUTO_REFRESH_AFTER_VOTE) scheduleAutoRefresh();
return;
}
console.log(`🤖 AUTO-VOTE: Starting for ${buttons.length} posts`);
showAutoVoteIndicator(buttons.length);
let index = 0;
function voteNext() {
if (index >= buttons.length) {
console.log("✅ AUTO-VOTE: Complete");
hideAutoVoteIndicator();
if (AUTO_REFRESH_AFTER_VOTE) scheduleAutoRefresh();
return;
}
updateAutoVoteIndicator(index + 1, buttons.length);
buttons[index].click();
index++;
setTimeout(voteNext, AUTO_VOTE_DELAY);
}
voteNext();
}
// ========== VOTE ALL FUNCTION (MANUAL) ==========
function voteAll() {
const buttons = document.querySelectorAll("button.vote-btn:not([disabled])");
if (buttons.length === 0) {
console.log("✅ No eligible posts - refreshing in 5 seconds");
scheduleAutoRefresh();
return;
}
let index = 0;
function voteNext() {
if (index >= buttons.length) {
console.log("✅ Voting complete - refreshing in 5 seconds");
scheduleAutoRefresh();
return;
}
buttons[index].click();
index++;
setTimeout(voteNext, 3000);
}
voteNext();
}
...
0
0
0.000
0 comments