Tweaks to get the progress bar working as expected.
This commit is contained in:
@@ -92,50 +92,72 @@ class BrickInstructions(object):
|
|||||||
|
|
||||||
# Download an instruction file
|
# Download an instruction file
|
||||||
def download(self, path: str, /) -> None:
|
def download(self, path: str, /) -> None:
|
||||||
|
"""
|
||||||
|
Streams the PDF in chunks and uses self.socket.update_total
|
||||||
|
+ self.socket.progress_count to drive a determinate bar.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# start progress
|
|
||||||
self.socket.progress(message=f'Downloading {self.filename}')
|
|
||||||
target = self.path(filename=secure_filename(self.filename))
|
target = self.path(filename=secure_filename(self.filename))
|
||||||
|
|
||||||
# skip if already exists
|
# Skip if we already have it
|
||||||
if os.path.isfile(target):
|
if os.path.isfile(target):
|
||||||
return self.socket.complete(
|
return self.socket.complete(
|
||||||
message=f'File {self.filename} already exists, skipped'
|
message=f"File {self.filename} already exists, skipped"
|
||||||
)
|
)
|
||||||
|
|
||||||
# path is already a full URL from find_instructions()
|
# Fetch PDF via cloudscraper (to bypass Cloudflare)
|
||||||
url = path
|
|
||||||
self.socket.progress(message=f'Requesting {url}')
|
|
||||||
# use cloudscraper to pass the CF challenge here too
|
|
||||||
scraper = cloudscraper.create_scraper()
|
scraper = cloudscraper.create_scraper()
|
||||||
scraper.headers.update({'User-Agent': current_app.config['REBRICKABLE_USER_AGENT']})
|
scraper.headers.update({
|
||||||
response = scraper.get(url, stream=True)
|
"User-Agent": current_app.config['REBRICKABLE_USER_AGENT']
|
||||||
if not response.ok:
|
})
|
||||||
raise DownloadException(f'Failed to download: HTTP {response.status_code}')
|
resp = scraper.get(path, stream=True)
|
||||||
|
if not resp.ok:
|
||||||
|
raise DownloadException(f"Failed to download: HTTP {resp.status_code}")
|
||||||
|
|
||||||
# record size if available
|
# Tell the socket how many bytes in total
|
||||||
try:
|
total = int(resp.headers.get("Content-Length", 0))
|
||||||
self.size = int(response.headers.get('Content-Length', 0))
|
self.socket.update_total(total)
|
||||||
except ValueError:
|
|
||||||
self.size = 0
|
|
||||||
|
|
||||||
# download to disk
|
# Reset the counter and kick off at 0%
|
||||||
self.socket.progress(message=f'Downloading {self.filename} ({self.human_size()})')
|
self.socket.progress_count = 0
|
||||||
with open(target, 'wb') as f:
|
self.socket.progress(message=f"Starting download {self.filename}")
|
||||||
copyfileobj(response.raw, f)
|
|
||||||
|
|
||||||
logger.info(f'The instruction file {self.filename} has been downloaded')
|
# Write out in 8 KiB chunks and update the counter
|
||||||
self.socket.complete(message=f'File {self.filename} downloaded ({self.human_size()})')
|
with open(target, "wb") as f:
|
||||||
|
for chunk in resp.iter_content(chunk_size=8192):
|
||||||
|
if not chunk:
|
||||||
|
continue
|
||||||
|
f.write(chunk)
|
||||||
|
|
||||||
|
# Bump the internal counter and emit
|
||||||
|
self.socket.progress_count += len(chunk)
|
||||||
|
self.socket.progress(
|
||||||
|
message=(
|
||||||
|
f"Downloading {self.filename} "
|
||||||
|
f"({humanize.naturalsize(self.socket.progress_count)}/"
|
||||||
|
f"{humanize.naturalsize(self.socket.progress_total)})"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Done!
|
||||||
|
logger.info(f"Downloaded {self.filename}")
|
||||||
|
self.socket.complete(
|
||||||
|
message=f"File {self.filename} downloaded ({self.human_size()})"
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.socket.fail(
|
|
||||||
message=f'Error downloading {self.filename}: {e}'
|
|
||||||
)
|
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
|
self.socket.fail(
|
||||||
|
message=f"Error downloading {self.filename}: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
# Display the size in a human format
|
# Display the size in a human format
|
||||||
def human_size(self) -> str:
|
def human_size(self) -> str:
|
||||||
return humanize.naturalsize(self.size)
|
try:
|
||||||
|
size = self.size
|
||||||
|
except AttributeError:
|
||||||
|
size = os.path.getsize(self.path())
|
||||||
|
return humanize.naturalsize(size)
|
||||||
|
|
||||||
# Display the time in a human format
|
# Display the time in a human format
|
||||||
def human_time(self) -> str:
|
def human_time(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user