自分のQiita記事をインクリメンタル検索するAlfred Workflowを作ってみた


消防士時代からQiita投稿を続け、累計投稿数は140記事を超えました。
投稿記事が増えると「あれ?これ前Qiitaに書いた気がするけどなんだっけな..?」となっても、自分の過去投稿を探すのが一苦労です。
そんな手間を解消するため、Qiita APIとAlfredを使って自分のQiita記事をインクリメント検索するAflred Workflowを作ってみました。

結構便利なので、Qiitaヘビーユーザーの方々に使ってもらえると嬉しいです。

alfred-my-qiita

こちらのGIF画像のように、自分の投稿記事をインクリメンタル検索できます。
初回はAPIリクエストが走るので少し時間がかかりますが、その後はキャッシュが効くのである程度高速に動作します。

インストール・環境変数の設定

以下コマンドでnpmからインストールできます(後述するAlfyで実現しています)。
npmインストールするだけでAlfredがWorkflowを認識し、すぐに使えるようになります。

$ npm i -g alfred-my-qiita

また、GitHubのリリース から直接alfred-my-qiita.workflowファイルをダウンロードし、Alfredに取り込むことも可能です。

インストールが完了したら、AlfredのWorkflow設定画面から alfred-my-qiita を選択して、環境変数を設定してください。

設定する環境変数は以下2つです。

名前
API_TOKEN Qiita APIのAPIトークン。こちらの案内にしたがって取得・設定してください。
USER_NAME Qiitaのユーザー名(@を除く)を設定してください。

これで準備は完了です。
Alfredを開き.qiitaと打ち、あとは半角スペースを空けて検索したい文字列を入力すればOKです!!

実装

今回も以前こちらの記事で紹介したAlfy というNode.jsベースでAlfred Workflowを作れるフレームワークを使っています。

Alfyを使う利点は以下の通りです。

  • Node.jsでWorkflowを作れる
  • npmモジュールが使える
  • npmに公開し、手軽にインストールしてもらえるようになる

何より、Bashスクリプト書かなくてよいというのが最高便利です。

今回のworkflowは以下2つのファイルで構成されています。

1つはQiita APIから投稿記事を取得する処理です。
最初に自分の投稿総数を取得して、その後Promise.allとmapを使い全投稿データを取得しています。

lib/fetchAllPosts.js
import alfy from "alfy"

export const fetchAllPosts = async (username, token) => {
  const options = {
    headers: {
      Authorization: `Bearer ${token}`,
    },
    json: true,
    maxAge: 60000
  };

  const user = await alfy.fetch(
    `https://qiita.com/api/v2/users/${username}`,
    options
  );

  const maxPage = Math.ceil(user.items_count / 100);

  let posts = [];
  await Promise.all(
    [...Array(maxPage)].map(async (_, i) => {
      const res = await alfy.fetch(
        `https://qiita.com/api/v2/authenticated_user/items?page=${
          i + 1
        }&per_page=100`,
        options
      );
      posts = [...posts, ...res];
    })
  );

  return posts
};

そして、index.jsがメインの処理です。AlfyのinputMatches APIを使い投稿記事をフィルタリングして出力しています。

index.js
import alfy from "alfy";
import { fetchAllPosts } from "./lib/fetchAllPosts";

const token = process.env.apiToken;
const username = process.env.username;

const createResponse = (title, subtitle, url) => {
  return {
    title,
    subtitle,
    arg: url,
    icon: {
      type: "png",
      path: "icon.png",
    }
  };
}

(async () => {
  const posts = await fetchAllPosts(username, token);

  if(alfy.input.length > 1) {
    const items = alfy.inputMatches(posts, "title").map(
        (p) => createResponse(p.title, p.body, p.url));

    if (!items.length) {
      alfy.output(
          [createResponse("The requested post was not found. ⚠️", "", "")]);
      return;
    }
    alfy.output(items);
  } else {
    alfy.output([createResponse("Loading...", "", "")])
  }
})()

終わりに

以上「自分のQiita記事をインクリメンタル検索するAlfred Workflowを作ってみた」でした。
完全自分用のツールとして作ってみたものなのですが、Qiita投稿数が多い方には何かと便利だと思います。使ってもらえると嬉しいです。
(もし動かない場合は、TwitterGitHub Issue, この記事のコメントで教えてください