mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-04 04:00:18 +03:00
Merge branch 'master' into asyncio
This commit is contained in:
commit
41f0e0c0a8
|
@ -9,6 +9,14 @@ the ``session``, and defaults to be the session name (or full path). That is,
|
||||||
if you create a ``TelegramClient('anon')`` instance and connect, an
|
if you create a ``TelegramClient('anon')`` instance and connect, an
|
||||||
``anon.session`` file will be created on the working directory.
|
``anon.session`` file will be created on the working directory.
|
||||||
|
|
||||||
|
Note that if you pass a string it will be a file in the current working
|
||||||
|
directory, although you can also pass absolute paths.
|
||||||
|
|
||||||
|
The session file contains enough information for you to login without
|
||||||
|
re-sending the code, so if you have to enter the code more than once,
|
||||||
|
maybe you're changing the working directory, renaming or removing the
|
||||||
|
file, or using random names.
|
||||||
|
|
||||||
These database files using ``sqlite3`` contain the required information to
|
These database files using ``sqlite3`` contain the required information to
|
||||||
talk to the Telegram servers, such as to which IP the client should connect,
|
talk to the Telegram servers, such as to which IP the client should connect,
|
||||||
port, authorization key so that messages can be encrypted, and so on.
|
port, authorization key so that messages can be encrypted, and so on.
|
||||||
|
|
|
@ -39,6 +39,13 @@ Note that ``'some_name'`` will be used to save your session (persistent
|
||||||
information such as access key and others) as ``'some_name.session'`` in
|
information such as access key and others) as ``'some_name.session'`` in
|
||||||
your disk. This is by default a database file using Python's ``sqlite3``.
|
your disk. This is by default a database file using Python's ``sqlite3``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
It's important that the library always accesses the same session file so
|
||||||
|
that you don't need to re-send the code over and over again. By default it
|
||||||
|
creates the file in your working directory, but absolute paths work too.
|
||||||
|
|
||||||
|
|
||||||
Before using the client, you must be connected to Telegram.
|
Before using the client, you must be connected to Telegram.
|
||||||
Doing so is very easy:
|
Doing so is very easy:
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ from .tl.functions.channels import (
|
||||||
)
|
)
|
||||||
from .tl.types import (
|
from .tl.types import (
|
||||||
DocumentAttributeAudio, DocumentAttributeFilename,
|
DocumentAttributeAudio, DocumentAttributeFilename,
|
||||||
InputDocumentFileLocation, InputFileLocation,
|
|
||||||
InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
|
InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
|
||||||
Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
|
Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
|
||||||
InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID,
|
InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID,
|
||||||
|
@ -105,6 +104,14 @@ class TelegramClient(TelegramBareClient):
|
||||||
used otherwise. If it's ``None``, the session will not be saved,
|
used otherwise. If it's ``None``, the session will not be saved,
|
||||||
and you should call :meth:`.log_out()` when you're done.
|
and you should call :meth:`.log_out()` when you're done.
|
||||||
|
|
||||||
|
Note that if you pass a string it will be a file in the current
|
||||||
|
working directory, although you can also pass absolute paths.
|
||||||
|
|
||||||
|
The session file contains enough information for you to login
|
||||||
|
without re-sending the code, so if you have to enter the code
|
||||||
|
more than once, maybe you're changing the working directory,
|
||||||
|
renaming or removing the file, or using random names.
|
||||||
|
|
||||||
api_id (`int` | `str`):
|
api_id (`int` | `str`):
|
||||||
The API ID you obtained from https://my.telegram.org.
|
The API ID you obtained from https://my.telegram.org.
|
||||||
|
|
||||||
|
@ -531,7 +538,8 @@ class TelegramClient(TelegramBareClient):
|
||||||
offset_peer=InputPeerEmpty(), _total=None):
|
offset_peer=InputPeerEmpty(), _total=None):
|
||||||
"""
|
"""
|
||||||
Returns an iterator over the dialogs, yielding 'limit' at most.
|
Returns an iterator over the dialogs, yielding 'limit' at most.
|
||||||
Dialogs are the open "chats" or conversations with other people.
|
Dialogs are the open "chats" or conversations with other people,
|
||||||
|
groups you have joined, or channels you are subscribed to.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
limit (`int` | `None`):
|
limit (`int` | `None`):
|
||||||
|
@ -739,6 +747,11 @@ class TelegramClient(TelegramBareClient):
|
||||||
message (`str` | :tl:`Message`):
|
message (`str` | :tl:`Message`):
|
||||||
The message to be sent, or another message object to resend.
|
The message to be sent, or another message object to resend.
|
||||||
|
|
||||||
|
The maximum length for a message is 35,000 bytes or 4,096
|
||||||
|
characters. Longer messages will not be sliced automatically,
|
||||||
|
and you should slice them manually if the text to send is
|
||||||
|
longer than said length.
|
||||||
|
|
||||||
reply_to (`int` | :tl:`Message`, optional):
|
reply_to (`int` | :tl:`Message`, optional):
|
||||||
Whether to reply to a message or not. If an integer is provided,
|
Whether to reply to a message or not. If an integer is provided,
|
||||||
it should be the ID of the message that it should reply to.
|
it should be the ID of the message that it should reply to.
|
||||||
|
@ -1881,59 +1894,48 @@ class TelegramClient(TelegramBareClient):
|
||||||
``None`` if no photo was provided, or if it was Empty. On success
|
``None`` if no photo was provided, or if it was Empty. On success
|
||||||
the file path is returned since it may differ from the one given.
|
the file path is returned since it may differ from the one given.
|
||||||
"""
|
"""
|
||||||
photo = entity
|
# hex(crc32(x.encode('ascii'))) for x in
|
||||||
possible_names = []
|
# ('User', 'Chat', 'UserFull', 'ChatFull')
|
||||||
try:
|
ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697)
|
||||||
is_entity = entity.SUBCLASS_OF_ID in (
|
# ('InputPeer', 'InputUser', 'InputChannel')
|
||||||
0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697
|
INPUTS = (0xc91c90b6, 0xe669bf46, 0x40f202fd)
|
||||||
)
|
if not isinstance(entity, TLObject) or entity.SUBCLASS_OF_ID in INPUTS:
|
||||||
except AttributeError:
|
|
||||||
return None # Not even a TLObject as attribute access failed
|
|
||||||
|
|
||||||
if is_entity:
|
|
||||||
# Maybe it is an user or a chat? Or their full versions?
|
|
||||||
#
|
|
||||||
# The hexadecimal numbers above are simply:
|
|
||||||
# hex(crc32(x.encode('ascii'))) for x in
|
|
||||||
# ('User', 'Chat', 'UserFull', 'ChatFull')
|
|
||||||
entity = await self.get_entity(entity)
|
entity = await self.get_entity(entity)
|
||||||
|
|
||||||
|
possible_names = []
|
||||||
|
if entity.SUBCLASS_OF_ID not in ENTITIES:
|
||||||
|
photo = entity
|
||||||
|
else:
|
||||||
if not hasattr(entity, 'photo'):
|
if not hasattr(entity, 'photo'):
|
||||||
# Special case: may be a ChatFull with photo:Photo
|
# Special case: may be a ChatFull with photo:Photo
|
||||||
# This is different from a normal UserProfilePhoto and Chat
|
# This is different from a normal UserProfilePhoto and Chat
|
||||||
if hasattr(entity, 'chat_photo'):
|
if not hasattr(entity, 'chat_photo'):
|
||||||
return await self._download_photo(
|
|
||||||
entity.chat_photo, file,
|
|
||||||
date=None, progress_callback=None
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# Give up
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
return await self._download_photo(
|
||||||
|
entity.chat_photo, file, date=None, progress_callback=None)
|
||||||
|
|
||||||
for attr in ('username', 'first_name', 'title'):
|
for attr in ('username', 'first_name', 'title'):
|
||||||
possible_names.append(getattr(entity, attr, None))
|
possible_names.append(getattr(entity, attr, None))
|
||||||
|
|
||||||
photo = entity.photo
|
photo = entity.photo
|
||||||
|
|
||||||
if not isinstance(photo, UserProfilePhoto) and \
|
if isinstance(photo, (UserProfilePhoto, ChatPhoto)):
|
||||||
not isinstance(photo, ChatPhoto):
|
loc = photo.photo_big if download_big else photo.photo_small
|
||||||
return None
|
else:
|
||||||
|
try:
|
||||||
|
loc = utils.get_input_location(photo)
|
||||||
|
except TypeError:
|
||||||
|
return None
|
||||||
|
|
||||||
photo_location = photo.photo_big if download_big else photo.photo_small
|
|
||||||
file = self._get_proper_filename(
|
file = self._get_proper_filename(
|
||||||
file, 'profile_photo', '.jpg',
|
file, 'profile_photo', '.jpg',
|
||||||
possible_names=possible_names
|
possible_names=possible_names
|
||||||
)
|
)
|
||||||
|
|
||||||
# Download the media with the largest size input file location
|
|
||||||
try:
|
try:
|
||||||
await self.download_file(
|
await self.download_file(loc, file)
|
||||||
InputFileLocation(
|
return file
|
||||||
volume_id=photo_location.volume_id,
|
|
||||||
local_id=photo_location.local_id,
|
|
||||||
secret=photo_location.secret
|
|
||||||
),
|
|
||||||
file
|
|
||||||
)
|
|
||||||
except LocationInvalidError:
|
except LocationInvalidError:
|
||||||
# See issue #500, Android app fails as of v4.6.0 (1155).
|
# See issue #500, Android app fails as of v4.6.0 (1155).
|
||||||
# The fix seems to be using the full channel chat photo.
|
# The fix seems to be using the full channel chat photo.
|
||||||
|
@ -1947,7 +1949,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
else:
|
else:
|
||||||
# Until there's a report for chats, no need to.
|
# Until there's a report for chats, no need to.
|
||||||
return None
|
return None
|
||||||
return file
|
|
||||||
|
|
||||||
async def download_media(self, message, file=None, progress_callback=None):
|
async def download_media(self, message, file=None, progress_callback=None):
|
||||||
"""
|
"""
|
||||||
|
@ -2028,16 +2029,8 @@ class TelegramClient(TelegramBareClient):
|
||||||
f.close()
|
f.close()
|
||||||
return file
|
return file
|
||||||
|
|
||||||
await self.download_file(
|
await self.download_file(photo.location, file, file_size=photo.size,
|
||||||
InputFileLocation(
|
progress_callback=progress_callback)
|
||||||
volume_id=photo.location.volume_id,
|
|
||||||
local_id=photo.location.local_id,
|
|
||||||
secret=photo.location.secret
|
|
||||||
),
|
|
||||||
file,
|
|
||||||
file_size=photo.size,
|
|
||||||
progress_callback=progress_callback
|
|
||||||
)
|
|
||||||
return file
|
return file
|
||||||
|
|
||||||
async def _download_document(self, document, file, date, progress_callback):
|
async def _download_document(self, document, file, date, progress_callback):
|
||||||
|
@ -2073,16 +2066,8 @@ class TelegramClient(TelegramBareClient):
|
||||||
date=date, possible_names=possible_names
|
date=date, possible_names=possible_names
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.download_file(
|
await self.download_file(document, file, file_size=file_size,
|
||||||
InputDocumentFileLocation(
|
progress_callback=progress_callback)
|
||||||
id=document.id,
|
|
||||||
access_hash=document.access_hash,
|
|
||||||
version=document.version
|
|
||||||
),
|
|
||||||
file,
|
|
||||||
file_size=file_size,
|
|
||||||
progress_callback=progress_callback
|
|
||||||
)
|
|
||||||
return file
|
return file
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -2186,8 +2171,10 @@ class TelegramClient(TelegramBareClient):
|
||||||
Downloads the given input location to a file.
|
Downloads the given input location to a file.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_location (:tl:`InputFileLocation`):
|
input_location (:tl:`FileLocation` | :tl:`InputFileLocation`):
|
||||||
The file location from which the file will be downloaded.
|
The file location from which the file will be downloaded.
|
||||||
|
See `telethon.utils.get_input_location` source for a complete
|
||||||
|
list of supported types.
|
||||||
|
|
||||||
file (`str` | `file`, optional):
|
file (`str` | `file`, optional):
|
||||||
The output file path, directory, or stream-like object.
|
The output file path, directory, or stream-like object.
|
||||||
|
|
|
@ -10,17 +10,17 @@ dummyHttpWait = HttpWait;
|
||||||
//int128 4*[ int ] = Int128;
|
//int128 4*[ int ] = Int128;
|
||||||
//int256 8*[ int ] = Int256;
|
//int256 8*[ int ] = Int256;
|
||||||
|
|
||||||
resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
|
resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes server_public_key_fingerprints:Vector<long> = ResPQ;
|
||||||
|
|
||||||
p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
|
p_q_inner_data#83c95aec pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
|
||||||
p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
|
p_q_inner_data_temp#3c6a84d4 pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
|
||||||
|
|
||||||
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
|
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
|
||||||
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
|
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:bytes = Server_DH_Params;
|
||||||
|
|
||||||
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
|
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:bytes g_a:bytes server_time:int = Server_DH_inner_data;
|
||||||
|
|
||||||
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
|
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:bytes = Client_DH_Inner_Data;
|
||||||
|
|
||||||
dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
|
dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
|
||||||
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
|
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
|
||||||
|
@ -28,7 +28,7 @@ dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = S
|
||||||
|
|
||||||
bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner;
|
bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner;
|
||||||
|
|
||||||
//rpc_result#f35c6d01 req_msg_id:long result:string = RpcResult;
|
//rpc_result#f35c6d01 req_msg_id:long result:bytes = RpcResult;
|
||||||
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
|
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
|
||||||
|
|
||||||
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
|
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
|
||||||
|
@ -46,10 +46,10 @@ destroy_session_none#62d350c9 session_id:long = DestroySessionRes;
|
||||||
new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
|
new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
|
||||||
|
|
||||||
//msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
|
//msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
|
||||||
//message msg_id:long seqno:int bytes:int body:string = Message;
|
//message msg_id:long seqno:int bytes:int body:bytes = Message;
|
||||||
//msg_copy#e06046b2 orig_message:Message = MessageCopy;
|
//msg_copy#e06046b2 orig_message:Message = MessageCopy;
|
||||||
|
|
||||||
gzip_packed#3072cfa1 packed_data:string = Object;
|
gzip_packed#3072cfa1 packed_data:bytes = Object;
|
||||||
|
|
||||||
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
|
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
|
||||||
|
|
||||||
|
@ -63,15 +63,15 @@ msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo;
|
||||||
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||||
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||||
|
|
||||||
rsa_public_key n:string e:string = RSAPublicKey;
|
rsa_public_key n:string e:bytes = RSAPublicKey;
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
|
||||||
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
||||||
|
|
||||||
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
|
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:bytes q:bytes public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
|
||||||
|
|
||||||
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
|
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;
|
||||||
|
|
||||||
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
|
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
|
||||||
get_future_salts#b921bd04 num:int = FutureSalts;
|
get_future_salts#b921bd04 num:int = FutureSalts;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user