mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-25 02:43:45 +03:00
Added ability to upload large files
This commit is contained in:
parent
922f17956b
commit
15994d0b78
|
@ -216,7 +216,7 @@ if __name__ == '__main__':
|
|||
client.run()
|
||||
|
||||
except Exception as e:
|
||||
print('Unexpected error ({}): {} at\n{}', type(e), e, traceback.format_exc())
|
||||
print('Unexpected error ({}): {} at\n{}'.format(type(e), e, traceback.format_exc()))
|
||||
|
||||
finally:
|
||||
print_title('Exit')
|
||||
|
|
|
@ -21,7 +21,6 @@ class TcpClient:
|
|||
"""Connects to the specified IP and port number"""
|
||||
self.socket.connect((ip, port))
|
||||
self.connected = True
|
||||
self.socket.setblocking(False)
|
||||
|
||||
def close(self):
|
||||
"""Closes the connection"""
|
||||
|
@ -34,18 +33,9 @@ class TcpClient:
|
|||
|
||||
# Ensure that only one thread can send data at once
|
||||
with self.lock:
|
||||
# Do not use .sendall:
|
||||
# "on error, an exception is raised, and there is no way to
|
||||
# determine how much data, if any, was successfully sent."
|
||||
while data:
|
||||
try:
|
||||
sent = self.socket.send(data)
|
||||
data = data[sent:]
|
||||
except BlockingIOError as e:
|
||||
if 'Errno 11' in str(e): # Error #11: Resource temporary unavailable
|
||||
time.sleep(0.1) # Sleep a bit waiting for the resource to be available
|
||||
else:
|
||||
raise e
|
||||
# Set blocking so it doesn't error
|
||||
self.socket.setblocking(True)
|
||||
self.socket.sendall(data)
|
||||
|
||||
def read(self, buffer_size):
|
||||
"""Reads (receives) the specified bytes from the connected peer"""
|
||||
|
@ -55,6 +45,9 @@ class TcpClient:
|
|||
# Ensure it is not cancelled at first, so we can enter the loop
|
||||
self.cancelled = False
|
||||
|
||||
# Set non-blocking so it can be cancelled
|
||||
self.socket.setblocking(False)
|
||||
|
||||
with BinaryWriter() as writer:
|
||||
while writer.written_count < buffer_size:
|
||||
# Only do cancel if no data was read yet
|
||||
|
|
|
@ -16,6 +16,7 @@ from tl import MTProtoRequest
|
|||
from tl import Session
|
||||
|
||||
# The Requests and types that we'll be using
|
||||
from tl.functions.upload import SaveBigFilePartRequest
|
||||
from tl.types import \
|
||||
PeerUser, PeerChat, PeerChannel, \
|
||||
InputPeerUser, InputPeerChat, InputPeerChannel, InputPeerEmpty, \
|
||||
|
@ -270,35 +271,41 @@ class TelegramClient:
|
|||
|
||||
def upload_file(self, file_path, part_size_kb=64, file_name=None):
|
||||
"""Uploads the specified media with the given chunk (part) size, in KB.
|
||||
If no custom file name is specified, the real file name will be used.
|
||||
This method will fail when trying to upload files larger than 10MB!"""
|
||||
If no custom file name is specified, the real file name will be used"""
|
||||
|
||||
if part_size_kb > 512:
|
||||
raise ValueError('The part size must be less or equal to 512KB')
|
||||
|
||||
part_size = int(part_size_kb * 1024)
|
||||
if part_size % 1024 != 0:
|
||||
raise ValueError('The part size must be evenly divisible by 1024')
|
||||
|
||||
# Determine whether the file is too big (over 10MB) or not
|
||||
# Telegram does make a distinction between smaller or larger files
|
||||
file_size = path.getsize(file_path)
|
||||
is_large = file_size > 10 * 1024 * 1024
|
||||
part_count = (file_size + part_size - 1) // part_size
|
||||
|
||||
# Multiply the datetime timestamp by 10^6 to get the ticks
|
||||
# This is high likely going to be unique
|
||||
file_id = int(datetime.now().timestamp() * (10 ** 6))
|
||||
part_index = 0
|
||||
hash_md5 = md5()
|
||||
|
||||
with open(file_path, 'rb') as file:
|
||||
while True:
|
||||
for part_index in range(part_count):
|
||||
# Read the file by in chunks of size part_size
|
||||
part = file.read(part_size)
|
||||
|
||||
# If we have read no data (0 bytes), the file is over
|
||||
# So there is nothing left to upload
|
||||
if not part:
|
||||
break
|
||||
|
||||
print('I read {} out of {}'.format(len(part), part_size))
|
||||
# The SavePartRequest is different depending on whether
|
||||
# the file is too large or not (over or less than 10MB)
|
||||
if is_large:
|
||||
request = SaveBigFilePartRequest(file_id, part_index, part_count, part)
|
||||
else:
|
||||
request = SaveFilePartRequest(file_id, part_index, part)
|
||||
|
||||
# Invoke the file upload and increment both the part index and MD5 checksum
|
||||
result = self.invoke(SaveFilePartRequest(file_id, part_index, part))
|
||||
result = self.invoke(request)
|
||||
if result:
|
||||
part_index += 1
|
||||
hash_md5.update(part)
|
||||
else:
|
||||
raise ValueError('Could not upload file part #{}'.format(part_index))
|
||||
|
@ -309,7 +316,7 @@ class TelegramClient:
|
|||
|
||||
# After the file has been uploaded, we can return a handle pointing to it
|
||||
return InputFile(id=file_id,
|
||||
parts=part_index,
|
||||
parts=part_count,
|
||||
name=file_name,
|
||||
md5_checksum=hash_md5.hexdigest())
|
||||
|
||||
|
@ -331,6 +338,10 @@ class TelegramClient:
|
|||
# TODO If the input file is an audio, find out:
|
||||
# Performer and song title and add DocumentAttributeAudio
|
||||
]
|
||||
# Ensure we have a mime type, any; but it cannot be None
|
||||
# «The "octet-stream" subtype is used to indicate that a body contains arbitrary binary data.»
|
||||
if not mime_type:
|
||||
mime_type = 'application/octet-stream'
|
||||
self.send_media_file(InputMediaUploadedDocument(file=input_file,
|
||||
mime_type=mime_type,
|
||||
attributes=attributes,
|
||||
|
|
Loading…
Reference in New Issue
Block a user