重複するURLのタグを開くことを制限するクローム拡張機能
キーワード選定のとき、関連キーワードを順次クリックして調べるわけだが、そのとき同じURLを開いてしまい時間が無駄になる。それを回避するために、この拡張機能を作った。
1.拡張機能の概要
どういった場面で使う拡張機能なのかを説明
この拡張機能は、Webブラウザを使って関連キーワードを順番に調べていく場面で使用されます。特に、同じURLを複数のタブで開いてしまい、無駄にページを再読み込みしてしまう状況を防ぐために作成されました。たとえば、検索結果のリンクをクリックしていくと、同じページを何度も開いてしまうことがあります。これを防ぐために、この拡張機能がURLの重複を検出し、すでに開かれているページを再度開かないようにします。
なぜ必要なのかを説明
同じURLを何度も開いてしまうと、無駄な時間を消費し、作業効率が落ちます。この拡張機能は、すでに開かれているタブを検出して、新しく開こうとしているタブを無視するか、警告を出してタブを閉じることによって、ユーザーの時間を節約し、作業効率を向上させます。
2.拡張機能の仕様書
仕様書の作成過程
拡張機能の仕様書は、最初に基本的な機能を設定し、それを基に別の角度から同じ機能を検証する形で進めました。最終的に、必要なすべての機能を網羅し、拡張機能の動作が意図通りに実現できるように確認しました。
仕様書
1. アイコンクリックでON/OFF切り替え
- ONのとき: 拡張機能が有効になり、同じURLが開こうとするとBEEP音が鳴り、タブが閉じられます。
- OFFのとき: 何も処理を行わず、通常通り新しいタブが開きます。
2. aタグクリック時
- ONのとき: クリックしたURLがすでに開かれている場合、新しいタブを開かせず、BEEP音を鳴らします。
- OFFのとき: 何も処理を行いません。
3. 既存タブのURL変更時
- ONのとき: 既存タブのURLが変更されると、重複をチェックし、重複していればBEEP音を鳴らし、タブを閉じます。
- OFFのとき: 何も処理を行いません。
4. 拡張機能の起動時
- ONのとき: 拡張機能が起動したとき、すべてのタブをチェックし、すでに開かれているURLが重複していれば警告を表示します。
- OFFのとき: 何も処理を行いません。
仕様書の検査方法
- 動作確認:
- アイコンのON/OFF切り替え、aタグクリック時、URL変更時に実際に確認する。
- エラー処理:
- エラーが出る場合はコンソールに表示されるので、それを確認する。
- ファイルの確認:
- 使用するアイコン画像やBEEP音など、すべてのリソースファイルが正しく配置されていることを確認する。
使用するファイル名と資源
- アイコン画像ファイル:
icon_48x48.png
(ON時)icon_48x48_off.png
(OFF時)
- 音源ファイル:
beep.mp3
(BEEP音)
3.拡張機能制作のプロンプト
プロンプトの作成過程
最初に拡張機能の仕様を基にプロンプトを作成しました。その後、別の角度から同じ機能を記述し、どちらも同じ動作が確認できるように設計しました。
プロンプト
-
アイコンのON/OFF切り替えを実現するプロンプト
- アイコンをクリックすることで拡張機能をON/OFF切り替え、ONのときは重複URLの検出、OFFのときは何も処理を行わない。
-
aタグクリック時の重複URLチェックを実現するプロンプト
- aタグがクリックされたとき、URLがすでに開かれていればBEEP音を鳴らし、新しいタブを開かせない。
-
既存タブのURL変更時に重複URLを検出するプロンプト
- 既存タブのURLが変更された場合、重複していればBEEP音を鳴らす。
-
拡張機能起動時にすべてのタブをチェックするプロンプト
- 拡張機能が起動したときに、すべてのタブのURLをチェックして重複があれば警告を出す。
プロンプトの検査方法
- 動作確認:
- 各機能が意図通りに動作するかをテストする。
- 重複チェック:
- 実際に同じURLを開く際に、重複が検出されて警告が表示されるかを確認する。
4.テスト記録
テスト方法
-
アイコンクリックによるON/OFFの切り替え
- ONの場合、同じURLが開かれないことを確認。
- OFFの場合、何も処理が行われないことを確認。
-
aタグクリック時の動作確認
- 同じURLが開かれない場合、BEEP音が鳴ることを確認。
-
既存タブURL変更時の動作確認
- 変更後のURLが他のタブにすでに開かれていれば、BEEP音が鳴ることを確認。
5.ソースコードの表示
ソースコードの作成過程
最初に作成したコードを基に、仕様書とプロンプトに沿った内容に修正を加え、エラー処理やログ出力などの機能を強化しました。
ソースコード
Icon
ON:

OFF:

