2017-05-12 20:51:49 +02:00
|
|
|
import functools
|
2017-07-28 20:01:19 +03:00
|
|
|
import hashlib
|
2017-09-02 22:16:28 +03:00
|
|
|
import random
|
|
|
|
import string
|
2017-05-12 20:51:49 +02:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
|
|
|
|
def sha1_hash(input_bytes):
|
|
|
|
""" Hash given bytes with hashlib.sha1 and return the digest (as bytes) """
|
|
|
|
return hashlib.sha1(input_bytes).digest()
|
|
|
|
|
|
|
|
|
|
|
|
def sorted_pathdict(input_dict):
|
|
|
|
""" Sorts a parsed torrent filelist dict by alphabat, directories first """
|
|
|
|
directories = OrderedDict()
|
|
|
|
files = OrderedDict()
|
|
|
|
|
|
|
|
for key, value in input_dict.items():
|
|
|
|
if isinstance(value, dict):
|
|
|
|
directories[key] = sorted_pathdict(value)
|
|
|
|
else:
|
|
|
|
files[key] = value
|
|
|
|
|
|
|
|
return OrderedDict(sorted(directories.items()) + sorted(files.items()))
|
|
|
|
|
|
|
|
|
2017-09-02 22:16:28 +03:00
|
|
|
def random_string(length, charset=None):
|
|
|
|
if charset is None:
|
|
|
|
charset = string.ascii_letters + string.digits
|
|
|
|
return ''.join(random.choice(charset) for i in range(length))
|
|
|
|
|
|
|
|
|
2017-05-12 20:51:49 +02:00
|
|
|
def cached_function(f):
|
|
|
|
sentinel = object()
|
|
|
|
f._cached_value = sentinel
|
|
|
|
|
|
|
|
@functools.wraps(f)
|
|
|
|
def decorator(*args, **kwargs):
|
|
|
|
if f._cached_value is sentinel:
|
|
|
|
f._cached_value = f(*args, **kwargs)
|
|
|
|
return f._cached_value
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
2017-07-08 00:14:37 +03:00
|
|
|
def flatten_dict(d, result=None):
|
2017-05-12 20:51:49 +02:00
|
|
|
if result is None:
|
|
|
|
result = {}
|
|
|
|
for key in d:
|
|
|
|
value = d[key]
|
|
|
|
if isinstance(value, dict):
|
|
|
|
value1 = {}
|
|
|
|
for keyIn in value:
|
|
|
|
value1["/".join([key, keyIn])] = value[keyIn]
|
2017-07-08 00:14:37 +03:00
|
|
|
flatten_dict(value1, result)
|
2017-05-12 20:51:49 +02:00
|
|
|
elif isinstance(value, (list, tuple)):
|
|
|
|
for indexB, element in enumerate(value):
|
|
|
|
if isinstance(element, dict):
|
|
|
|
value1 = {}
|
|
|
|
index = 0
|
|
|
|
for keyIn in element:
|
|
|
|
newkey = "/".join([key, keyIn])
|
2017-07-08 00:14:37 +03:00
|
|
|
value1[newkey] = value[indexB][keyIn]
|
2017-05-12 20:51:49 +02:00
|
|
|
index += 1
|
|
|
|
for keyA in value1:
|
2017-07-08 00:14:37 +03:00
|
|
|
flatten_dict(value1, result)
|
2017-05-12 20:51:49 +02:00
|
|
|
else:
|
|
|
|
result[key] = value
|
|
|
|
return result
|
2017-07-08 00:50:55 +03:00
|
|
|
|
|
|
|
|
|
|
|
def chain_get(source, *args):
|
|
|
|
''' Tries to return values from source by the given keys.
|
|
|
|
Returns None if none match.
|
|
|
|
Note: can return a None from the source. '''
|
|
|
|
sentinel = object()
|
|
|
|
for key in args:
|
|
|
|
value = source.get(key, sentinel)
|
|
|
|
if value is not sentinel:
|
|
|
|
return value
|
|
|
|
return None
|