複数のYouTube動画のいいね数を取得してLINEグループに通知するようにする

# 本題に関係ある前置き

本職はバックエンドエンジニアですが、趣味でスティールパンという楽器をやっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/76998402-4bb2-4907-8941-45504afee9a4.png)


こういう打楽器です。`ディズニーのリトルマーメイドの曲の中でポロンポロン陽気な音を鳴らしてる楽器` というと8割くらいの人が「あー、あれね」となんとなくわかってくれます。

## SuperOTONA Fes. 2025の本戦出場に挑戦中
このスティールパンを使ったバンドである pangie に所属していまして、2025年3月22日現在、 [SuperOTONA Fes. 2025](https://kidoairaku.club/super-otona-fes/2025/) の出場をかけて二次審査に挑戦中です。

### YouTube動画のいいね数の上位5組が本戦出場
[イベント主催者様のYouTubeチャンネル](https://www.youtube.com/@%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%81%8A%E3%81%A8%E3%81%AA%E3%83%95%E3%82%A7%E3%82%B9%E5%85%AC%E5%BC%8F%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB)で、同じく二次審査挑戦中のバンドの動画が公開されており、3月31日までの間にいいね数が多かった上位5バンドが本戦出場というルールになっています。

### 毎日各バンドのいいね数を見るのはちょっと大変
私の所属する pangie ですが、現在のところ8位前後をうろうろしており、上位5バンドに入るか際どいところです。気になって他のバンドのいいね数を見るんですが、出場バンド数が結構あって全部をチェックするのは大変なので自動化することにしました。

# 全バンドのいいね数を取得できるようにしてみた
ということで本題です。

## 事前準備: YouTube Data APIを使う
GCPで適当なプロジェクトを作成したあと、まずはYouTube Data APIv3を有効化します。
`有効なAPIとサービス` -> `APIとサービスを有効にする` としていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/f3ddfbd9-b061-447c-974f-163b655cb8d9.png)

API ライブラリから `youtube` で検索すると `youtube data api v3` が出てくるので選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/f5d1649f-3e1a-4980-9a89-5f023962be1c.png)

選択画面で有効化したあと、 `管理` -> `認証情報` と移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/e668a5f2-19cf-4be7-85bb-4831772e29a1.png)

上図右下の `認証情報を作成` をクリックし `APIキー` を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/023f35c0-c605-44aa-a8b8-eaf84f72f3f5.png)

APIキーが作成されるのでメモします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/8a530e46-4378-4e3b-bb5c-2542aaa340b9.png)


## いいね数を取得して表示するPythonスクリプトを作成する
YouTube Data APIv3をPythonで使うには google-api-python-client が必要なのでインストールします
```bash
pip install google-api-python-client requests
```

コードは以下です

```python
from googleapiclient.discovery import build

# YouTube APIキーの設定
api_key = "YOUR_API_KEY"

# YouTube APIクライアントを作成
youtube = build('youtube', 'v3', developerKey=api_key)

# 動画IDリストを指定
### 各バンドの動画のID (https://www.youtube.com/watch?v=XXXXX の XXXXX がID）
video_id_list = ["hogehoge", "fugafuga"]


def get_video_likes(video_id):
    # 動画の詳細情報を取得
    request = youtube.videos().list(
        part="statistics,snippet",
        id=video_id
    )
    response = request.execute()

    items = response.get("items", [])
    if not items:
        print("動画が見つかりませんでした。")
        return None
    
    statistics = items[0]["statistics"]
    title = items[0]['snippet']['title']
    like_count = int(statistics.get("likeCount", 0))  # 非公開の場合は0を返す
    
    return [title, like_count]

def find_index(data, target):
    for index, item in enumerate(data):
        if target in item:
            return index + 1  # 順位は1から始まるように調整
    return None


# 各動画のタイトルといいね数を取得しリスト化
video_data = []
for video_id in video_id_list:
    result = get_video_likes(video_id)
    if result:
        video_data.append(result)

# いいね数で降順ソート
video_data.sort(key=lambda x: x[1], reverse=True)

# メッセージを作成
message_lines = []
for rank, (title, likes) in enumerate(video_data, start=1):
    message_lines.append(f"{rank}位: 「{title}」 のいいね数: {likes}")

print(*message_lines, sep="\n")
```
実行するとこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/46766d7b-44ee-4593-aabc-b6db9aace586.png)

我が pangie は8位です…。

```python
    request = youtube.videos().list(
        part="statistics,snippet",
        id=video_id
    )
```
上記のようにYouTube Data API v3を使うときですが、partに何を指定するかで取れる情報が変わってきます。
* snippet には「いいね数」
* statistics には動画タイトル

が含まれています。

今回主催者様側のYouTubeチャンネルで動画タイトル＝バンド名としてくれていたので動画タイトルをまんま取得しています。

