66import threading
77import concurrent .futures
88
9- from .utils import format_bytes
10- from .exceptions import DownloadException , WatermarkIDDownloadException
9+ from .utils import format_bytes , normalize_filename
10+ from .exceptions import DownloadException , WatermarkIDDownloadException , AssetNotFullyUploaded
1111
1212thread_local = threading .local ()
1313
1414class FrameioDownloader (object ):
15- def __init__ (self , asset , download_folder , prefix , acceleration = False , concurrency = 5 ):
16- self .acceleration = acceleration
15+ def __init__ (self , asset , download_folder , prefix , multi_part = False , concurrency = 5 ):
16+ self .multi_part = multi_part
1717 self .asset = asset
18+ self .asset_type = None
1819 self .download_folder = download_folder
1920 self .resolution_map = dict ()
2021 self .destination = None
2122 self .watermarked = False
22- self .file_size = asset [' filesize' ]
23+ self .file_size = asset [" filesize" ]
2324 self .concurrency = concurrency
2425 self .futures = list ()
25- self .chunk_size = (52428800 / 2 ) # 25 MB chunk size or so
26- self .chunks = math .floor (self .file_size / self .chunk_size )
26+ self .chunk_size = (25 * 1024 * 1024 ) # 25 MB chunk size
27+ self .chunks = math .ceil (self .file_size / self .chunk_size )
2728 self .prefix = prefix
28- self .filename = asset ['name' ]
29+ self .filename = normalize_filename (asset ["name" ])
30+
31+ self ._evaluate_asset ()
32+
33+ def _evaluate_asset (self ):
34+ if self .asset .get ("_type" ) != "file" :
35+ raise DownloadException (message = "Unsupport Asset type: {}" .format (self .asset .get ("_type" )))
36+
37+ if self .asset .get ("upload_completed_at" ) == None :
38+ raise AssetNotFullyUploaded
2939
3040 def _get_session (self ):
3141 if not hasattr (thread_local , "session" ):
@@ -35,11 +45,11 @@ def _get_session(self):
3545 def _create_file_stub (self ):
3646 try :
3747 fp = open (self .destination , "wb" )
38- fp .write (b' \0 ' * self .file_size )
48+ fp .write (b" \0 " * self .file_size )
3949 fp .close ()
40- except Exception as e :
50+ except FileExistsError as e :
4151 print (e )
42- return False
52+ raise e
4353 return True
4454
4555 def get_download_key (self ):
@@ -88,49 +98,48 @@ def download_handler(self):
8898 if self .watermarked == True :
8999 return self .download (url )
90100 else :
91- if self .acceleration == True :
92- return self .accelerated_download (url )
101+ if self .multi_part == True :
102+ return self .multi_part_download (url )
93103 else :
94104 return self .download (url )
95105
96106 def download (self , url ):
97107 start_time = time .time ()
98- print ("Beginning download -- {} -- {}" .format (self .asset [' name' ], format_bytes (self .file_size , type = "size" )))
108+ print ("Beginning download -- {} -- {}" .format (self .asset [" name" ], format_bytes (self .file_size , type = "size" )))
99109
100110 # Downloading
101111 r = requests .get (url )
102- open (self .destination , 'wb' ).write (r .content )
112+ open (self .destination , "wb" ).write (r .content )
103113
104114 download_time = time .time () - start_time
105115 download_speed = format_bytes (math .ceil (self .file_size / (download_time )))
106- print ("Downloaded {} at {}" .format (self .file_size , download_speed ))
116+ print ("Downloaded {} at {}" .format (format_bytes ( self .file_size ) , download_speed ))
107117
108118 return self .destination , download_speed
109119
110- def accelerated_download (self , url ):
120+ def multi_part_download (self , url ):
111121 start_time = time .time ()
112122
113123 # Generate stub
114124 try :
115125 self ._create_file_stub ()
116126
117127 except Exception as e :
118- raise DownloadException
119- print ("Aborting" , e )
128+ raise DownloadException (message = e )
120129
121130 offset = math .ceil (self .file_size / self .chunks )
122131 in_byte = 0 # Set initially here, but then override
123132
124- print ("Accelerated download -- {} -- {}" .format (self .asset [' name' ], format_bytes (self .file_size , type = "size" )))
133+ print ("Multi-part download -- {} -- {}" .format (self .asset [" name" ], format_bytes (self .file_size , type = "size" )))
125134
126135 # Queue up threads
127136 with concurrent .futures .ThreadPoolExecutor (max_workers = self .concurrency ) as executor :
128137 for i in range (int (self .chunks )):
129- out_byte = offset * (i + 1 ) # Advance by one byte to get proper offset
138+ out_byte = offset * (i + 1 ) # Increment by the iterable + 1 so we don't mutiply by zero
130139 task = (url , in_byte , out_byte , i )
131140
132141 self .futures .append (executor .submit (self .download_chunk , task ))
133- in_byte = out_byte + 1 # Reset new in byte
142+ in_byte = out_byte # Reset new in byte equal to last out byte
134143
135144 # Wait on threads to finish
136145 for future in concurrent .futures .as_completed (self .futures ):
@@ -143,14 +152,13 @@ def accelerated_download(self, url):
143152 # Calculate and print stats
144153 download_time = time .time () - start_time
145154 download_speed = format_bytes (math .ceil (self .file_size / (download_time )))
146- print ("Downloaded {} at {}" .format (self .file_size , download_speed ))
155+ print ("Downloaded {} at {}" .format (format_bytes ( self .file_size ) , download_speed ))
147156
148157 return self .destination
149158
150-
151159 def download_chunk (self , task ):
152160 # Download a particular chunk
153- # Called by the threadpool execuor
161+ # Called by the threadpool executor
154162
155163 url = task [0 ]
156164 start_byte = task [1 ]
@@ -161,7 +169,7 @@ def download_chunk(self, task):
161169 print ("Getting chunk {}/{}" .format (chunk_number + 1 , self .chunks ))
162170
163171 # Specify the starting and ending of the file
164- headers = {' Range' : ' bytes=%d-%d' % (start_byte , end_byte )}
172+ headers = {" Range" : " bytes=%d-%d" % (start_byte , end_byte )}
165173
166174 # Grab the data as a stream
167175 r = session .get (url , headers = headers , stream = True )
@@ -171,6 +179,4 @@ def download_chunk(self, task):
171179 fp .write (r .content ) # Write the data
172180 print ("Done writing chunk {}/{}" .format (chunk_number + 1 , self .chunks ))
173181
174- print ("Completed chunk {}/{}" .format (chunk_number + 1 , self .chunks ))
175-
176182 return "Complete!"
0 commit comments