diff --git a/youtube_dl_gui/downloaders.py b/youtube_dl_gui/downloaders.py index 6662237..94e6a14 100644 --- a/youtube_dl_gui/downloaders.py +++ b/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 diff --git a/youtube_dl_gui/downloadmanager.py b/youtube_dl_gui/downloadmanager.py index 26ccf11..ba582e9 100644 --- a/youtube_dl_gui/downloadmanager.py +++ b/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"