# 結果をLINEグループに送るようにする
SuperOTONA Fes. 2025に関する連絡はLINEグループで行っていたので結果をLINEに通知するようにしました。
## 事前準備: 公式アカウントを作成し、チャンネルトークンを取得
通知には公式アカウントが必要になります。いろんな方が書いている記事がありますので割愛しますがざっと以下の手順です。
* LINE Developersで公式アカウントを作成
* LINE DevelopersコンソールでMessaging APIチャネルを作成し、チャネルアクセストークンを取得
* 「グループチャットへの参加を許可する」を有効化
* 作成した公式アカウントをやり取りしているLINEグループに招待
* グループ内でメッセージを送信し、WebhookイベントからgroupIdを取得する

groupIdの取得については https://qiita.com/enbanbunbun123/items/2504687e4b6c13a289db を参考にさせていただきました。

## 結果をLINE通知するように修正
まず  line-bot-sdk をインストールします
```bash
pip install line-bot-sdk
```

修正したソースが以下です
```python
from googleapiclient.discovery import build
from linebot import LineBotApi
from linebot.models import TextSendMessage

# YouTube APIキーとLINE Messaging APIの設定
api_key = "YOUR_API_KEY"
line_access_token = "YOUR_LINE_ACCESS_TOKEN"  # LINEチャネルアクセストークン
line_user_id = "YOUR_LINE_GROUP_ID"  # LINEユーザーID（またはグループID）

# YouTube APIクライアントを作成
youtube = build('youtube', 'v3', developerKey=api_key)

# 動画IDリストを指定
### 各バンドの動画のID (https://www.youtube.com/watch?v=XXXXX の XXXXX がID）
video_id_list = ["hogehoge", "fugafuga"]

# LINE Bot APIのインスタンスを作成
line_bot_api = LineBotApi(line_access_token)

def get_video_likes(video_id):
    # 動画の詳細情報を取得（statisticsにいいね数が含まれる）
    request = youtube.videos().list(
        part="statistics,snippet",
        id=video_id
    )
    response = request.execute()

    items = response.get("items", [])
    if not items:
        print("動画が見つかりませんでした。")
        return None
    
    statistics = items[0]["statistics"]
    title = items[0]['snippet']['title']
    like_count = int(statistics.get("likeCount", 0))  # 非公開の場合は0を返す
    
    return [title, like_count]

def find_index(data, target):
    for index, item in enumerate(data):
        if target in item:
            return index + 1  # 順位は1から始まるように調整
    return None

def send_line_notification(message):
    try:
        line_bot_api.push_message(line_user_id, TextSendMessage(text=message))
        print("LINE通知を送信しました。")
    except Exception as e:
        print(f"LINE通知の送信に失敗しました: {e}")

# 各動画のタイトルといいね数を取得しリスト化
video_data = []
for video_id in video_id_list:
    result = get_video_likes(video_id)
    if result:
        video_data.append(result)

# いいね数で降順ソート
video_data.sort(key=lambda x: x[1], reverse=True)

# 結果を表示し、LINEに通知するメッセージを作成
message_lines = []
for rank, (title, likes) in enumerate(video_data, start=1):
    message_lines.append(f"{rank}位: 「{title}」 のいいね数: {likes}")

pangie_rank = find_index(video_data, 'pangie')
if pangie_rank:
    message_lines.append(f"\npangieは現在{pangie_rank}位です")
else:
    message_lines.append("\npangieはランキングにありません")

# LINE通知の送信
final_message = "\n".join(message_lines)
send_line_notification(final_message)
```

ついでに pangie の現在ランクも表示されるよう修正しています。

実行した結果が以下です
![Screenshot_20250322-093027.LINE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294409/1155c750-6307-4f4d-8e6f-eba100997112.png)

これで毎日頑張って各バンドのいいね数をチェックしにいかなくてよくなりました。

# 定期実行どうしよう

最終的には AWS Lambda + EventBridge に置き換えたんですが、直近面倒だったので自PCのcrontab に仕掛けました。
```
0 8 * * * /usr/bin/python3 /home/shun/otonafes_notification.py
```
家のPCつけっぱなし＆普段からLinux使いなのでできた技かなと思っています。
最近だとWindowsのWSL2とかでも同じことできるのかな？

Macは触ったことないので知りません。（会社の後輩に「いつMac買うんですか？」と言われ続けたので意地でもMacは買わないと決めています。たまに欲しくなるけど）

# 最後に
ということで、我がスティールパンバンド pangie、SuperOTONA Fes.2025本戦出場を目指しております！よければ動画にいいねお願いします！
https://www.youtube.com/watch?v=O0eDCZpEJpE

# 参考資料
https://qiita.com/enbanbunbun123/items/2504687e4b6c13a289db