[Python] TkinterでYoutube Downloaderを作ってみた。

#1.はじめに

TkinterとPytubeを用いて、Youtubeの動画をダウンロードするGUIプロるグラムを作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/d54c757e-6f1c-27e7-5cbf-dc5631b10a72.png)

##2.1.pytyube

Pytubeの設置方法、使い方は下記のリンクを参考にしてください。

https://python-pytube.readthedocs.io/en/latest/

##2.2.Threading導入

GUIの応答性を維持しながら、Freezeするために、Multi-threadingを導入します。

###2.2.1. 生成順番
下記の順番で、Threadを設計します。
StartボタンのCall Back関数　→　Thread生成メソッド　→　実行メソッド

```Python
from threading import Thread

#Call Back関数
def click_me(self):
    self.create_thread()

#Thread生成メソッド
def create_thread(self):
    self.run_thread = Thread( target=self.method_in_a_thread )
    self.run_thread.start()
    print(self.run_thread)

#実行メソッド
def method_in_a_thread(self):
    print('New Thread is Running.')
    self.get_youtube( self.URL_name.get(), self.Folder_name.get())
```
###2.2.2. 呼び出し

```Python
self.btn_Start = tk.Button(self.frame_form, text = 'Start')
self.btn_Start.configure( font= self.font02 )
self.btn_Start.grid( column=1, row=2, padx=20, pady=20, sticky= tk.W + tk.E )
self.btn_Start.configure( command = self.click_me)
```

#3.使い方

ダウンロードするYoutube動画のURLを入力し、ダウンロードするフォルダーを指定します。
そして、Startボタンを押します。
最近、NHK大河ドラマ「麒麟がくる」の解説動画で躍進中のMr.武士道さんの動画を例として挙げます。
https://www.youtube.com/watch?v=NYUYYMs-5UY
ダウンロードした後、プレーヤーで再生する様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/f6719ed3-e633-450f-19a6-804d7129c387.png)


#4.まとめ
1. YoutubeダウンロードにPytubeというモジュールを利用。
2. Tkinterを利用し、GUI化する。
3. GUIの応答性を維持するため、Multi-threadingを導入。

#5.コード

