class method bug fix, verbose output option added, download progress
This commit is contained in:
parent
fc96c963e4
commit
115fcbced1
3 changed files with 28 additions and 16 deletions
39
mega/mega.py
39
mega/mega.py
|
@ -11,10 +11,11 @@ import time
|
||||||
import shutil
|
import shutil
|
||||||
from .errors import ValidationError, RequestError
|
from .errors import ValidationError, RequestError
|
||||||
from .crypto import *
|
from .crypto import *
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
class Mega(object):
|
class Mega(object):
|
||||||
def __init__(self):
|
def __init__(self, options=None):
|
||||||
self.schema = 'https'
|
self.schema = 'https'
|
||||||
self.domain = 'mega.co.nz'
|
self.domain = 'mega.co.nz'
|
||||||
self.timeout = 160 # max time (secs) to wait for resp from api requests
|
self.timeout = 160 # max time (secs) to wait for resp from api requests
|
||||||
|
@ -22,11 +23,14 @@ class Mega(object):
|
||||||
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
||||||
self.request_id = make_id(10)
|
self.request_id = make_id(10)
|
||||||
|
|
||||||
@classmethod
|
if options is None:
|
||||||
def login(cls, email, password):
|
options = {}
|
||||||
instance = cls()
|
self.options = options
|
||||||
instance.login_user(email, password)
|
|
||||||
return instance
|
|
||||||
|
def login(self, email, password):
|
||||||
|
self.login_user(email, password)
|
||||||
|
return self
|
||||||
|
|
||||||
def login_user(self, email, password):
|
def login_user(self, email, password):
|
||||||
password_aes = prepare_key(str_to_a32(password))
|
password_aes = prepare_key(str_to_a32(password))
|
||||||
|
@ -394,7 +398,7 @@ class Mega(object):
|
||||||
meta_mac = file['meta_mac']
|
meta_mac = file['meta_mac']
|
||||||
|
|
||||||
# Seems to happens sometime... When this occurs, files are
|
# Seems to happens sometime... When this occurs, files are
|
||||||
# inaccessible also in the official also in the official webapp.
|
# inaccessible also in the official also in the official web app.
|
||||||
# Strangely, files can come back later.
|
# Strangely, files can come back later.
|
||||||
if 'g' not in file_data:
|
if 'g' not in file_data:
|
||||||
raise RequestError('File not accessible anymore')
|
raise RequestError('File not accessible anymore')
|
||||||
|
@ -403,14 +407,15 @@ class Mega(object):
|
||||||
attribs = base64_url_decode(file_data['at'])
|
attribs = base64_url_decode(file_data['at'])
|
||||||
attribs = decrypt_attr(attribs, k)
|
attribs = decrypt_attr(attribs, k)
|
||||||
file_name = attribs['n']
|
file_name = attribs['n']
|
||||||
file_name_tmp = '.megapy-%s-%s' % (int(time.time() * 1000), file_name)
|
|
||||||
|
|
||||||
input_file = requests.get(file_url, stream=True).raw
|
input_file = requests.get(file_url, stream=True).raw
|
||||||
|
|
||||||
if dest_path:
|
if dest_path is None:
|
||||||
output_file = open(dest_path + '/' + file_name_tmp, 'wb')
|
dest_path = ''
|
||||||
else:
|
else:
|
||||||
output_file = open(file_name_tmp, 'wb')
|
dest_path += '/'
|
||||||
|
|
||||||
|
temp_output_file = tempfile.NamedTemporaryFile(mode='w+b', prefix='megapy_', delete=False)
|
||||||
|
|
||||||
counter = Counter.new(
|
counter = Counter.new(
|
||||||
128, initial_value=((iv[0] << 32) + iv[1]) << 64)
|
128, initial_value=((iv[0] << 32) + iv[1]) << 64)
|
||||||
|
@ -420,7 +425,7 @@ class Mega(object):
|
||||||
for chunk_start, chunk_size in sorted(get_chunks(file_size).items()):
|
for chunk_start, chunk_size in sorted(get_chunks(file_size).items()):
|
||||||
chunk = input_file.read(chunk_size)
|
chunk = input_file.read(chunk_size)
|
||||||
chunk = aes.decrypt(chunk)
|
chunk = aes.decrypt(chunk)
|
||||||
output_file.write(chunk)
|
temp_output_file.write(chunk)
|
||||||
|
|
||||||
chunk_mac = [iv[0], iv[1], iv[0], iv[1]]
|
chunk_mac = [iv[0], iv[1], iv[0], iv[1]]
|
||||||
for i in range(0, len(chunk), 16):
|
for i in range(0, len(chunk), 16):
|
||||||
|
@ -441,13 +446,19 @@ class Mega(object):
|
||||||
file_mac[2] ^ chunk_mac[2],
|
file_mac[2] ^ chunk_mac[2],
|
||||||
file_mac[3] ^ chunk_mac[3]]
|
file_mac[3] ^ chunk_mac[3]]
|
||||||
file_mac = aes_cbc_encrypt_a32(file_mac, k)
|
file_mac = aes_cbc_encrypt_a32(file_mac, k)
|
||||||
output_file.close()
|
|
||||||
|
if self.options.get('verbose') is True:
|
||||||
|
# temp file size
|
||||||
|
file_info = os.stat(temp_output_file.name)
|
||||||
|
print('{0} of {1} downloaded'.format(file_info.st_size, file_size))
|
||||||
|
|
||||||
|
temp_output_file.close()
|
||||||
|
|
||||||
# check mac integrity
|
# check mac integrity
|
||||||
if (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]) != meta_mac:
|
if (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]) != meta_mac:
|
||||||
raise ValueError('Mismatched mac')
|
raise ValueError('Mismatched mac')
|
||||||
|
|
||||||
shutil.move(file_name_tmp, file_name)
|
shutil.move(temp_output_file.name, dest_path + file_name)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# UPLOAD
|
# UPLOAD
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -30,7 +30,7 @@ def get_package_data(package):
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='mega.py',
|
name='mega.py',
|
||||||
version='0.9.5',
|
version='0.9.6',
|
||||||
packages=get_packages('mega'),
|
packages=get_packages('mega'),
|
||||||
package_data=get_package_data('mega'),
|
package_data=get_package_data('mega'),
|
||||||
description='Python lib for the Mega.co.nz API',
|
description='Python lib for the Mega.co.nz API',
|
||||||
|
|
3
tests.py
3
tests.py
|
@ -13,6 +13,7 @@ def test():
|
||||||
password = 'password'
|
password = 'password'
|
||||||
|
|
||||||
mega = Mega()
|
mega = Mega()
|
||||||
|
#mega = Mega({'verbose': True}) # verbose option for print output
|
||||||
|
|
||||||
#login
|
#login
|
||||||
m = mega.login(email, password)
|
m = mega.login(email, password)
|
||||||
|
@ -43,7 +44,7 @@ def test():
|
||||||
print(link)
|
print(link)
|
||||||
|
|
||||||
#download file. by file object or url
|
#download file. by file object or url
|
||||||
m.download(file, '/tmp')
|
print m.download(file, '/tmp')
|
||||||
#m.download_url(link)
|
#m.download_url(link)
|
||||||
|
|
||||||
#delete or destroy file. by id or url
|
#delete or destroy file. by id or url
|
||||||
|
|
Loading…
Reference in a new issue