Javascriptでxbarプラグインを書く
週末のプロジェクトとして、xbar用の簡単なプラグインを書きたかったのですが、最近それを見つけたアプリケーションです。 xbar自体はプログラミング言語「Go」で記述されており、基盤となるサービスとして「Wails」を使用して、開発者がmacOSのメニューバーのカスタムメニューエントリを記述できるようにします(はい、現在macOSのみに制限されています)。
xbarの良いところは、Javascriptも含むさまざまなプログラミング言語をサポートしていることです。したがって、私自身Web開発者として、プライバシーに配慮した分析サービスであるPlausible.ioに接続するカスタムプラグインを簡単に作成できることを知りたかったのです。目標は、現在このWebアプリを使用している現在のすべてのユーザーをレンダリングすることです。執筆時点では、プルリクエストはまだ審査中です。
基本的なxbarセットアップ
xbarは、Macにダウンロードしてインストールするだけです。初めて起動すると、ダウンロード可能で公開されているすべてのプラグインを含む画面を使用して、必要なプラグインを取得できます。
インストールプロセスでは、プラグインのソースコード(プラグインごとに1つのファイル)を特別なフォルダにコピーするだけで、xbarはそこから現在インストールされているすべてのプラグインを読み取ります。独自のプラグインの作成を開始するには、ディレクトリにファイルを作成してハッキングを開始するだけです。きちんとした!
xbarファイル名の規則
ファイルの名前は3つの部分で構成され、すべてドットで区切られています。
- あなたのユニークなプラグイン名
- CRONジョブと同様に、コードが実行される時間間隔
- 共通ファイルの接尾辞
plausible.1m.js
JSでのxbarプラグインのコーディング
これで、コーディングを開始する準備が整いました。まず、ノードインスタンスを見つける必要がある場所をxbarに指示するために必要なshebangディレクティブを含めます。
#!/usr/bin/env /usr/local/bin/node
次の部分は、いくつかのメタデータを追加することです。もちろん、ローカル開発の場合、これは省略できますが、Plausibleプラグインに使用しているものは次のとおりです。
// 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>
プラグインを実行するために必要なのはこれだけです。これで、ユーザーのNode.js-instanceによって実行される純粋なJavascriptでコーディングできるキャンバスができました。これは、「https」などのすべてのコアノードパッケージにアクセスできることを意味します。私のユースケースでは、ユーザーの追跡にはPlausible.io-APIからのフェッチが必要なだけなので、これが必要なすべてです。
次のコードは、私が話す価値があると思う最も関連性の高い部分を示しています。完全なコードは、このページの最後にある補遺のリンクにある関連する公開リポジトリで入手できます。
// 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();
xbarのコーディングは簡単です
プロセス全体が完了するまでに数時間かかりました。ほとんどの場合、xbarからAPIをチェックし、スタイリングのさまざまな構成を試してみました。全体として、このような単純なプラグインを作成することは、本当に楽しいことではありません。時間に余裕があるなら、ぜひ試してみてください!
xbarについて最もよく話しているのは、この柔軟で迅速な開発が可能にするスクリプトの機会だと思います。クラウド設定または分析サービス用のカスタムトラッカーを作成して、macOSのメニューバーにメトリックがすべて一目で表示されるようにすることができます。それはいいですね!