#!/usr/bin/env python3.6
import tkinter as tk
import os.path


from pytube import YouTube
from threading import Thread
from tkinter import filedialog, messagebox, ttk
from download_youtube_video import download_youtube_video
from pytube.exceptions import PytubeError, RegexMatchError


class YouTubeDownloadGUI(tk.Frame):

    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.label_video_title = None
        self.btn_download = None
        self.btn_output_browse = None
        self.btn_check_id = None
        self.text_url = None
        self.text_output_path = None
        self.text_filename_override = None
        self.text_proxy = None
        self.radio_video_audio = []
        self.audio_only = tk.BooleanVar(self)
        self.output_path = tk.StringVar(self)
        self.filename_override = tk.StringVar(self)
        self.proxy = tk.StringVar(self)
        self.video = None
        self.stream = tk.IntVar(self)
        self.streams = []
        self.stream_widgets = []
        self.file_size = 0
        self.progress_bar = None

        self.last_row = 0

        self.create_widgets()

    def create_widgets(self):
        tk.Label(self, text='YouTube URL/ID').grid(row=0, column=0)
        self.text_url = tk.Entry(self, width=60)
        self.text_url.grid(row=0, column=1, columnspan=2)
        self.btn_check_id = tk.Button(self, width=10)
        self.btn_check_id['text'] = 'Check Video'
        self.btn_check_id['command'] = self.check_video
        self.btn_check_id.grid(row=0, column=3)

        tk.Label(self, text='Output Directory').grid(row=1, column=0)
        self.text_output_path = tk.Entry(self, width=60, textvariable=self.output_path)
        self.text_output_path.grid(row=1, column=1, columnspan=2)
        self.btn_output_browse = tk.Button(self, width=10)
        self.btn_output_browse['text'] = 'Browse...'
        self.btn_output_browse['command'] = self.browse_output_path
        self.btn_output_browse.grid(row=1, column=3)

        tk.Label(self, text='Filename Override').grid(row=2, column=0)
        self.text_filename_override = tk.Entry(self, width=60, textvariable=self.filename_override)
        self.text_filename_override.grid(row=2, column=1, columnspan=2)

        tk.Label(self, text='Proxy').grid(row=3, column=0)
        self.text_proxy = tk.Entry(self, width=60, textvariable=self.proxy)
        self.text_proxy.grid(row=3, column=1, columnspan=2)

        tk.Label(self, text='Media Type').grid(row=4, column=0)
        self.radio_video_audio.append(tk.Radiobutton(self, text='Video', variable=self.audio_only,
                                                     value=False, command=self.check_video))
        self.radio_video_audio.append(tk.Radiobutton(self, text='Audio (Takes Longer)', variable=self.audio_only,
                                                     value=True, command=self.check_video))
        self.radio_video_audio[0].grid(row=4, column=1)
        self.radio_video_audio[1].grid(row=4, column=2)

        self.label_video_title = tk.Label(self)
        self.label_video_title.grid(row=5, column=0, columnspan=4)

        self.content = tk.Frame(self, relief='groove', bd=3)
        self.canvas = tk.Canvas(self.content, borderwidth=0, height=250, width=600)
        self.scrll_bar = tk.Scrollbar(self.content, orient="vertical", command=self.canvas.yview)
        self.frame = tk.Frame(self.canvas)
        self.canvas.configure(yscrollcommand=self.scrll_bar.set)

        self.content.grid_configure(row=6, column=0, rowspan=1, columnspan=4, sticky='NSEW')
        self.scrll_bar.pack(side="right", fill="y")
        self.canvas.pack(side='left')
        self.canvas.create_window((0, 0), window=self.frame, anchor="nw",
                                  tags="self.frame")

        self.frame.bind("<Configure>", self.on_frame_configure)

        self.progress_bar = ttk.Progressbar(self, orient='horizontal', length=350, mode='determinate')
        self.progress_bar.grid(row=7, column=1, columnspan=2)

        self.progress_bar['value'] = 0
        self.progress_bar['maximum'] = 100

        self.btn_download = tk.Button(self)
        self.btn_download['text'] = 'Download'
        self.btn_download['command'] = self.download
        self.btn_download.config(state=tk.NORMAL)
        self.btn_download.grid(row=8, column=1, columnspan=2)

    def on_frame_configure(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def browse_output_path(self):
        self.output_path.set(filedialog.askdirectory(initialdir='/', title='Select Output Folder'))

    def check_video(self):
        self.btn_check_id['text'] = 'Checking...'
        self.btn_check_id.config(state=tk.DISABLED)
        Thread(target=self.threaded_check_video).start()

    def threaded_check_video(self):
        self.last_row = 0
        self.stream.set(0)
        [radio_button.destroy() for radio_button in self.stream_widgets]
        url = self.text_url.get()
        if 'https' not in url:
            url = 'https://www.youtube.com/watch?v=%s' % url
        try:
            if self.proxy.get() != '':
                self.video = YouTube(url, proxies={self.proxy.get().split(':')[0]: self.proxy.get()})
            else:
                self.video = YouTube(url)
            self.label_video_title['text'] = self.video.title
            self.streams = self.video.streams.filter(only_audio=self.audio_only.get()).all()

            for stream in self.streams:
                if self.audio_only.get():
                    text = f'Codec: {stream.audio_codec}, ' \
                           f'ABR: {stream.abr} ' \
                           f'File Type: {stream.mime_type.split("/")[1]}, Size: {stream.filesize // 1024} KB'
                else:
                    if stream.video_codec is None:
                        continue
                    text = f'Res: {stream.resolution}, FPS: {stream.fps},' \
                           f' Video Codec: {stream.video_codec}, Audio Codec: {stream.audio_codec}, ' \
                           f'File Type: {stream.mime_type.split("/")[1]}, Size: {stream.filesize // 1024} KB'
                radio_button = tk.Radiobutton(self.frame, text=text, variable=self.stream, value=stream.itag)
                self.last_row += 1
                radio_button.grid(row=self.last_row, column=0, columnspan=4)
                self.stream_widgets.append(radio_button)
        except PytubeError as e:
            messagebox.showerror('Something went wrong...', e)
        except RegexMatchError as e:
            messagebox.showerror('Something went wrong...', e)
        finally:
            self.btn_check_id['text'] = 'Check Video'
            self.btn_check_id.config(state=tk.NORMAL)

    def download(self):
        self.btn_download['text'] = 'Downloading...'
        self.btn_download.config(state=tk.DISABLED)
        self.btn_check_id.config(state=tk.DISABLED)
        self.btn_output_browse.config(state=tk.DISABLED)
        [radio_button.config(state=tk.DISABLED) for radio_button in self.radio_video_audio]
        Thread(target=self.threaded_download).start()

    def update_progress_bar(self, stream, chunk, file_handle, bytes_remaining):
        percentage = ((self.file_size - bytes_remaining) / self.file_size) * 100
        self.progress_bar['value'] = percentage

    def threaded_download(self):
        try:
            if self.proxy.get() != '':
                proxy = {self.proxy.get().split(':')[0]: self.proxy.get()}
            else:
                proxy = None
            for search_stream in self.streams:
                if int(search_stream.itag) == int(self.stream.get()):
                    self.file_size = search_stream.filesize
                    break
            filename = download_youtube_video(self.text_url.get(), itag=self.stream.get(),
                                              output_path=self.output_path.get(),
                                              filename=self.filename_override.get()
                                              if self.filename_override.get() != '' else None,
                                              proxies=proxy, progress_callback=self.update_progress_bar)
            messagebox.showinfo('Download Complete!', 'Download Complete!\n%s' % filename)
        except PytubeError as e:
            messagebox.showerror('Something went wrong...', e)
        except RegexMatchError as e:
            messagebox.showerror('Something went wrong...', e)
        except Exception as e:
            messagebox.showerror('Something went wrong',
                                 'Something unknown went wrong. Is this a live stream? Wait until the stream ends.'
                                 '\n\n%s' % e)
        finally:
            self.btn_download['text'] = 'Download'
            self.btn_download.config(state=tk.NORMAL)
            self.btn_check_id.config(state=tk.NORMAL)
            self.btn_output_browse.config(state=tk.NORMAL)
            [radio_button.config(state=tk.NORMAL) for radio_button in self.radio_video_audio]


def resource_path(relative_path):
    import sys
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath('.'), relative_path)


if __name__ == '__main__':
    root = tk.Tk()
    app = YouTubeDownloadGUI(master=root)
    app.master.title('YouTube Video/Audio Downloader')
    app.master.tk.call('wm', 'iconphoto', app.master._w, tk.PhotoImage(file=resource_path('assets/ytdl.png')))
    app.mainloop()