8
8
import concurrent .futures
9
9
10
10
from .utils import Utils
11
- from .exceptions import DownloadException , WatermarkIDDownloadException , AssetNotFullyUploaded
11
+ from .exceptions import (
12
+ DownloadException ,
13
+ WatermarkIDDownloadException ,
14
+ AssetNotFullyUploaded ,
15
+ AssetChecksumNotPresent ,
16
+ AssetChecksumMismatch
17
+ )
12
18
13
19
thread_local = threading .local ()
14
20
15
21
class FrameioDownloader (object ):
16
- def __init__ (self , asset , download_folder , prefix , multi_part = False , concurrency = 5 , replace = False ):
22
+ def __init__ (self , asset , download_folder , prefix = None , replace = False , checksum_verification = True , multi_part = False , concurrency = 5 ):
17
23
self .multi_part = multi_part
18
24
self .asset = asset
19
25
self .asset_type = None
@@ -29,8 +35,10 @@ def __init__(self, asset, download_folder, prefix, multi_part=False, concurrency
29
35
self .prefix = prefix
30
36
self .filename = Utils .normalize_filename (asset ["name" ])
31
37
self .replace = replace
38
+ self .checksum_verification = checksum_verification
32
39
33
40
self ._evaluate_asset ()
41
+ self ._get_path ()
34
42
35
43
def _evaluate_asset (self ):
36
44
if self .asset .get ("_type" ) != "file" :
@@ -45,19 +53,39 @@ def _get_session(self):
45
53
return thread_local .session
46
54
47
55
def _create_file_stub (self ):
56
+ if self .replace == True :
57
+ os .remove (self .destination ) # Remove the file
58
+ self ._create_file_stub () # Create a new stub
59
+
48
60
try :
49
61
fp = open (self .destination , "w" )
50
62
# fp.write(b"\0" * self.file_size) # Disabled to prevent pre-allocatation of disk space
51
63
fp .close ()
52
- except FileExistsError as e :
53
- if self .replace == True :
54
- os .remove (self .destination ) # Remove the file
55
- self ._create_file_stub () # Create a new stub
56
- else :
57
- print (e )
58
- raise e
64
+
65
+ except Exception as e :
66
+ raise e
67
+
59
68
return True
60
69
70
+ def _get_path (self ):
71
+ print ("prefix:" , self .prefix )
72
+ if self .prefix != None :
73
+ self .filename = self .prefix + self .filename
74
+
75
+ if self .destination == None :
76
+ final_destination = os .path .join (self .download_folder , self .filename )
77
+ self .destination = final_destination
78
+
79
+ return self .destination
80
+
81
+ def _get_checksum (self ):
82
+ try :
83
+ self .original_checksum = self .asset ['checksums' ]['xx_hash' ]
84
+ except (TypeError , KeyError ):
85
+ self .original_checksum = None
86
+
87
+ return self .original_checksum
88
+
61
89
def get_download_key (self ):
62
90
try :
63
91
url = self .asset ['original' ]
@@ -84,26 +112,27 @@ def get_download_key(self):
84
112
85
113
return url
86
114
87
- def get_path (self ):
88
- if self .prefix != None :
89
- self .filename = self .prefix + self .filename
115
+ def download_handler (self ):
116
+ if os .path .isfile (self .destination ) and self .replace != True :
117
+ try :
118
+ raise FileExistsError
119
+ except NameError :
120
+ raise OSError ('File exists' ) # Python < 3.3
90
121
91
- if self .destination == None :
92
- final_destination = os .path .join (self .download_folder , self .filename )
93
- self .destination = final_destination
94
-
95
- return self .destination
122
+ url = self .get_download_key ()
96
123
97
- def download_handler (self ):
98
- if os .path .isfile (self .get_path ()):
99
- print ("File already exists at this location." )
100
- return self .destination
124
+ if self .watermarked == True :
125
+ return self .download (url )
101
126
else :
102
- url = self .get_download_key ()
103
-
104
- if self .watermarked == True :
127
+ # Don't use multi-part download for files below 25 MB
128
+ if self .asset ['filesize' ] < 26214400 :
105
129
return self .download (url )
130
+ if self .multi_part == True :
131
+ return self .multi_part_download (url )
106
132
else :
133
+ # Don't use multi-part download for files below 25 MB
134
+ if self .asset ['filesize' ] < 26214400 :
135
+ return self .download (url )
107
136
if self .multi_part == True :
108
137
return self .multi_part_download (url )
109
138
else :
@@ -114,8 +143,17 @@ def download(self, url):
114
143
print ("Beginning download -- {} -- {}" .format (self .asset ["name" ], Utils .format_bytes (self .file_size , type = "size" )))
115
144
116
145
# Downloading
117
- r = requests .get (url )
118
- open (self .destination , "wb" ).write (r .content )
146
+ session = self ._get_session ()
147
+ r = session .get ('GET' , url , stream = True )
148
+
149
+ with open (self .destination , 'wb' ) as handle :
150
+ try :
151
+ # TODO make sure this approach works for SBWM download
152
+ for chunk in r .iter_content (chunk_size = 4096 ):
153
+ if chunk :
154
+ handle .write (chunk )
155
+ except requests .exceptions .ChunkedEncodingError as e :
156
+ raise e
119
157
120
158
download_time = time .time () - start_time
121
159
download_speed = Utils .format_bytes (math .ceil (self .file_size / (download_time )))
@@ -161,7 +199,17 @@ def multi_part_download(self, url):
161
199
download_speed = Utils .format_bytes (math .ceil (self .file_size / (download_time )))
162
200
print ("Downloaded {} at {}" .format (Utils .format_bytes (self .file_size , type = "size" ), download_speed ))
163
201
164
- return self .destination
202
+ if self .checksum_verification == True :
203
+ # Check for checksum, if not present throw error
204
+ if self ._get_checksum () == None :
205
+ raise AssetChecksumNotPresent
206
+ else :
207
+ if Utils .calculate_hash (self .destination ) != self .original_checksum :
208
+ raise AssetChecksumMismatch
209
+ else :
210
+ return self .destination
211
+ else :
212
+ return self .destination
165
213
166
214
def download_chunk (self , task ):
167
215
# Download a particular chunk
0 commit comments