【かんたん個人開発】Youtubeを集中して見るショートカット

# Overview 🔍

**作業用音楽を再生していたはずなのに、ついつい気になる動画をクリックしてしまう...**
そんな悩みを解決する「Chrome拡張機能」をご紹介します！
この拡張機能は、**不要な情報を排除して集中力をアップさせる**ことを目的としています。



| 通常 | 使用後 |
|:-:|:-:|
|  ![スクリーンショット 2024-12-08 19.54.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/79b11751-b5c9-d1bc-3fda-9045e045bbf1.png) |  ![スクリーンショット 2024-12-08 19.57.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/2a9d988d-c9c9-d1fc-4cf5-e9678f6cc21f.png) |

### レポジトリ
https://github.com/Kohki-Takatama/youtube-focus-embed/tree/master

拡張機能は公開していないため、使用する際は`git clone`を行ってください。

### インストール方法
1. リポジトリをcloneまたはforkでローカルに取得する
1. Chromium系ブラウザの「拡張機能を管理」を開く
1. デベロッパーモードを有効にする
1. 「パッケージ化されていない拡張機能を読み込む」をクリックし、取得したディレクトリを選択する
1. Alt+Shift+Fのショートカットで集中モードに切り替える


注意: 一部の動画には使用できない場合があります。

# 設計 ⚙️

「動画の埋め込み」を使用し、動画だけにフォーカスしています。

この拡張機能は、「動画の埋め込み」に焦点を当てています。仕組みはシンプルで、URLを書き換えることで実現しています。

通常のURL例: `https://www.youtube.com/watch?v=VIDEOID`
埋め込みURL例: `https://www.youtube.com/embed/VIDEOID`

## コード
### ◇ 設定ファイル
以下のような設定を使用しています。特に注目すべきは`permissions`と`host_permissions`の設定です。

```json:manifest.json
{
  "manifest_version": 3,
  "name": "Youtube-focus",
  "version": "1.0.0",
  "permissions": ["scripting", "tabs"],
  "commands": {
    "focus": {
      "suggested_key": {
        "default": "Alt+Shift+F"
      },
      "description": "Focus on YouTube video only"
    }
  },
  "background": {
    "service_worker": "background.js"
  },
  "host_permissions": ["https://www.youtube.com/*"]
}
```
### ◆ メインファイル
大まかな流れ
1. `active`なタブを取得
1. 再生時間を除くURLを作成
1. 再生時間を取得してURLを更新
1. タブを新しいURLにアップデート

```js:background.js
chrome.commands.onCommand.addListener(async (command) => {
  if (command === 'focus') {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      const currentTab = tabs[0];
      const currentUrl = new URL(currentTab.url);
      // youtube以外では動作させない
      if (!(currentUrl.hostname === 'www.youtube.com')) {
        return;
      }

      const createUrl = (prevUrl, time) => {
        // 動画パラメータ
        const EMBED_PATH = '/embed';
        const WATCH_PATH = '/watch';
        const AUTOPLAY_PARAM = '?autoplay=1';
        let videoId = '';
        let newUrl = prevUrl;

        // NOTE: switchは使えない。pathnameが理由。watch: idを含まない / embed: 含む = 完全一致が不可
        if (prevUrl.pathname.includes(WATCH_PATH)) {
          videoId = prevUrl.searchParams.get('v');
          // embedの場合のみautoplayを付加する
          newUrl = `https://www.youtube.com${EMBED_PATH}/${videoId}${AUTOPLAY_PARAM}&start=${time}`;
        } else if (prevUrl.pathname.includes) {
          videoId = prevUrl.pathname.replace(EMBED_PATH + '/', '');
          newUrl = `https://www.youtube.com${WATCH_PATH}?v=${videoId}&t=${time}`;
        }
        return newUrl;
      };

      // 再生時間を取得
      chrome.scripting.executeScript({ target: { tabId: currentTab.id }, files: ['getPlayingTime.js'] }, () => {
        chrome.runtime.onMessage.addListener((message) => {
          if (message.currentTime !== undefined) {
            const newUrl = createUrl(currentUrl, message.currentTime);
            // 画面切り替え
            chrome.tabs.update(currentTab.id, { url: newUrl });
          } else if (message.error) {
            console.error(message.error);
          }
        });
      });
    });
  }
});
```
### ◇ 再生時間取得スクリプト
切り替え前後で動画再生時間を保持するためのスクリプトです。
```js:getPlayingTime.js
(() => {
  // YouTubeプレイヤーの再生時間を取得
  const player = document.querySelector('video');
  if (player) {
    const currentTime = Math.floor(player.currentTime); // 秒単位で取得
    chrome.runtime.sendMessage({ currentTime });
  } else {
    chrome.runtime.sendMessage({ error: 'Video player not found' });
  }
})();
```

### 特徴
- トグル機能: 通常モードと埋め込みモードの切り替えが可能です
- 再生時間保持: 動画の再生時間を共有し、途中から再生できます
- 自動再生: 埋め込みモード時に自動再生を有効化

# 今後の展望 🔭
（やる気と時間があれば・・・）
### 実装したい機能
- 音楽プレイヤー風のUI
  - 再生・停止・次へ・前へボタン
  - サムネイル表示
- 「静かな画面」モードのままYouTube検索
課題
- 一部動画は埋め込みを拒否する設定があり、切り替えができません

そもそも、実装の簡単さを優先し「URL書き換え」というアプローチを取りましたが、
これ以上機能を大きくする場合は正当なアプローチを取ったほうが良いと思います。
（videoのみ取得し表示・他の要素を非表示にするなど）

---

以上、お読みいただきありがとうございました！🙌