PythonでYoutubeの動画を検索して、自動で再生リストに追加するプログラムを作ってみた。

## はじめに
毎週複数の同じ検索ワードで検索しては、再生リストに追加してYoutube動画を見ていました。
それが面倒になり、自動化できないかプログラミングしてみました。

## 環境
- python 3.9.7
- vscode
- youtube api v3
- windows 10
## 仕様
- 7日以内にアップロードされた動画を対象とする
- 各検索ワードに対して、関連度が高い1つの動画を再生リストに追加する
- すでに再生リストに含まれる動画は重複しないようにする
- APIの認証の通し方はhttps://dev.classmethod.jp/articles/oauth2-youtube-data-api/ を参考にした

## 流れ
1. youtubeの認証を通す
1. 7日前の日付を取得する
1. 検索ワードで検索結果を取得する
1. すでに再生リストに含まれるかチェックする
1. 検索された動画を再生リストに追加する
## つまづいたところ
- oauth2clientが非推奨のためか、利用できなかった
    - https://dev.classmethod.jp/articles/oauth2client-is-deprecated/
    - 上記サイトで解決
- CLIENT_SECRETS_FILEは、実行ファイルと同じディレクトリに入れておく
- 検索結果を出す個数はmaxResultsで指定する。
    - 今回の場合、1個にした。
## コード
``` python
import datetime
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

API_SERVICE_NAME = "youtube"
API_VERSION = "v3"
SCOPES = ["https://www.googleapis.com/auth/youtube"]
CLIENT_SECRETS_FILE = 'client_secret_no_fairu_namae.json'
PLAYLIST_ID = "Pureirisuto no id dayo"

KEYWORD_ARRAY =[]
KEYWORD_ARRAY.append('乃木坂')
KEYWORD_ARRAY.append('日向坂')
KEYWORD_ARRAY.append('櫻坂')

# https://dev.classmethod.jp/articles/oauth2client-is-deprecated/ より引用
def get_authenticated_service():
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    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_SECRETS_FILE, SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    return build(API_SERVICE_NAME, API_VERSION, credentials=creds)

def searchVideosByKeywords(youtube,keywords,strLastWeek):
    videoIdArray = []
    for keyword in keywords:    
        searchResponse = youtube.search().list(
            q=keyword,part='snippet',
            type='video',
            regionCode='jp',
            maxResults=1,
            publishedAfter=strLastWeek,
            ).execute()
        sr = searchResponse['items'][0]
        snippetInfo = sr['snippet']
        title = snippetInfo['title']
        channelTitle = snippetInfo['channelTitle']
        videoIdArray.append(sr['id']['videoId'])
    return videoIdArray

def insertVideosIntoPlaylist(youtube,playlistItem_list_response,videoIdArray):
    videoAlready = []
    for item in playlistItem_list_response["items"]:
        videoAlready.append(item["snippet"]["resourceId"]["videoId"])

    for id in videoIdArray:
        if id not in videoAlready:
            playlistItem_insert_response = youtube.playlistItems().insert(
            part="snippet,status",
            body=dict(
                snippet=dict(
                    playlistId=PLAYLIST_ID,
                    resourceId=dict(
                        videoId=id,
                        kind="youtube#video",
                    )
                )
            )
            ).execute()

def main():
        

    youtube = get_authenticated_service()


    dtNow = datetime.datetime.now()
    dtLastWeek = dtNow - datetime.timedelta(days=7)
    strLastWeek = dtLastWeek.strftime(f'%Y-%m-%dT%H:%M:%SZ')

    videoIdArray = searchVideosByKeywords(youtube,KEYWORD_ARRAY,strLastWeek)

    playlistItem_list_response = youtube.playlistItems().list(
        part="snippet",
        playlistId=PLAYLIST_ID,
        maxResults = 50,
    ).execute()

    insertVideosIntoPlaylist(youtube,playlistItem_list_response,videoIdArray)

    print("done")

if __name__ == "__main__":
    main()

```

## 終わりに
これで、動画の収集がはかどりますね！