はじめに
2010年発売の初代iPadが自宅に眠っていました。
すっかり放電していたのですが、充電してみると無事に起動。
しかし、SafariでGoogleやYahoo! JAPANを開こうとしても表示されません。
せっかくなので、料理のレシピを見る端末として再利用できないかと考えました。
初代iPadの最終OSはiOS 5.1.1。現代のWebサイトを閲覧するには、あまりにも古い環境です。
Linuxに入れ替えることも考えましたが、タッチ操作やWi-Fiを含めて実用的に動かすのは難しそうです。
そこで発想を変えました。
「最新のWebサイトをiPadで開く」のではなく、「別のパソコンでレシピを取得して、古いiPadでも読めるHTMLに変換すればいいのでは?」
結果として、Chrome拡張機能(Braveでも動作)とNode.jsを使い、ワンクリックでレシピを初代iPadに送れる仕組みができました。
完成したもの
使い方は簡単です。
- Macのブラウザで、普段どおりGoogle検索する
- 気に入ったレシピのページを開く
- 拡張機能の「iPadに送る」ボタンを押す
- 初代iPadに材料と作り方が自動表示される
URLのコピーや貼り付けは不要です。
家族が使うものなので、できるだけ操作を少なくしました。
実際の表示
レシピ名、材料、作り方を大きな文字で表示します。
広告や余計なナビゲーションがないので、料理中に必要な情報だけを確認できます。
システム構成
Mac(Brave / Chrome)
│
│ Googleでレシピを検索
▼
レシピサイト
│
│ 拡張機能のボタンをクリック
▼
ブラウザ拡張機能(Manifest V3)
│
│ Recipe構造化データなどを抽出
│ JSONをlocalhost:8000へPOST
▼
Node.js HTTPサーバー
│
├─ current-recipe.json に保存
│
└─ 古いSafari向けHTMLを生成
│
│ 家庭内Wi-Fi / HTTP
▼
初代iPad(iOS 5.1.1)
│
└─ 12秒ごとに更新を確認
使用したものは以下のとおりです。
| 項目 | 環境 |
|---|---|
| 表示端末 | 初代iPad(2010年) |
| OS | iOS 5.1.1 |
| サーバー | iMac / macOS Sonoma |
| ブラウザ | Brave(Chromeでも利用可能) |
| 拡張機能 | Manifest V3 |
| サーバー | Node.js |
| 保存形式 | JSON |
| 通信 | 家庭内LANのHTTP |
Reactなどのフレームワークは使用していません。
Node.jsも標準モジュールだけで動くので、npm install は不要です。
1. まずは古いSafariでHTMLを表示できるか検証
最初にMacで簡単なHTMLファイルを用意し、PythonのHTTPサーバーで配信しました。
python3 -m http.server 8000
初代iPadのSafariで、MacのIPアドレスを指定します。
http://192.168.1.xxx:8000/
すると、問題なく表示されました。
ここで、初代iPadでもシンプルなHTMLなら十分に使えることが確認できました。
2. レシピを取得するChrome拡張機能
次に考えたのは、レシピの取得方法です。
最初は、Webアプリ内にGoogle検索を組み込もうとしました。
しかし、Google検索をiframeで埋め込むことには制限があります。また、独自の検索APIを使うほどのシステムでもありません。
そこで、ブラウザ拡張機能を使うことにしました。
Google検索はいつもどおり利用し、レシピのページを開いた状態でボタンを押すだけです。
拡張機能では chrome.scripting.executeScript() を利用して、現在のページからレシピ情報を抽出します。
送信処理の主要部分は次のようになっています(エラー処理などは省略)。
chrome.action.onClicked.addListener(async (tab) => {
const results = await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: extractRecipeFromPage
});
const recipe = results[0].result;
await fetch('http://127.0.0.1:8000/api/recipe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(recipe)
});
});
Recipe構造化データを利用
多くのレシピサイトには、schema.org/Recipe に基づいたJSON-LDが埋め込まれています。
例えば、次のようなデータです。
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "肉じゃが",
"recipeYield": "4人分",
"recipeIngredient": [
"じゃがいも 3個",
"玉ねぎ 1個",
"牛肉 200g"
],
"recipeInstructions": [
{
"@type": "HowToStep",
"text": "材料を食べやすい大きさに切る"
},
{
"@type": "HowToStep",
"text": "鍋で材料を炒める"
}
]
}
これなら、サイトごとに複雑なHTMLを解析しなくても、材料や作り方を取得できます。
実装では、ページ内の
document.querySelectorAll(
'script[type="application/ld+json"]'
)
からJSON-LDを取得し、@graph などの入れ子構造もたどって Recipe 型を探しています。
3. すべてのレシピサイトで動くわけではない
実際に試してみると、サイトによって結果が違いました。
| レシピサイト | 結果 |
|---|---|
| クックパッド | OK |
| キユーピー3分クッキング | OK |
| クラシル | OK |
| 楽天レシピ | OK |
| キッコーマン | 初回NG → 対応 |
| デリッシュキッチン | 初回NG → 抽出処理を追加 |
キッコーマンの一部のレシピ記事では、期待したRecipe構造化データを取得できませんでした。
そこで、見出しや手順番号を使って本文から抽出する処理を追加しました。
デリッシュキッチンについても、「材料」「手順」などの表示テキストを解析する専用処理を追加しています。
ただし、この方式はサイトのHTML構造が変更されると動かなくなる可能性があります。
すべてのレシピサイトに対応することは目指さず、家族がよく使うサイトから順番に対応する方針です。
4. 初代iPad向けのHTML
iPad側では、最新のJavaScriptフレームワークを使いません。
Node.js側でHTMLを生成し、Safariはそれを表示するだけにしています。
CSSもシンプルです。
body {
font-family: Arial, sans-serif;
color: #222;
background: #fffdf7;
margin: 0;
padding: 18px 28px;
font-size: 30px;
line-height: 1.65;
}
h1 {
font-size: 40px;
line-height: 1.4;
}
h2 {
font-size: 36px;
}
最初は本文25pxでしたが、少し離れたところからでも読みやすいように30pxに変更しました。
自動更新の仕組み
Macから新しいレシピを送信した際、iPad側で毎回Safariを更新するのは面倒です。
そこで、12秒ごとにサーバーへ問い合わせる仕組みにしました。
setInterval(update, 12000);
update() 内では、古いSafariでも利用できる XMLHttpRequest を使って /api/version を取得します。
現在表示しているレシピのバージョンと異なれば、ページを再読み込みします。
WebSocketなどは使っていません。
初代iPadでも、この仕組みは問題なく動作しました。
5. iMacでサーバーを自動起動
家族が使う以上、毎回ターミナルで
node server.js
を実行してもらうわけにはいきません。
そこで、macOSの launchd を利用して、ログイン時にNode.jsサーバーが自動起動するようにしました。
LaunchAgentには次の設定を使用しています。
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
これでログイン時に自動起動し、プロセスが終了した場合も再起動を試みます。
実際には、インストール用スクリプトを用意して、
zsh install_autostart.command
で登録できるようにしました。
動作確認には、次のURLを使用します。
http://localhost:8000/health
OK と表示されればサーバーが稼働しています。
なお、iMacがスリープしている間は利用できませんが、復帰すれば通常は利用を再開できます。
6. セキュリティと制限事項
初代iPadはすでにセキュリティ更新が終了しています。
今回の仕組みは、信頼できる家庭内LANでの利用を前提としています。
- サーバーをインターネットに公開しない
- ルーターでポート転送を設定しない
- iPadでは銀行や個人情報を扱うサイトにアクセスしない
- レシピの送信APIはローカルホストからのアクセスに限定する
また、レシピの本文は家庭内での個人的な閲覧用として扱い、取得したコンテンツを公開・再配布しないようにしています。
現時点では写真の表示やお気に入り機能には対応していません。
おわりに
最初は「古いiPadでレシピサイトくらい見られないかな」という程度の思いつきでした。
しかし、初代iPadそのものを現代のWebに対応させようとするのではなく、Webの情報を古い端末に合わせて変換するという方法で、思いのほか実用的なものができました。
最新のブラウザやフレームワークを動かす必要がないので、16年前の端末でも十分に役立ちます。
現在は基本機能が完成し、家族に実際に使ってもらっている段階です。
使い勝手を確認しながら、必要があれば改善していこうと思っています。
古いハードウェアでも、役割を限定すればまだまだ使えるものですね。

