自作の強制TV会議参加プログラムで、会議への参加遅れを撲滅した話

リモートで仕事してると、集中してTV会議の開始に気づかず、参加が遅れてしまうことって、よくありますよね。

私はよくありました。

なので、これを撲滅するために、自作の強制TV会議参加スクリプトを作成し、参加遅れを撲滅した話を紹介します。

_(この投稿は[Mobility Technologies Advent Calendar 2021](https://adventar.org/calendars/6771)の一部です)_

## 要件

* Googleカレンダーに入っているZoom, Microsoft Teams, Google MeetのTV会議について開始前に通知する
* TV会議の開始時間になったら、参加するためのURLをブラウザ(Google Chrome)で自動的に開く

## 実装

TV会議チェックプログラムを作り、それを定期実行することで実現しました。

* TV会議チェックプログラム：Pythonを用いて、Googleカレンダーの予定から直近２分のTV会議を探して、もしあればブラウザでURLを起動する。
* 定期実行：作ったプログラムをMacOSのcrontabを使って定期実行する。


### TV会議チェックプログラム

TV会議チェックプログラムは以下の処理を行います

1. GoogleカレンダーAPIのクレデンシャルを取得
2. クレデンシャルをつかってGoogleカレンダーの予定を取得
3. カレンダーの予定からTV会議のURLを取得
4. RLをブラウザで開く

#### 1. GoogleカレンダーAPIのクレデンシャルを取得

[ここ](https://developers.google.com/calendar/quickstart/python)にサンプルコードが有るので、それを参考にして作りました。

```python
def get_credentials() -> Credentials:
    """
    secret/credentails.jsonをもとにGoogleカレンダーAPIのトークンを取得する。
    トークンがない場合はブラウザによるOauth2認証を行う。
    取得したトークンは保存しておき、有効な限りそれを使う。
    """
    creds = None
    if os.path.exists(TOKEN_PATH):
        with open(TOKEN_PATH, 'rb') as token:
            creds = pickle.load(token)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            # ブラウザを用いて認証しトークンを取得
            flow = InstalledAppFlow.from_client_secrets_file(
                CREDENTIAL_APTH, ['https://www.googleapis.com/auth/calendar.readonly'])
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open(TOKEN_PATH, "wb") as token:
            pickle.dump(creds, token)
            os.chmod(TOKEN_PATH, 0o755)
            logger.info(f"make {TOKEN_PATH}")
    return creds
```

#### 2. クレデンシャルをつかってGoogleカレンダーの予定を取得

上記で得られたクレデンシャルを使ってGoogleカレンダーのAPIを実行し、予定をとってきます。以下のAPIの叩き方で、現在時刻から後の 5 件のカレンダー情報がとれます。

```python
def call_calender_api(creds):
    service = build('calendar', 'v3', credentials=creds, cache_discovery=False)
    events_result = service.events().list(
        calendarId='primary',
        timeMin=datetime.datetime.utcnow().isoformat() + 'Z',  # 'Z' indicates UTC time,
        maxResults=5,
        singleEvents=True,
        orderBy='startTime',
    ).execute()
    return events_result
```

#### 3. カレンダーの予定からTV会議のURLを取得

上記のAPIの結果はの`items`のキーに、開始時間、会議名、場所、本文などが入ってきます。
例えばzoomの場合であれば、locationのところにzoomのURLが入って来るのでそれを取ります。

```python
{'accessRole': 'owner',
 'defaultReminders': [{'method': 'popup', 'minutes': 2}],
 'etag': '"xxxxxxx"',
 'items': [{
    {
      'start': {'dateTime': '2021-12-24T13:00:00+09:00', 'timeZone': 'Asia/Tokyo'},
      'summary': '〇〇会議',
      'location': 'https://zoom.us/j/99999?pwd=XXXXXX',
      ...
    }
  }]
```

zoom, Google Meet, Microsoft TeamsでそれぞれURLの取得方法が異なるため、それぞれ対応しています。

#### 4. URLをブラウザで開く

最後に、取得した会議の開始時間が2分以内であれば、MacOS標準のopenコマンドを使ってURLを開きます。私の環境ではopenコマンドにURLが指定された場合はGoogle Chromeが起動するようになっています。

```python
    def open_event_url(url):
        os.system(f"open -a '/Applications/Google Chrome.app' {url}")
```

また、実装方法は割愛しますが、一度ブラウザを開いた会議は二度開かないように、状態をファイルで管理しています。

#### ソースコード全量

こちらで公開しています。

https://github.com/fetaro/gcal_forcerun

### 定期実行

作ったプログラムは、MacOSのcrontabで定期実行します。

`su -` でrootになり、`crontab -e` でcrontabの定義を編集します。

会議は毎時の0分、15分、30分、45分に始まるので、その１分前と２分前にこのツールを動かすようにしています。

```
13,14,28,29,43,44,58,59 * * * * /path/to/python /path/to/gcal_forcerun/main.py >> /tmp/gcal_forcerun.log 2>&1
```



## 結果

このツールのおかげで、いちいち時計を見なくても２分前になれば勝手にブラウザが開くので、会議に遅れなくなりました！


## 後日追記

2024年1月に、Pythonのインストールが不要の、Go言語版のツールを開発しました。こちらから利用できます→https://github.com/fetaro/gcal-run