TL;DR
Chrome上で動画を見ながら、VSCodeで作業している状態から、ショートカットキー1発で動画の再生・停止を行う方法を検討してみました。
背景
Web上の動画系教材(UdemyやYouTubeなど)を利用して何かを学習する際、「Chromeで動画を見ながら、VSCodeで作業する」ことって多々ありますよね。その際、以下のような理由で「動画を一時停止 → VSCodeでコード書く → ひと段落した後、動画を再生」という作業が結構な頻度で発生します。
- 「講師の方がコード書くの早すぎ & 正確すぎて、ついていけない」
- 「この関数の挙動がよく分からないから、簡単なコード書いて確かめてみるか」
- 「この処理シェルにまとめておくか」
この**「動画を一時停止 → VSCode上でコード書く → ひと段落した後、動画を再生」**という作業を普通に行うと、以下のようになると思います(Active Window が VSCode の場合)。
- Chrome を Activate (カーソル移動とクリック or
command + shift
) - 動画停止
- VSCode を Activate
- コード書く
- ひと段落した後、再び Chrome を Activate
- 動画再生
この一連の作業を何度も繰り返していると**「面倒臭い」**という感情が芽生えてきます。そこで、以下の2つのアイテムを組み合わせれば、この問題を解決できると考えました。
- VSCode上から、あるショートカットキーをトリガーにして、任意のスクリプトを実行する機能
- 「Chrome を Activate → 動画停止 or 再生 → VSCode を Activate」を自動(できれば高速)で行うスクリプト
実現方法
VSCode のタスク機能と Python を組み合わせることにしました。
VSCode タスク機能
VSCode には build や test を自動化できる機能(Tasks in Visual Studio Code)が備わっていることを最近知りました。本来の使用方法とは異なる気がしますが、この機能を利用して、Python のスクリプトを VSCode 上からショートカットキーで実行できるようにします。
-
command + shift + p
でコマンドパレットを表示 -
Tasks: Configure Task
を選択 -
Create tasks.json file from template
を選択 -
Others
を選択(.vscode/tasks.json
が生成される) - 以下を
.vscode/tasks.json
に貼り付け
これで、command + shift + b
でpython ~/Desktop/clicker/clicker.py
を実行できるようになりました。
{
"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
を使用して実装しました。処理の流れは以下のようになります。
- プログラム実行時のカーソルの位置を取得
(x_now, y_now)
- 動画の位置
(x_click, y_click)
までカーソル移動 - 2回クリック(1回目で Chrome を Activate して、2回目で動画の再生・停止)
- カーソルを元の位置
(x_now, y_now)
に戻す -
command + tab
で VSCode を Activate
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()
動画の位置をどのように取得するか考えたのですが、以下の手順で事前に取得する方式にしました。他にもっと良い方法が無いか現在模索中です、、、
-
-u
オプション付きでプログラムを実行(python clicker.py -u
) - カーソルを動画の位置まで動かして Enter
- スクリプト内の
x_click, y_click
の値が更新される
得られたもの
- これで学習が捗る
- VSCode のタスク機能はこれ以外にも利用できそう