```Python:GUI_youtube.py
from pytube import YouTube
import tkinter as tk

from tkinter import Menu
from tkinter import messagebox as msg
from tkinter import font
from tkinter import filedialog

from tkinter import ttk
import os
from time import sleep
from threading import Thread

class Application(tk.Frame):
    def __init__(self,master):
        super().__init__(master)
        self.pack()

        self.master.geometry("800x500")
        self.master.title("Youtube Downloader")
        self.master.resizable(False, False)

        # ---------------------------------------
        # Favicon
        # ---------------------------------------
        self.iconfile = "./favicon.ico"
        self.master.iconbitmap(default=self.iconfile)
        self.create_widgets()



    def create_widgets(self):


        # ---------------------------------------
        # font
        # ---------------------------------------
        self.font01 = font.Font(family="Helvetica", size=15, weight="normal")
        self.font02 = font.Font(family='Helvetica', size=15, weight='bold')
        self.font03 = font.Font(family='Helvetica', size=30, weight='bold')

        # ---------------------------------------
        # Menu
        # ---------------------------------------
        self.menu_bar = Menu( self.master )
        self.master.config( menu=self.menu_bar )

        self.file_menu = Menu( self.menu_bar, tearoff=0 )
        self.file_menu.add_command( label='Exit', command=self._quit )
        self.menu_bar.add_cascade( label='File', menu=self.file_menu )



        # Add another help menu
        self.help_menu = Menu( self.menu_bar, tearoff=0 )
        self.help_menu.add_command( label='About', command=self._msgBox )  # Display messagebox when clicked
        self.menu_bar.add_cascade( label='Help', menu=self.help_menu )

        # ---------------------------------------
        # Main Label
        # ---------------------------------------
        self.lbl_main = ttk.Label(self.master, text = 'Youtube Downloader', font=self.font03)

        self.lbl_main.place(relx = 0.25, rely = 0.02)

        # ---------------------------------------
        # Frame : URL Input Form, Downloader Folder
        # ---------------------------------------
        self.frame_form = tk.Label(self.master)
        self.frame_form.place(relx = 0.01 , rely = 0.25, height = 400 , width= 780 )
        # ---------------------------------------
        # URL Input Form
        # ---------------------------------------

        self.lbl_URL = ttk.Label(self.frame_form, text = 'URL')
        self.lbl_URL.configure(font=self.font01)
        self.lbl_URL.grid(column=0, row=0, padx = 20, pady= 20)

        self.URL_name = tk.StringVar()

        self.ent_URL = ttk.Entry(self.frame_form, textvariable = self.URL_name)
        self.ent_URL.configure(width = 35, font= self.font01)
        self.ent_URL.grid(column=1, row=0, padx = 20, pady= 20)
        self.ent_URL.focus()


        # ---------------------------------------
        # Download Folder
        # ---------------------------------------

        self.Folder_name = tk.StringVar()

        self.lbl_folder = ttk.Label( self.frame_form, text='Download\n  Folder' )
        self.lbl_folder.configure( font=self.font01 )
        self.lbl_folder.grid( column=0, row=1, padx=20, pady=20 )

        self.ent_Folder = ttk.Entry(self.frame_form,textvariable = self.Folder_name)
        self.ent_Folder.configure(width =35,font= self.font01)
        self.ent_Folder.grid(column=1, row=1, padx=20, pady=20)


        self.btn_Folder = tk.Button( self.frame_form, text = 'Set Folder Path')
        self.btn_Folder.configure(font = self.font02)
        self.btn_Folder.grid(column=2, row=1, padx=20, pady=20, sticky=tk.W + tk.E )
        self.btn_Folder.configure( command= self._get_Folder_Path)



        # ---------------------------------------
        # Start Button
        # ---------------------------------------

        self.btn_Start = tk.Button(self.frame_form, text = 'Start')
        self.btn_Start.configure( font= self.font02 )
        self.btn_Start.grid( column=1, row=2, padx=20, pady=20, sticky= tk.W + tk.E )
        self.btn_Start.configure( command = self.click_me)
        #
        # ---------------------------------------
        # Progress Bar
        # ---------------------------------------

        self.progress_bar = ttk.Progressbar(self.frame_form, orient='horizontal', length=286, mode = 'determinate')
        self.progress_bar.grid(column=1, row=3, padx=20, pady=12,sticky=tk.W + tk.E)


    # ---------------------------------------
    # Create Callback Functions
    # ---------------------------------------

    #Python Treading to prevent GUI freezing.

    def click_me(self):
        self.create_thread()

    def create_thread(self):
        self.run_thread = Thread( target=self.method_in_a_thread )
        self.run_thread.start()
        print(self.run_thread)

    def method_in_a_thread(self):
        print('New Thread is Running.')
        self.get_youtube( self.URL_name.get(), self.Folder_name.get())


    # Display a Message Box
    def _msgBox(self):
        msg.showinfo('Program Information', 'Youtube Downloader with Tkinter \n (c) 2020 Tomomi Research Inc.')

    # Youtube Download Function
    def get_youtube(self, y_url, download_folder):

        #Youtube Instance
        yt = YouTube(y_url)
        yt.streams.filter(progressive=True ,subtype='mp4' ).get_highest_resolution().download( download_folder )

        #progress bar

        self.progress_bar["maximum"] = 100

        for i in range(101):
            sleep(0.05)
            self.progress_bar["value"]= i
            self.progress_bar.update()

    # Exit GUI cleanly
    def _quit(self):
        self.master.quit()
        self.master.destroy()
        exit()

    # Get Folder Path
    def _get_Folder_Path(self):
        iDir = os.path.abspath(os.path.dirname(__file__))
        folder_Path = filedialog.askdirectory(initialdir = iDir)

        self.Folder_name.set(folder_Path)

def main():
    root = tk.Tk()
    app = Application(master=root)#Inherit
    app.mainloop()

if __name__ == "__main__":
    main()


```

#参考資料

1.[pytubeを使ってみよう](https://qiita.com/pycys/items/4ac9c80be216401eb68b)
2.[YouTubeから動画をダウンロードしてくるGUIツール(Python)](https://qiita.com/KMim/items/5583da12d33e913f1c10)
3.[Threading in Tkinter python improve the performance](https://youtu.be/FwKQwx91NAM)