Browse Source

Refactor code

rename YoutubeDLInterpreter -> YDLOptionsParser
pep8
etc..
doc-issue-template
MrS0m30n3 11 years ago
parent
commit
93868c8e24
11 changed files with 1326 additions and 1266 deletions
  1. 36
      youtube_dl_gui/DownloadObject.py
  2. 162
      youtube_dl_gui/DownloadThread.py
  3. 70
      youtube_dl_gui/LogManager.py
  4. 174
      youtube_dl_gui/OptionsHandler.py
  5. 47
      youtube_dl_gui/UpdateThread.py
  6. 105
      youtube_dl_gui/Utils.py
  7. 175
      youtube_dl_gui/YDLOptionsParser.py
  8. 1653
      youtube_dl_gui/YoutubeDLGUI.py
  9. 163
      youtube_dl_gui/YoutubeDLInterpreter.py
  10. 6
      youtube_dl_gui/__init__.py
  11. 1
      youtube_dl_gui/data.py

36
youtube_dl_gui/DownloadObject.py

@ -24,7 +24,12 @@ class DownloadObject(object):
download()
Params: URL to download
Options list e.g. ['--help']
Return: On download error return False else True.
Return: See downlaoad() return codes
Return-Codes:
OK : 'Url downloaded successfully'
ERROR : 'Error occured while downloading'
ALREADY: 'Url is already downloaded'
stop()
Params: None
@ -37,6 +42,11 @@ class DownloadObject(object):
See self._init_data().
'''
# download() return codes
OK = 0
ERROR = 1
ALREADY = -1
STDERR_IGNORE = '' # Default filter for our self._log() method
def __init__(self, youtubedl_path, data_hook=None, logger=None):
@ -44,6 +54,7 @@ class DownloadObject(object):
self.data_hook = data_hook
self.logger = logger
self.files_list = []
self._return_code = 0
self._proc = None
self._init_data()
@ -61,8 +72,7 @@ class DownloadObject(object):
}
def download(self, url, options):
''' Download url using given options list. '''
error = False
self._return_code = self.OK
cmd = self._get_cmd(url, options)
cmd = self._encode_cmd(cmd)
@ -77,7 +87,7 @@ class DownloadObject(object):
synced = self._sync_data(data)
if stderr != '':
error = True
self._return_code = self.ERROR
if self.logger is not None:
self._log(stderr)
@ -85,10 +95,9 @@ class DownloadObject(object):
if self.data_hook is not None and synced:
self._hook_data()
return (not error)
return self._return_code
def stop(self):
''' Stop download process. '''
if self._proc is not None:
self._proc.kill()
@ -104,13 +113,17 @@ class DownloadObject(object):
# Keep only the filename not the path on data['filename']
data['filename'] = get_filename(data['filename'])
if key == 'status':
# Set self._return_code to already downloaded
if data[key] == 'already_downloaded':
self._return_code = self.ALREADY
self._data[key] = data[key]
synced = True
return synced
def _add_on_files_list(self, filename):
''' Add filename on files_list. '''
self.files_list.append(filename)
def _log(self, data):
@ -137,7 +150,6 @@ class DownloadObject(object):
return stdout, stderr
def _read_stdout(self):
''' Read subprocess stdout. '''
if self._proc is None:
return ''
@ -145,7 +157,6 @@ class DownloadObject(object):
return stdout.rstrip()
def _read_stderr(self):
''' Read subprocess stderr. '''
if self._proc is None:
return ''
@ -199,9 +210,11 @@ def extract_data(stdout):
if header == 'download':
data_dictionary['status'] = 'download'
# Get filename
if stdout[0] == 'Destination:':
data_dictionary['filename'] = ' '.join(stdout[1:])
# Get progress info
elif '%' in stdout[0]:
if stdout[0] == '100%':
data_dictionary['speed'] = ''
@ -211,10 +224,15 @@ def extract_data(stdout):
data_dictionary['speed'] = stdout[4]
data_dictionary['eta'] = stdout[6]
# Get playlist info
elif stdout[0] == 'Downloading' and stdout[1] == 'video':
data_dictionary['playlist_index'] = stdout[2]
data_dictionary['playlist_size'] = stdout[4]
# Get file already downloaded status
elif stdout[-1] == 'downloaded':
data_dictionary['status'] = 'already_downloaded'
if header == 'ffmpeg':
data_dictionary['status'] = 'post_process'

162
youtube_dl_gui/DownloadThread.py

@ -7,7 +7,7 @@ from wx import CallAfter
from wx.lib.pubsub import setuparg1
from wx.lib.pubsub import pub as Publisher
from .YoutubeDLInterpreter import YoutubeDLInterpreter
from .YDLOptionsParser import OptionsParser
from .DownloadObject import DownloadObject
from .Utils import (
@ -23,104 +23,100 @@ class DownloadManager(Thread):
PUBLISHER_TOPIC = 'download_manager'
MAX_DOWNLOAD_THREADS = 3
def __init__(self, downloadlist, opt_manager, logmanager=None):
def __init__(self, download_list, opt_manager, log_manager=None):
super(DownloadManager, self).__init__()
self.downloadlist = downloadlist
self.download_list = download_list
self.opt_manager = opt_manager
self.logmanager = logmanager
self.running = True
self.kill = False
self.procList = []
self.procNo = 0
self.log_manager = log_manager
self._threads_lst = []
self._running = True
self._kill = False
self.start()
def run(self):
while self.running:
if self.downloadlist:
# Extract url, index from data
url, index = self.extract_data()
# Wait for your turn if there are not more positions in 'queue'
while self.procNo >= self.MAX_DOWNLOAD_THREADS:
proc = self.check_queue()
if proc != None:
self.procList.remove(proc)
self.procNo -= 1
sleep(1)
# If we still running create new ProcessWrapper thread
if self.running:
self.procList.append(
DownloadThread(
url,
index,
self.opt_manager,
self.logmanager
)
)
self.procNo += 1
while self._running:
# If download list is not empty
if self.download_list:
url, index = self._extract_data()
self._check_download_queue()
if self._running:
self._download(url, index)
else:
# Return True if at least one process is alive else return False
if not self.downloading():
self.running = False
self._running = False
else:
sleep(0.1)
# If we reach here close down all child threads
self.terminate_all()
if not self.kill:
self._terminate_all()
if not self._kill:
self._callafter('finish')
def downloading(self):
for proc in self.procList:
if proc.isAlive():
''' Return True if at least one download thread is alive '''
for thread in self._threads_lst:
if thread.is_alive():
return True
return False
def _add_download_item(self, downloadItem):
self.downloadlist.append(downloadItem)
def add_download_item(self, item):
''' Add download item on download list '''
self.download_list.append(item)
def close(self, kill=False):
self._callafter('close')
self._running = False
self._kill = kill
def _download(self, url, index):
''' Download given url '''
dl_thread = DownloadThread(url, index, self.opt_manager, self.log_manager)
self._threads_lst.append(dl_thread)
def extract_data(self):
data = self.downloadlist.pop(0)
def _extract_data(self):
''' Extract url, index from download list '''
data = self.download_list.pop(0)
url = data['url']
index = data['index']
return url, index
def terminate_all(self):
for proc in self.procList:
if proc.isAlive():
proc.close()
proc.join()
def check_queue(self):
for proc in self.procList:
if not self.running: break
if not proc.isAlive():
return proc
return None
def _terminate_all(self):
''' Close down all download threads '''
for thread in self._threads_lst:
if thread.is_alive():
thread.close()
thread.join()
def _check_download_queue(self):
while len(self._threads_lst) >= self.MAX_DOWNLOAD_THREADS:
sleep(1)
for thread in self._threads_lst:
if not self._running:
return
if not thread.is_alive():
self._threads_lst.remove(thread)
def _callafter(self, data):
CallAfter(Publisher.sendMessage, self.PUBLISHER_TOPIC, data)
def close(self, kill=False):
self.kill = kill
self.procNo = 0
self.running = False
self._callafter('close')
class DownloadThread(Thread):
'''
Params
url: URL to download.
index: ListCtrl index for the current DownloadThread.
opt_manager: OptionsHandler.OptionsHandler object.
log_manager: Any logger which implements log().
Accessible Methods
close()
Params: None
'''
PUBLISHER_TOPIC = 'download_thread'
def __init__(self, url, index, opt_manager, log_manager=None):
super(DownloadThread, self).__init__()
self.log_manager = log_manager
@ -129,28 +125,32 @@ class DownloadThread(Thread):
self.url = url
self._dl_object = None
self.start()
def run(self):
youtubedl_path = self._get_youtubedl_path()
options = YoutubeDLInterpreter(self.opt_manager).get_options()
options = OptionsParser(self.opt_manager).parse()
self._dl_object = DownloadObject(youtubedl_path, self._data_hook, self.log_manager)
success = self._dl_object.download(self.url, options)
return_code = self._dl_object.download(self.url, options)
if self.opt_manager.options['clear_dash_files']:
self._clear_dash()
if success:
if return_code == self._dl_object.OK:
self._callafter(self._get_status_pack('Finished'))
else:
elif return_code == self._dl_object.ERROR:
self._callafter(self._get_status_pack('Error'))
elif return_code == self._dl_object.ALREADY:
self._callafter(self._get_status_pack('Already-Downloaded'))
def close(self):
if self._dl_object is not None:
self._callafter(self._get_status_pack('Stopping'))
self._dl_object.stop()
def _clear_dash(self):
''' Clear DASH files after ffmpeg mux '''
for fl in self._dl_object.files_list:
@ -165,28 +165,30 @@ class DownloadThread(Thread):
def _callafter(self, data):
CallAfter(Publisher.sendMessage, self.PUBLISHER_TOPIC, data)
def _get_status_pack(self, message):
''' Return simple status pack '''
data = {'index': self.index, 'status': message}
return data
def _get_status(self, data):
''' Return download process status '''
if data['playlist_index'] is not None:
playlist_info = '%s/%s' % (data['playlist_index'], data['playlist_size'])
else:
playlist_info = ''
if data['status'] == 'pre_process':
msg = 'Pre-Processing %s' % playlist_info
elif data['status'] == 'download':
msg = 'Downloading %s' % playlist_info
elif data['status'] == 'post_process':
msg = 'Post-Processing %s' % playlist_info
else:
msg = ''
return msg
def _get_youtubedl_path(self):
''' Retrieve youtube-dl path '''
path = self.opt_manager.options['youtubedl_path']

70
youtube_dl_gui/LogManager.py

@ -4,59 +4,65 @@ import wx
from time import strftime
from .Utils import (
fix_path,
get_filesize,
check_path,
file_exist,
get_filesize
fix_path
)
LOG_FILENAME = 'log'
LOG_FILESIZE = 524288 # 524288B = 512kB
class LogManager():
class LogManager(object):
def __init__(self, path, add_time=False):
self.path = fix_path(path) + LOG_FILENAME
self.add_time = add_time
self.init_log()
self.auto_clear_log()
def auto_clear_log(self):
if self.size() > LOG_FILESIZE:
self.clear()
LOG_FILENAME = 'log'
MAX_FILESIZE = 524288 # 524288B = 512kB
def init_log(self):
if not file_exist(self.path):
self.clear()
def __init__(self, config_path, add_time=False):
self.config_path = config_path
self.add_time = add_time
self.log_file = self._get_log_file()
self._auto_clear_log()
def size(self):
return get_filesize(self.path)
if not file_exist(self.log_file):
return 0
return get_filesize(self.log_file)
def clear(self):
with open(self.path, 'w') as fl:
fl.write('')
self._write('', 'w')
def log(self, data):
self.write(data)
def write(self, data):
with open(self.path, 'a') as fl:
self._write(data, 'a')
def _write(self, data, mode):
check_path(self.config_path)
with open(self.log_file, mode) as fl:
if self.add_time:
t = '[%s] ' % strftime('%c')
fl.write(t)
fl.write(data)
fl.write('\n')
fl.write(data + '\n')
def _auto_clear_log(self):
if self.size() > self.MAX_FILESIZE:
self.clear()
def _get_log_file(self):
return fix_path(self.config_path) + self.LOG_FILENAME
class LogGUI(wx.Frame):
title = 'Log Viewer'
TITLE = 'Log Viewer'
def __init__(self, path, parent=None, id=-1):
wx.Frame.__init__(self, parent, id, self.title, size=(650, 200))
def __init__(self, log_file, parent=None, id=-1):
wx.Frame.__init__(self, parent, id, self.TITLE, size=(650, 200))
panel = wx.Panel(self)
textArea = wx.TextCtrl(panel, -1, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
text_area = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
sizer = wx.BoxSizer()
sizer.Add(textArea, 1, wx.EXPAND)
sizer.Add(text_area, 1, wx.EXPAND)
panel.SetSizerAndFit(sizer)
textArea.LoadFile(path)
text_area.LoadFile(log_file)

174
youtube_dl_gui/OptionsHandler.py

@ -2,110 +2,112 @@
import json
from data import __appname__
from .Utils import (
get_user_config_path,
get_HOME,
check_path,
file_exist,
fix_path,
check_path
get_home,
fix_path
)
SETTINGS_FILENAME = 'settings.json'
CONFIG_PATH = fix_path(get_user_config_path()) + __appname__.lower()
class OptionsHandler():
settings_abs_path = ''
sensitive_keys = ('sudo_password', 'password', 'video_password')
class OptionsHandler(object):
def __init__(self):
self.set_settings_path()
self.load_settings()
SETTINGS_FILENAME = 'settings.json'
SENSITIVE_KEYS = ('sudo_password', 'password', 'video_password')
def load_settings(self):
def __init__(self, config_path):
self.config_path = config_path
self.settings_file = self._get_settings_file()
self.load_default()
check_path(self.get_config_path())
if file_exist(self.settings_abs_path):
self.load_from_file()
self.load_from_file()
def load_default(self):
self.options = {
'save_path': get_HOME(),
'video_format': 'default',
'dash_audio_format': 'none',
'clear_dash_files': False,
'to_audio': False,
'keep_video': False,
'audio_format': 'mp3',
'audio_quality': 'mid',
'restrict_filenames': False,
'output_format': 'title',
'output_template': '%(uploader)s/%(title)s.%(ext)s',
'playlist_start': 1,
'playlist_end': 0,
'max_downloads': 0,
'min_filesize': '0',
'max_filesize': '0',
'write_subs': False,
'write_all_subs': False,
'write_auto_subs': False,
'embed_subs': False,
'subs_lang': 'English',
'ignore_errors': True,
'open_dl_dir': False,
'write_description': False,
'write_info': False,
'write_thumbnail': False,
'retries': 10,
'user_agent': '',
'referer': '',
'proxy': '',
'shutdown': False,
'sudo_password': '',
'username': '',
'password': '',
'video_password': '',
'youtubedl_path': self.get_config_path(),
'cmd_args': '',
'enable_log': True,
'log_time': True
'save_path': get_home(),
'video_format': 'default',
'dash_audio_format': 'none',
'clear_dash_files': False,
'to_audio': False,
'keep_video': False,
'audio_format': 'mp3',
'audio_quality': 'mid',
'restrict_filenames': False,
'output_format': 'title',
'output_template': '%(uploader)s/%(title)s.%(ext)s',
'playlist_start': 1,
'playlist_end': 0,
'max_downloads': 0,
'min_filesize': '0',
'max_filesize': '0',
'write_subs': False,
'write_all_subs': False,
'write_auto_subs': False,
'embed_subs': False,
'subs_lang': 'English',
'ignore_errors': True,
'open_dl_dir': True,
'write_description': False,
'write_info': False,
'write_thumbnail': False,
'retries': 10,
'user_agent': '',
'referer': '',
'proxy': '',
'shutdown': False,
'sudo_password': '',
'username': '',
'password': '',
'video_password': '',
'youtubedl_path': self.config_path,
'cmd_args': '',
'enable_log': True,
'log_time': False
}
def get_config_path(self):
return CONFIG_PATH
def set_settings_path(self):
self.settings_abs_path = fix_path(self.get_config_path()) + SETTINGS_FILENAME
def settings_are_valid(self, settings_dictionary):
''' Check settings.json dictionary '''
for key in self.options:
if key not in settings_dictionary:
return False
if len(settings_dictionary) != len(self.options):
return False
return True
def remove_sensitive_data(self):
for key in self.sensitive_keys:
self.options[key] = ''
def load_from_file(self):
with open(self.settings_abs_path, 'rb') as f:
if not file_exist(self.settings_file):
self.load_default()
return
with open(self.settings_file, 'rb') as f:
try:
options = json.load(f)
if self.settings_are_valid(options):
self.options = options
else:
self.load_default()
# Raise WrongSettings Exception if NOT
self._settings_are_valid(options)
self.options = options
except:
self.load_default()
def save_to_file(self):
check_path(self.get_config_path())
with open(self.settings_abs_path, 'wb') as f:
self.remove_sensitive_data()
check_path(self.config_path)
with open(self.settings_file, 'wb') as f:
self._remove_sensitive_data()
json.dump(self.options, f, indent=4, separators=(',', ': '))
def _settings_are_valid(self, settings_dictionary):
''' Check settings.json dictionary and raise WrongSettings Exception '''
if len(settings_dictionary) != len(self.options):
raise WrongSettings()
for key in self.options:
if key not in settings_dictionary:
raise WrongSettings()
def _remove_sensitive_data(self):
''' Remove sensitive data from self.options (passwords, etc) '''
for key in self.SENSITIVE_KEYS:
self.options[key] = ''
def _get_settings_file(self):
''' Return abs path to settings file '''
return fix_path(self.config_path) + self.SETTINGS_FILENAME
class WrongSettings(Exception):
''' Wrong settings exception.
This exception will be raised if settings dictionary is not valid.
'''
pass

47
youtube_dl_gui/UpdateThread.py

@ -8,37 +8,44 @@ from threading import Thread
from urllib2 import urlopen, URLError, HTTPError
from .Utils import (
fix_path,
file_exist,
makedir
get_youtubedl_filename,
check_path,
fix_path
)
LATEST_YOUTUBE_DL = 'https://yt-dl.org/latest/'
PUBLISHER_TOPIC = 'update'
DOWNLOAD_TIMEOUT = 20
class UpdateThread(Thread):
def __init__(self, updatePath, youtubeDLFile):
LATEST_YOUTUBE_DL = 'https://yt-dl.org/latest/'
PUBLISHER_TOPIC = 'update'
DOWNLOAD_TIMEOUT = 20
def __init__(self, download_path):
super(UpdateThread, self).__init__()
self.youtubeDLFile = youtubeDLFile
self.updatePath = fix_path(updatePath)
self.url = LATEST_YOUTUBE_DL + youtubeDLFile
self.check_path()
self.download_path = fix_path(download_path)
self._youtubedl_file = get_youtubedl_filename()
self.start()
def run(self):
CallAfter(Publisher.sendMessage, PUBLISHER_TOPIC, "Downloading latest youtube-dl. Please wait...")
self._callafter("Downloading latest youtube-dl. Please wait...")
dl_url = self.LATEST_YOUTUBE_DL + self._youtubedl_file
dst_file = self.download_path + self._youtubedl_file
check_path(self.download_path)
try:
f = urlopen(self.url, timeout=DOWNLOAD_TIMEOUT)
with open(self.updatePath + self.youtubeDLFile, 'wb') as lf:
lf.write(f.read())
f = urlopen(dl_url, timeout=self.DOWNLOAD_TIMEOUT)
with open(dst_file, 'wb') as bf:
bf.write(f.read())
msg = 'Youtube-dl downloaded correctly'
except (HTTPError, URLError, IOError) as e:
msg = 'Youtube-dl download failed ' + str(e)
CallAfter(Publisher.sendMessage, PUBLISHER_TOPIC, msg)
CallAfter(Publisher.sendMessage, PUBLISHER_TOPIC, 'finish')
def check_path(self):
if not file_exist(self.updatePath):
makedir(self.updatePath)
self._callafter(msg)
self._callafter('finish')
def _callafter(self, data):
CallAfter(Publisher.sendMessage, self.PUBLISHER_TOPIC, data)

105
youtube_dl_gui/Utils.py

@ -12,68 +12,74 @@ from os import (
)
from os.path import (
exists as file_exist,
getsize as get_filesize
getsize as get_filesize,
exists as file_exist
)
def remove_empty_items(array):
return [x for x in array if x != '']
def remove_spaces(string):
return string.replace(' ', '')
def string_to_array(string, char=' '):
return string.split(char)
def preferredencoding():
try:
pref = locale.getpreferredencoding()
u'TEST'.encode(pref)
except:
pref = 'UTF-8'
return pref
def get_encoding():
if sys.version_info >= (3, 0):
return None
if sys.platform == 'win32':
return preferredencoding()
try:
enc = locale.getpreferredencoding()
u'TEST'.encode(enc)
except:
enc = 'UTF-8'
return enc
return None
def encode_list(data_list, encoding):
return [x.encode(encoding, 'ignore') for x in data_list]
def encode_list(lst, encoding):
return [item.encode(encoding, 'ignore') for item in lst]
def video_is_dash(video):
return "DASH" in video
def have_dash_audio(audio):
def audio_is_dash(audio):
return audio != "none"
def get_path_seperator():
def path_seperator():
''' Return path seperator for current OS '''
return '\\' if os_type == 'nt' else '/'
def fix_path(path):
if path != '' and path[-1:] != get_path_seperator():
path += get_path_seperator()
path_list = path.split(get_path_seperator())
for i in range(len(path_list)):
if path_list[i] == '~':
path_list[i] = get_HOME()
return get_path_seperator().join(path_list)
def get_HOME():
''' Add path seperator at the end of the path
if not exist and replace ~ with user $HOME '''
if path == '':
return path
if path[-1:] != path_seperator():
path += path_seperator()
path_list = path.split(path_seperator())
for index, item in enumerate(path_list):
if item == '~':
path_list[index] = get_home()
path = path_seperator().join(path_list)
return path
def get_home():
return os.path.expanduser("~")
def add_PATH(path):
os.environ["PATH"] += os.pathsep + path
def abs_path(filename):
path = os.path.abspath(filename).split(get_path_seperator())
path = os.path.realpath(os.path.abspath(filename))
path = path.split(path_seperator())
path.pop()
return get_path_seperator().join(path)
return path_seperator().join(path)
def get_filename(path):
return path.split(get_path_seperator())[-1]
return path.split(path_seperator())[-1]
def open_dir(path):
if os_type == 'nt':
@ -81,23 +87,27 @@ def open_dir(path):
else:
subprocess.call(('xdg-open', path))
def check_path(path):
if not file_exist(path):
makedir(path)
def get_youtubedl_filename():
youtubedl_fl = 'youtube-dl'
if os_type == 'nt':
youtubedl_fl += '.exe'
return youtubedl_fl
def get_user_config_path():
if os_type == 'nt':
path = os.getenv('APPDATA')
else:
path = fix_path(get_HOME()) + '.config'
path = fix_path(get_home()) + '.config'
return path
def shutdown_sys(password=''):
if os_type == 'nt':
subprocess.call(['shutdown', '/s', '/t', '1'])
@ -105,7 +115,8 @@ def shutdown_sys(password=''):
if password == '':
subprocess.call(['/sbin/shutdown', '-h', 'now'])
else:
p = subprocess.Popen(['sudo', '-S', '/sbin/shutdown', '-h', 'now'],
stdin=subprocess.PIPE)
p.communicate(password+'\n')
p = subprocess.Popen(
['sudo', '-S', '/sbin/shutdown', '-h', 'now'],
stdin=subprocess.PIPE
)
p.communicate(password + '\n')

175
youtube_dl_gui/YDLOptionsParser.py

@ -0,0 +1,175 @@
#! /usr/bin/env python
from .Utils import (
video_is_dash,
fix_path
)
SUBS_LANG = {
"English": "en",
"Greek": "gr",
"Portuguese": "pt",
"French": "fr",
"Italian": "it",
"Russian": "ru",
"Spanish": "es",
"German": "de"
}
VIDEO_FORMATS = {
"default": "0",
"mp4 [1280x720]": "22",
"mp4 [640x360]": "18",
"webm [640x360]": "43",
"flv [400x240]": "5",
"3gp [320x240]": "36",
"mp4 1080p(DASH)": "137",
"mp4 720p(DASH)": "136",
"mp4 480p(DASH)": "135",
"mp4 360p(DASH)": "134"
}
DASH_AUDIO_FORMATS = {
"none": "none",
"DASH m4a audio 128k": "140",
"DASH webm audio 48k": "171"
}
AUDIO_QUALITY = {
"high": "0",
"mid": "5",
"low": "9"
}
class OptionsParser():
''' Parse OptionsHandler object into youtube-dl options list '''
def __init__(self, opt_manager):
self._options = opt_manager.options
self.opts = []
def parse(self):
self._set_progress_opts()
self._set_output_opts()
self._set_auth_opts()
self._set_connection_opts()
self._set_video_opts()
self._set_playlist_opts()
self._set_filesystem_opts()
self._set_subtitles_opts()
self._set_audio_opts()
self._set_other_opts()
return self.opts
def _set_progress_opts(self):
''' Do NOT change this option '''
self.opts.append('--newline')
def _set_playlist_opts(self):
if self._options['playlist_start'] != 1:
self.opts.append('--playlist-start')
self.opts.append(str(self._options['playlist_start']))
if self._options['playlist_end'] != 0:
self.opts.append('--playlist-end')
self.opts.append(str(self._options['playlist_end']))
if self._options['max_downloads'] != 0:
self.opts.append('--max-downloads')
self.opts.append(str(self._options['max_downloads']))
if self._options['min_filesize'] != '0':
self.opts.append('--min-filesize')
self.opts.append(self._options['min_filesize'])
if self._options['max_filesize'] != '0':
self.opts.append('--max-filesize')
self.opts.append(self._options['max_filesize'])
def _set_auth_opts(self):
if self._options['username'] != '':
self.opts.append('-u')
self.opts.append(self._options['username'])
if self._options['password'] != '':
self.opts.append('-p')
self.opts.append(self._options['password'])
if self._options['video_password'] != '':
self.opts.append('--video-password')
self.opts.append(self._options['video_password'])
def _set_connection_opts(self):
if self._options['retries'] != 10:
self.opts.append('-R')
self.opts.append(str(self._options['retries']))
if self._options['proxy'] != '':
self.opts.append('--proxy')
self.opts.append(self._options['proxy'])
if self._options['user_agent'] != '':
self.opts.append('--user-agent')
self.opts.append(self._options['user_agent'])
if self._options['referer'] != '':
self.opts.append('--referer')
self.opts.append(self._options['referer'])
def _set_video_opts(self):
if self._options['video_format'] != 'default':
self.opts.append('-f')
if video_is_dash(self._options['video_format']):
vf = VIDEO_FORMATS[self._options['video_format']]
af = DASH_AUDIO_FORMATS[self._options['dash_audio_format']]
if af != 'none':
self.opts.append(vf + '+' + af)
else:
self.opts.append(vf)
else:
self.opts.append(VIDEO_FORMATS[self._options['video_format']])
def _set_filesystem_opts(self):
if self._options['ignore_errors']:
self.opts.append('-i')
if self._options['write_description']:
self.opts.append('--write-description')
if self._options['write_info']:
self.opts.append('--write-info-json')
if self._options['write_thumbnail']:
self.opts.append('--write-thumbnail')
def _set_subtitles_opts(self):
if self._options['write_all_subs']:
self.opts.append('--all-subs')
if self._options['write_auto_subs']:
self.opts.append('--write-auto-sub')
if self._options['write_subs']:
self.opts.append('--write-sub')
if self._options['subs_lang'] != 'English':
self.opts.append('--sub-lang')
self.opts.append(SUBS_LANG[self._options['subs_lang']])
if self._options['embed_subs']:
self.opts.append('--embed-subs')
def _set_output_opts(self):
path = fix_path(self._options['save_path'])
self.opts.append('-o')
if self._options['output_format'] == 'id':
self.opts.append(path + '%(id)s.%(ext)s')
elif self._options['output_format'] == 'title':
self.opts.append(path + '%(title)s.%(ext)s')
elif self._options['output_format'] == 'custom':
self.opts.append(path + self._options['output_template'])
if self._options['restrict_filenames']:
self.opts.append('--restrict-filenames')
def _set_audio_opts(self):
if self._options['to_audio']:
self.opts.append('-x')
self.opts.append('--audio-format')
self.opts.append(self._options['audio_format'])
if self._options['audio_quality'] != 'mid':
self.opts.append('--audio-quality')
self.opts.append(AUDIO_QUALITY[self._options['audio_quality']])
if self._options['keep_video']:
self.opts.append('-k')
def _set_other_opts(self):
if self._options['cmd_args'] != '':
for option in self._options['cmd_args'].split():
self.opts.append(option)

1653
youtube_dl_gui/YoutubeDLGUI.py
File diff suppressed because it is too large
View File

163
youtube_dl_gui/YoutubeDLInterpreter.py

@ -1,163 +0,0 @@
#! /usr/bin/env python
from .Utils import (
video_is_dash,
fix_path
)
LANGUAGES = {"English":"en",
"Greek":"gr",
"Portuguese":"pt",
"French":"fr",
"Italian":"it",
"Russian":"ru",
"Spanish":"es",
"German":"de"}
VIDEOFORMATS = {"default":"0",
"mp4 [1280x720]":"22",
"mp4 [640x360]":"18",
"webm [640x360]":"43",
"flv [400x240]":"5",
"3gp [320x240]":"36",
"mp4 1080p(DASH)":"137",
"mp4 720p(DASH)":"136",
"mp4 480p(DASH)":"135",
"mp4 360p(DASH)":"134"}
DASH_AUDIO_FORMATS = {"none":"none",
"DASH m4a audio 128k":"140",
"DASH webm audio 48k":"171"}
AUDIO_Q = {"high":"0",
"mid":"5",
"low":"9"}
class YoutubeDLInterpreter():
def __init__(self, optManager):
self.optManager = optManager
self.opts = []
self.set_progress_opts()
self.set_output_opts()
self.set_auth_opts()
self.set_connection_opts()
self.set_video_opts()
self.set_playlist_opts()
self.set_filesystem_opts()
self.set_subtitles_opts()
self.set_audio_opts()
self.set_other_opts()
def get_options(self):
return self.opts
def set_progress_opts(self):
''' Do NOT change this option '''
self.opts.append('--newline')
def set_playlist_opts(self):
if self.optManager.options['playlist_start'] != 1:
self.opts.append('--playlist-start')
self.opts.append(str(self.optManager.options['playlist_start']))
if self.optManager.options['playlist_end'] != 0:
self.opts.append('--playlist-end')
self.opts.append(str(self.optManager.options['playlist_end']))
if self.optManager.options['max_downloads'] != 0:
self.opts.append('--max-downloads')
self.opts.append(str(self.optManager.options['max_downloads']))
if self.optManager.options['min_filesize'] != '0':
self.opts.append('--min-filesize')
self.opts.append(self.optManager.options['min_filesize'])
if self.optManager.options['max_filesize'] != '0':
self.opts.append('--max-filesize')
self.opts.append(self.optManager.options['max_filesize'])
def set_auth_opts(self):
if self.optManager.options['username'] != '':
self.opts.append('-u')
self.opts.append(self.optManager.options['username'])
if self.optManager.options['password'] != '':
self.opts.append('-p')
self.opts.append(self.optManager.options['password'])
if self.optManager.options['video_password'] != '':
self.opts.append('--video-password')
self.opts.append(self.optManager.options['video_password'])
def set_connection_opts(self):
if self.optManager.options['retries'] != 10:
self.opts.append('-R')
self.opts.append(str(self.optManager.options['retries']))
if self.optManager.options['proxy'] != '':
self.opts.append('--proxy')
self.opts.append(self.optManager.options['proxy'])
if self.optManager.options['user_agent'] != '':
self.opts.append('--user-agent')
self.opts.append(self.optManager.options['user_agent'])
if self.optManager.options['referer'] != '':
self.opts.append('--referer')
self.opts.append(self.optManager.options['referer'])
def set_video_opts(self):
if self.optManager.options['video_format'] != 'default':
self.opts.append('-f')
if video_is_dash(self.optManager.options['video_format']):
vf = VIDEOFORMATS[self.optManager.options['video_format']]
af = DASH_AUDIO_FORMATS[self.optManager.options['dash_audio_format']]
if af != 'none':
self.opts.append(vf+'+'+af)
else:
self.opts.append(vf)
else:
self.opts.append(VIDEOFORMATS[self.optManager.options['video_format']])
def set_filesystem_opts(self):
if self.optManager.options['ignore_errors']:
self.opts.append('-i')
if self.optManager.options['write_description']:
self.opts.append('--write-description')
if self.optManager.options['write_info']:
self.opts.append('--write-info-json')
if self.optManager.options['write_thumbnail']:
self.opts.append('--write-thumbnail')
def set_subtitles_opts(self):
if self.optManager.options['write_all_subs']:
self.opts.append('--all-subs')
if self.optManager.options['write_auto_subs']:
self.opts.append('--write-auto-sub')
if self.optManager.options['write_subs']:
self.opts.append('--write-sub')
if self.optManager.options['subs_lang'] != 'English':
self.opts.append('--sub-lang')
self.opts.append(LANGUAGES[self.optManager.options['subs_lang']])
if self.optManager.options['embed_subs']:
self.opts.append('--embed-subs')
def set_output_opts(self):
path = fix_path(self.optManager.options['save_path'])
self.opts.append('-o')
if self.optManager.options['output_format'] == 'id':
self.opts.append(path + '%(id)s.%(ext)s')
elif self.optManager.options['output_format'] == 'title':
self.opts.append(path + '%(title)s.%(ext)s')
elif self.optManager.options['output_format'] == 'custom':
self.opts.append(path + self.optManager.options['output_template'])
if self.optManager.options['restrict_filenames']:
self.opts.append('--restrict-filenames')
def set_audio_opts(self):
if self.optManager.options['to_audio']:
self.opts.append('-x')
self.opts.append('--audio-format')
self.opts.append(self.optManager.options['audio_format'])
if self.optManager.options['audio_quality'] != 'mid':
self.opts.append('--audio-quality')
self.opts.append(AUDIO_Q[self.optManager.options['audio_quality']])
if self.optManager.options['keep_video']:
self.opts.append('-k')
def set_other_opts(self):
if self.optManager.options['cmd_args'] != '':
for option in self.optManager.options['cmd_args'].split():
self.opts.append(option)

6
youtube_dl_gui/__init__.py

@ -4,9 +4,8 @@ from sys import exit
try:
import wx
except ImportError, e:
print '[ERROR]', e
print 'Please install latest wx.Python'
except ImportError as e:
print e
exit(1)
from .YoutubeDLGUI import MainFrame
@ -22,6 +21,7 @@ from .data import (
__licensefull__
)
def main():
app = wx.App()
frame = MainFrame()

1
youtube_dl_gui/data.py

@ -1,6 +1,7 @@
__author__ = 'Sotiris Papadopoulos'
__contact__ = 'ytubedlg@gmail.com'
__projecturl__ = 'http://mrs0m30n3.github.io/youtube-dl-gui/'
__appname__ = 'Youtube-DLG'
__license__ = 'UNLICENSE'

Loading…
Cancel
Save