3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AI agent活用】作業中のSNS断ちを強制する!!ポモドーロタイマー付きChrome拡張機能を作ってみた

Last updated at Posted at 2025-06-14

はじめに

作業中についついSNSや動画サイトを開いてしまい、集中力が途切れてしまうことはありませんか?

「今度こそ集中するぞ!」と意気込んでも、気がつくとTwitterやYouTubeを開いてしまい、気づけば数時間経過...なんて経験、きっと多くの方が持っているのではないでしょうか。

そこで今回は、ポモドーロテクニックサイトブロック機能を組み合わせたChrome拡張機能を開発してみました。この記事では、

  • Chrome拡張機能の開発のススメ
  • AI agent(Codex)の活用方法

も含めて、Chrome拡張機能の作り方を詳しく解説していきます!

6/15日現在は、この拡張機能のリリースを申請中です。
ローカルでの使用方法を以下に記載してあります。

📱 完成した拡張機能の機能

まずは、今回作成した拡張機能の主な機能をご紹介します:

  • 25分間のポモドーロタイマー
  • タイマー実行中の集中力を妨げるサイトの自動ブロック
  • アイコン上に残り時間を表示
  • ブロック中のカスタムページ表示
  • タイマー完了時の通知表示

デモ動画

chrome-test.gif

↑画質が荒いのですが、お許しください

🎯 なぜこの拡張機能を作ったのか

私自身、研究や仕事において在宅ワークが増える中で集中力の維持に課題を感じていました。特に:

  1. 意志力に頼る限界: 「見ないようにしよう」と思っても、つい開いてしまう
  2. 既存ツールの不満: 市販のサイトブロッカーは設定が複雑で使いづらい
  3. ポモドーロテクニックとの組み合わせ: 25分という区切りでブロックしたい

これらの課題を解決するため、シンプルで使いやすい拡張機能を自作することにしました。

🤖 AI agentを活用した開発プロセス

今回の開発では、CodexというChatGPT内で動作するAI開発エージェントを積極的に活用しました。AIツールを使うことで、開発効率が大幅に向上したので、その過程もご紹介します。

AIとの対話例

: 「ポモドーロタイマー付きのサイトブロッカーChrome拡張機能を作りたいです。Manifest V3で、25分間特定のサイトをブロックする機能を実装したいのですが、どのような構成にすべきでしょうか?」

Codex: 「Manifest V3でのサイトブロック機能でしたら、declarativeNetRequestを使用するのが最適です。以下のような構成をお勧めします...」

このように、AIと対話しながら設計を固めていきました。特に以下の点でAIが有効でした:

  1. 技術選択の相談: 使用パッケージの最新仕様に関するアドバイス
  2. コード生成: 基本的な構造の雛形作成
  3. デバッグ支援: エラーの原因特定と解決策の提案
  4. ベストプラクティスの確認: セキュリティやパフォーマンスの観点

🏗️ 拡張機能の構成

Chrome拡張機能は以下のファイルで構成されています:

pomodoro-blocker-extension/
├── manifest.json          # 拡張機能の設定ファイル
├── popup.html             # ポップアップUI
├── popup.js               # タイマー制御ロジック
├── background.js          # サイトブロック制御
└── icons/                 # アイコンファイル
    └── icon.png

📝 開発ステップバイステップ

Step 1: manifest.jsonの設定

Chrome拡張機能の心臓部となるmanifest.jsonから始めます:

