def merge_multithreaded_download_parts(self): # merging parts with open(self.filepath, 'wb') as wfd: for f in range(ConfigHandler.get_threads(self)): tempfilepath = ConfigHandler.get_temp_dir( self) + "/temp" + str(f) with open(tempfilepath, "rb") as fd: shutil.copyfileobj(fd, wfd) # delete copied segment FileHandler.delete_file(self, tempfilepath)
def download(self): ConfigHandler.parse_config(self) if ConfigHandler.get_proxy(self): self.http = urllib3.ProxyManager(ConfigHandler.get_proxy(self)) else: self.http = urllib3.PoolManager() # make sure that download path and temp directory exists FileHandler.create_dir(self, ConfigHandler.get_download_dir(self)) FileHandler.create_dir(self, ConfigHandler.get_temp_dir(self)) # extracting filename from URL self.filename = os.path.basename(self.url.replace("%20", "_")) # getting complete filepath self.filepath = ConfigHandler.get_download_dir( self) + "/" + self.filename #making an initial request to get header information resp = self.make_request() # extracting the size of file to be downloaded in bytes, from header self.filesize = int(resp.headers['Content-Length']) # if server supports segmented download if self.range_download_support(resp): # get ranges for download for each thread ranges_list = self.get_download_ranges_list() # perform multithreaded download on single system self.multithreaded_download(ranges_list) # merge multithreaded download parts self.merge_multithreaded_download_parts() else: print('''Server doesn't support multithreaded downloads! Download will be performed using single thread, on master system.''') self.seg_handler(self.filepath, 0, self.filesize - 1) # perform final cleaning after download completion self.final_clean(interrupted=False)
def multithreaded_download(self, ranges_list): # downloading each segment for f in range(ConfigHandler.get_threads(self)): # calling seg_handler() for each thread t = threading.Thread(target=self.seg_handler, kwargs={ 'tempfilepath': ConfigHandler.get_temp_dir(self) + "/temp" + str(f), 'range_left': ranges_list[f][0], 'range_right': ranges_list[f][1] }) t.setDaemon(True) t.start() # except main_thread, calling join() for each thread # it ensures that merging of parts occur only after each thread has completed downloading main_thread = threading.current_thread() for t in threading.enumerate(): if t is main_thread: continue t.join()
def final_clean(self, interrupted=False): FileHandler.delete_dir(self, ConfigHandler.get_temp_dir(self)) if interrupted == True: ''' delete the partially downloaded file if user interrupted the download ''' FileHandler.delete_file(self, self.filepath)