You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
851 lines
30 KiB
851 lines
30 KiB
#! /usr/bin/env python
|
|
|
|
'''
|
|
This file contains all gui classes
|
|
MainFrame
|
|
Custom wx.ListCtrl class
|
|
OptionsFrame
|
|
GeneralPanel
|
|
AudioPanel
|
|
ConnectionPanel
|
|
VideoPanel
|
|
FilesystemPanel
|
|
SubtitlesPanel
|
|
OtherPanel
|
|
UpdatePanel
|
|
AuthenticationPanel
|
|
PlaylistPanel
|
|
'''
|
|
|
|
import wx
|
|
from wx.lib.pubsub import setuparg1
|
|
from wx.lib.pubsub import pub as Publisher
|
|
|
|
from .version import __version__
|
|
from .UpdateThread import UpdateThread
|
|
from .DownloadThread import DownloadManager
|
|
from .OptionsHandler import OptionsHandler
|
|
from .YoutubeDLInterpreter import YoutubeDLInterpreter
|
|
from .SignalHandler import DownloadHandler
|
|
from .LogManager import LogManager, LogGUI
|
|
from .Utils import (
|
|
video_is_dash,
|
|
have_dash_audio,
|
|
get_os_type,
|
|
file_exist,
|
|
fix_path,
|
|
get_abs_path
|
|
)
|
|
|
|
if get_os_type() == 'nt':
|
|
YOUTUBE_DL_FILENAME = 'youtube-dl.exe'
|
|
else:
|
|
YOUTUBE_DL_FILENAME = 'youtube-dl'
|
|
|
|
TITLE = 'Youtube-dlG'
|
|
|
|
AUDIOFORMATS = ["mp3", "wav", "aac", "m4a"]
|
|
|
|
VIDEOFORMATS = ["default",
|
|
"mp4 [1280x720]",
|
|
"mp4 [640x360]",
|
|
"webm [640x360]",
|
|
"flv [400x240]",
|
|
"3gp [320x240]",
|
|
"mp4 1080p(DASH)",
|
|
"mp4 720p(DASH)",
|
|
"mp4 480p(DASH)",
|
|
"mp4 360p(DASH)"]
|
|
|
|
DASH_AUDIO_FORMATS = ["NO SOUND",
|
|
"DASH m4a audio 128k",
|
|
"DASH webm audio 48k"]
|
|
|
|
LANGUAGES = ["English",
|
|
"Greek",
|
|
"Portuguese",
|
|
"French",
|
|
"Italian",
|
|
"Russian",
|
|
"Spanish",
|
|
"German"]
|
|
|
|
class MainFrame(wx.Frame):
|
|
|
|
def __init__(self, parent=None, id=-1):
|
|
wx.Frame.__init__(self, parent, id, TITLE+' '+__version__, size=(600, 410), style = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
|
|
|
|
# set sizers for status box (Windows & Linux)
|
|
statusListSizer, statusBarSizer = self.set_sizers()
|
|
|
|
# create panel, trackList, statusBox using global statusBoxSizer
|
|
self.panel = wx.Panel(self)
|
|
wx.StaticText(self.panel, -1, "URLs", (15, 10))
|
|
self.trackList = wx.TextCtrl(self.panel, -1, pos=(10, 25), size=(580, 110), style = wx.TE_MULTILINE | wx.TE_DONTWRAP)
|
|
self.statusList = ListCtrl(self.panel, -1, pos=(10, 190), size=statusListSizer, style = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
|
|
self.statusBar = wx.StaticText(self.panel, -1, 'Author: Sotiris Papadopoulos', pos=statusBarSizer)
|
|
|
|
# create buttons
|
|
self.downloadButton = wx.Button(self.panel, label="Download", pos=(100, 145), size=(-1, 30))
|
|
self.updateButton = wx.Button(self.panel, label="Update", pos=(250, 145), size=(-1, 30))
|
|
self.optionsButton = wx.Button(self.panel, label="Options", pos=(390, 145), size=(-1, 30))
|
|
|
|
# bind events
|
|
self.Bind(wx.EVT_BUTTON, self.OnDownload, self.downloadButton)
|
|
self.Bind(wx.EVT_BUTTON, self.OnUpdate, self.updateButton)
|
|
self.Bind(wx.EVT_BUTTON, self.OnOptions, self.optionsButton)
|
|
self.Bind(wx.EVT_TEXT, self.OnTrackListChange, self.trackList)
|
|
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
|
|
# set app icon
|
|
icon = wx.Icon('../icons/ytube.png', wx.BITMAP_TYPE_ICO)
|
|
self.SetIcon(icon)
|
|
|
|
# set publisher for update thread
|
|
Publisher.subscribe(self.update_handler, "update")
|
|
|
|
# set publisher for download thread
|
|
Publisher.subscribe(self.download_handler, "download")
|
|
|
|
# init Options and DownloadHandler objects
|
|
self.optionsList = OptionsHandler(self.status_bar_write)
|
|
self.downloadHandler = None
|
|
|
|
# init log manager
|
|
if self.optionsList.enableLog:
|
|
self.logManager = LogManager(
|
|
self.optionsList.get_config_path(),
|
|
self.optionsList.writeTimeToLog
|
|
)
|
|
|
|
# init some thread variables
|
|
self.downloadThread = None
|
|
self.updateThread = None
|
|
|
|
# init urlList for evt_text on self.trackList
|
|
self.urlList = []
|
|
|
|
# check & update libraries (youtube-dl)
|
|
self.check_if_youtube_dl_exist()
|
|
if (self.optionsList.autoUpdate):
|
|
self.status_bar_write("Auto update enable")
|
|
self.update_youtube_dl()
|
|
|
|
def set_sizers(self):
|
|
if get_os_type() == 'nt':
|
|
statusListSizer = (580, 165)
|
|
statusBarSizer = (15, 365)
|
|
else:
|
|
statusListSizer = (580, 195)
|
|
statusBarSizer = (15, 390)
|
|
return statusListSizer, statusBarSizer
|
|
|
|
def check_if_youtube_dl_exist(self):
|
|
path = fix_path(self.optionsList.updatePath)+YOUTUBE_DL_FILENAME
|
|
if not file_exist(path):
|
|
self.status_bar_write("Youtube-dl is missing, trying to download it...")
|
|
self.update_youtube_dl()
|
|
|
|
def update_youtube_dl(self):
|
|
self.downloadButton.Disable()
|
|
self.updateThread = UpdateThread(self.optionsList.updatePath, YOUTUBE_DL_FILENAME)
|
|
|
|
def status_bar_write(self, msg):
|
|
self.statusBar.SetLabel(msg)
|
|
|
|
def fin_task(self, error):
|
|
if error:
|
|
msg = 'An error occured while downloading. See Options>Log.'
|
|
self.status_bar_write(msg)
|
|
else:
|
|
self.status_bar_write('Done')
|
|
self.downloadButton.SetLabel('Download')
|
|
self.updateButton.Enable()
|
|
self.downloadThread.join()
|
|
self.downloadThread = None
|
|
self.downloadHandler = None
|
|
self.urlList = []
|
|
self.finished_popup()
|
|
|
|
def download_handler(self, msg):
|
|
self.downloadHandler.handle(msg)
|
|
if self.downloadHandler._has_closed():
|
|
self.status_bar_write('Stoping downloads')
|
|
if self.downloadHandler._has_finished():
|
|
self.fin_task(self.downloadHandler._has_error())
|
|
|
|
def update_handler(self, msg):
|
|
if msg.data == 'finish':
|
|
self.downloadButton.Enable()
|
|
self.updateThread.join()
|
|
self.updateThread = None
|
|
else:
|
|
self.status_bar_write(msg.data)
|
|
|
|
def stop_download(self):
|
|
self.downloadThread.close()
|
|
|
|
def start_download(self, trackList):
|
|
self.statusList._clear_list()
|
|
for url in trackList:
|
|
if url != '':
|
|
self.urlList.append(url)
|
|
self.statusList._add_item(url)
|
|
if not self.statusList._is_empty():
|
|
options = YoutubeDLInterpreter(self.optionsList, YOUTUBE_DL_FILENAME).get_options()
|
|
self.status_bar_write('Download started')
|
|
self.downloadThread = DownloadManager(
|
|
options,
|
|
self.statusList._get_items(),
|
|
self.optionsList.clearDashFiles,
|
|
self.logManager
|
|
)
|
|
self.downloadHandler = DownloadHandler(self.statusList)
|
|
self.downloadButton.SetLabel('Stop')
|
|
self.updateButton.Disable()
|
|
else:
|
|
self.no_url_popup()
|
|
|
|
def save_options(self):
|
|
self.optionsList.save_to_file()
|
|
|
|
def finished_popup(self):
|
|
wx.MessageBox('Downloads completed.', 'Info', wx.OK | wx.ICON_INFORMATION)
|
|
|
|
def no_url_popup(self):
|
|
wx.MessageBox('You need to provide at least one url.', 'Error', wx.OK | wx.ICON_EXCLAMATION)
|
|
|
|
def OnTrackListChange(self, event):
|
|
if self.downloadThread != None:
|
|
''' Get current url list from trackList textCtrl '''
|
|
curList = self.trackList.GetValue().split('\n')
|
|
''' For each url in current url list '''
|
|
for url in curList:
|
|
''' If url is not in self.urlList (original downloads list) and url is not empty '''
|
|
if url not in self.urlList and url != '':
|
|
''' Add url into original download list '''
|
|
self.urlList.append(url)
|
|
''' Add url into statusList '''
|
|
index = self.statusList._add_item(url)
|
|
''' Retrieve last item as {url:url, index:indexNo} '''
|
|
item = self.statusList._get_last_item()
|
|
''' Pass that item into downloadThread '''
|
|
self.downloadThread.add_download_item(item)
|
|
|
|
def OnDownload(self, event):
|
|
if self.downloadThread != None:
|
|
self.stop_download()
|
|
else:
|
|
self.start_download(self.trackList.GetValue().split('\n'))
|
|
|
|
def OnUpdate(self, event):
|
|
if (self.downloadThread == None and self.updateThread == None):
|
|
self.status_bar_write("Updating youtube-dl...")
|
|
self.update_youtube_dl()
|
|
|
|
def OnOptions(self, event):
|
|
optionsFrame = OptionsFrame(self.optionsList, self, logger=self.logManager)
|
|
optionsFrame.Show()
|
|
|
|
def OnClose(self, event):
|
|
self.save_options()
|
|
self.Destroy()
|
|
|
|
class ListCtrl(wx.ListCtrl):
|
|
''' Custom ListCtrl class '''
|
|
def __init__(self, parent, id, pos, size, style):
|
|
wx.ListCtrl.__init__(self, parent, id, pos, size, style)
|
|
self.InsertColumn(0, 'URL', width=150)
|
|
self.InsertColumn(1, 'Size', width=90)
|
|
self.InsertColumn(2, 'Percent', width=80)
|
|
self.InsertColumn(3, 'ETA', width=50)
|
|
self.InsertColumn(4, 'Speed', width=90)
|
|
self.InsertColumn(5, 'Status', width=150)
|
|
self.ListIndex = 0
|
|
|
|
''' Add single item on list '''
|
|
def _add_item(self, item):
|
|
self.InsertStringItem(self.ListIndex, item)
|
|
self.ListIndex += 1
|
|
return self.ListIndex
|
|
|
|
''' Write data on index, column '''
|
|
def _write_data(self, index, column, data):
|
|
self.SetStringItem(index, column, data)
|
|
|
|
''' Clear list and set index to 0'''
|
|
def _clear_list(self):
|
|
self.DeleteAllItems()
|
|
self.ListIndex = 0
|
|
|
|
''' Return True if list is empty '''
|
|
def _is_empty(self):
|
|
return self.ListIndex == 0
|
|
|
|
''' Get last item inserted, Returns dictionary '''
|
|
def _get_last_item(self):
|
|
data = {}
|
|
last_item = self.GetItem(itemId=self.ListIndex-1, col=0)
|
|
data['url'] = last_item.GetText()
|
|
data['index'] = self.ListIndex-1
|
|
return data
|
|
|
|
''' Retrieve all items [start, self.ListIndex), Returns list '''
|
|
def _get_items(self, start=0):
|
|
items = []
|
|
for row in range(start, self.ListIndex):
|
|
item = self.GetItem(itemId=row, col=0)
|
|
data = {}
|
|
data['url'] = item.GetText()
|
|
data['index'] = row
|
|
items.append(data)
|
|
return items
|
|
|
|
class LogPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList, log):
|
|
self.optList = optList
|
|
self.log = log
|
|
self.size, self.path = self.set_data()
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
self.enableLogChk = wx.CheckBox(self, -1, 'Enable log', (240, 20))
|
|
self.enableTimeChk = wx.CheckBox(self, -1, 'Write time', (240, 50))
|
|
self.clearLogButton = wx.Button(self, label="Clear Log", pos=(200, 90))
|
|
self.viewLogButton = wx.Button(self, label="View Log", pos=(300, 90))
|
|
wx.StaticText(self, -1, 'Path: ' + self.path, (180, 140))
|
|
self.sizeText = wx.StaticText(self, -1, 'Log Size: ' + self.size, (230, 170))
|
|
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnEnable, self.enableLogChk)
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnTime, self.enableTimeChk)
|
|
self.Bind(wx.EVT_BUTTON, self.OnClear, self.clearLogButton)
|
|
self.Bind(wx.EVT_BUTTON, self.OnView, self.viewLogButton)
|
|
|
|
def set_data(self):
|
|
if self.log != None:
|
|
size = str(self.log.log_size()) + ' Bytes'
|
|
path = self.log.path
|
|
else:
|
|
size = ''
|
|
path = ''
|
|
return size, path
|
|
|
|
def OnTime(self, event):
|
|
if self.log != None:
|
|
self.log.add_time = self.enableTimeChk.GetValue()
|
|
|
|
def OnEnable(self, event):
|
|
if self.enableLogChk.GetValue():
|
|
self.enableTimeChk.Enable()
|
|
else:
|
|
self.enableTimeChk.Disable()
|
|
self.restart_popup()
|
|
|
|
def OnClear(self, event):
|
|
if self.log != None:
|
|
self.log.clear()
|
|
self.sizeText.SetLabel('Log Size: 0 Bytes')
|
|
|
|
def OnView(self, event):
|
|
if self.log != None:
|
|
log_gui = LogGUI(self.path, parent=self)
|
|
log_gui.Show()
|
|
|
|
def load_options(self):
|
|
self.enableLogChk.SetValue(self.optList.enableLog)
|
|
self.enableTimeChk.SetValue(self.optList.writeTimeToLog)
|
|
if self.optList.enableLog == False:
|
|
self.enableTimeChk.Disable()
|
|
if self.log == None:
|
|
self.clearLogButton.Disable()
|
|
self.viewLogButton.Disable()
|
|
|
|
def save_options(self):
|
|
self.optList.enableLog = self.enableLogChk.GetValue()
|
|
self.optList.writeTimeToLog = self.enableTimeChk.GetValue()
|
|
|
|
def restart_popup(self):
|
|
wx.MessageBox('Please restart ' + TITLE, 'Restart', wx.OK | wx.ICON_INFORMATION)
|
|
|
|
class UpdatePanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
text = '''Enter the path where youtube-dlG should
|
|
download the latest youtube-dl.'''
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, text, (85, 10))
|
|
wx.StaticText(self, -1, 'Path', (95, 60))
|
|
self.updatePathBox = wx.TextCtrl(self, -1, pos=(90, 80), size=(400, -1))
|
|
self.autoUpdateChk = wx.CheckBox(self, -1, 'Auto Update youtube-dl', (100, 130))
|
|
|
|
def load_options(self):
|
|
self.updatePathBox.SetValue(self.optList.updatePath)
|
|
self.autoUpdateChk.SetValue(self.optList.autoUpdate)
|
|
|
|
def save_options(self):
|
|
self.optList.updatePath = get_abs_path(self.updatePathBox.GetValue())
|
|
self.optList.autoUpdate = self.autoUpdateChk.GetValue()
|
|
|
|
class PlaylistPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, 'Playlist Options', (100, 20))
|
|
wx.StaticText(self, -1, 'Start', (90, 53))
|
|
self.startBox = wx.TextCtrl(self, -1, pos=(160, 50), size=(50, -1))
|
|
wx.StaticText(self, -1, 'Stop', (90, 83))
|
|
self.stopBox = wx.TextCtrl(self, -1, pos=(160, 80), size=(50, -1))
|
|
wx.StaticText(self, -1, 'Max DLs', (90, 113))
|
|
self.maxBox = wx.TextCtrl(self, -1, pos=(160, 110), size=(50, -1))
|
|
wx.StaticText(self, -1, 'Filesize (e.g. 50k or 44.6m)', (330, 20))
|
|
wx.StaticText(self, -1, 'Min', (360, 63))
|
|
self.minFilesizeBox = wx.TextCtrl(self, -1, pos=(400, 60), size=(70, -1))
|
|
wx.StaticText(self, -1, 'Max', (360, 93))
|
|
self.maxFilesizeBox = wx.TextCtrl(self, -1, pos=(400, 90), size=(70, -1))
|
|
|
|
def load_options(self):
|
|
self.startBox.SetValue(self.optList.startTrack)
|
|
self.stopBox.SetValue(self.optList.endTrack)
|
|
self.maxBox.SetValue(self.optList.maxDownloads)
|
|
self.minFilesizeBox.SetValue(self.optList.minFileSize)
|
|
self.maxFilesizeBox.SetValue(self.optList.maxFileSize)
|
|
|
|
def save_options(self):
|
|
self.optList.startTrack = self.startBox.GetValue()
|
|
self.optList.endTrack = self.stopBox.GetValue()
|
|
self.optList.maxDownloads = self.maxBox.GetValue()
|
|
self.optList.minFileSize = self.minFilesizeBox.GetValue()
|
|
self.optList.maxFileSize = self.maxFilesizeBox.GetValue()
|
|
|
|
class ConnectionPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, 'Retries', (15, 12))
|
|
self.retriesBox = wx.TextCtrl(self, -1, pos=(65, 10), size=(50, -1))
|
|
wx.StaticText(self, -1, 'User Agent', (15, 50))
|
|
self.userAgentBox = wx.TextCtrl(self, -1, pos=(10, 70), size=(320, -1))
|
|
wx.StaticText(self, -1, 'Referer', (15, 100))
|
|
self.refererBox = wx.TextCtrl(self, -1, pos=(10, 120), size=(320, -1))
|
|
wx.StaticText(self, -1, 'Proxy', (15, 150))
|
|
self.proxyBox = wx.TextCtrl(self, -1, pos=(10, 170), size=(450, -1))
|
|
|
|
def load_options(self):
|
|
self.userAgentBox.SetValue(self.optList.userAgent)
|
|
self.refererBox.SetValue(self.optList.referer)
|
|
self.proxyBox.SetValue(self.optList.proxy)
|
|
self.retriesBox.SetValue(self.optList.retries)
|
|
|
|
def save_options(self):
|
|
self.optList.userAgent = self.userAgentBox.GetValue()
|
|
self.optList.referer = self.refererBox.GetValue()
|
|
self.optList.proxy = self.proxyBox.GetValue()
|
|
self.optList.retries = self.retriesBox.GetValue()
|
|
|
|
class AuthenticationPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self,parent)
|
|
wx.StaticText(self, -1, 'Username', (250, 10))
|
|
self.usernameBox = wx.TextCtrl(self, -1, pos=(175, 30), size=(230, 25))
|
|
wx.StaticText(self, -1, 'Password', (255, 70))
|
|
self.passwordBox = wx.TextCtrl(self, -1, pos=(175, 90), size=(230, 25), style = wx.TE_PASSWORD)
|
|
wx.StaticText(self, -1, 'Video Password (vimeo, smotri)', (190, 130))
|
|
self.videopassBox = wx.TextCtrl(self, -1, pos=(175, 150), size=(230, 25), style = wx.TE_PASSWORD)
|
|
|
|
def load_options(self):
|
|
self.usernameBox.SetValue(self.optList.username)
|
|
self.passwordBox.SetValue(self.optList.password)
|
|
self.videopassBox.SetValue(self.optList.videoPass)
|
|
|
|
def save_options(self):
|
|
self.optList.username = self.usernameBox.GetValue()
|
|
self.optList.password = self.passwordBox.GetValue()
|
|
self.optList.videoPass = self.videopassBox.GetValue()
|
|
|
|
class AudioPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
self.toAudioChk = wx.CheckBox(self, -1, 'Convert to Audio', (225, 10))
|
|
self.keepVideoChk = wx.CheckBox(self, -1, 'Keep Video', (245, 40))
|
|
wx.StaticText(self, -1, 'Audio Format', (250, 80))
|
|
self.audioFormatCombo = wx.ComboBox(self, choices=AUDIOFORMATS, pos=(210, 100), size=(160, 30))
|
|
wx.StaticText(self, -1, "Audio Quality 0 (best) 9 (worst)", (200, 140))
|
|
self.audioQualitySpnr = wx.SpinCtrl(self, -1, "", (245, 160))
|
|
self.audioQualitySpnr.SetRange(0, 9)
|
|
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnAudioCheck, self.toAudioChk)
|
|
|
|
def OnAudioCheck(self, event):
|
|
if self.toAudioChk.GetValue():
|
|
self.keepVideoChk.Enable()
|
|
self.audioFormatCombo.Enable()
|
|
self.audioQualitySpnr.Enable()
|
|
else:
|
|
self.keepVideoChk.Disable()
|
|
self.audioFormatCombo.Disable()
|
|
self.audioQualitySpnr.Disable()
|
|
|
|
def load_options(self):
|
|
self.toAudioChk.SetValue(self.optList.toAudio)
|
|
self.keepVideoChk.SetValue(self.optList.keepVideo)
|
|
self.audioFormatCombo.SetValue(self.optList.audioFormat)
|
|
self.audioQualitySpnr.SetValue(self.optList.audioQuality)
|
|
if self.optList.toAudio == False:
|
|
self.keepVideoChk.Disable()
|
|
self.audioFormatCombo.Disable()
|
|
self.audioQualitySpnr.Disable()
|
|
|
|
def save_options(self):
|
|
self.optList.toAudio = self.toAudioChk.GetValue()
|
|
self.optList.keepVideo = self.keepVideoChk.GetValue()
|
|
self.optList.audioFormat = self.audioFormatCombo.GetValue()
|
|
self.optList.audioQuality = self.audioQualitySpnr.GetValue()
|
|
|
|
class VideoPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, 'Video Format', (250, 10))
|
|
self.videoFormatCombo = wx.ComboBox(self, choices=VIDEOFORMATS, pos=(210, 30), size=(160, 30))
|
|
wx.StaticText(self, -1, 'DASH Audio', (250, 80))
|
|
self.dashAudioFormatCombo = wx.ComboBox(self, choices=DASH_AUDIO_FORMATS, pos=(210, 100), size=(160, 30))
|
|
self.clearDashFilesChk = wx.CheckBox(self, -1, 'Clear DASH audio/video files', (180, 150))
|
|
|
|
self.Bind(wx.EVT_COMBOBOX, self.OnVideoFormatPick, self.videoFormatCombo)
|
|
self.Bind(wx.EVT_COMBOBOX, self.OnAudioFormatPick, self.dashAudioFormatCombo)
|
|
|
|
def OnAudioFormatPick(self, event):
|
|
if have_dash_audio(self.dashAudioFormatCombo.GetValue()):
|
|
self.clearDashFilesChk.Enable()
|
|
else:
|
|
self.clearDashFilesChk.SetValue(False)
|
|
self.clearDashFilesChk.Disable()
|
|
|
|
def OnVideoFormatPick(self, event):
|
|
if video_is_dash(self.videoFormatCombo.GetValue()):
|
|
self.dashAudioFormatCombo.Enable()
|
|
if have_dash_audio(self.dashAudioFormatCombo.GetValue()):
|
|
self.clearDashFilesChk.Enable()
|
|
else:
|
|
self.clearDashFilesChk.SetValue(False)
|
|
self.clearDashFilesChk.Disable()
|
|
self.dashAudioFormatCombo.Disable()
|
|
|
|
def load_options(self):
|
|
self.videoFormatCombo.SetValue(self.optList.videoFormat)
|
|
self.dashAudioFormatCombo.SetValue(self.optList.dashAudioFormat)
|
|
self.clearDashFilesChk.SetValue(self.optList.clearDashFiles)
|
|
if not video_is_dash(self.optList.videoFormat):
|
|
self.dashAudioFormatCombo.Disable()
|
|
if not have_dash_audio(self.optList.dashAudioFormat):
|
|
self.clearDashFilesChk.SetValue(False)
|
|
self.clearDashFilesChk.Disable()
|
|
|
|
def save_options(self):
|
|
self.optList.videoFormat = self.videoFormatCombo.GetValue()
|
|
self.optList.dashAudioFormat = self.dashAudioFormatCombo.GetValue()
|
|
self.optList.clearDashFiles = self.clearDashFilesChk.GetValue()
|
|
|
|
class FilesystemPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
self.idAsNameChk = wx.CheckBox(self, -1, 'ID as Name', (10, 10))
|
|
self.ignoreErrorsChk = wx.CheckBox(self, -1, 'Ignore Errors', (10, 40))
|
|
self.writeDescriptionChk = wx.CheckBox(self, -1, 'Write description to file', (10, 70))
|
|
self.writeInfoChk = wx.CheckBox(self, -1, 'Write info to (.json) file', (10, 100))
|
|
self.writeThumbnailChk = wx.CheckBox(self, -1, 'Write thumbnail to disk', (10, 130))
|
|
|
|
def load_options(self):
|
|
self.writeDescriptionChk.SetValue(self.optList.writeDescription)
|
|
self.writeInfoChk.SetValue(self.optList.writeInfo)
|
|
self.writeThumbnailChk.SetValue(self.optList.writeThumbnail)
|
|
self.ignoreErrorsChk.SetValue(self.optList.ignoreErrors)
|
|
self.idAsNameChk.SetValue(self.optList.idAsName)
|
|
|
|
def save_options(self):
|
|
self.optList.writeDescription = self.writeDescriptionChk.GetValue()
|
|
self.optList.writeInfo = self.writeInfoChk.GetValue()
|
|
self.optList.writeThumbnail = self.writeThumbnailChk.GetValue()
|
|
self.optList.ignoreErrors = self.ignoreErrorsChk.GetValue()
|
|
self.optList.idAsName = self.idAsNameChk.GetValue()
|
|
|
|
class SubtitlesPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
self.writeSubsChk = wx.CheckBox(self, -1, 'Download subtitle file by language', (10, 10))
|
|
self.writeAllSubsChk = wx.CheckBox(self, -1, 'Download all available subtitles', (10, 40))
|
|
self.writeAutoSubsChk = wx.CheckBox(self, -1, 'Download automatic subtitle file (YOUTUBE ONLY)', (10, 70))
|
|
self.embedSubsChk = wx.CheckBox(self, -1, 'Embed subtitles in the video (only for mp4 videos)', (10, 100))
|
|
wx.StaticText(self, -1, 'Subtitles Language', (15, 135))
|
|
self.subsLangCombo = wx.ComboBox(self, choices=LANGUAGES, pos=(10, 155), size=(140, 30))
|
|
self.embedSubsChk.Disable()
|
|
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnWriteSubsChk, self.writeSubsChk)
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnWriteAllSubsChk, self.writeAllSubsChk)
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnWriteAutoSubsChk, self.writeAutoSubsChk)
|
|
|
|
def subs_are_on(self):
|
|
return self.writeAutoSubsChk.GetValue() or self.writeSubsChk.GetValue()
|
|
|
|
def OnWriteAutoSubsChk(self, event):
|
|
if self.writeAutoSubsChk.GetValue():
|
|
self.writeAllSubsChk.Disable()
|
|
self.writeSubsChk.Disable()
|
|
self.subsLangCombo.Disable()
|
|
self.embedSubsChk.Enable()
|
|
else:
|
|
self.writeAllSubsChk.Enable()
|
|
self.writeSubsChk.Enable()
|
|
self.subsLangCombo.Enable()
|
|
self.embedSubsChk.Disable()
|
|
self.embedSubsChk.SetValue(False)
|
|
|
|
def OnWriteSubsChk(self, event):
|
|
if self.writeSubsChk.GetValue():
|
|
self.writeAllSubsChk.Disable()
|
|
self.writeAutoSubsChk.Disable()
|
|
self.embedSubsChk.Enable()
|
|
else:
|
|
self.writeAllSubsChk.Enable()
|
|
self.writeAutoSubsChk.Enable()
|
|
self.embedSubsChk.Disable()
|
|
self.embedSubsChk.SetValue(False)
|
|
|
|
def OnWriteAllSubsChk(self, event):
|
|
if self.writeAllSubsChk.GetValue():
|
|
self.writeSubsChk.Disable()
|
|
self.subsLangCombo.Disable()
|
|
self.writeAutoSubsChk.Disable()
|
|
else:
|
|
self.writeSubsChk.Enable()
|
|
self.subsLangCombo.Enable()
|
|
self.writeAutoSubsChk.Enable()
|
|
|
|
def load_options(self):
|
|
self.writeSubsChk.Enable()
|
|
self.subsLangCombo.Enable()
|
|
self.writeAllSubsChk.Enable()
|
|
self.writeAutoSubsChk.Enable()
|
|
self.writeSubsChk.SetValue(self.optList.writeSubs)
|
|
self.writeAllSubsChk.SetValue(self.optList.writeAllSubs)
|
|
self.subsLangCombo.SetValue(self.optList.subsLang)
|
|
self.writeAutoSubsChk.SetValue(self.optList.writeAutoSubs)
|
|
self.embedSubsChk.SetValue(self.optList.embedSubs)
|
|
if self.optList.writeSubs:
|
|
self.writeAllSubsChk.Disable()
|
|
self.writeAutoSubsChk.Disable()
|
|
self.embedSubsChk.Enable()
|
|
if self.optList.writeAllSubs:
|
|
self.writeSubsChk.Disable()
|
|
self.subsLangCombo.Disable()
|
|
self.writeAutoSubsChk.Disable()
|
|
if self.optList.writeAutoSubs:
|
|
self.writeAllSubsChk.Disable()
|
|
self.writeSubsChk.Disable()
|
|
self.subsLangCombo.Disable()
|
|
self.embedSubsChk.Enable()
|
|
if not self.subs_are_on():
|
|
self.embedSubsChk.Disable()
|
|
|
|
def save_options(self):
|
|
self.optList.writeSubs = self.writeSubsChk.GetValue()
|
|
self.optList.writeAllSubs = self.writeAllSubsChk.GetValue()
|
|
self.optList.subsLang = self.subsLangCombo.GetValue()
|
|
self.optList.writeAutoSubs = self.writeAutoSubsChk.GetValue()
|
|
self.optList.embedSubs = self.embedSubsChk.GetValue()
|
|
|
|
class GeneralPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList, controlParent):
|
|
self.optList = optList
|
|
self.parent = controlParent
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, "Save Path", (250, 20))
|
|
self.savePathBox = wx.TextCtrl(self, -1, pos=(60, 50), size=(450, -1))
|
|
self.aboutButton = wx.Button(self, label="About", pos=(70, 100), size=(110, 40))
|
|
self.openButton = wx.Button(self, label="Open", pos=(230, 100), size=(110, 40))
|
|
self.resetButton = wx.Button(self, label="Reset Options", pos=(390, 100), size=(110, 40))
|
|
wx.StaticText(self, -1, "Settings: " + self.optList.settings_abs_path, (140, 170))
|
|
|
|
self.Bind(wx.EVT_BUTTON, self.OnAbout, self.aboutButton)
|
|
self.Bind(wx.EVT_BUTTON, self.OnOpen, self.openButton)
|
|
self.Bind(wx.EVT_BUTTON, self.OnReset, self.resetButton)
|
|
|
|
def OnReset(self, event):
|
|
self.parent.reset()
|
|
|
|
def OnOpen(self, event):
|
|
dlg = wx.DirDialog(None, "Choose directory")
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
self.savePathBox.SetValue(dlg.GetPath())
|
|
dlg.Destroy()
|
|
|
|
def OnAbout(self, event):
|
|
description = '''A cross platform front-end GUI of
|
|
the popular youtube-dl written in Python.'''
|
|
|
|
license = '''This is free and unencumbered software released into the public domain.
|
|
|
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
distribute this software, either in source code form or as a compiled
|
|
binary, for any purpose, commercial or non-commercial, and by any
|
|
means.
|
|
|
|
In jurisdictions that recognize copyright laws, the author or authors
|
|
of this software dedicate any and all copyright interest in the
|
|
software to the public domain. We make this dedication for the benefit
|
|
of the public at large and to the detriment of our heirs and
|
|
successors. We intend this dedication to be an overt act of
|
|
relinquishment in perpetuity of all present and future rights to this
|
|
software under copyright law.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
For more information, please refer to <http://unlicense.org/>'''
|
|
|
|
info = wx.AboutDialogInfo()
|
|
|
|
info.SetIcon(wx.Icon('../icons/ytube.png', wx.BITMAP_TYPE_ICO))
|
|
info.SetName(TITLE)
|
|
info.SetVersion(__version__)
|
|
info.SetDescription(description)
|
|
info.SetWebSite('https://github.com/MrS0m30n3/youtube-dl-gui')
|
|
info.SetLicense(license)
|
|
info.AddDeveloper('Sotiris Papadopoulos')
|
|
wx.AboutBox(info)
|
|
|
|
def load_options(self):
|
|
self.savePathBox.SetValue(self.optList.savePath)
|
|
|
|
def save_options(self):
|
|
self.optList.savePath = get_abs_path(self.savePathBox.GetValue())
|
|
|
|
class OtherPanel(wx.Panel):
|
|
|
|
def __init__(self, parent, optList):
|
|
self.optList = optList
|
|
|
|
wx.Panel.__init__(self, parent)
|
|
wx.StaticText(self, -1, 'Command line arguments (e.g. --help)', (25, 20))
|
|
self.cmdArgsBox = wx.TextCtrl(self, -1, pos=(20, 40), size=(470, -1))
|
|
|
|
def load_options(self):
|
|
self.cmdArgsBox.SetValue(self.optList.cmdArgs)
|
|
|
|
def save_options(self):
|
|
self.optList.cmdArgs = self.cmdArgsBox.GetValue()
|
|
|
|
class OptionsFrame(wx.Frame):
|
|
|
|
def __init__(self, optionsList, parent=None, id=-1, logger=None):
|
|
wx.Frame.__init__(self, parent, id, "Options", size=(580, 250))
|
|
|
|
self.optionsList = optionsList
|
|
|
|
panel = wx.Panel(self)
|
|
notebook = wx.Notebook(panel)
|
|
|
|
self.generalTab = GeneralPanel(notebook, self.optionsList, self)
|
|
self.audioTab = AudioPanel(notebook, self.optionsList)
|
|
self.connectionTab = ConnectionPanel(notebook, self.optionsList)
|
|
self.videoTab = VideoPanel(notebook, self.optionsList)
|
|
self.filesysTab = FilesystemPanel(notebook, self.optionsList)
|
|
self.subtitlesTab = SubtitlesPanel(notebook, self.optionsList)
|
|
self.otherTab = OtherPanel(notebook, self.optionsList)
|
|
self.updateTab = UpdatePanel(notebook, self.optionsList)
|
|
self.authTab = AuthenticationPanel(notebook, self.optionsList)
|
|
self.videoselTab = PlaylistPanel(notebook, self.optionsList)
|
|
self.logTab = LogPanel(notebook, self.optionsList, logger)
|
|
|
|
notebook.AddPage(self.generalTab, "General")
|
|
notebook.AddPage(self.videoTab, "Video")
|
|
notebook.AddPage(self.audioTab, "Audio")
|
|
notebook.AddPage(self.videoselTab, "Playlist")
|
|
notebook.AddPage(self.subtitlesTab, "Subtitles")
|
|
notebook.AddPage(self.filesysTab, "Filesystem")
|
|
notebook.AddPage(self.connectionTab, "Connection")
|
|
notebook.AddPage(self.authTab, "Authentication")
|
|
notebook.AddPage(self.updateTab, "Update")
|
|
notebook.AddPage(self.logTab, "Log")
|
|
notebook.AddPage(self.otherTab, "Commands")
|
|
|
|
sizer = wx.BoxSizer()
|
|
sizer.Add(notebook, 1, wx.EXPAND)
|
|
panel.SetSizer(sizer)
|
|
|
|
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
|
|
self.load_all_options()
|
|
|
|
def OnClose(self, event):
|
|
self.save_all_options()
|
|
if not file_exist(fix_path(self.optionsList.updatePath)+YOUTUBE_DL_FILENAME):
|
|
self.wrong_youtubedl_path()
|
|
self.Destroy()
|
|
|
|
def wrong_youtubedl_path(self):
|
|
text = '''The path under Options>Update is invalid
|
|
please do one of the following:
|
|
*) restart youtube-dlG
|
|
*) click the update button
|
|
*) change the path to point where youtube-dl is'''
|
|
wx.MessageBox(text, 'Error', wx.OK | wx.ICON_EXCLAMATION)
|
|
|
|
def reset(self):
|
|
self.optionsList.load_default()
|
|
self.load_all_options()
|
|
|
|
def load_all_options(self):
|
|
self.generalTab.load_options()
|
|
self.audioTab.load_options()
|
|
self.connectionTab.load_options()
|
|
self.videoTab.load_options()
|
|
self.filesysTab.load_options()
|
|
self.subtitlesTab.load_options()
|
|
self.otherTab.load_options()
|
|
self.updateTab.load_options()
|
|
self.authTab.load_options()
|
|
self.videoselTab.load_options()
|
|
self.logTab.load_options()
|
|
|
|
def save_all_options(self):
|
|
self.generalTab.save_options()
|
|
self.audioTab.save_options()
|
|
self.connectionTab.save_options()
|
|
self.videoTab.save_options()
|
|
self.filesysTab.save_options()
|
|
self.subtitlesTab.save_options()
|
|
self.otherTab.save_options()
|
|
self.updateTab.save_options()
|
|
self.authTab.save_options()
|
|
self.videoselTab.save_options()
|
|
self.logTab.save_options()
|
|
|