Posts

From Hive Votes to Discord: The Struggles Behind a Little PHP Project

2 comments·0 reblogs
we-are-ai
62
·
0 views
·
min-read

Image from thread

From Hive Votes to Discord: The Struggles Behind a Little PHP Project

I wanted to create a small program that would send the votes made by my Hive account, @we-are-ai, to a Discord channel.

At first, I thought it would be pretty simple: retrieve my votes and send them to Discord. But the project came with quite a few surprises! 😅

The RSS feed didn’t track my votes

My first idea was to use a PeakD RSS feed. I soon realised it wasn’t the right solution for tracking my account’s votes, so I had to find another way to retrieve Hive operations directly.

PHP, WampServer, and connection problems

Since I use WampServer, I wanted to run the PHP program locally on my computer, which stays on all the time. The code could retrieve the information, but connecting to the Hive API caused problems because of the SSL certificate.

I had to find the cacert.pem file and then update PHP’s configuration in the php.ini file, which I accessed through WampServer’s menus. That wasn’t exactly easy when you’re not familiar with those settings!

The Discord webhook and lots of testing

Next, I had to get the messages working through a Discord webhook. The page could detect votes, but the messages didn’t always appear in the channel. I checked the webhook, tested several versions of the code, and went through the setup more than once.

I won’t lie: I lost my temper several times in front of the screen! 😂 Between the errors, pages loading forever, and changes that seemed to break everything, there were a few frustrating moments.

Preventing duplicates and refreshing the page

I also wanted to stop the program from sending the same votes over and over. The code therefore remembers the last operation it processed, so it can try to send only new ones.

I then added an automatic refresh every 60 seconds, with a visible countdown until the next reload.

It finally works!

After lots of testing, fixes, and a few moments of frustration, it finally works: the program detects new votes and sends them to Discord. The page also displays a countdown before the next check.

It may have been a small project, but it turned into quite an adventure for me. When you’re just starting out, every detail—PHP, WampServer, the SSL certificate, or the webhook—can quickly become a real headache. But I finally got there! 🙌

The code

I’ll share the final code at the end of the post, without my webhook. You’ll need to replace the placeholder with your own webhook. Be careful: a webhook is a secret URL that allows messages to be sent to its associated channel. Don’t publish it.

// Replace this with your own webhook, and never share it publicly: 
$discordWebhook = 'PASTE_YOUR_WEBHOOK_HERE'; 

The famous code

<?php 
ini_set('display_errors', '1'); 
error_reporting(E_ALL); 
 
$account = 'we-are-ai'; 
$hiveUrl = 'https://api.hive.blog'; 
$discordWebhook = 'PASTE_YOUR_WEBHOOK_HERE'; 
$stateFile = __DIR__ . '/votes_state.json'; 
 
function postJson($url, $payload) 
{ 
    $ch = curl_init($url); 
 
    curl_setopt_array($ch, [ 
        CURLOPT_POST => true, 
        CURLOPT_POSTFIELDS => json_encode($payload), 
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'], 
        CURLOPT_RETURNTRANSFER => true, 
        CURLOPT_TIMEOUT => 20 
    ]); 
 
    $response = curl_exec($ch); 
    $error = curl_error($ch); 
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
    curl_close($ch); 
 
    return [$response, $error, $httpCode]; 
} 
 
// Retrieve the latest Hive account operations 
$payload = [ 
    'jsonrpc' => '2.0', 
    'method' => 'condenser_api.get_account_history', 
    'params' => [$account, -1, 1000], 
    'id' => 1 
]; 
 
[$response, $error, $httpCode] = postJson($hiveUrl, $payload); 
 
if ($response === false || $error !== '') { 
    die('Hive connection error: ' . htmlspecialchars($error)); 
} 
 
$data = json_decode($response, true); 
 
if ($httpCode !== 200 || !isset($data['result']) || !is_array($data['result'])) { 
    die('Invalid response from Hive:<pre>' . htmlspecialchars($response) . '</pre>'); 
} 
 
$history = $data['result']; 
 
// On the first run, save the current position without sending old votes. 
if (!file_exists($stateFile)) { 
    $latestIndex = -1; 
 
    foreach ($history as $entry) { 
        if (isset($entry[0]) && $entry[0] > $latestIndex) { 
            $latestIndex = (int)$entry[0]; 
        } 
    } 
 
    file_put_contents($stateFile, json_encode(['last_index' => $latestIndex])); 
    die('Initialization complete. No previous votes were sent. Reload the page to check again.'); 
} 
 
$state = json_decode(file_get_contents($stateFile), true); 
$lastIndex = (int)($state['last_index'] ?? -1); 
 
// Sort operations from oldest to newest 
usort($history, function ($a, $b) { 
    return ($a[0] ?? 0) <=> ($b[0] ?? 0); 
}); 
 
$sent = 0; 
 
foreach ($history as $entry) { 
    $index = (int)($entry[0] ?? -1); 
 
    if ($index <= $lastIndex) { 
        continue; 
    } 
 
    $operation = $entry[1]['op'] ?? null; 
 
    if ( 
        is_array($operation) && 
        ($operation[0] ?? '') === 'vote' 
    ) { 
        $vote = $operation[1]; 
 
        $author = $vote['author'] ?? '?'; 
        $permlink = $vote['permlink'] ?? '?'; 
        $weight = $vote['weight'] ?? '?'; 
        $timestamp = $entry[1]['timestamp'] ?? ''; 
 
        $message = "🗳️ New vote from **@{$account}**\n" 
                 . "Post: https://peakd.com/@{$author}/{$permlink}\n" 
                 . "Weight: {$weight}\n" 
                 . "Date: {$timestamp}"; 
 
        [$discordResponse, $discordError, $discordCode] = postJson( 
            $discordWebhook . '?wait=true', 
            ['content' => $message] 
        ); 
 
        if ($discordError !== '' || $discordCode < 200 || $discordCode >= 300) { 
            die('Discord error (HTTP ' . $discordCode . '): ' 
                . htmlspecialchars($discordError ?: $discordResponse)); 
        } 
 
        $sent++; 
    } 
 
    // Save each processed operation to prevent it from being sent again. 
    $lastIndex = $index; 
    file_put_contents($stateFile, json_encode(['last_index' => $lastIndex])); 
} 
 
echo $sent > 0 
    ? $sent . ' new vote(s) sent to Discord.' 
    : 'No new votes to send.'; 
?> 
 
<p>Next check in <strong><span id="countdown">60</span> seconds</strong>.</p> 
 
<script> 
let seconds = 60; 
const countdown = document.getElementById('countdown'); 
 
setInterval(function () { 
    seconds--; 
    countdown.textContent = seconds; 
 
    if (seconds <= 0) { 
        window.location.reload(); 
    } 
}, 1000); 
</script> 
 

image.png

On Discord, go to your server and open the channel where you want your vote RSS feed to appear. Click Edit Channel (the gear icon), then Integrations, and choose Create Webhook. Copy the webhook URL and paste it into the code.

Posted Using INLEO