Fix streamTrack

Fixes several cases:
- When connection error thrown on retry, and subsequent retry started
  from the beginning, not the partial start
- Clone headers instead of adding Range header to dz.http_headers
  variables - this was causing errors on other requests
- Use 'with self.dz.session.get' to make sure request cleaned up on
  failure
- Fix calculation of downloadPercentage for retries: complete is now
  the size of the retry, so percentage needs to account for start
  value
This commit is contained in:
kermit 2020-09-29 19:39:17 +01:00
parent 04eb63b4cd
commit bb98953963
1 changed files with 43 additions and 32 deletions

View File

@ -642,43 +642,54 @@ class DownloadJob:
return error_num # fallback is enabled and loop went through all formats return error_num # fallback is enabled and loop went through all formats
def streamTrack(self, stream, track, range=None): def streamTrack(self, stream, track, start=0):
if self.queueItem.cancel: raise DownloadCancelled if self.queueItem.cancel: raise DownloadCancelled
try: headers=dict(self.dz.http_headers)
headers=self.dz.http_headers if range != 0:
if range is not None: headers['Range'] = f'bytes={start}-'
headers['Range'] = range chunkLength = start
request = self.dz.session.get(track.downloadUrl, headers=self.dz.http_headers, stream=True, timeout=10)
except request_exception.ConnectionError:
eventlet.sleep(2)
return self.streamTrack(stream, track)
request.raise_for_status()
blowfish_key = str.encode(self.dz._get_blowfish_key(str(track.id)))
complete = int(request.headers["Content-Length"])
if complete == 0:
raise DownloadEmpty
chunkLength = 0
percentage = 0 percentage = 0
try: try:
for chunk in request.iter_content(2048 * 3): with self.dz.session.get(track.downloadUrl, headers=headers, stream=True, timeout=10) as request:
eventlet.sleep(0) request.raise_for_status()
if self.queueItem.cancel: raise DownloadCancelled
if len(chunk) >= 2048: blowfish_key = str.encode(self.dz._get_blowfish_key(str(track.id)))
chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(chunk[0:2048]) + chunk[2048:]
stream.write(chunk) complete = int(request.headers["Content-Length"])
chunkLength += len(chunk) if complete == 0:
if isinstance(self.queueItem, QISingle): raise DownloadEmpty
percentage = (chunkLength / complete) * 100 if start != 0:
self.downloadPercentage = percentage responseRange = request.headers["Content-Range"]
logger.info(f'{track.title} downloading range {responseRange}')
else: else:
chunkProgres = (len(chunk) / complete) / self.queueItem.size * 100 logger.info(f'{track.title} downloading {complete} bytes')
self.downloadPercentage += chunkProgres
self.updatePercentage() for chunk in request.iter_content(2048 * 3):
except SSLError: if self.queueItem.cancel: raise DownloadCancelled
range = f'bytes={chunkLength}-'
logger.info(f'retrying {track.title} with range {range}') if len(chunk) >= 2048:
return self.streamTrack(stream, track, range) chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(chunk[0:2048]) + chunk[2048:]
stream.write(chunk)
chunkLength += len(chunk)
if isinstance(self.queueItem, QISingle):
percentage = (chunkLength / (complete + start)) * 100
self.downloadPercentage = percentage
else:
chunkProgres = (len(chunk) / (complete + start)) / self.queueItem.size * 100
self.downloadPercentage += chunkProgres
self.updatePercentage()
except SSLError as e:
logger.info(f'retrying {track.title} from byte {chunkLength}')
return self.streamTrack(stream, track, chunkLength)
except (request_exception.ConnectionError, requests.exceptions.ReadTimeout):
eventlet.sleep(2)
return self.streamTrack(stream, track, start)
def updatePercentage(self): def updatePercentage(self):
if round(self.downloadPercentage) != self.lastPercentage and round(self.downloadPercentage) % 2 == 0: if round(self.downloadPercentage) != self.lastPercentage and round(self.downloadPercentage) % 2 == 0: