Youtube Data APIとPythonを使ってYoutube Music用の音楽プレイリストを作る

##はじめに
Youtube Musicで自分の好きな音楽をプレイリストとして再生することを目標としています。
Youtube Music用のAPIは無いのでYoutube Data API経由でプレイリストを作成します。

##環境
Windows 10
Python 3.9.6（Python3系なら多分動作します）
##準備
###APIの有効化
Youtube Data API v3を事前に有効化しておく必要があります。
https://console.developers.google.com
より「プロダクトとリソースの検索」→「Youtube」で検索→「YouTube Data API v3」→「有効にする」
###APIキーの生成
続いてAPIを使用するためにAPIキーを作成します。
「認証情報」→「認証情報を作成」→「APIキー」にて作成できます。
これで作成できるのですが、実際に運用する際には「APIキーを編集」より制限をかけておきましょう。
固定IPの自宅からのみ使うのであればIPアドレス制限をかけるのが一番良いと思われます。他にも使用するAPIを制限できるのでYoutubeのみAPI操作をするだけであれば「YouTube Data API v3」を指定しておくのが良いでしょう。
###必要なパッケージをインストール
Youtube APIに限らず、Google系のAPIをPythonで使用する時にはGoogle公式で提供されているPythonクライアントライブラリを用いるのが便利です。

```
pip install google-api-python-client
```

##動画を検索する
Search: listを使用します。
APIの返り値はdictなのでjsonモジュールで整形できます。
公式ドキュメント
https://developers.google.com/youtube/v3/docs/search/list?hl=ja

```Py
import json

from googleapiclient.discovery import build  
#公式ではapiclient.discoveryだがVSCodeの補完を働かせるために変更

YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
YOUTUBE_API_KEY = "Your-API-Key"

youtube = build(YOUTUBE_API_SERVICE_NAME,
                YOUTUBE_API_VERSION,
                developerKey=YOUTUBE_API_KEY)

def youtube_search(youtube, word):
    response = youtube.search().list(part="snippet",
                                     q=word,
                                     type="video",
                                     videoCategoryId="10"  # videoCategoryIdもstr型
                                     ).execute()
    print(type(response))  # <class 'dict'>
    for item in response.get('items', []):
        print(item["snippet"]["title"], item["id"]["videoId"])


search_word = "夜に駆ける"
youtube_search(youtube, search_word)
```

```
YOASOBI - 夜に駆ける / THE HOME TAKE j1hft9Wjq9U
YOASOBI LIVE [夜に駆ける] Yoru ni Kakeru | YOASOBI 1st LIVE [KEEP OUT THEATER] HD 1080p 4bCvy49cst4
YOASOBI「夜に駆ける」 Official Music Video x8VYWazR5mE
【歌詞付き･超高音質】夜に駆ける　えふてぃー J7Ft5vGaQKI
YOASOBI 「Into The Night」 （夜に駆ける 英語版） フルバージョン English version Vz_sMm7qWM8
```

タイトル、videoIdの順に表示しています。videoIdはプレイリストに追加する時に使用します。videoIdは動画のURLに含まれています。

`https://www.youtube.com/watch?v={videoId}`

