[Python] Youtubeから音声のみのファイルを作ってみる

in SCT.암호화폐.Crypto5 years ago (edited)

こんにちは、@yasuです。

車で音楽を聴くのために、Youtubeから音声のみをダウンロードしています。これまでは、あるサイトを利用して音声ファイルをダウンロードしていましたが、簡単にできないかと考えてみました^^

こんな機能を作ってみました^^

  • Youtube動画URLを指定して音声のみをダウンロードする
  • ダウンロード中には、プログレスバーを経過を把握できるようにする
  • Youtubeチャンネルの再生リストを指定して、動画URLを取得する
  • ダウンロード中には、サムネイルを表示する

あまり動かしすぎると、Youtubeのサーバから拒否られます。(拒否られました^^)私の場合は、数日間アクセスを休んだらまたできるようになりました。

環境

  • 今回はhttps://repl.it/ ではなくVisual Studio Codeで行います
  • pytube3ライブラリのインストール
    pip install pytube3
  • ワークスペースにdownloadフォルダを作る

コード

from pytube import YouTube,Playlist
import os

#
# YouTubeから音声だけをダウンロードする。
#
# 参考サイト
# 
def downlod_audio(yt):

    try:
        ys = yt.streams.get_audio_only()

        #ダウンロード
        print("Downloading...")
        filepath = ys.download(output_path="./download")
        print("Download completed!!")

        if os.path.exists(filepath):
            root_ext_pair = os.path.splitext(filepath)
            dst = root_ext_pair[0] + ".mp3"
            print(root_ext_pair)
            if os.path.exists(dst):
                os.remove(dst)
            os.rename(filepath, dst)
    except :
            print(sys.exc_info())
    finally:
        pass

#
# プレイリストの動画URLを抽出する。
#
def get_playlist(playlisturl):
    
    from pytube import Playlist
    import re

    playlist = Playlist(playlisturl)

    playlist._video_regex = re.compile(r"\"url\":\"(/watch\?v=[\w-]*)")
    print(len(playlist.video_urls))
    for url in playlist.video_urls:
        print(url)

    return playlist.video_urls

def getImageByUrl(thumbnail_url):
    from PIL import Image, ImageTk
    from urllib.request import urlopen
    from io import BytesIO

    with urlopen(thumbnail_url) as f:
        raw_data = f.read()

    im = Image.open(BytesIO(raw_data))
    resize_image = im.resize((200,200))
    photo2 = ImageTk.PhotoImage(resize_image)

    return photo2


from tkinter import simpledialog
# 
# 入力ダイアログ
# 
class MyDialog(simpledialog.Dialog): 

    def body(self, master): 
        #self.geometry("800x600")
        self.label = Label(master, text="プレイリストのURLを入力してください。")
        self.label.pack(anchor="nw")

        self.entry = Entry(master,width=80 )
        self.entry.pack()

        #self.entry.insert(0,"https://www.youtube.com/playlist?list=PLfxuH4AnuITJ5Y3TLnVrlYmSED2GHKvwL")
        self.entry.insert(0,"https://www.youtube.com/playlist?list=PLfxuH4AnuITKgM38P9NLBPxLv-4NSxOcJ")
        
        return self.entry # initial focus 

    def apply(self): 
        first = self.entry.get()
        print (first) 
        #return first
        self.result = first


#
# メイン
#
import os
import tkinter.ttk as ttk
from tkinter import *

root = Tk()
root.title("Youtubeから動画の音声をダウンロードする")
root.geometry("640x480")

def command_run_download():
    s = txt.get("1.0","end")
    lines = [x for x in s.splitlines(False) if x != ""]

    print("■lines",lines)

    p_var.set(1)
    progress_bar.update()

    for line in enumerate(lines):
        
        yt = None

        try:
            print("■line",line)

            yt = YouTube(line[1])

            #-----------------
            #global photo
            print(yt.thumbnail_url) 
            photo = getImageByUrl(yt.thumbnail_url)
            label_photo.config(image=photo)
            label_photo.update()
            #-----------------

            downlod_audio(yt)
            #downlod_video(yt)

            p_var.set(100 / len(lines) * (line[0]+1))
            progress_bar.update()

        except:
            print(sys.exc_info())
        finally:
            pass

    p_var.set(100)
    
def command_get_playlist():

    from tkinter import simpledialog
    
    d = MyDialog(root) #added this 
   
    print(d.result)

    playlisturl = d.result
    video_urls = get_playlist(playlisturl)

    for url in video_urls:
        txt.insert(END,url+"\n")

#
# メイン
#
menu = Menu(root)

menu_file = Menu(menu, tearoff=0)
menu_file.add_command(label = "終了", command=root.quit)
menu.add_cascade(label="ファイル", menu=menu_file)

menu_tool = Menu(menu, tearoff=0)
menu_tool.add_command(label = "プレイリストから動画を抽出する", command=command_get_playlist)
menu.add_cascade(label="ツール", menu=menu_tool)

#
#
#
top_frame = Frame(root)
top_frame.pack(side="top",fill="both" ,expand=True, padx=5,pady=5)


lbl = Label(top_frame,text="YoutubeのURLを記述してください。")
lbl.pack(side="top",anchor = 'nw')

label_photo = Label(top_frame)
label_photo.pack(side="right",anchor = 'n')

#スクロールバー
scrollbar = Scrollbar(top_frame)
scrollbar.pack(side="right",fill="y")

txt = Text(top_frame, yscrollcommand=scrollbar.set)
txt.pack(side="left",fill="both",expand = True)

scrollbar.config(command=txt.yview)

#
#プログレスフレーム
#
progress_frame = LabelFrame(root,text="進行状況")
progress_frame.pack(fill="x", padx=5,pady=5,ipady=5)

p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame,maximum=100,variable=p_var)
progress_bar.pack(fill="x",padx=5,pady=5)

#
#ボタン
#
run_frame = Frame(root)
run_frame.pack(fill="x",padx=5,pady=5)

btn_close = Button(run_frame, padx=5,pady=5,text="閉じる",width=12,command=root.quit)
btn_close.pack(side="right",padx=5,pady=5)

btn_start = Button(run_frame, padx=5,pady=5,text="ダウンロード開始",width=15,command=command_run_download)
btn_start.pack(side="right",padx=5,pady=5)

root.config(menu=menu)
root.mainloop()

動作結果

image.png

参考

Youtubeチャンネルの再生リストのURL取得方法

Sort:  

@yasu transfered 0.5 KRWP to @krwp.burn. voting percent : 6.77%, voting power : 60.03%, steem power : 1937084.07, STU KRW : 1200.
@yasu staking status : 250 KRWP
@yasu limit for KRWP voting service : 0.5 KRWP (rate : 0.002)
What you sent : 0.5 KRWP [47652071 - 01901a5fa16433e5aa76dd706e7fc3a4c38b2fd0]

Coin Marketplace

STEEM 0.13
TRX 0.34
JST 0.033
BTC 122587.47
ETH 4505.25
SBD 0.79