【Python】LINEからYoutubeの曲や動画を落としたい2/3
概要
・【Python】LINEからYoutubeの曲や動画を落としたい1/3
・【Python】LINEからYoutubeの曲や動画を落としたい2/3
・【Python】LINEからYoutubeの曲や動画を落としたい3/3
・Githubへアップロードしました。
・その他
マルチプロセス+ノンブロッキング処理
LINEへの返答、GoogleDriveへのアップロード部分の作成
前回では、youtubeやsoundcloud、ニコニコ動画に対応するダウンローダーのプログラムを作成しました。
今回はyoutube-dlを使い実際にLINEに応答を返したりGoogleDriveへアップロードする部分を作成します。
まず、始める前にGoogleDriveへアップロードできるか確認しておきましょう。
GoogleDriveへのアップロードができるか確認する(手順は大きく3つ)
①GoogleDriveで共有のフォルダを一つ作成する。
GoogleDrive上で右クリック → 新しいフォルダ → 名前を入力 → 名前を付けたフォルダを右クリック →
共有可能なリンクを取得 → [制限付き▼]をクリック → リンクを知っている全員に変えておく。
※ここを変えておかないと、LINEから直接音楽を聴いたりができなくなります。
(LINEサーバ上にデータは保管されず、あくまでストリーミングとしてGoogleDrive上の音楽を取得しに行ってるからです。)
②共有フォルダーのフォルダーIDを確認する。
フォルダーを作成できたらそのフォルダを開く → URLを確認 → https://drive.google.com/drive/folders/
以降のランダムな文字列がフォルダーIDになります。
③GoogleDriveへのアップロードを行う部分のテストプログラムを作成して確認する
前回作成したyoutube.pyと同じディレクトリ上で作業します。
・client_idとclient_secret、GoogleDriveAPIの有効化が必要です。参考
※[JSONをダウンロード]も実施して名前を「client_secrets.json」に変更し、$HOME/lineに設置します。
まずはsettings.yamlファイルを作成します
cd $HOME/line
vim settings.yaml
client_config_backend: settings
client_config:
client_id: "ここにGoogleClientID"
client_secret: "ここにSecretID"
save_credentials: True
save_credentials_backend: file
save_credentials_file: credentials.json
get_refresh_token: True
oauth_scope:
- https://www.googleapis.com/auth/drive.file
- https://www.googleapis.com/auth/drive.install
次にyoutube-dlを使用してGoogleDriveへのアップロードまでのプログラム
vim upload.py
#!/bin/env python
import youtube
import os
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
# ダウンロードディレクトリ
dl_dir = "youtube/"
#GoogleFolderID
folder_id = 'フォルダーID'
#GoogleDrive認証設定
gauth = GoogleAuth()
gauth.CommandLineAuth()
drive = GoogleDrive(gauth)
message = "/mp3 GoogleDriveへアップロードしたいyoutubeの曲"
url = message.split()[1]
transaction = message.split()[0]
file_name = youtube.main(transaction,url,dl_dir)
for i in range(len(file_name)):
f = drive.CreateFile({'title': file_name[i],
'mimeType': 'audio/mpeg',
'parents': [{'kind': 'drive#fileLink', 'id':folder_id}]})
f.SetContentFile(dl_dir + f['title'])
#UploadGoogleDrive
f.Upload()
ここまでできたら、実行してアップロードできるか確認してみましょう。
$ chmod +x upload.py
$ ./upload.py
問題なくアップロードできたら、次にLINE BOTアプリを作成していきます。
LINE BOTアプリを作成する
環境変数に登録する
//未登録であることを確認
export -p
//登録を実施
echo 'export LINE_CHANNEL_ACCESS_TOKEN="ここにアクセストークン"' >> ~/.bash_profile
echo 'export LINE_CHANNEL_SECRET="ここにチャンネルシークレット"' >> ~/.bash_profile
source ~/.bash_profile
//登録されていることを確認
export -p
アプリの作成
vim app.py
#!/bin/env python
import os
import re
import youtube
import math
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
AudioSendMessage
)
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from mutagen.mp3 import MP3
# アプリケーションフレームワーク
app = Flask(__name__)
#LINE Channel Secret
LINE_CHANNEL_SECRET = os.environ['LINE_CHANNEL_SECRET']
#LINE Access Token
LINE_CHANNEL_ACCESS_TOKEN = os.environ['LINE_CHANNEL_ACCESS_TOKEN']
line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(LINE_CHANNEL_SECRET)
# DownloadDirectory
dl_dir = "youtube/"
os.makedirs(dl_dir, exist_ok=True)
# GoogleDriveAuthSettings
gauth = GoogleAuth()
gauth.CommandLineAuth()
drive = GoogleDrive(gauth)
#GoogleFolderShareID
folder_id = 'GoogleDriveの共有フォルダーIDを記入'
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
# Message
def messagebox(event,transaction,url):
transaction_dict = {
'/mp3':'曲',
'/mov':'本の動画',
'/nomov':'本の動画'
}
set_transaction = transaction_dict.get(transaction)
if "&list=" in url:
line_bot_api.reply_message(event.reply_token,
TextSendMessage(text="プレイリストの" + set_transaction
+ "をGoogleDriveにアップロードします。\n"
+ "処理に時間が掛かる場合があります。"))
elif "nicovideo" in url:
line_bot_api.reply_message(event.reply_token,
TextSendMessage(text="ニコニコ動画は処理に時間が掛かる場合があります。"))
else:
line_bot_api.reply_message(event.reply_token,
TextSendMessage(text="1" + set_transaction + "をGoogleDriveにアップロードします。"))
# Music
def music(get_id,file_name):
for i in range(len(file_name)):
f = drive.CreateFile({'title': file_name[i],
'mimeType': 'audio/mpeg',
'parents': [{'kind': 'drive#fileLink', 'id':folder_id}]})
f.SetContentFile(dl_dir + f['title'])
#UploadGoogleDrive
f.Upload()
file_id = drive.ListFile({'q': 'title =\"' + file_name[i] + '\"'}).GetList()[0]['id']
if len(file_name) == 1 :
file_length = MP3(dl_dir + file_name[i]).info.length
link = "https://drive.google.com/uc?export=view&id=" + file_id
dur = math.floor(file_length * 1000)
line_bot_api.push_message(get_id,messages=(
TextSendMessage(text=file_name[i]),
AudioSendMessage(original_content_url=link,duration=dur)))
line_bot_api.push_message(get_id,messages=(TextSendMessage(text=link)))
os.remove(dl_dir + file_name[i])
break
os.remove(dl_dir + file_name[i])
else:
line_bot_api.push_message(get_id,messages=(
TextSendMessage(text=str(len(file_name))
+ "曲をGoogleDriveにアップロードしました。\n"
+ "https://drive.google.com/drive/folders/" + folder_id)))
# Video
def video(get_id,file_name):
video_ext_dicts = {
'.mp4':'video/mp4',
'.webm':'video/webm',
'.mkv':'video/x-matroska'
}
for i in range(len(file_name)):
root, ext = os.path.splitext(file_name[i])
mimeType = video_ext_dicts.get(ext)
f = drive.CreateFile({'title': file_name[i],
'mimeType': mimeType,
'parents': [{'kind': 'drive#fileLink', 'id':folder_id}]})
f.SetContentFile(dl_dir + f['title'])
#UploadGoogleDrive
f.Upload()
os.remove(dl_dir + file_name[i])
line_bot_api.push_message(get_id,messages=(
TextSendMessage(text=str(len(file_name))
+ "本をGoogleDriveにアップロードしました。\n"
+ "https://drive.google.com/drive/folders/" + folder_id)))
@handler.add(MessageEvent, message=(TextMessage))
def contents(event):
#LINE Message
message = event.message.text
try:
get_id = event.source.group_id
except AttributeError:
get_id = event.source.user_id
param = ["/mp3","/mov","/nomov"]
prm = [l for l in param if message.split()[0] in l]
try:
if message.startswith(prm[0]):
url = message.split()[1]
messagebox(event,prm[0],url)
#youtube-dl
file_name = youtube.main(prm[0],url,dl_dir)
if str(file_name) in "ERROR" or file_name == []:
line_bot_api.push_message(get_id,messages=(
TextSendMessage(text="ダウンロード処理に失敗しました。")))
if prm[0] == "/mp3":
music(get_id,file_name)
else:
video(get_id,file_name)
except IndexError: pass
if __name__ == "__main__":
app.run(host="127.0.0.1", port="9000")
ここまでできればほぼ完成です。あとはシェルスクリプトを書いて、挙動を確認して終了です。
ではまた次回でお会いしましょう。
Discussion