@@ -177,62 +177,89 @@ def show_app_detail(self, app):
177177 intent .putExtra ("appstore" , self )
178178 self .startActivity (intent )
179179
180- async def download_url (self , url , outfile = None , total_size = None , progress_callback = None ):
180+ '''
181+ This async download function can be used in 3 ways:
182+ - with just a url => returns the content
183+ - with a url and an outfile => writes the content to the outfile
184+ - with a url and a chunk_callback => calls the chunk_callback(chunk_data) for each chunk
185+
186+ Optionally:
187+ - progress_callback is called with the % (0-100) progress
188+ - if total_size is not provided, it will be taken from the response headers (if present) or default to 100KB
189+
190+ Can return either:
191+ - the actual content
192+ - None: if the content failed to download
193+ - True: if the URL was successfully downloaded (and written to outfile, if provided)
194+ - False: if the URL was not successfully download and written to outfile
195+ '''
196+ async def download_url (self , url , outfile = None , total_size = None , progress_callback = None , chunk_callback = None ):
181197 print (f"Downloading { url } " )
182198 #await TaskManager.sleep(4) # test slowness
183199 try :
184200 async with self .aiohttp_session .get (url ) as response :
185201 if response .status < 200 or response .status >= 400 :
186202 return False if outfile else None
187203
188- # Always use chunked downloading
189- chunk_size = 1024
204+ # Figure out total size
190205 print ("headers:" ) ; print (response .headers )
191206 if total_size is None :
192207 total_size = response .headers .get ('Content-Length' ) # some servers don't send this in the headers
193- print (f"download_url { 'writing to ' + outfile if outfile else 'reading' } { total_size } bytes in chunks of size { chunk_size } " )
194-
195- fd = open (outfile , 'wb' ) if outfile else None
196- chunks = [] if not outfile else None
208+ if total_size is None :
209+ print ("WARNING: Unable to determine total_size from server's reply and function arguments, assuming 100KB" )
210+ total_size = 100 * 1024
211+
212+ fd = None
213+ if outfile :
214+ fd = open (outfile , 'wb' )
215+ if not fd :
216+ print ("WARNING: could not open {outfile} for writing!" )
217+ return False
218+ chunks = []
197219 partial_size = 0
220+ chunk_size = 1024
198221
199- if fd :
200- print ("opened file..." )
222+ print (f"download_url { 'writing to ' + outfile if outfile else 'downloading' } { total_size } bytes in chunks of size { chunk_size } " )
201223
202224 while True :
203225 tries_left = 3
204- chunk = None
226+ chunk_data = None
205227 while tries_left > 0 :
206228 try :
207- chunk = await TaskManager .wait_for (response .content .read (chunk_size ), 10 )
229+ chunk_data = await TaskManager .wait_for (response .content .read (chunk_size ), 10 )
208230 break
209231 except Exception as e :
210- print (f"Waiting for response.content.read of next chunk got error: { e } " )
232+ print (f"Waiting for response.content.read of next chunk_data got error: { e } " )
211233 tries_left -= 1
212234
213235 if tries_left == 0 :
214- print ("ERROR: failed to download chunk , even with retries!" )
236+ print ("ERROR: failed to download chunk_data , even with retries!" )
215237 if fd :
216238 fd .close ()
217239 return False if outfile else None
218240
219- if chunk :
220- partial_size += len (chunk )
241+ if chunk_data :
242+ # Output
243+ if fd :
244+ fd .write (chunk_data )
245+ elif chunk_callback :
246+ await chunk_callback (chunk_data )
247+ else :
248+ chunks .append (chunk_data )
249+ # Report progress
250+ partial_size += len (chunk_data )
221251 progress_pct = round ((partial_size * 100 ) / int (total_size ))
222252 print (f"progress: { partial_size } / { total_size } bytes = { progress_pct } %" )
223253 if progress_callback :
224254 await progress_callback (progress_pct )
225255 #await TaskManager.sleep(1) # test slowness
226- if fd :
227- fd .write (chunk )
228- else :
229- chunks .append (chunk )
230256 else :
231- print ("chunk is None while there was no error so this was the last one" )
232- print (f"Done downloading { url } " )
257+ print ("chunk_data is None while there was no error so this was the last one.\n Finished downloading {url}" )
233258 if fd :
234259 fd .close ()
235260 return True
261+ elif chunk_callback :
262+ return True
236263 else :
237264 return b'' .join (chunks )
238265 except Exception as e :
0 commit comments