Schreiben eines xbar-Plugins für Plausible.io

Wie ich ein JS-Plugin für die xbar-App geschrieben habe, um die aktuelle Besucherzahl zu sehen

Schreiben eines xbar-Plugins in Javascript

Als Wochenend-Projekt wollte ich ein einfaches Plugin für xbar schreiben, eine Anwendung über die ich kürzlich gestolpert bin. xbar selbst ist in der Programmiersprache „Go“ geschrieben und verwendet „Wails“ als zugrunde liegenden Dienst, damit Entwickler benutzerdefinierte Menüeinträge für die Menüleiste in macOS schreiben können (ja, es ist derzeit nur auf macOS beschränkt).

Das Schöne an xbar ist, dass es eine Vielzahl von Programmiersprachen unterstützt, zu denen auch Javascript gehört. Da ich selbst Webentwickler bin, wollte ich daher sehen, wie einfach es ist, ein benutzerdefiniertes Plugin zu schreiben, das sich mit Plausible.io, meinem datenschutzfreundlichen Analysedienst, verbindet. Das Ziel ist es, alle aktuellen Benutzer zu rendern, die sich derzeit in dieser Web-App befinden. Zum Zeitpunkt des Schreibens befindet sich der Pull-Request noch in der Überprüfung.

Image 52d29c4414ce

Image 67e4f6e5107d

Grundlegendes xbar-Setup

xbar kann einfach heruntergeladen und auf Ihrem Mac installiert werden. Wenn Sie es zum ersten Mal starten, kann ein Bildschirm mit allen herunterladbaren und veröffentlichten Plugins verwendet werden, um das gewünschte Plugin zu erhalten.

Der Installationsprozess kopiert einfach den Quellcode des Plugins (eine einzelne Datei pro Plugin) in einen speziellen Ordner, aus dem xbar alle aktuell installierten Plugins liest. Um mit dem Schreiben Ihres eigenen Plugins zu beginnen, erstellen Sie einfach eine Datei im Verzeichnis und beginnen mit dem Hacken. Sauber!

xbar-Dateinamenkonvention

Der Dateiname besteht aus drei Teilen, die alle durch einen Punkt getrennt sind.

  • dein eindeutiger Plugin-Name
  • das Zeitintervall, in dem Ihr Code ausgeführt wird, ähnlich einem CRON-Job
  • das gemeinsame Datei-Suffix
plausible.1m.js

Codieren eines xbar-Plugins in JS

Jetzt können Sie mit dem Codieren beginnen! Fügen Sie zuerst die erforderliche Shebang-Direktive ein, um xbar mitzuteilen, wo die Knoteninstanz zu finden ist.

#!/usr/bin/env /usr/local/bin/node

Im nächsten Teil werden dann einige Metadaten hinzugefügt. Für die lokale Entwicklung kann dies natürlich weggelassen werden, aber hier ist, was ich für das Plausible-Plugin verwende.

// Metadata allows your plugin to show up in the app, and website.
//
//  <xbar.title>Plausible Tracker</xbar.title>
//  <xbar.version>v1.0</xbar.version>
//  <xbar.author>Tom Schönmann</xbar.author>
//  <xbar.author.github>flaming-codes</xbar.author.github>
//  <xbar.desc>See who's on your site at-a-glance.</xbar.desc>
//  <xbar.dependencies>node</xbar.dependencies>
//  <xbar.abouturl>https://flaming.codes</xbar.abouturl>
//  <xbar.image>https://raw.githubusercontent.com/flaming-codes/xbar-plausible-stats/main/plausible-icon-36-36-144.png</xbar.image>

Und das ist alles, was für die Ausführung Ihres Plugins erforderlich ist. Jetzt haben Sie eine Leinwand, auf der Sie in reinem Javascript codieren können, das von der Node.js-Instanz des Benutzers ausgeführt wird. Damit haben wir Zugriff auf alle Kern-Node-Pakete, wie zum Beispiel „https“. Für meinen Anwendungsfall ist das alles, was ich brauche, da das Tracking von Benutzern lediglich einen Abruf aus der Plausible.io-API erfordert.

