GitHubにブックマークをコミットして管理できるはてなブックマークみたいなブックマークシステムを書きました。 詳しいモチベーションなどについては次のスライドで発表しています。

はてなブックマークのAPIが2019/5/31ぐらいエラーを返すようになって困ったので自分用のブックマークの仕組みを突貫で作りました。 (はてなブックマーク APIは2019/6/3には直ってました。) 逆にじっくり開発していくアプリについては次のスライドで話しています。

azu/asocial-bookmark: Personal Bookmark System.

socialじゃないのでasocial bookmarkです。

特に運用の費用的なコストはゼロにしたかったのと、自分用なのでややこしいワークフローになっています。 簡単にまとめると、次のような動きでブックマークの登録と検索だけを行います。

  • 0. GitHubにブックマークを置くリポジトリを作る
  • 1. GitHubにpostem経由でブックマークデータをコミットする
  • 2. GitHubとNetlifyを連携してブックマークデータをJSONとして配信する(privateなブックマークは特に扱ってない)
  • 3. JSONデータを はてなブックマーク検索PWAを使って検索する

具体的な動かし方はソースを読んだりazu/asocial-bookmarkのREADMEに書いています。 GitHubをファイルシステムのように読み書きをすることになるので、fsモジュールのようにGitHubのRead/Write/Deleteを扱うライブラリも書きました。

自分のブックマークシステム

とりあえず今自分のブックマークシステムは次のような感じで作ってあります。 (NetlifyのところはGitHub Action + gh-pagesなどCI/CDがあれば何でもいいと思います。)

1. GitHubにリポジトリを作る

  • Example: https://github.com/{your}/mybookmarks

2. リポジトリに"はてなブックマーク"のブックマークを"asocial-bookmark"形式にしてインポートする

- 手元にリポジトリをcloneしてきて、そのディレクトリ内で次のコマンドを実行
- `$ migrate-hatenabookmark-to-asocial-bookmark --hatena <user-name>`
- 大量の`/:year/:month/index.json`が作成されるのでコミットしてpush
- 詳しくは[migrate-hatenabookmark-to-asocial-bookmark.ts](https://github.com/azu/asocial-bookmark/blob/master/src/cli/migrate-hatenabookmark-to-asocial-bookmark.ts)を見て下さい。

3. Setup CI/CD - ここではNetlifyを使ってます

  • Netlifyのbuild.commandasocial-bookmark-create-index を実行するとすべてのブックマークをまとめたindex.jsonを作ってデプロイできます。
    • あとはこのデータにCORSヘッダをつけておきます https://<your-bookmark>/index.json
    • APIとしては次のようなものができあがります
    • All bookmarks: https://<your-bookmark>/index.json
    • All tags: https://<your-bookmark>/tags.json
    • Block bookmarks by month: https://<your-bookmark>/:year/:month/index.json

具体的には次のような.netlify.tomlの設定をブックマークリポジトリにおいています。

.netlify.toml:

# example netlify.toml
[build]
  command = "asocial-bookmark-create-index"
  functions = "functions"
  publish = "."
[[headers]]
  for = "/index.json"
  [headers.values]
    Access-Control-Allow-Origin = "*"

この状態でブックマークリポジトリが更新されれば、 https://<your-bookmark>/index.json でブックマークデータを取得できます。 (publicです)

4. ブックマークをpostem経由で登録する

- See <https://github.com/azu/postem/blob/master/src/services/asocial-bookmark/README.md>

postemについては次の記事で紹介しています。

postemsrc/services/asocial-bookmark/consumer.jsonにファイルを作成し、 自分のasocial-bookmarkのリポジトリについての情報を書きます。

GitHubのリポジトリがyour/watashi-no-bookmark"なら次のような形になります。

src/services/asocial-bookmark/consumer.json:

{
  "github": {
    "owner": "your",
    "repo": "watashi-no-bookmark",
    "ref": "heads/master",
    "token": "Github TOKEN(repo)権限"
  }
}

また、postemではsrc/service.jsでクロスポストするサービスを定義できます。

次のようにすれば

  • Twitter
  • asocial-bookmark(デフォルトチェック)
  • はてなブックマーク(デフォルトチェック)

の両方に投稿できます。

const path = require("path");
module.exports = [
    {
        enabled: true,
        name: "twitter",
        indexPath: path.join(__dirname, "services/twitter/index.js")
    },
    {
        enabled: true,
        isDefaultChecked: true,
        name: "AsocialBookmark",
        indexPath: path.join(__dirname, "services/asocial-bookmark/index.js")
    },
    {
        enabled: true,
        isDefaultChecked: true,
        name: "hatebu",
        indexPath: path.join(__dirname, "services/hatebu/index.js")
    },
];

postem

postemJSer.infoの更新クライアントでもあるので、 はてなブックマークより登録できる項目が多いです。 どこから見つけたのかのviaURL、関連するURLやタイトルなどを登録できたり、文字数制限がないです。 そのため、今はasocial-bookmarkとはてなブックマークにクロスポストしています。

5. ブックマークをはてなブックマーク検索PWAで検索する

はてなブックマーク検索PWAについては次の記事で紹介しています。

はてなブックマークを検索するウェブアプリですが、asocial-bookmarkのデータ構造はかなり似ているのでasocial-bookmarkも検索できるように改造しました。

  • "hatena user name" に対して、自分のブックマークデータのURL( https://<your-bookmark>/index.json )を入れると動きます。

後は検索するだけです。

おわりに

azu/asocial-bookmark: Personal Bookmark System.はかなり突貫で自分の需要で作りました。 ホントはServerlessな感じにしたりとかしても良かった気がしますが、ブックマークデータを単なる静的なデータとして扱ったほうが簡単そうと思ってこんな仕組みになりました。