ここでvideoCategoryIdは動画のジャンルを示します。
https://developers.google.com/youtube/v3/docs/videoCategories/list?hl=ja
[youtube data API v3 categoryId 一覧](https://qiita.com/taka10257/items/7b3f0582b20467a06de8)

2021年8月現在、上記のidの通りでしたので上記記事を参考にvideoCategoryIdを10とすると音楽のジャンルに属する動画のみが検索できます。
なお、APIを叩くことでもジャンルが得られます。

```Py
response = youtube.videoCategories().list(part="snippet",regionCode="JP").execute()
```

これにて目的の動画の情報が得られました。
デフォルトの上から5番目の情報までで大抵の場合目的の動画が出てくるはずですが、出てこなかった場合はq（検索単語）の調整やorder（表示順）のオプションの付与で対処してみてください。

##OAuth認証を設定する
次にプレイリストへの操作（作成、挿入）を行います。
しかし、**APIキーだけでは本操作を行えません。**
動画の検索だけであれば非Googleユーザーでも可能なのでAPIキーだけで操作可能でしたが、プレイリストへの操作はGoogleユーザーである必要があるのでOAuth認証が必要です。
OAuth認証についての説明は詳しい記事が既にありましたのでこちらを参照していただければと思います。
[APIキー、OAuthクライアントID、サービスアカウントキーの違い:Google APIs](https://messefor.hatenablog.com/entry/2020/10/08/080414#%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95-1)

OAuth認証をするためのライブラリをインストールしておきます。

```
pip install --upgrade google-auth-httplib2 google-auth-oauthlib
```

クライアントシークレットが同一ディレクトリに「client_secret.json」として用意されていることとします。

OAuth認証方法は公式ドキュメントに載っているのでそれを使用します。
[Python Quickstart](https://developers.google.com/drive/api/v3/quickstart/python#step_3_set_up_the_sample)

```Py
import os

from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

CLIENT_SECRET_FILE = "client_secret.json"
SCOPE = "https://www.googleapis.com/auth/youtube"


def OAuth_credentials(client_secret_file, scopes, token_storage="token.json"):
    creds = None
    # 2回目以降は既存アクセストークンを使用
    if os.path.exists(token_storage):
        creds = Credentials.from_authorized_user_file(token_storage, scopes)

    # 初回認証時処理
    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(
                client_secret_file, scopes=scopes)
            creds = flow.run_local_server(port=0)

        # アクセストークンを保存
        with open(token_storage, 'w') as token:
            token.write(creds.to_json())

    return creds


creds = OAuth_credentials(CLIENT_SECRET_FILE, SCOPE)
```

本プログラムを実行すると、ブラウザが起動して認証を求められるので画面の指示に従います。
完了するとOAuthアクセストークンが生成され、プレイリストへの操作が可能になります。

##プレイリストを作成する
Playlists: insertを使用します。
公式ドキュメント
https://developers.google.com/youtube/v3/docs/playlists/insert

なお、OAuth認証を用いてAPIにアクセスした場合でも動画の検索機能は使用可能です。上位互換と言ってもいいですね。（実際には動画検索だけするならセキュリティの関係でAPIキーを用いるべきです）

```Py
def make_playlist(youtube, playlist_title):
    responce = youtube.playlists().insert(
        part="snippet,status",
        body=dict(
            snippet=dict(
                title=playlist_title,
                description="A private playlist created with the YouTube API v3"
            ),
            status=dict(
                privacyStatus="private"
            )
        )
    ).execute()
    print(responce["id"])  #playlistid


youtube = build("youtube", "v3", credentials=creds)
make_playlist(youtube, "test")
```

プレイリストの作成に成功すると作成したプレイリストについての情報が返ってきます。
今回は後ほど使用するplaylistIdを表示しています。本値はブラウザ上でプレイリストを表示した時のURLに含まれています。
`https://www.youtube.com/playlist?list={playlistId}`

##プレイリストに動画を追加する
PlaylistItems: insertを使用します。
公式ドキュメント
https://developers.google.com/youtube/v3/docs/playlistItems/insert

```Py
def add_to_playlist(youtube, playlistid, videoid):
    response = youtube.playlistItems().insert(
        part="snippet",
        body=dict(
            snippet=dict(
                playlistId=playlistid,
                resourceId=dict(
                    kind="youtube#video",
                    videoId=videoid
                )
            )
        )
    ).execute()
    print(response)


add_to_playlist(youtube, playlistId, videoId)
```

playlistidはプレイリストを作成した時に得られた値、
追加に成功すると追加した動画についての情報がjsonとして帰ってきます。