Die folgenden Codeteile zeigen den relevantesten Teil, über den ich denke, dass es sich lohnt, darüber zu sprechen. Der vollständige Code ist im zugehörigen öffentlichen Repository verfügbar, Link im Anhang am Ende dieser Seite.

// Here you see how to make network
// requests with 'https'-only.
// This is a native node-lib that
// works w/ data streams, as you'll see.

const https = require("https");

// Those have to edited by the
// user directly in the file,
// after it has been downloaded
// (aka installed)!
const SITE_ID = "";
const API_KEY = "";

// ... other code ...

async function fetcher() {
  return new Promise((resolve, reject) => {
    let body = "";
    const request = {
      host: "plausible.io",
      path: `/api/v1/stats/realtime/visitors?site_id=${SITE_ID}`,
      method: "GET",
      headers: {
        Authorization: `Bearer ${API_KEY}`,
      },
    };

    try {
      const req = https.get(request, (res) => {
        res.on("data", (data) => {
          body += data;
        });
        res.on("end", () => {
          resolve(JSON.parse(body));
        });
      });

      req.on("error", (error) => {
        console.error(error);
      });

      req.end();
    } catch (error) {
      reject(error);
    }
  });
}
// I've implemented an array of tuples
// that hold an icon + count threshold
// when to active it.

// The first entry doesn't render a 
// string (which can be direclty used),
// but rather a mapping that results in
// the following code:
//
// `image="..." font=Menlo color=white`
//
// This is a special syntax that tells
// xbar to render a base64 image w/
// a custom font and color.
//
// 'plausibleIconWhite' is just the string
// for the base64-image.
const stepIcons = [
  [0, `${plausibleIconWhite} Menlo white`, "image font color"],
  [5, "💫"],
  [10, "⭐️"],
  [50, "🌟"],
  [100, "⚡️"],
  [500, "💥"],
];
// Actually rendering stuff in xbar
// is super simple - just output it
// with console.log(...).
//
// As you'll see, '---' define 
// separator. The first log-call
// gets rendered as acutal menu item.

const linksMenu = [
  "---",
  `🔮 Open dashboard | href=https://plausible.io/${SITE_ID}`,
  `🔥 Made by flaming.codes | href=https://flaming.codes`,
];

function renderError(props) {
  const { error } = props;
  const output = [
    "❔",
    "---",
    "No data accessible",
    "Please check your user data",
    ...linksMenu,
  ];

  console.log(output.join("\n"));
}

// Finally, I defined a single function
// where everything starts. This function
// just gets called to kick everyting off.
// Plain JS, it's that simple.

async function render() {
  const { data, error } = await fetcher()
    .then((data) => ({ data }))
    .catch((error) => ({ error }));

  if (data >= 0) return renderData({ data });
  if (error) return renderError({ error });
}

render();

Die Codierung für xbar ist einfach

Der gesamte Prozess hat einige Stunden gedauert, hauptsächlich das Überprüfen der API von xbar sowie das Herumspielen mit verschiedenen Konfigurationen für das Styling. Alles in allem ist das Schreiben eines einfachen Plugins wie dieses wirklich nicht viel Aufwand, der wirklich Spaß macht. Wenn Sie ein paar freie Stunden haben, sollten Sie es auch versuchen!

Ich denke, was am meisten für xbar spricht, ist die Möglichkeit zur Skripterstellung, die diese flexible und schnelle Entwicklung ermöglicht. Sie können benutzerdefinierte Tracker für Ihre Cloud-Setups oder Analysedienste schreiben, sodass die Metriken in Ihrer Menüleiste in macOS auf einen Blick sichtbar sind. Ich mag das!