Zoomミーティング予定をSlackに流し、Zoom APIを用いて通知しようとしたけどうまくいかなかった話

## はじめに

&emsp;山形大学大学院修士1年のHagianです。この記事は[Qiita Engineer Festa 2022 「Zoom API/SDKを使ってみよう！」](https://qiita.com/official-events/86d8555146e1b14fef24)に参加するつもり（つもり）で執筆しました。

## やってみたかったこと

&emsp;コロナ禍になってから、大学の講義も一気にオンライン（ミーティングツールを用いたリアルタイム形式）やオンデマンド（資料を参照しながら講義を決められた時間内に受ける形式）等によるものが増えました。最近では講義ごとにPDFファイルなどにまとめられて、ミーティング予定が提示されるようになりました。しかし、毎回開いて確認するのが少し ~~面倒~~ 手間だなと感じていました。

&emsp;そこで、このミーティングの予定をSlackに流し、スマホ等の別端末でも確認できるようにしたいと思いました。まとめますと以下の通りです。

* PDFの情報をCSVに変換、保存
* ミーティングID・パスコード抽出
* Slackに予約投稿
* ミーティングが始まったらZoom API経由でSlackに通知

## 現実

&emsp;おそらく私の勉強と知識の不足が原因なんですが、やってみたかったことの4番目、「ミーティングが始まったらZoom API経由でSlackに通知」が今日までに実現できませんでした... ~~（Zoom APIを使った技術といえない気が…）~~

&emsp;当初の予定では、Zoom Webhookを用いてミーティング開始を検知し、これをSlackに投稿して通知する仕組みを実装するつもりでした。

&emsp;とっても悔しいのですが、Slackに予約投稿するところまでは実装できましたので以下に記します。

## 開発環境

* MacBook Pro (M1, 2020)
* macOS Monterey 12.4
* Python 3.10.5

## 実装

### PDFの情報をCSVに変換、保存
&emsp;今回、想定しているPDFは以下のような形式です。また、毎週同じ時間に開かれるオンライン授業を想定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021972/41c15f95-0e2c-5272-b4e7-4c3f16980485.png)
上のようなPDFの情報をCSVに変換、保存します。

&emsp;PDFから情報を取り出してPythonで処理する方法にはいくつかあるのですが、今回は```tabula```というライブラリを用いました。ライブラリの紹介はここでは省きますが、以下の記事を参考に実装しました。

https://qiita.com/OgawaHideyuki/items/5e474976b6d85f1029dc

&emsp;実装例は以下のとおりです。

```python:pdf2csv.py
import tabula

#PDFファイルパス
PDFPATH = f"PDFファイルへのパス"

#PDFの読み込み
read_pdf = tabula.read_pdf(PDFPATH, stream=True, pages="all", encoding='utf-8')

#読み込んだPDFを確認
print(read_pdf[0])

#CSVへ出力
for out in read_pdf:
    out.to_csv("result.csv", index=None)
```


&emsp;```tabula```を用いて読み込んだPDFは```pandas.dataframe```形式になります。

### ミーティングID・パスコード抽出

&emsp;保存したCSVから必要な情報（ここでは日付とミーティングID、パスコード）を抽出したのち、ミーティング1つずつ、それぞれの値をリストに格納します。現在時刻とミーティング日の差から、未来のミーティングのみを検出します。

&emsp;リマインダー機能を実装したかったため、2日以内に始まるミーティングのみSlackで通知するようにしました。実装例は以下のとおりです。

```python:csv2reminder.py
import pandas as pd
import datetime

# ミーティング情報抽出
df = pd.read_csv("result.csv", header=0, usecols=["日程", "zoom ID", "password"])

# 実行日の日付取得
dt_now = datetime.date.today()

# 日時・ID・PWの値を格納
for row in df.values:
    row = list(row)
    if type(row[0]) == str and type(row[2]) == str:
        date_str = row[0]
        mid = row[1]
        passc = row[2]
        date_str = datetime.datetime.strptime(date_str, f"%m月%d日")
        date_str = datetime.date(dt_now.year,date_str.month,date_str.day)
        countdown = date_str-dt_now
        if 0 < countdown.days <= 2:
             minfo = str(str(date_str)+"　10:30~12:00\nミーティングID："+mid+"\nパスコード："+passc+"\n")
        else:
             pass
    else:
        pass
```

