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.

120 lines
4.6 KiB

3 years ago
import threading
import time
from . import utils
class ControlThread(threading.Thread):
"A class that shows information about a running SmartDL object."
def __init__(self, obj):
threading.Thread.__init__(self)
self.obj = obj
self.progress_bar = obj.progress_bar
self.logger = obj.logger
self.shared_var = obj.shared_var
self.dl_speed = 0
self.eta = 0
self.lastBytesSamples = [] # list with last 50 Bytes Samples.
self.last_calculated_totalBytes = 0
self.calcETA_queue = []
self.calcETA_i = 0
self.calcETA_val = 0
self.dl_time = -1.0
self.daemon = True
self.start()
def run(self):
t1 = time.time()
self.logger.info("Control thread has been started.")
while not self.obj.pool.done():
self.dl_speed = self.calcDownloadSpeed(self.shared_var.value)
if self.dl_speed > 0:
self.eta = self.calcETA((self.obj.filesize-self.shared_var.value)/self.dl_speed)
if self.progress_bar:
if self.obj.filesize:
status = r"[*] %s / %s @ %s/s %s [%3.1f%%, %s left] " % (utils.sizeof_human(self.shared_var.value), utils.sizeof_human(self.obj.filesize), utils.sizeof_human(self.dl_speed), utils.progress_bar(1.0*self.shared_var.value/self.obj.filesize), self.shared_var.value * 100.0 / self.obj.filesize, utils.time_human(self.eta, fmt_short=True))
else:
status = r"[*] %s / ??? MB @ %s/s " % (utils.sizeof_human(self.shared_var.value), utils.sizeof_human(self.dl_speed))
status = status + chr(8)*(len(status)+1)
print(status, end=' ', flush=True)
time.sleep(0.1)
if self.obj._killed:
self.logger.info("File download process has been stopped.")
return
if self.progress_bar:
if self.obj.filesize:
print(r"[*] %s / %s @ %s/s %s [100%%, 0s left] " % (utils.sizeof_human(self.obj.filesize), utils.sizeof_human(self.obj.filesize), utils.sizeof_human(self.dl_speed), utils.progress_bar(1.0)))
else:
print(r"[*] %s / %s @ %s/s " % (utils.sizeof_human(self.shared_var.value), utils.sizeof_human(self.shared_var.value), utils.sizeof_human(self.dl_speed)))
t2 = time.time()
self.dl_time = float(t2-t1)
while self.obj.post_threadpool_thread.is_alive():
time.sleep(0.1)
self.obj.pool.shutdown()
self.obj.status = "finished"
if not self.obj.errors:
self.logger.info("File downloaded within %.2f seconds." % self.dl_time)
def get_eta(self):
if self.eta <= 0 or self.obj.status == 'paused':
return 0
return self.eta
def get_speed(self):
if self.obj.status == 'paused':
return 0
return self.dl_speed
def get_dl_size(self):
if self.shared_var.value > self.obj.filesize:
return self.obj.filesize
return self.shared_var.value
def get_final_filesize(self):
return self.obj.filesize
def get_progress(self):
if not self.obj.filesize:
return 0
return 1.0*self.shared_var.value/self.obj.filesize
def get_dl_time(self):
return self.dl_time
def calcDownloadSpeed(self, totalBytes, sampleCount=30, sampleDuration=0.1):
'''
Function calculates the download rate.
@param totalBytes: The total amount of bytes.
@param sampleCount: How much samples should the function take into consideration.
@param sampleDuration: Duration of a sample in seconds.
'''
l = self.lastBytesSamples
newBytes = totalBytes - self.last_calculated_totalBytes
self.last_calculated_totalBytes = totalBytes
if newBytes >= 0: # newBytes may be negetive, will happen
# if a thread has crushed and the totalBytes counter got decreased.
if len(l) == sampleCount: # calc download for last 3 seconds (30 * 100ms per signal emit)
l.pop(0)
l.append(newBytes)
dlRate = sum(l)/len(l)/sampleDuration
return dlRate
def calcETA(self, eta):
self.calcETA_i += 1
l = self.calcETA_queue
l.append(eta)
if self.calcETA_i % 10 == 0:
self.calcETA_val = sum(l)/len(l)
if len(l) == 30:
l.pop(0)
if self.calcETA_i < 50:
return 0
return self.calcETA_val