【Python】LINEからYoutubeの曲や動画を落としたい1/3

#概要
・[【Python】LINEからYoutubeの曲や動画を落としたい1/3](https://qiita.com/Trusted_Dream/items/9e1019efe2a14b6e5199)
・[【Python】LINEからYoutubeの曲や動画を落としたい2/3](https://qiita.com/Trusted_Dream/items/b02e8d84e149b15280bc)
・[【Python】LINEからYoutubeの曲や動画を落としたい3/3](https://qiita.com/Trusted_Dream/items/f564041ce8c6cb7f3513)

・[GitHub](https://github.com/Trusted-Dream/Media-Downloader_for_LINE)へアップロードしました。

・Zennの記事の方が最新です。
https://zenn.dev/trusted_dream/articles/6fbb229fb71216

##経緯について
Androidに曲を落としたいがYoutubeの曲落とすアプリだと広告うざい。
かと言ってWEBから落とせるのもあるが、ずっと変換終わるまで待たないといけない。
もういっそ、自分でアレンジして作ってみようって考えた末、開発に至りました。

#本プログラムについて
・Youtubeの曲、SoundCloud、ニコニコ動画に対応しています。
・Youtubeのプレイリストからでも曲、動画の複数ダウンロードに対応しています。
・データはGoogleDrive上に保管されます。
・LINEを閉じようが何しようが、一旦コマンドを送れば自動的に処理が終わります。
・LINE MessageAPIとWebhook、GoogleDriveAPI、Youtube-dlを使用します。
・さくらのVPSサーバを使用しています。

#出来上がりの状態
![出来上がり](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672611/9931e2f6-5ac8-b824-4a5b-851631d8bfb8.gif)

##仕様について
・SoundCloudのURLで間違って動画を取得しようとした際は取得できないエラーが発生します。
　※ただしプログラムが停止してしまうことはありません。

#前提条件
・[GoogleDriveAPI(GCPを使用)](https://console.cloud.google.com/apis/credentials)が使用できること。[参考にした記事](https://qiita.com/akabei/items/f25e4f79dd7c2f754f0e)
・[LINE MessageAPI](https://developers.line.biz/console/)が使用できること。[参考](https://developers.line.biz/ja/docs/messaging-api/getting-started/#using-console)
・[ngrok](https://ngrok.com/)が利用できること。[参考にした記事](https://qiita.com/mininobu/items/b45dbc70faedf30f484e)
・Pythonの基礎知識があること。(なくてもほぼコピペで動くようには書くつもり)

#動作環境
・Python 3.8.4 (3系なら動く)
・CentOS Linux release 7.8.2003 (Core) (7系ならOK)
・ngrok version 2.3.35
・pip 20.1.1
・line-bot-sdk 1.16.0
・google-api-python-client 1.9.3
・PyDrive 1.3.1
・youtube-dl 2020.06.16.1
・Flask 1.1.2
・ffmpeg 3.4.8
・httplib 0.18.1

~~**・httplib 0.15.0 (最新の0.16.0では大きい動画だとGoogleDriveへアップロード時に以下のエラーが出ます)**
`Redirected but the response is missing a Location: header.` [詳細はこちら](https://github.com/googleapis/google-api-python-client/issues/803)~~
2020/07/22 0.18.1が来てました。こちらでは問題なく動いたようです。
#ディレクトリ構造
```
$HOME/
   ┝ line/
       ┝ app.py
       ┝ youtube.py
       ┝ start.sh
       ┝ credentials.json
       ┝ settings.yaml
       ┕ youtube/
              ┕ sound.mp3,movie.mp4
```

##実装に必要なライブラリ等のインストール
```
# pip install line-bot-sdk
# pip install google-api-python-client
# pip install PyDrive
# pip install youtube-dl
//最新にアップデート推奨
# pip install -U httplib
```
以下から一般ユーザーで作成しています。
##ディレクトリ作成
```console
$ mkdir $HOME/line/youtube
$ cd $HOME/line
```

では早速、youtube-dlのプログラムから作成していきます。
オプション設定については[こちら](https://github.com/ytdl-org/youtube-dl/blob/3e4cedf9e8cd3157df2457df7274d0c842421945/youtube_dl/YoutubeDL.py#L137-L312)をご参考ください。

##youtube.pyの作成
```console
$ vim youtube.py
```
```youtube.py
#!/bin/env python3
import youtube_dl
import sys
import os
import re
from glob import glob

def option_setting(opt,dl_dir):
    options = {
        'outtmpl':dl_dir + '%(title)s.%(ext)s',
        'restrictfilenames':'True',
        'quiet':'True',
        'default_search':'error'
    }
    options.update(opt)
    return options

def download(option,url):
    try:
        with youtube_dl.YoutubeDL(option) as ydl: ydl.download([url])
    except Exception as e:
        return e

def convert(op,files):
    ext_dict = {
        '.m4a' : ['ffmpeg -y -i "%s" -ab 256k "%s" -loglevel quiet','/mp3'],
        '.mp4' : ['ffmpeg -y -i "%s" -ab 256k "%s" -loglevel quiet','/mp3'],
        '.webm': ['ffmpeg -y -i "%s" "%s" -loglevel quiet','/mov'],
        '.mkv' : ['ffmpeg -y -i "%s" -vcodec copy "%s" -loglevel quiet','/mov'],
    }
    root, ext = os.path.splitext(files)
    formats = ext_dict.get(ext)
    if formats != None and formats[1] == op:
        if ext != ".mp4" and op == "/mov":
            cnv_mp4 = '%s.mp4' % root
            cmd = formats[0] % (root+ext, cnv_mp4)
            os.system(cmd)
            os.remove(root+ext)

        else:
            cnv_mp3 = '%s.mp3' % root
            cmd = formats[0] % (root+ext, cnv_mp3)
            os.system(cmd)
            os.remove(root+ext)

def main(operation,url,dl_dir):
    #ニコニコ動画は変換なし
    if "nicovideo" in url:
        opt = {}
    elif operation == "/mp3":
        opt = ({'format':'bestaudio[ext=mp3]/bestaudio[ext=m4a]/bestaudio'})
    elif operation == "/mov" or operation == "/nomov":
        opt = ({'format':'bestvideo+bestaudio'})

    option = option_setting(opt,dl_dir)
    msg = download(option,url)
    if "retries" in str(msg):
        while True:
            msg = download(option,url)
            if not "retries" in str(msg):
                break

    if operation == "/mp3" or operation == "/mov":
        fileExtensions = [ "mp4", "m4a","mkv","webm"]
        files_grabbed = []
        for ext in fileExtensions:
            files_grabbed.extend(glob(dl_dir + "*." + ext))

        for cnv_file in files_grabbed:
            convert (operation,cnv_file)

    all_file = [f.strip(dl_dir) for f in glob(dl_dir + "*.*")]
#    print (all_file)
    return all_file
#if __name__ == "__main__":
#    dl_dir = "youtube/"
#    main("/mp3","https://www.youtube.com/watch?v=9swXEd6SWjA",dl_dir)
```
下部の4つのコメント部分を外して実際に動くか確認してみるといいです。
フリーBGMの[Shall we meet?.mp3]が取得できればまずは成功です。

※/nomovについては動画変換なしにそのままアップロードする機能です。

今回は一旦ここまでとします。[次回](https://qiita.com/Trusted_Dream/items/b02e8d84e149b15280bc)はこのyoutube-dlを使ってプログラムを組んでいきます。