VSCodeからショートカットキー1発で、Chrome上の動画の再生・停止を行う

## TL;DR
Chrome上で動画を見ながら、VSCodeで作業している状態から、ショートカットキー１発で動画の再生・停止を行う方法を検討してみました。


## 背景
Web上の動画系教材（UdemyやYouTubeなど）を利用して何かを学習する際、「Chromeで動画を見ながら、VSCodeで作業する」ことって多々ありますよね。その際、以下のような理由で「動画を一時停止 → VSCodeでコード書く → ひと段落した後、動画を再生」という作業が結構な頻度で発生します。

- 「講師の方がコード書くの早すぎ ＆ 正確すぎて、ついていけない」
- 「この関数の挙動がよく分からないから、簡単なコード書いて確かめてみるか」
- 「この処理シェルにまとめておくか」

この**「動画を一時停止 → VSCode上でコード書く → ひと段落した後、動画を再生」**という作業を普通に行うと、以下のようになると思います（Active Window が VSCode の場合）。

1. Chrome を Activate (カーソル移動とクリック or `command + shift`)
2. 動画停止
3. VSCode を Activate
4. コード書く
5. ひと段落した後、再び Chrome を Activate
6. 動画再生

この一連の作業を何度も繰り返していると**「面倒臭い」**という感情が芽生えてきます。そこで、以下の２つのアイテムを組み合わせれば、この問題を解決できると考えました。

1. VSCode上から、あるショートカットキーをトリガーにして、任意のスクリプトを実行する機能
2. 「Chrome を Activate → 動画停止 or 再生 → VSCode を Activate」を自動（できれば高速）で行うスクリプト

## 実現方法
VSCode のタスク機能と Python を組み合わせることにしました。

## VSCode タスク機能
VSCode には build や test を自動化できる機能（[Tasks in Visual Studio Code](https://code.visualstudio.com/docs/editor/tasks)）が備わっていることを最近知りました。本来の使用方法とは異なる気がしますが、この機能を利用して、Python のスクリプトを VSCode 上からショートカットキーで実行できるようにします。

1. `command + shift + p`でコマンドパレットを表示
2. `Tasks: Configure Task`を選択
3. `Create tasks.json file from template`を選択
4. `Others`を選択（`.vscode/tasks.json`が生成される）
5. 以下を`.vscode/tasks.json`に貼り付け

これで、`command + shift + b`で`python ~/Desktop/clicker/clicker.py`を実行できるようになりました。

```json:tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "click",
            "type": "shell",
            "command": "python ~/Desktop/clicker/clicker.py",
            "presentation": {
                "reveal": "silent",
            },
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
```

## Python 動画再生・停止スクリプト
`pyautogui`を使用して実装しました。処理の流れは以下のようになります。

1. プログラム実行時のカーソルの位置を取得`(x_now, y_now)`
2. 動画の位置`(x_click, y_click)`までカーソル移動
3. ２回クリック（１回目で Chrome を Activate して、２回目で動画の再生・停止）
4. カーソルを元の位置`(x_now, y_now)`に戻す
5. `command + tab`で VSCode を Activate

```python:clicker.py
import os
import sys
import re
import argparse
import pyautogui as pag


def get_click_pos():
    _ = input('\nMove the cursor where you want to click and press <Enter>')
    x, y = pag.position()
    return x, y


def update_click_pos():
    x, y = get_click_pos()
    print(f'New click position x:{x} y:{y}')
    this_file_abs_path = os.path.realpath(__file__)
    with open(this_file_abs_path, 'r') as f:
        content = f.read()

    content = re.sub(r'(x_click = )-?\d+', r'\g<1>' + str(x), content)
    content = re.sub(r'(y_click = )-?\d+', r'\g<1>' + str(y), content)
    with open(this_file_abs_path, 'w') as f:
        f.write(content)


def main():
    # '-u' を付けて呼ぶと、x_click, y_click の値をアップデートする
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', '--update', action='store_true')
    args = parser.parse_args()
    
    if args.update:
        update_click_pos()
        sys.exit()

    x_now, y_now = pag.position()
    x_click = 0
    y_click = 0
    pag.click(x_click, y_click, clicks=2)
    pag.moveTo(x_now, y_now)
    pag.hotkey('command', 'tab')


if __name__ == '__main__':
    main()

```

動画の位置をどのように取得するか考えたのですが、以下の手順で事前に取得する方式にしました。他にもっと良い方法が無いか現在模索中です、、、

1. `-u`オプション付きでプログラムを実行（`python clicker.py -u`）
2. カーソルを動画の位置まで動かして Enter
3. スクリプト内の`x_click, y_click`の値が更新される

# 得られたもの
- これで学習が捗る
- VSCode のタスク機能はこれ以外にも利用できそう