+# Title string normalization
+def title_string_norm(title):
+ title = ''.join((x in string.ascii_letters or x in string.digits) and x or ' ' for x in title)
+ title = '_'.join(title.split())
+ title = title.lower()
+ return title
+
+# Title string minimal transformation
+def title_string_touch(title):
+ return title.replace(os.sep, '%')
+
+# Generic download step
+def download_step(return_data_flag, step_title, step_error, url, post_data=None):
+ try:
+ cond_print('%s... ' % step_title)
+ data = perform_request(url, post_data).read()
+ cond_print('done.\n')
+ if return_data_flag:
+ return data
+ return None
+
+ except (urllib2.URLError, ValueError, httplib.HTTPException, TypeError, socket.error):
+ cond_print('failed.\n')
+ error_advice_exit(step_error)
+
+ except KeyboardInterrupt:
+ sys.exit('\n')
+
+# Generic extract step
+def extract_step(step_title, step_error, regexp, data):
+ try:
+ cond_print('%s... ' % step_title)
+ match = regexp.search(data)
+
+ if match is None:
+ cond_print('failed.\n')
+ error_advice_exit(step_error)
+
+ extracted_data = match.group(1)
+ cond_print('done.\n')
+ return extracted_data
+
+ except KeyboardInterrupt:
+ sys.exit('\n')
+
+# Calculate new block size based on previous block size
+def new_block_size(before, after, bytes):
+ new_min = max(bytes / 2.0, 1.0)
+ new_max = max(bytes * 2.0, 1.0)
+ dif = after - before
+ if dif < 0.0001:
+ return int(new_max)
+ rate = bytes / dif
+ if rate > new_max:
+ return int(new_max)
+ if rate < new_min:
+ return int(new_min)
+ return int(rate)
+
+# Get optimum 1k exponent to represent a number of bytes
+def optimum_k_exp(num_bytes):
+ global const_1k
+ if num_bytes == 0:
+ return 0
+ return long(math.log(num_bytes, const_1k))
+
+# Get optimum representation of number of bytes
+def format_bytes(num_bytes):
+ global const_1k
+ try:
+ exp = optimum_k_exp(num_bytes)
+ suffix = 'bkMGTPEZY'[exp]
+ if exp == 0:
+ return '%s%s' % (num_bytes, suffix)
+ converted = float(num_bytes) / float(const_1k**exp)
+ return '%.2f%s' % (converted, suffix)
+ except IndexError:
+ sys.exit('Error: internal error formatting number of bytes.')
+
+# Calculate ETA and return it in string format as MM:SS
+def calc_eta(start, now, total, current):
+ if current == 0:
+ return '--:--'
+ rate = float(current) / (now - start)
+ eta = long((total - current) / rate)
+ eta_mins = eta / 60
+ eta_secs = eta % 60
+ if eta_mins > 99:
+ return '--:--'
+ return '%02d:%02d' % (eta_mins, eta_secs)
+
+# Calculate speed and return it in string format
+def calc_speed(start, now, bytes):
+ if bytes == 0:
+ return 'N/A b'
+ return format_bytes(float(bytes) / (now - start))
+