&emsp;上記例では授業が午前10時半から12時に行われると仮定して、実装しています。

### Slackに予約投稿

&emsp;SlackBotを作成し、APIを用いて予約投稿を行います。SlackBotの作成にも何種類か方法がありますが、今回はSlack公式提供のSDKを用いました。様々なところで方法の解説がされているので、大まかな流れは記しませんが、実装にあたって以下の記事を参考にしました。

https://zenn.dev/kou_pg_0131/articles/slack-api-post-message

https://qiita.com/seratch/items/93714b5cf3974c2f5327

&emsp;予約投稿にあたっては、APIの ```chat.scheduleMessage```メソッドを用いました。

https://api.slack.com/methods/chat.scheduleMessage

&emsp;投稿時間はUNIX時間で指定する必要があるため、Pythonの```datetime.datetime.now().timestamp()```でUNIX時間に変換しました。この値は小数点を含むため、```round```関数で丸めて最小単位を1秒にしました。

&emsp;この部分のPythonでの実装例は以下のとおりです。
```python:reservedmessage.py
from slack_sdk import WebClient
import datetime

api_token = "ここに Bot User OAuth Tokenを記入"
client = WebClient(api_token)
# 下記の例では3600秒後（1時間後）に投稿
reserve_time = round(datetime.datetime.now().timestamp())+3600
res = client.chat_scheduleMessage(
    channel="チャンネルID、もしくは'#'に続けてチャンネル名を記入",
    text="ここに投稿したいメッセージを入力",
    post_at=reserve_time
    )
```

## まとめ

&emsp;ここまでのプロセスを関数として部分ごとにまとめ、以下のように実装しました。

```python:zoomreminder.py

import tabula
from slack_sdk import WebClient
import datetime
import pandas as pd



def pdf2csv():

    #PDFファイルパス
    PDFPATH = "PDFファイルへのパス"

    #PDFの読み込み
    read_pdf = tabula.read_pdf(PDFPATH, stream=True,pages="all", encoding='utf-8')

    #CSVへ出力
    for out in read_pdf:
        out.to_csv("result.csv", index=None)


def reservedmessage(data):
    api_token = "ここに Bot User OAuth Tokenを記入"
    client = WebClient(api_token)
    reserve_time = round(datetime.datetime.now().timestamp())+3600
    res = client.chat_scheduleMessage(
        channel="チャンネルID、もしくは'#'に続けてチャンネル名を記入",
        text=data,
        post_at=reserve_time
    )


def csv2reminder():

    # ミーティング情報抽出
    df = pd.read_csv("result.csv", header=0, usecols=["日程", "zoom ID", "password"])

    # 実行日の日付取得
    dt_now = datetime.date.today()

    # 日時・ID・PWの値を格納
    for row in df.values:
        row = list(row)
        if type(row[0]) == str and type(row[2]) == str:
            date_str = row[0]
            mid = row[1]
            passc = row[2]
            #print(date_str, mid, passc)
            date_str = datetime.datetime.strptime(date_str, f"%m月%d日")
            date_str = datetime.date(dt_now.year,date_str.month,date_str.day)
            countdown = date_str-dt_now
            if 0 < countdown.days <= 2:
                #print(str(date_str)+"\n","ミーティングID："+mid+"\n","パスコード："+passc+"\n")
                minfo = str(str(date_str)+"　10:30~12:00\nミーティングID："+mid+"\nパスコード："+passc+"\n")
                reservedmessage(minfo)
            else:
                pass
        else:
            pass

if __name__ == "__main__":
    pdf2csv()
    csv2reminder()
```

&emsp;以下の画像は実行した際、Slackに投稿されたメッセージです（情報保護の観点からID・パスコードは加工しています）。
![unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021972/1a59ac7f-f755-58e3-cbb7-640068a107bc.png)

&emsp;これでパソコンでZoomとPDFを行ったり来たりせず、スマホのSlackを参照しながらZoomに入ることができます☆

## おわりに

&emsp;とりあえずリマインダー機能を実装することはできましたが、ミーティングが始まったらZoom Webhookを通じてSlackに投稿する機能、近いうちに実装したいと思います。