Browse Source

Move download info to the Worker class

Move download informations from the downloaders.py module
to the downloadmanager.py Worker class. By moving those
informations to the Worker class we don't need to add them
in each downloader separately every time a new one gets
implemented, giving us a better design overall.
doc-issue-template
MrS0m30n3 9 years ago
parent
commit
6b3c6ac306
2 changed files with 101 additions and 102 deletions
  1. 112
      youtube_dl_gui/downloaders.py
  2. 91
      youtube_dl_gui/downloadmanager.py

112
youtube_dl_gui/downloaders.py

@ -98,9 +98,6 @@ class YoutubeDLDownloader(object):
log_data (function): Optional callback function to write data to
the log file.
Note:
For available data keys check self._data under __init__().
Warnings:
The caller is responsible for calling the close() method after he has
finished with the object in order for the object to be able to properly
@ -134,18 +131,6 @@ class YoutubeDLDownloader(object):
self._return_code = self.OK
self._proc = None
self._data = {
'playlist_index': None,
'playlist_size': None,
'extension': None,
'filesize': None,
'filename': None,
'percent': None,
'status': None,
'speed': None,
'path': None,
'eta': None
}
self._encoding = self._get_encoding()
self._stderr_queue = Queue()
@ -171,7 +156,7 @@ class YoutubeDLDownloader(object):
STOPPED (5): The download process was stopped by the user.
"""
self._reset()
self._return_code = self.OK
cmd = self._get_cmd(url, options)
self._create_process(cmd)
@ -183,8 +168,9 @@ class YoutubeDLDownloader(object):
stdout = stdout.decode(self._encoding, 'ignore')
if stdout:
self._sync_data(extract_data(stdout))
self._hook_data()
data_dict = extract_data(stdout)
self._extract_info(data_dict)
self._hook_data(data_dict)
# Read stderr after download process has been completed
# We don't need to read stderr in real time
@ -231,36 +217,31 @@ class YoutubeDLDownloader(object):
def _last_data_hook(self):
"""Set the last data information based on the return code. """
data_dictionary = {}
if self._return_code == self.OK:
self._data['status'] = 'Finished'
data_dictionary['status'] = 'Finished'
elif self._return_code == self.ERROR:
self._data['status'] = 'Error'
self._data['speed'] = ''
self._data['eta'] = ''
data_dictionary['status'] = 'Error'
data_dictionary['speed'] = ''
data_dictionary['eta'] = ''
elif self._return_code == self.WARNING:
self._data['status'] = 'Warning'
self._data['speed'] = ''
self._data['eta'] = ''
data_dictionary['status'] = 'Warning'
data_dictionary['speed'] = ''
data_dictionary['eta'] = ''
elif self._return_code == self.STOPPED:
self._data['status'] = 'Stopped'
self._data['speed'] = ''
self._data['eta'] = ''
data_dictionary['status'] = 'Stopped'
data_dictionary['speed'] = ''
data_dictionary['eta'] = ''
elif self._return_code == self.ALREADY:
self._data['status'] = 'Already Downloaded'
data_dictionary['status'] = 'Already Downloaded'
else:
self._data['status'] = 'Filesize Abort'
self._hook_data()
def _reset(self):
"""Reset the data. """
self._return_code = self.OK
data_dictionary['status'] = 'Filesize Abort'
for key in self._data:
self._data[key] = None
self._hook_data(data_dictionary)
def _sync_data(self, data):
"""Synchronise self._data with data. It also filters some keys.
def _extract_info(self, data):
"""Extract informations about the download process from the given data.
Args:
data (dictionary): Python dictionary that contains different
@ -268,31 +249,28 @@ class YoutubeDLDownloader(object):
empty when there are no data to extract. See extract_data().
"""
for key in data:
if key == 'status':
if data['status'] == 'Already Downloaded':
# Set self._return_code to already downloaded
# and trash that key
self._set_returncode(self.ALREADY)
data['status'] = None
if data['status'] == 'Filesize Abort':
# Set self._return_code to filesize abort
# and trash that key
self._set_returncode(self.FILESIZE_ABORT)
data['status'] = None
self._data[key] = data[key]
if 'status' in data:
if data['status'] == 'Already Downloaded':
# Set self._return_code to already downloaded
# and trash that key
self._set_returncode(self.ALREADY)
data['status'] = None
if data['status'] == 'Filesize Abort':
# Set self._return_code to filesize abort
# and trash that key
self._set_returncode(self.FILESIZE_ABORT)
data['status'] = None
def _log(self, data):
"""Log data using the callback function. """
if self.log_data is not None:
self.log_data(data)
def _hook_data(self):
"""Pass self._data back to the data_hook. """
def _hook_data(self, data):
"""Pass data back to the caller. """
if self.data_hook is not None:
self.data_hook(self._data)
self.data_hook(data)
def _proc_is_alive(self):
"""Returns True if self._proc is alive else False. """
@ -366,11 +344,23 @@ def extract_data(stdout):
stdout (string): String that contains the youtube-dl stdout.
Returns:
Python dictionary. For available keys check self._data under
YoutubeDLDownloader.__init__().
Python dictionary. The returned dictionary can be empty if there are
no data to extract else it may contain one or more of the
following keys:
'status' : Contains the status of the download process.
'path' : Destination path.
'extension' : The file extension.
'filename' : The filename without the extension.
'percent' : The percentage of the video being downloaded.
'eta' : Estimated time for the completion of the download process.
'speed' : Download speed.
'filesize' : The size of the video file being downloaded.
'playlist_index' : The playlist index of the current video file being downloaded.
'playlist_size' : The number of videos in the playlist.
"""
data_dictionary = dict()
data_dictionary = {}
if not stdout:
return data_dictionary

91
youtube_dl_gui/downloadmanager.py

@ -207,7 +207,7 @@ class DownloadManager(Thread):
class Worker(Thread):
"""Simple worker which downloads the given url using a downloader
from the 'downloaders' module.
from the downloaders.py module.
Attributes:
WAIT_TIME (float): Time in seconds to sleep.
@ -225,6 +225,9 @@ class Worker(Thread):
If the log_manager is set (not None) then the caller has to make
sure that the log_lock is also set.
Note:
For available data keys see self._data under the __init__() method.
"""
WAIT_TIME = 0.1
@ -237,25 +240,37 @@ class Worker(Thread):
self._downloader = YoutubeDLDownloader(youtubedl, self._data_hook, self._log_data)
self._options_parser = OptionsParser()
self._running = True
self._url = None
self._index = -1
self._successful = 0
self._running = True
self._data = {
'playlist_index': None,
'playlist_size': None,
'extension': None,
'filesize': None,
'filename': None,
'percent': None,
'status': None,
'index': None,
'speed': None,
'path': None,
'eta': None,
'url': None
}
self.start()
def run(self):
while self._running:
if self._url is not None:
if self._data['url'] is not None:
options = self._options_parser.parse(self.opt_manager.options)
ret_code = self._downloader.download(self._url, options)
ret_code = self._downloader.download(self._data['url'], options)
if (ret_code == YoutubeDLDownloader.OK or
ret_code == YoutubeDLDownloader.ALREADY):
self._successful += 1
# Reset url value
self._url = None
self._reset()
time.sleep(self.WAIT_TIME)
@ -272,8 +287,8 @@ class Worker(Thread):
download process.
"""
self._url = item['url']
self._index = item['index']
self._data['url'] = item['url']
self._data['index'] = item['index']
def stop_download(self):
"""Stop the download process of the worker. """
@ -286,13 +301,18 @@ class Worker(Thread):
def available(self):
"""Return True if the worker has no job else False. """
return self._url is None
return self._data['url'] is None
@property
def successful(self):
"""Return the number of successful downloads for current worker. """
return self._successful
def _reset(self):
"""Reset self._data back to the original state. """
for key in self._data:
self._data[key] = None
def _log_data(self, data):
"""Callback method for self._downloader.
@ -309,43 +329,32 @@ class Worker(Thread):
self.log_lock.release()
def _data_hook(self, data):
"""Callback method to be used with the YoutubeDLDownloader object.
"""Callback method for self._downloader.
This method takes the data from the downloader, merges the
playlist_info with the current status(if any) and sends the
data back to the GUI using the self._talk_to_gui method.
This method updates self._data and sends them back to the GUI
using the self._talk_to_gui() method.
Args:
data (dictionary): Python dictionary which contains information
about the download process. (See YoutubeDLDownloader class).
about the download process. For more info see the
extract_data() function under the downloaders.py module.
"""
if data['status'] is not None and data['playlist_index'] is not None:
playlist_info = ' '
playlist_info += data['playlist_index']
playlist_info += '/'
playlist_info += data['playlist_size']
# Update each key
for key in data:
self._data[key] = data[key]
data['status'] += playlist_info
# Build the playlist status
if self._data['status'] is not None and self._data['playlist_index'] is not None:
self._data['status'] = '{status} {index}/{size}'.format(
status=self._data['status'],
index=self._data['playlist_index'],
size=self._data['playlist_size']
)
self._talk_to_gui(data)
self._talk_to_gui()
def _talk_to_gui(self, data):
"""Send data back to the GUI after inserting the index. """
data['index'] = self._index
CallAfter(Publisher.sendMessage, WORKER_PUB_TOPIC, data)
if __name__ == '__main__':
"""Direct call of the module for testing.
Raises:
ValueError: Attempted relative import in non-package
def _talk_to_gui(self):
"""Send self._data back to the GUI. """
CallAfter(Publisher.sendMessage, WORKER_PUB_TOPIC, self._data)
Note:
Before you run the tests change relative imports else an exceptions
will be raised. You need to change relative imports on all the modules
you are gonna use.
"""
print "No tests available"
Loading…
Cancel
Save