‼️ Steemit API - DIY ⚒ Liste der zuletzt erhaltenen Upvotes! ⬆️

Die Verwendung der Steemit API geht in die 2. Runde

Dieses Mal zeige ich euch, wie ihr eine Liste der zuletzt erhaltenen Upvotes angezeigt bekommt. Dazu nutzen wir die Steemit API auf die wir mit JavaScript zugreifen. Viel Spaß!

work-731198_1920_2.png

1. Das Grundgerüst

Bevor wir in die vollen gehen, brauchen wir erstmal ein Grundbaustein, auf dem wir aufsetzen können. Dazu legen wir eine HTML-Datei an und fügen die bekannten Basis-Tags <html>, <head> und <body> ein. Zusätzlich binden wir die API von Steemit in das <head>-Tag ein. Weiterhin brauchen wir Platz für unseren Code. Deswegen öffnen und schließen wir im <head>-Tag ein <script>-Bereich. Im body-Bereich bauen wir ein <div>ein, dass die ID "output" trägt. Hier wird später unsere Ausgabe erfolgen.

<html>

  <head>
    <script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>

    <script language="JavaScript">

      // Unser Code

    </script>
  </head>

  <body>

    <div style="white-space: pre;" id="output"></div>

  </body>

</html>

2. Erster Aufruf der API-Funktion

Alle Funktionen der JavaScript-Steemit-API findet ihr hier. Auf dieser Seite findet ihr auch die Funktion steem.api.getAccountHistory(account, from, limit, function(err, result) {});, die wir für unser Vorhaben benötigen.

Wir sehen an dieser Stelle schon, dass die Übergabeparameter account, from und limit erwartet werden. Doch was steckt hinter diesen Werten. Hier eine tabellarische Übersicht:

VariableTypVerwendungszweck
account   stringBenutzer, dessen Historie abgerufen werden soll.
fromuint32_tDer früheste Zeitpunkt, von dem die Daten abgeholt werden sollen als Zahl.
limituint32_tDie Anzahl der Einträge, die maximal abgerufen werden sollen (API interne Grenze bei 10.000)

Also fügen wir in unseren Codebereich folgendes Script inkl. Variablen ein:

var account = "cuby";
var from = Date.parse('2015-01-01T00:00:00');
var limit = 10; //max. 10.000

steem.api.getAccountHistory(account, from, limit, function(err, result) {
  console.log(err, result);
});

 
Date.parse('2015-01-01T00:00:00') ist eine Funktion, die uns die Zeit, seit dem übergebenen Datum, als uint32_t zurückgibt. Jetzt können wir die HTML-Datei im Browser öffnen und uns die ersten Ergebnisse in der Konsole anschauen (hier eine Erklärung, wie man zur Konsole des jeweiligen Browsers kommt). Die Ausgabe sollte in etwa so aussehen:

vote-note-img-1.png


3. Aus der Konsole in den Browser

Da die Ausgabe in der Konsole nicht allzu übersichtlich ist, wollen wir nun die Daten auf der Browseroberfläche (im body-Tag) anzeigen lassen. Was müssen wir dazu tun? Zu allererst brauchen wir ein paar Prüfungen, um sicher zu gehen, dass der API-Call sauber verlaufen ist und wir auch Daten haben, mit den wir arbeiten können. Wir ersetzen console.log(err, result); durch folgenden Code:

if(!err && result != undefined && result.length > 0){

     document.getElementById("output").textContent = JSON.stringify(result, null, "\t");

}

 
Da wir jetzt sicher sein können, dass bei der weiteren Arbeit, Daten zu Verfügung stehen, können wir diese auf der Oberfläche bringen. Dazu holen wir uns das Ausgabe-Element mit der ID "output" und fügen seinem Textinhalt das Ergebnis des API-Calls hinzu. Um das Ergebnis lesbarer zu machen, jagen wir es vorher durch die Methode JSON.stringify(result, null, "\t"), die für uns die Zeichenkette formatiert. Bei erneutem Aufruf der HTML-Datei sollte euer Browser etwa so aussehen:

vote-note-img-2.png


4. Analyse der Ausgabe

Das erste was auffällt ist, dass jeder Eintrag mit einer ID behaftet ist, an der ein Objekt mit den eigentlich interessanten Daten hängt. Im Objekt finden wir zum einen den timestamp, der uns mitteilt, wann der Eintrag entstanden ist und zum anderen das Objekt op.

Das erste Element von op signalisiert uns, um welche Art Eintrag es sich handelt. Wir wollen nur jene Einträge berücksichtigen, die "votes" beinhalten. Weiterhin ist im op-Objekt der Author des gevoteten Inhalts, der "Permlink" zum Inhalt und der Voter selbst angegeben. Abschließend wird die Gewichtung des Votes unter weightfestgehalten.

Was heißt das jetzt für uns? Wir können über die gewonnen Erkenntnisse eine Filterung auf die erzielten Ergebnisse anwenden, um dem gesetzten Ziel einen Schritt näher zu kommen: Die Auflistung der erhaltenen Upvotes.


