mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-31 16:07:44 +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