diff --git a/telethon/telegram_bare_client.py b/telethon/telegram_bare_client.py index 2c1b6188..d2e84ee6 100644 --- a/telethon/telegram_bare_client.py +++ b/telethon/telegram_bare_client.py @@ -571,6 +571,7 @@ class TelegramBareClient: file, part_size_kb=None, file_name=None, + allow_cache=True, progress_callback=None): """Uploads the specified file and returns a handle (an instance of InputFile or InputFileBig, as required) which can be later used. @@ -633,10 +634,12 @@ class TelegramBareClient: file = stream.read() hash_md5 = md5(file) tuple_ = self.session.get_file(hash_md5.digest(), file_size) - if tuple_: + if tuple_ and allow_cache: __log__.info('File was already cached, not uploading again') return InputFile(name=file_name, md5_checksum=tuple_[0], id=tuple_[2], parts=tuple_[3]) + elif tuple_ and not allow_cache: + self.session.clear_file(hash_md5.digest(), file_size) else: hash_md5 = None diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index 1fccda50..ac06b8eb 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -16,7 +16,7 @@ from . import helpers, utils from .errors import ( RPCError, UnauthorizedError, PhoneCodeEmptyError, PhoneCodeExpiredError, PhoneCodeHashEmptyError, PhoneCodeInvalidError, LocationInvalidError, - SessionPasswordNeededError) + SessionPasswordNeededError, FilePartMissingError) from .network import ConnectionMode from .tl import TLObject from .tl.custom import Draft, Dialog @@ -813,6 +813,7 @@ class TelegramClient(TelegramBareClient): reply_to=None, attributes=None, thumb=None, + allow_cache=True, **kwargs): """ Sends a file to the specified entity. @@ -849,9 +850,13 @@ class TelegramClient(TelegramBareClient): Optional attributes that override the inferred ones, like ``DocumentAttributeFilename`` and so on. - thumb (:obj:`str` | :obj:`bytes` | :obj:`file`): + thumb (:obj:`str` | :obj:`bytes` | :obj:`file`, optional): Optional thumbnail (for videos). + allow_cache (:obj:`bool`, optional): + Whether to allow using the cached version stored in the + database or not. Defaults to ``True`` to avoid reuploads. + Kwargs: If "is_voice_note" in kwargs, despite its value, and the file is sent as a document, it will be sent as a voice note. @@ -868,7 +873,7 @@ class TelegramClient(TelegramBareClient): ) file_handle = self.upload_file( - file, progress_callback=progress_callback) + file, progress_callback=progress_callback, allow_cache=allow_cache) if as_photo and not force_document: media = InputMediaUploadedPhoto(file_handle, caption) @@ -926,9 +931,19 @@ class TelegramClient(TelegramBareClient): media=media, reply_to_msg_id=self._get_reply_to(reply_to) ) - result = self(request) - - return self._get_response_message(request, result) + try: + return self._get_response_message(request, self(request)) + except FilePartMissingError: + # After a while, cached files are invalidated and this + # error is raised. The file needs to be uploaded again. + if not allow_cache: + raise + return self.send_file( + entity, file, allow_cache=False, + caption=caption, force_document=force_document, + progress_callback=progress_callback, reply_to=reply_to, + attributes=attributes, thumb=thumb, **kwargs + ) def send_voice_note(self, entity, file, caption='', upload_progress=None, reply_to=None): diff --git a/telethon/tl/session.py b/telethon/tl/session.py index 34427314..1dbf99c5 100644 --- a/telethon/tl/session.py +++ b/telethon/tl/session.py @@ -433,3 +433,11 @@ class Session: (md5_digest, file_size, file_id, part_count) ) self.save() + + def clear_file(self, md5_digest, file_size): + with self._db_lock: + self._conn.execute( + 'delete from sent_files where ' + 'md5_digest = ? and file_size = ?', (md5_digest, file_size) + ) + self.save()