5. Filterung der Daten

Um die Filterung der Daten umsetzen zu können, müssen wir zuerst eine Schleife einbauen, die über die Ergebnisse geht. Dann können wir je Ergebnis die enthaltenen Daten prüfen und aussortieren (Nur "vote" und nicht den Benutzer aus der Variable account als Voter). Wo wir gerade bei der Sortierung sind: die Ergebnisse werden aus dem API-Call von alt nach neu zurückgegeben. Um das zu ändern, laufen wir in der Schleife vom letzten Element bis zum Ersten:

for (var i = result.length - 1; i >= 0; i--) {

  if (result[i][1].op[0] == "vote" && result[i][1].op[1].voter != account) {

    var type = (result[i][1].op[1].permlink.includes("re-")) ? "Kommentar" : "Post";

    var datum = new Date(result[i][1].timestamp).toLocaleDateString("de-DE", { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });

    document.getElementById("output").textContent += JSON.stringify(result[i], null, "\t");

  }

}

 
Die Ausgabe des ausgeführten Scripts hat sich nun nur minimal geändert. Statt der ältesten Einträge bekommen wir nun die neusten zuerst angezeigt. Weiterhin sind alle Einträge nicht ausgegeben worden, die keine Upvotes für den angegebenen Account sind. Hinweis: Das in der Codezeile document.getElementById("output").textContent += JSON.stringify(result[i], null, "\t"); vorhandene += sorgt dafür, dass nicht nur das letzte verarbeitete Ergebnis auf der Seite angezeigt wird, sondern dass es zu den bereits vorhandenen hinzugefügt wird. Dies wird auch konkatenieren genannt.

In der Variable typespeichern wir, ob es sich um einen Upvote für einen Kommentar oder einen Post handelt. Das können wir daran erkenne, dass im permlinkdes Votes ein vorangestelltes "re-" steht, das auf die Antwort eines Posts via Kommentar hindeutet.

Damit der Zeitpunkt, an dem der Vote getätigt wurde nicht in der unschön formatierten Art und Weise auf unserer Oberfläche angezeigt wird, speichern wir das Ergebnis der formatierten Ausgabe in der Variable datum.


6. Bootstrap anbinden

Das bis hierhin erreichte Ergebnis ist schon ganz nett, aber die Lesbarkeit der JSON-Strings ist im Vergleich zu gestyltem HTML nur ausreichend. Deswegen ist der nächste Schritt, den wir machen werden, die Anbindung des Frameworks Bootstrap (Hier geht es zur Webseite).

http://getbootstrap.com/assets/img/bootstrap-stack.png

Für die Anbindung benötigen wir zum einen die CSS-Datei und die JS-Dateien des Frameworks. Alles fügen wir dem head-Tag hinzu:

<html>

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

[...]

 
An dieser Stelle sollte sich auf unserer Oberfläche nur die Schriftart geändert haben. Alles andere bleibt vorerst so wie es ist.


7. Die Daten aufbereiten

Damit unsere Einträge nicht einfach als Text auf die Webseite geworfen werden, müssen wir die für uns relevanten Daten raussuchen und in einem HTML-Element verpacken, das wir danach der Oberfläche hinzufügen.

var vote = {
  voter: result[i][1].op[1].voter,
  timestamp: datum,
  weight: result[i][1].op[1].weight / 100,
  typ: type
}

 
Das Objekt vote ermöglicht uns einen super einfachen Zugriff auf die enthaltenen Daten. Das HTML-Element legen wir als einfach String-Variable an und konkatenieren die Werte aus vote mit hinein. Anschließend fügen wir das HTML-Element dem div-Tag mit der ID "output" hinzu:

var htmlElement = '

@' + vote.voter + ' hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' + '' + '

' + vote.timestamp + ''; $("#output").append(htmlElement);

 
Nach diesen Änderungen sieht unsere Webseite schon wesentlich lesbarer aus. Auch wenn sie noch sehr spartanisch wirkt. Aber darum kümmern wir uns im nächsten Schritt.

vote-note-img-3.png


8. Es darf ruhig hübsch aussehen

Zwar haben wir bereits in Schritt 6 das Framework Bootstrap angebunden, aber wir verwenden noch keine Klassen, um auf die bereitgestellten Elemente zugreifen zu können. Ich habe mich für die Komponente "Alert" entschieden, um unsere Einträgen auf der Oberfläche zu visualisieren.

vote-note-img-4.png

Was müssen wir dafür machen, damit unserer Votes so aussehen, wie die Alert-Komponente von Bootstrap? Zuerst kopieren wir uns den auf der Webseite von Bootstrap und fügen ihn unserem Code hinzu. Anschließend schieben wir unsere Daten in die HTML-Struktur und fügen das alles je Eintrag dem div-Tag mit der ID "output" hinzu. Fertig!

var htmlElement = '<div class="alert alert-info role="alert">' +
                    '@' + vote.voter + '  hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' +
                    '