BEEP
beep.mp3
manifest.json
0001 {
0002 "manifest_version": 3,
0003 "name": "URL 重複防止拡張機能",
0004 "description": "同じURLを複数回開かないようにする拡張機能。",
0005 "version": "1.0",
0006 "permissions": [
0007 "tabs",
0008 "storage",
0009 "scripting",
0010 "notifications"
0011 ],
0012 "background": {
0013 "service_worker": "background.js"
0014 },
0015 "action": {
0016 "default_icon": "icon_48x48.png",
0017 "default_title": "URL 重複防止"
0018 },
0019 "icons": {
0020 "48": "icon_48x48.png"
0021 },
0022 "host_permissions": [
0023 "http://*/*",
0024 "https://*/*"
0025 ],
0026 "web_accessible_resources": [
0027 {
0028 "resources": ["beep.mp3"],
0029 "matches": [""]
0030 }
0031 ]
0032 }
0033
background.js
0001 // 拡張機能がインストールまたは更新されたときに、初期状態をONに設定する
0002 chrome.runtime.onInstalled.addListener(function() {
0003 chrome.storage.local.set({ extensionStatus: true }, function() {
0004 updateIcon(true);
0005 playBeep(); // インストール時の動作確認用BEEP
0006 });
0007 });
0008
0009 // アイコンをクリックすると、拡張機能のON/OFFを切り替える
0010 chrome.action.onClicked.addListener(function() {
0011 chrome.storage.local.get("extensionStatus", function(data) {
0012 var newStatus = !data.extensionStatus;
0013 chrome.storage.local.set({ extensionStatus: newStatus }, function() {
0014 updateIcon(newStatus);
0015 playBeep(); // 切り替え時にBEEPでフィードバック
0016 });
0017 });
0018 });
0019
0020 // 拡張機能の状態に応じて、表示するアイコンを更新する関数
0021 // ONの場合は "icon_48x48.png" を、OFFの場合は "icon_48x48_off.png" を使用する
0022 function updateIcon(isEnabled) {
0023 var iconPath = isEnabled
0024 ? chrome.runtime.getURL("icon_48x48.png")
0025 : chrome.runtime.getURL("icon_48x48_off.png");
0026 chrome.action.setIcon({ path: iconPath }, function() {
0027 if (chrome.runtime.lastError) {
0028 console.error("アイコン設定エラー:" + chrome.runtime.lastError);
0029 }
0030 });
0031 }
0032
0033 // タブのURLが更新されたときに呼ばれるイベント
0034 // aタグクリックや既存タブのURL変更の場合、activeならBEEPのみ再生し、タブは閉じない
0035 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
0036 if (changeInfo.url) {
0037 var shouldClose = !tab.active; // activeならshouldCloseはfalse
0038 checkDuplicateTabs(tabId, changeInfo.url, true);
0039 }
0040 });
0041
0042 // 新しいタブが作成されたときに呼ばれるイベント
0043 // ここでは、tab.active が false ならCTRL+クリックとみなしてタブを閉じる
0044 chrome.tabs.onCreated.addListener(function(tab) {
0045 if (tab && tab.url) {
0046 var shouldClose = !tab.active;
0047 checkDuplicateTabs(tab.id, tab.url, shouldClose);
0048 }
0049 });
0050
0051 // すべてのタブを走査し、重複するURLが存在する場合に処理を実行する関数
0052 // shouldClose が true の場合は、重複が検出されたタブを閉じる(CTRL+クリックの場合)
0053 // shouldClose が false の場合は、BEEP音のみを再生し、タブは閉じない(通常のaタグクリックや既存タブ更新の場合)
0054 function checkDuplicateTabs(tabId, newUrl, shouldClose) {
0055 chrome.storage.local.get("extensionStatus", function(data) {
0056 if (!data.extensionStatus) return; // 拡張機能がOFFの場合は何もしない
0057 chrome.tabs.query({}, function(tabs) {
0058 for (var i = 0; i < tabs.length; i++) {
0059 var tab = tabs[i];
0060 if (tab.url && tab.url === newUrl && tab.id !== tabId) {
0061 playBeep();
0062 chrome.tabs.remove(tabId);
0063 return;
0064 }
0065 }
0066 });
0067 });
0068 }
0069 //
0070 // すべてのタブを走査し、重複するURLが存在する場合に処理を実行する関数
0071 // shouldClose が true の場合は、重複が検出されたタブを閉じる(CTRL+クリックの場合)
0072 // shouldClose が false の場合は、BEEP音のみを再生し、タブは閉じない(通常のaタグクリックや既存タブ更新の場合)
0073 //---- 新しいタブが作成されたときに呼ばれるイベントで呼んでみたがBEEPがならない。---
0074 // とりあえず、CTRL+クリックで不要URLは閉じるのでこのままでよしとした。
0075 // NEWタブで同じURL突っ込んだらBEEPも鳴らさずNEWタブ閉じるけど、それもよしとした。
0076 //
0077 function checkDuplicateTabsBEEP(tabId, newUrl, shouldClose) {
0078 chrome.storage.local.get("extensionStatus", function(data) {
0079 if (!data.extensionStatus) return; // 拡張機能がOFFの場合は何もしない
0080 chrome.tabs.query({}, function(tabs) {
0081 for (var i = 0; i < tabs.length; i++) { var tab = tabs[i]; if (tab.url && tab.url === newUrl && tab.id !== tabId) { playBeep(); chrome.tabs.remove(tabId); return; } } }); }); } // トップレベルの関数 beepPlayer を定義する // この関数は chrome.scripting.executeScript に渡され、引数のURLからBEEP音を再生する function beepPlayer(url) { var audio = new Audio(url); audio.play(); } // BEEP音を再生する関数 // 現在アクティブなタブのURLが chrome:// で始まる場合は、スクリプト実行をスキップする function playBeep() { try { chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) { if (tabs.length > 0) {
0082 var activeTab = tabs[0];
0083 /*
0084 if (activeTab.url && activeTab.url.startsWith("chrome://")) {
0085 console.warn("アクティブタブはchrome://のためBEEP再生をスキップ");
0086 return;
0087 }
0088 */
0089 if (activeTab.url.startsWith("chrome://")) {
0090 console.warn("アクティブタブはchrome://のためBEEP再生をスキップ");
0091 return;
0092 }
0093 var beepUrl = chrome.runtime.getURL("beep.mp3");
0094 chrome.scripting.executeScript({
0095 target: { tabId: activeTab.id },
0096 func: beepPlayer,
0097 args: [beepUrl]
0098 });
0099 }
0100 });
0101 } catch (error) {
0102 console.error("BEEP再生エラー:" + error);
0103 }
0104 }
0105
6.操作マニュアル
1. 拡張機能アイコンの位置
- アイコンは、ブラウザの右上に表示されます。アドレスバーの右隣に表示され、ブラウザのツールバーに配置されます。
図1: アイコンの位置(アドレスバーの右隣に表示)
- (図:ブラウザ画面の上部、アドレスバーの右隣に拡張機能のアイコンを表示した図)
- アイコンの場所は、アドレスバーの右側、ブラウザの上部に位置します。
(ここに図を描いて、ブラウザの右上にアイコンが表示されている状態を示す)
注意:
- アドレスバーはウェブページのURLを入力する場所です。
- アイコンは、その右側に表示されます。
2. 拡張機能のON/OFF切り替え
- アイコンをクリックすると、拡張機能をONまたはOFFに切り替えることができます。
図2: アイコンをクリックしてON/OFF切り替え
- (図:アイコンをクリックして、ONの状態(青または緑)からOFFの状態(灰色)に変わる様子を示す)
- ONの時には、アイコンが青や緑で表示され、拡張機能が有効なことを示します。
- OFFの時には、アイコンが灰色で表示され、拡張機能が無効であることを示します。
(ここに図を描いて、アイコンをクリックすることで、色が変わる様子を示す)
3. URLの重複チェックとBEEP音の再生
- aタグをクリックした際、同じURLがすでに開かれていれば、新しいタブが開かれず、BEEP音が鳴ります。
図3: URL重複チェックとBEEP音
- (図:新しいタブを開こうとするが、すでに同じURLが開かれているため、BEEP音が鳴り、タブが開かれない様子を示す)
- 2つのタブが並んで表示され、一方でURLがすでに開かれていることを示し、BEEP音が鳴る様子を描きます。
(ここに図を描いて、2つのタブが開かれ、同じURLが重複している状態を示す)
4. タブのURL変更時
- 既存のタブのURLが変更されたときに、変更後のURLがすでに開かれている場合、そのタブは閉じられ、BEEP音が鳴ります。
図4: タブURL変更と重複チェック
- (図:既存のタブでURLが変更され、同じURLがすでに開かれているため、タブが閉じる様子を示す)
- 既存タブのURLが変更され、そのURLがすでに開かれているときに、タブが閉じる処理を示します。
(ここに図を描いて、URL変更時のタブの挙動とBEEP音を示す)
まとめ
新しいタブを開いてURLを投げ込んだ時(既に同じURLのタブがあるとき)、BEEPを鳴らすはずだったのだけど、BEEPがなるページとならないページの切り分けができなくて(かなりめんどう)あきらめた。同時にその場合タブを閉じないはずだったのに切り分けができなくてそれもあきらめた。
同じ理由で、そのページから既存TABに同じページがあった場合も切り分けができずBEEPも鳴らさずにTABを閉じるものとした。
つまり、拡張機能は、切り分けが難しすぎるのと制約が多すぎて、度のコマンドが度おこで使えてどこで使えないかわからん!
しかも、chatGPTと、やりとりしてるとどんどん精度が落ちてくる。
あるタイミングで完全に吹っ飛ぶみたいだ。
で、さらにわるいことに、AIの記憶はネットワークなので、どれが新しくてどれが古いかなんて吹っ飛ぶ。
なので、まぁ、小さいものなら(拡張機能はこれでも大きい方に入るみたいだ)あれだけど、この程度でもだめになる。
何世代か残す形でチェックさせたけど、途中でおかしくなる。
結論として、ノイマン型(一定方向に流れる処理)は、AIは処理できない。専用の思考構造と記憶構造を持ったタイプでないと100%無理だね。
よって、自動処理系のあいまいさを抱え込まないアプリの場合、プログラマとAIがセットでないと無理。
で、開発の主はプログラマAIはコマンドのチェックとか構文チェック(も、今回はだめっぽかった。何回やってもかっこバランスをクリアできなかった)をさせる。
でした、あなたの参考になれば幸いです。