{
  "manifest_version": 3,
  "name": "Pomodoro Blocker",
  "version": "1.0",
  "description": "25分間タイマー+特定サイトを集中のためブロックする拡張機能",
  "permissions": [
    "activeTab",
    "storage",
    "declarativeNetRequest",
    "notifications"
  ],
  "host_permissions": [
    "*://facebook.com/*",
    "*://twitter.com/*",
    "*://youtube.com/*"
    // その他ブロック対象サイト
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}

ポイント:

  • manifest_version: 3で最新版を使用
  • declarativeNetRequestでサイトブロック機能を実装
  • storageでタイマー状態を永続化

Step 2: ポップアップUI(popup.html)

ユーザーがクリックする拡張機能のポップアップを作成:

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Pomodoro Blocker</title>
    <style>
        body {
            width: 300px;
            height: 200px;
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 20px;
        }
        
        .timer-display {
            font-size: 48px;
            font-weight: bold;
            color: #333;
            margin: 20px 0;
        }
        
        button {
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        
        .start-btn {
            background-color: #4CAF50;
            color: white;
        }
        
        .stop-btn {
            background-color: #f44336;
            color: white;
        }
    </style>
</head>
<body>
    <h2>Pomodoro Blocker</h2>
    <div id="timer-display" class="timer-display">25:00</div>
    
    <div class="controls">
        <button id="start-btn" class="start-btn">開始</button>
        <button id="stop-btn" class="stop-btn">停止</button>
    </div>
    
    <script src="popup.js"></script>
</body>
</html>

Step 3: タイマー制御(popup.js)

ポップアップの動作を制御するJavaScriptを実装:

class PomodoroTimer {
    constructor() {
        this.duration = 25 * 60; // 25分(秒単位)
        this.timeLeft = this.duration;
        this.isRunning = false;
        
        this.timerDisplay = document.getElementById('timer-display');
        this.startBtn = document.getElementById('start-btn');
        this.stopBtn = document.getElementById('stop-btn');
        
        this.initializeEventListeners();
        this.loadState();
    }
    
    initializeEventListeners() {
        this.startBtn.addEventListener('click', () => this.startTimer());
        this.stopBtn.addEventListener('click', () => this.stopTimer());
    }
    
    startTimer() {
        this.isRunning = true;
        this.startTime = Date.now();
        this.startCountdown();
        
        // バックグラウンドスクリプトにブロック開始を通知
        chrome.runtime.sendMessage({
            action: 'startBlocking',
            duration: this.timeLeft
        });
    }
    
    startCountdown() {
        this.intervalId = setInterval(() => {
            const elapsed = Math.floor((Date.now() - this.startTime) / 1000);
            this.timeLeft = Math.max(0, this.duration - elapsed);
            
            this.updateDisplay();
            
            if (this.timeLeft <= 0) {
                this.timerComplete();
            }
        }, 1000);
    }
    
    updateDisplay() {
        const minutes = Math.floor(this.timeLeft / 60);
        const seconds = this.timeLeft % 60;
        this.timerDisplay.textContent = 
            `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
}

document.addEventListener('DOMContentLoaded', () => {
    new PomodoroTimer();
});

Step 4: サイトブロック機能(background.js)

拡張機能のコア機能である、サイトブロック処理を実装:

class PomodoroBlocker {
    constructor() {
        this.blockedSites = [
            'facebook.com',
            'twitter.com',
            'x.com',
            'instagram.com',
            'youtube.com',
            'netflix.com',
            'reddit.com'
            // その他ブロック対象サイト
        ];
        
        this.initializeEventListeners();
    }
    
    initializeEventListeners() {
        chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
            switch (message.action) {
                case 'startBlocking':
                    this.startBlocking(message.duration);
                    break;
                case 'stopBlocking':
                    this.stopBlocking();
                    break;
            }
        });
    }
    
    async startBlocking(duration) {
        this.isBlocking = true;
        
        // declarativeNetRequest用のルールを作成
        this.blockingRules = this.blockedSites.map((site, index) => ({
            id: index + 1,
            priority: 1,
            action: { 
                type: 'redirect', 
                redirect: { 
                    url: 'data:text/html;charset=utf-8,' + 
                         encodeURIComponent(this.createBlockPageContent(site)) 
                } 
            },
            condition: { 
                urlFilter: `||${site}^`,
                resourceTypes: ['main_frame']
            }
        }));

        // ブロックルールを適用
        await chrome.declarativeNetRequest.updateDynamicRules({
            addRules: this.blockingRules
        });
        
        // 指定時間後に自動停止
        setTimeout(() => {
            this.stopBlocking();
        }, duration * 1000);
    }
    
    createBlockPageContent(blockedSite) {
        return `
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>サイトがブロックされています</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            text-align: center;
        }
        .container {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            padding: 40px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div style="font-size: 72px;">🍅</div>
        <h1>サイトがブロックされています</h1>
        <p>ポモドーロタイマーが終了するまでお待ちください。</p>
        <p>集中して作業を続けましょう!</p>
    </div>
</body>
</html>`;
    }
}

new PomodoroBlocker();

🔧 開発で工夫したポイント

1. Manifest V3対応

Chrome拡張機能は2024年からManifest V3が必須となりました。従来のwebRequestからdeclarativeNetRequestへの移行が必要で、この部分でAIの助けが特に有効でした。

2. 状態の永続化

ブラウザを閉じてもタイマーが継続するよう、chrome.storage.localを使用して状態を保存しています。

3. リアルタイム表示

拡張機能のアイコンにバッジで残り時間を表示し、ユーザーが常に進捗を確認できるようにしました。

🚀 インストールと使い方

インストール方法

リリースは申請中なので、以下のようにローカルで使用してください。

  1. GitHubからコードをダウンロード
  2. Chrome の chrome://extensions/ にアクセス
  3. 「デベロッパーモード」を有効にする
  4. 「パッケージ化されていない拡張機能を読み込む」をクリック
  5. ダウンロードしたフォルダを選択

使い方

  1. Chrome ツールバーの拡張機能アイコンをクリック
  2. 「開始」ボタンでポモドーロタイマーを開始
  3. 25分間、指定したサイトが自動的にブロックされます
  4. タイマー完了時に通知が表示されます

🎨 あなた専用の拡張機能にカスタマイズ!

ブロック対象サイトの変更

background.jsblockedSites配列を編集することで、ブロック対象を自由に変更できます:

this.blockedSites = [
    'facebook.com',
    'twitter.com',
    'your-favorite-distraction.com'  // 追加
];

タイマー時間の変更

popup.jsduration変数を変更することで、25分以外の時間に設定可能です:

this.duration = 45 * 60; // 45分に変更

💡 AIツール活用のコツ

今回の開発を通じて学んだ、AIツールを効果的に活用するコツをまとめます:

1. 具体的な質問をする

❌ 悪い例: 「Chrome拡張機能を作りたい」
✅ 良い例: 「Manifest V3でサイトブロック機能を持つChrome拡張機能を作りたい。declarativeNetRequestを使用して、特定のドメインにアクセスした際にカスタムページにリダイレクトする方法を教えて」

2. エラーメッセージを共有する

エラーが発生した際は、エラーメッセージ全体をAIに共有することで、的確な解決策を得られます。

3. 段階的に開発する

すべてを一度に実装しようとせず、機能ごとに分けてAIに相談することで、より良いコードが得られます。

🔮 今後の改善案

現在の拡張機能をさらに発展させるアイデア:

  • 統計機能: 1日の集中時間や達成回数の記録
  • カスタムタイマー: 5分、15分、30分など複数の時間設定
  • ホワイトリスト機能: 仕事で必要なサイトの除外設定
  • 同期機能: 複数デバイス間での設定共有
  • 集中度分析: ブロックを試みた回数の分析

📚 参考リソース

Qita記事

Document集

まとめ

今回は、ポモドーロテクニックとサイトブロック機能を組み合わせたChrome拡張機能を開発しました。AIツールを活用することで、効率的に開発を進めることができ、特に最新のパッケージ仕様への対応において大きな助けとなりました。

この拡張機能を使うことで、作業中の誘惑を物理的に断ち切り、25分間の集中時間を確保できるようになります。ぜひ皆さんも試してみて、必要に応じてカスタマイズしてみてください!

何か質問やご意見がありましたら、コメント欄でお聞かせください。また、機能追加のアイデアなどもお待ちしています!

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?