複数のMacでフォントを自動同期するCLIツールを作った話
動機
MacBook AirとMac miniの2台体制で作業していると、地味に困ることがあります。それは、フォントの同期。 Adobe Fontsのように自動で同期してくれるものは問題ないのですが、自分で購入したりダウンロードしたフォントは、それぞれのマシンで手動インストールが必要なんですよね。フォント管理ソフトもありますが、多くは有料。クラウドアプリでフォントファイル自体を同期しても、結局インストールは手動で面倒です。 しかも僕にはフォント収集癖があって、フォントバンドルを衝動買いしちゃったりするタイプときました。なので、気づいたら「あれ、このフォント家のMacには入れたけど、外のMacBook Airには入れてなかった…」みたいなことがしょっちゅうおきてしまって作業が嫌になるみたいなことを繰り返していました。 ttfやotfファイルをひとつひとつダブルクリックしてインストールするのも、どれをインストール済みか覚えてないからどこまで何をやったかの記憶力もない。終わってます。 有料にするほど何かの制作を仕事として請け負っているわけではないし、ということで自分がミニマムに欲しい機能だけにフォーカスしてツールを作ってみることにしました。
実際に開発していく
今回はCursorを利用して、基本的にはすべてのコードを開発してもらいました。
要件
要件はシンプルにします。
- クラウド共有(Google Drive, Dropboxなど)のフォルダにフォントを入れる
- コマンドで各Macに同期される
- 新規・更新・削除を自動で判別
これだけできれば僕の悩みは解決しそうです。ゆくゆくはもっと細かいブラッシュアップもしても良さそうですが、一旦今の悩みを解決することを優先しましょう。
実装
1. 基本設計
macOSのフォント管理の仕組みは以下の通りです。
- ユーザーフォントは
~/Library/Fonts/に保存 - .otfや.ttfのファイルをこのディレクトリにコピーすれば認識される
- ファイルのハッシュ値で変更検出できる
ということで、以下のような構成にしました:
# 設定ファイル (~/.fontsync/config.json){ "sync_folder": "~/Dropbox/shared-fonts/", "installed_fonts": { "MyFont.otf": { "hash": "sha256_hash_value", "installed_at": "2024-01-01T00:00:00" } }}2. CLIの実装
CLIフレームワークにはTyperを採用。直感的でいい感じのCLIが簡単に作れるみたいです。
import typerfrom pathlib import Pathfrom rich.console import Consolefrom rich.progress import track
app = typer.Typer()console = Console()
@app.command()def sync(): """フォントを同期する""" config = load_config() sync_folder = Path(config["sync_folder"]).expanduser()
# フォントファイルをスキャン font_files = list(sync_folder.glob("*.otf")) + list(sync_folder.glob("*.ttf"))
# 差分を検出 to_install = [] for font_file in track(font_files, description="差分を確認中..."): if needs_update(font_file, config): to_install.append(font_file)
# インストール for font_file in track(to_install, description="インストール中..."): install_font(font_file)
console.print(f"✓ {len(to_install)}個のフォントを同期しました", style="green")3. 差分同期の仕組み
import hashlib
def calculate_hash(file_path: Path) -> str: """ファイルのSHA256ハッシュを計算""" hash_sha256 = hashlib.sha256() with open(file_path, "rb") as f: # メモリ効率のため、チャンクごとに読み込み for chunk in iter(lambda: f.read(4096), b""): hash_sha256.update(chunk) return hash_sha256.hexdigest()
def needs_update(font_file: Path, config: dict) -> bool: """フォントの更新が必要か判定""" font_name = font_file.name current_hash = calculate_hash(font_file)
# 新規フォント if font_name not in config["installed_fonts"]: return True
# ハッシュが異なる = 更新されている return config["installed_fonts"][font_name]["hash"] != current_hash4. 美しい表示
Richライブラリを使って、見やすい出力にしてもらいました。CLIツールのわかりやすい表示っていいですね。
from rich.table import Table
def list_fonts(): """フォント一覧を表示""" table = Table(title="フォント一覧") table.add_column("状態", style="cyan", width=6) table.add_column("フォント名", style="magenta") table.add_column("サイズ", justify="right") table.add_column("更新日時")
for font_file in font_files: status = "✓" if is_installed(font_file) else "✗" size = humanize.naturalsize(font_file.stat().st_size) modified = font_file.stat().st_mtime
table.add_row(status, font_file.name, size, format_datetime(modified))
console.print(table)という形で開発が完了します。 驚くべきことにここまで1時間もかからずに開発が終わりました。
実際に使ってみる
セットアップ
まず、共有フォルダを設定します。
$ font-sync init
font-syncの初期設定を開始します。
同期元フォルダのパスを入力してください。例: ~/Dropbox/shared-fonts/同期元フォルダのパス [~/Dropbox/shared-fonts/]: ~/Dropbox/MyFonts/
✓ 設定を保存しました。普段の使い方
新しいフォントを買ったら、共有フォルダにフォントファイルを放り込んで、以下のように実行
$ font-sync sync
同期元フォルダ: ~/Dropbox/MyFonts/
ℹ 23個のフォントファイルが見つかりました。
差分を確認中... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
✓ 3個のフォントを正常に同期しました。これで終わりです。もう片方のMacでも同じコマンドを実行すれば、同じフォント環境が手に入ります。
それでは、Cursor(Claude 4)ちゃんに技術的なアピールポイントを語って頂きましょう!
技術的なポイント(by Cursor)
1. macOS専用にした理由
最初はクロスプラットフォーム対応も考えたんですが:
- Windowsは
C:\\Windows\\Fonts\\で権限周りが複雑 - Linuxはディストリビューションごとに場所が違う
- フォントキャッシュの扱いも異なる
結局、自分が使うmacOSに特化することで、シンプルで確実な実装にしました。
2. なぜCLIなのか
GUIも考えましたが:
- サクッと作れる(週末プロジェクトなので)
- 自動化しやすい(cronやlaunchdで定期実行可能)
- リモートでも使える(SSH経由でも同期できる)
3. Pythonを選んだ理由
- macOSに標準でインストールされている
- ファイル操作が得意
- RichやTyperなど、CLIツール作成に便利なライブラリが豊富
今後の展望
現在は基本機能のみですが、以下の機能を追加予定:
- 自動同期: フォルダを監視して自動で同期
- フォントのプレビュー: ターミナル上でフォントの見た目を確認
- タグ機能: フォントをカテゴリ分けして管理
- GUI版: より使いやすいデスクトップアプリ版(有料予定)
ということでした。GUIは有料で売るらしい。そしたら買ってね! 自動同期についてはあると便利そう。コマンド叩くの忘れちゃいそうだから、なにかをフックに確認できるといいな。まあでもAdobeソフトを起動してフォントないって言われたら気づくか。ひとまずこれで、僕の悩みが解消されました888ってところです。
まとめ
「フォントの同期めんどくさいな〜小規模な趣味なのにそんなにお金も払いたくないな〜」という悩みから始まったプロジェクトですが、意外とちゃんとしたツールになりました。(AIのトークンにお金を払ってるじゃないかとかは言わない約束) せっかく公開したので、同じような悩みを持つ方がいたら、ぜひ使ってみてください。GitHubリポジトリで公開しているので、気が向いたらスター⭐️もしてね 😆