'
+ '

' + vote.timestamp + '' + ''; $("#output").append(htmlElement);

 
Ein erneuter Aufruf der Webseite und: Wow! Das sieht doch schon gar nicht mal so schlecht aus. Jetzt wollen wir noch die Anzahl der Vote-Einträge bestimmen können.

9. Zeige die letzen 25 Votes

Zu allererst setzen wir die Variable limit auf 1000 und fügen zwei weitere Variablen hinzu. Die Variable MAX speichert die Anzahl der maximal anzuzeigenden Vote-Einträge (in unserem Fall 25). counter hilft uns dabei zu zählen, wie viele Einträge wir bereits zusammen haben.

var limit = 1000;  //max. 10.000

var MAX = 25;
var counter = 0;

 
Kommen wir dazu diese beiden neuen Variablen auch zu verwenden. Wir müssen unseren Quellcode an ein paar Stellen anpassen:

$("#output").append(htmlElement);

counter++;

if(counter >= MAX){
  break;
}

 
Nachdem wir einen Eintrag der Oberfläche hinzugefügt haben zählen wir counterum einen hoch. Danach prüfen wir, ob counter bereits >= MAX ist. Wenn dem so ist, verlassen wir die for-Schleife durch einen break.

9. Das Ergebnis

vote-note-img-5.png

Was lässt sich zu dem Ergebnis sagen? Wir haben eine Oberfläche, die beim Aktualisieren die neusten Upvotes für den im Code hinterlegten Account anzeigt. Die Upvotes werden von neu nach alt sortiert und es wird zwischen Kommentar und Post unterschieden. So weit so gut.


10. Fazit und Verbesserungen

Es gibt viele Stellen an denen sich der Code noch optimieren lässt.

Das erste was mir einfällt wäre die Oberfläche. Auf dieser könnte, wenn es um einen Upvote für einen Post geht, ebenfalls der Titel des Posts angezeigt werden. Das habe ich versucht umzusetzen. Allerdings war ich mit der Art der Umsetzung sehr unzufrieden und habe mich deswegen dagegen entschieden, diese Lösung mit in diesen Beitrag einzubringen.

Weiterhin hat man keine Möglichkeit von der Oberfläche den Accountnamen, das Limit oder andere Stellschrauben zu verändern. Eine einfache Eingabemaske würde an diese Stelle vermutlich schon Abhilfe schaffen. Vielleicht ein Thema für meinen nächsten Beitrag.

Außerdem muss man die Seite manuell neu laden, um die Daten zu aktualisieren. Ein Listener darauf, ob es etwas neues gibt, ist hier noch nicht vorhanden. Auch eine Sache die sich im Nachhinein noch umsetzen lässt.

girl-1064659_1920.jpg

Zum Schluss aber der größte Kritikpunkt: Die Ladezeit. Prinzipiell funktioniert der Code so wie er dort steht, ABER wenn ein Account eingetragen wird, der im Bereich der limit Variable weniger als 25 Upvotes erhalten hat, dann werden auch keine 25 Upvotes angezeigt. Klingt erstmal logisch. Klar könnte man dem entgegen wirken und zuerst den Account aus der API ziehen, das Eintrittsdatum feststellen, das in die Variable from laden und die limit Variable auf das Maximum von 10.000 setzen, aber ist das wirklich die brauchbarste Lösung? Ich denke nicht ;)


Danke fürs Lesen

CuBy

PS: Fehler bei der Rechtschreibung und Grammatik sind stilistische Mittel und vom Autor bewusst platziert worden. :-D

Das Bild konnte nicht geladen werden :( [Hier](https://i.imgur.com/GiapkPg.gif) geht es zur Quelle!


Der gesamte Code

<html>

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>

    <script language="JavaScript">

      var account = "cuby";
      var from = Date.parse('2015-01-01T00:00:00');
      var limit = 200; //max. 10.000

      var MAX = 25;
      var counter = 0;

      steem.api.getAccountHistory(account, from, limit, function(err, result) {

        if(!err && result != undefined && result.length > 0){

          for (var i = result.length - 1; i >= 0; i--) {

            if (result[i][1].op[0] == "vote" && result[i][1].op[1].voter != account) {

              var type = (result[i][1].op[1].permlink.includes("re-")) ? "Kommentar" : "Post";

              var datum = new Date(result[i][1].timestamp).toLocaleDateString("de-DE", { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });

              var vote = {
                voter: result[i][1].op[1].voter,
                timestamp: datum,
                weight: result[i][1].op[1].weight / 100,
                typ: type
              }

              var htmlElement = '<div class="alert alert-info role="alert">' +
                                  '@' + vote.voter + '  hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' +
                                  '
'
+ '

' + vote.timestamp + '' + ''; $("#output").append(htmlElement); counter++; if(counter >= MAX){ break; } } } } }); </script> </head> <body> <div style="white-space: pre;" id="output"></div> </body> </html>

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now