From 33207c21388879244db668841ce93f175e7ce09c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 14 May 2018 00:02:58 +0200
Subject: [PATCH 001/145] Lazily compute html and markdown styled texts
---
pyrogram/client/ext/utils.py | 50 +++++++++++++++++++++---------------
1 file changed, 29 insertions(+), 21 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 54515eb2..13035ed1 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -33,26 +33,26 @@ log = logging.getLogger(__name__)
# TODO: Organize the code better?
class Str(str):
- def __init__(self, value):
- str.__init__(value)
- self._markdown = None
- self._html = None
+ def __init__(self, text):
+ str.__init__(text)
+ self._client = None
+ self._entities = None
+
+ def init(self, client, entities):
+ self._client = client
+ self._entities = entities
+
+ @property
+ def text(self):
+ return self
@property
def markdown(self):
- return self._markdown
-
- @markdown.setter
- def markdown(self, value):
- self._markdown = value
+ return self._client.markdown.unparse(self, self._entities)
@property
def html(self):
- return self._html
-
- @html.setter
- def html(self, value):
- self._html = value
+ return self._client.html.unparse(self, self._entities)
ENTITIES = {
@@ -580,17 +580,25 @@ def parse_messages(
reply_markup=reply_markup
)
- if m.text:
- args = (m.text, m.entities or [])
+ # TODO: lazily evaluate html and markdown?
- m.text.markdown = client.markdown.unparse(*args)
- m.text.html = client.html.unparse(*args)
+ if m.text:
+ m.text.init(m.client, m.entities or [])
if m.caption:
- args = (m.caption, m.caption_entities or [])
+ m.caption.init(m.client, m.caption_entities or [])
- m.caption.markdown = client.markdown.unparse(*args)
- m.caption.html = client.html.unparse(*args)
+ # if m.text:
+ # args = (m.text, m.entities or [])
+ #
+ # m.text.markdown = client.markdown.unparse(*args)
+ # m.text.html = client.html.unparse(*args)
+ #
+ # if m.caption:
+ # args = (m.caption, m.caption_entities or [])
+ #
+ # m.caption.markdown = client.markdown.unparse(*args)
+ # m.caption.html = client.html.unparse(*args)
if message.reply_to_msg_id and replies:
while True:
From 0955826b6c55227c8f7a2af025e81f243bb70bcc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 14 May 2018 00:48:18 +0200
Subject: [PATCH 002/145] Change sig and parent class init call
---
pyrogram/client/ext/utils.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 13035ed1..f83557f2 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -33,8 +33,8 @@ log = logging.getLogger(__name__)
# TODO: Organize the code better?
class Str(str):
- def __init__(self, text):
- str.__init__(text)
+ def __init__(self, *args):
+ super().__init__()
self._client = None
self._entities = None
From 3d74941bed2d27130b1defa4f30afb7f96ebc0bf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 14 May 2018 00:48:53 +0200
Subject: [PATCH 003/145] Add slots
---
pyrogram/client/ext/utils.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index f83557f2..5722032c 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -33,6 +33,8 @@ log = logging.getLogger(__name__)
# TODO: Organize the code better?
class Str(str):
+ __slots__ = "_client", "_entities"
+
def __init__(self, *args):
super().__init__()
self._client = None
From 963c4e9a7aaee2b5e4c402d9579c082a6a6ae59a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 14 May 2018 00:52:26 +0200
Subject: [PATCH 004/145] Update develop version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 44edb3cb..87689ebd 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès
Date: Tue, 15 May 2018 19:17:22 +0200
Subject: [PATCH 005/145] Refactor tcp_abridged
---
.../connection/transport/tcp/tcp_abridged.py | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_abridged.py b/pyrogram/connection/transport/tcp/tcp_abridged.py
index ad682fed..472f4799 100644
--- a/pyrogram/connection/transport/tcp/tcp_abridged.py
+++ b/pyrogram/connection/transport/tcp/tcp_abridged.py
@@ -26,28 +26,23 @@ log = logging.getLogger(__name__)
class TCPAbridged(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
- self.is_first_packet = None
def connect(self, address: tuple):
super().connect(address)
- self.is_first_packet = True
+ super().sendall(b"\xef")
+
log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
def sendall(self, data: bytes, *args):
length = len(data) // 4
- data = (
- bytes([length]) + data
- if length <= 126
- else b"\x7f" + int.to_bytes(length, 3, "little") + data
+ super().sendall(
+ (bytes([length])
+ if length <= 126
+ else b"\x7f" + length.to_bytes(3, "little"))
+ + data
)
- if self.is_first_packet:
- data = b"\xef" + data
- self.is_first_packet = False
-
- super().sendall(data)
-
def recvall(self, length: int = 0) -> bytes or None:
length = super().recvall(1)
From 5f414626efabc94076f19da8a94f5cb14cbb5430 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 16 May 2018 21:14:05 +0200
Subject: [PATCH 006/145] Refactor tcp_intermediate
---
.../connection/transport/tcp/tcp_intermediate.py | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate.py b/pyrogram/connection/transport/tcp/tcp_intermediate.py
index 55a7d071..d99ca463 100644
--- a/pyrogram/connection/transport/tcp/tcp_intermediate.py
+++ b/pyrogram/connection/transport/tcp/tcp_intermediate.py
@@ -27,22 +27,15 @@ log = logging.getLogger(__name__)
class TCPIntermediate(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
- self.is_first_packet = None
def connect(self, address: tuple):
super().connect(address)
- self.is_first_packet = True
+ super().sendall(b"\xee" * 4)
+
log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
def sendall(self, data: bytes, *args):
- length = len(data)
- data = pack(" bytes or None:
length = super().recvall(4)
@@ -50,4 +43,4 @@ class TCPIntermediate(TCP):
if length is None:
return None
- return super().recvall(unpack("
Date: Thu, 17 May 2018 16:49:35 +0200
Subject: [PATCH 007/145] Remove TODO
---
pyrogram/client/ext/utils.py | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 5722032c..dc2b1f28 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -582,26 +582,12 @@ def parse_messages(
reply_markup=reply_markup
)
- # TODO: lazily evaluate html and markdown?
-
if m.text:
m.text.init(m.client, m.entities or [])
if m.caption:
m.caption.init(m.client, m.caption_entities or [])
- # if m.text:
- # args = (m.text, m.entities or [])
- #
- # m.text.markdown = client.markdown.unparse(*args)
- # m.text.html = client.html.unparse(*args)
- #
- # if m.caption:
- # args = (m.caption, m.caption_entities or [])
- #
- # m.caption.markdown = client.markdown.unparse(*args)
- # m.caption.html = client.html.unparse(*args)
-
if message.reply_to_msg_id and replies:
while True:
try:
From c531e6d146db20f64b67c924e5bf0007dfcafb3c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 18 May 2018 13:47:47 +0200
Subject: [PATCH 008/145] Rename protocol impl files
---
pyrogram/connection/connection.py | 8 ++++----
pyrogram/connection/transport/tcp/__init__.py | 6 +++---
.../transport/tcp/{tcp_abridged.py => abridged.py} | 2 +-
.../connection/transport/tcp/{tcp_full.py => full.py} | 2 +-
.../tcp/{tcp_intermediate.py => intermediate.py} | 4 ++--
5 files changed, 11 insertions(+), 11 deletions(-)
rename pyrogram/connection/transport/tcp/{tcp_abridged.py => abridged.py} (98%)
rename pyrogram/connection/transport/tcp/{tcp_full.py => full.py} (99%)
rename pyrogram/connection/transport/tcp/{tcp_intermediate.py => intermediate.py} (96%)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 118f0d83..4b9cf6a8 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -27,15 +27,15 @@ log = logging.getLogger(__name__)
class Connection:
MODES = {
- 0: TCPFull,
- 1: TCPAbridged,
- 2: TCPIntermediate
+ 0: Full,
+ 1: Abridged,
+ 2: Intermediate
}
def __init__(self, address: tuple, proxy: dict, mode: int = 1):
self.address = address
self.proxy = proxy
- self.mode = self.MODES.get(mode, TCPAbridged)
+ self.mode = self.MODES.get(mode, Abridged)
self.lock = threading.Lock()
self.connection = None
diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py
index d1daff63..0298e04b 100644
--- a/pyrogram/connection/transport/tcp/__init__.py
+++ b/pyrogram/connection/transport/tcp/__init__.py
@@ -16,6 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .tcp_abridged import TCPAbridged
-from .tcp_full import TCPFull
-from .tcp_intermediate import TCPIntermediate
+from .abridged import Abridged
+from .full import Full
+from .intermediate import Intermediate
diff --git a/pyrogram/connection/transport/tcp/tcp_abridged.py b/pyrogram/connection/transport/tcp/abridged.py
similarity index 98%
rename from pyrogram/connection/transport/tcp/tcp_abridged.py
rename to pyrogram/connection/transport/tcp/abridged.py
index 472f4799..076badad 100644
--- a/pyrogram/connection/transport/tcp/tcp_abridged.py
+++ b/pyrogram/connection/transport/tcp/abridged.py
@@ -23,7 +23,7 @@ from .tcp import TCP
log = logging.getLogger(__name__)
-class TCPAbridged(TCP):
+class Abridged(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
diff --git a/pyrogram/connection/transport/tcp/tcp_full.py b/pyrogram/connection/transport/tcp/full.py
similarity index 99%
rename from pyrogram/connection/transport/tcp/tcp_full.py
rename to pyrogram/connection/transport/tcp/full.py
index 1b131678..5707cdfb 100644
--- a/pyrogram/connection/transport/tcp/tcp_full.py
+++ b/pyrogram/connection/transport/tcp/full.py
@@ -25,7 +25,7 @@ from .tcp import TCP
log = logging.getLogger(__name__)
-class TCPFull(TCP):
+class Full(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
self.seq_no = None
diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate.py b/pyrogram/connection/transport/tcp/intermediate.py
similarity index 96%
rename from pyrogram/connection/transport/tcp/tcp_intermediate.py
rename to pyrogram/connection/transport/tcp/intermediate.py
index d99ca463..46546d1d 100644
--- a/pyrogram/connection/transport/tcp/tcp_intermediate.py
+++ b/pyrogram/connection/transport/tcp/intermediate.py
@@ -19,12 +19,12 @@
import logging
from struct import pack, unpack
-from .tcp_abridged import TCP
+from .abridged import TCP
log = logging.getLogger(__name__)
-class TCPIntermediate(TCP):
+class Intermediate(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
From f0c801be8c75158ea319410d36914494c2c6a215 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 18 May 2018 14:15:35 +0200
Subject: [PATCH 009/145] Rename AES class methods and add ctr256_encrypt
---
pyrogram/crypto/aes.py | 19 ++++++++++---------
pyrogram/session/auth.py | 4 ++--
pyrogram/session/session.py | 4 ++--
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/pyrogram/crypto/aes.py b/pyrogram/crypto/aes.py
index 05a01044..19eec9a1 100644
--- a/pyrogram/crypto/aes.py
+++ b/pyrogram/crypto/aes.py
@@ -38,31 +38,32 @@ else:
# TODO: Ugly IFs
class AES:
@classmethod
- def ige_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
+ def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
if is_fast:
- return tgcrypto.ige_encrypt(data, key, iv)
+ return tgcrypto.ige256_encrypt(data, key, iv)
else:
return cls.ige(data, key, iv, True)
@classmethod
- def ige_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
+ def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
if is_fast:
- return tgcrypto.ige_decrypt(data, key, iv)
+ return tgcrypto.ige256_decrypt(data, key, iv)
else:
return cls.ige(data, key, iv, False)
@staticmethod
- def ctr_decrypt(data: bytes, key: bytes, iv: bytes, offset: int) -> bytes:
- replace = int.to_bytes(offset // 16, 4, "big")
- iv = iv[:-4] + replace
-
+ def ctr256_encrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes:
if is_fast:
- return tgcrypto.ctr_decrypt(data, key, iv)
+ return tgcrypto.ctr256_decrypt(data, key, iv, state)
else:
ctr = pyaes.AESModeOfOperationCTR(key)
ctr._counter._counter = list(iv)
return ctr.decrypt(data)
+ @staticmethod
+ def ctr256_decrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes:
+ return AES.ctr256_encrypt(data, key, iv, state)
+
@staticmethod
def xor(a: bytes, b: bytes) -> bytes:
return int.to_bytes(
diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py
index 449524b3..888d3a4d 100644
--- a/pyrogram/session/auth.py
+++ b/pyrogram/session/auth.py
@@ -163,7 +163,7 @@ class Auth:
server_nonce = int.from_bytes(server_nonce, "little", signed=True)
- answer_with_hash = AES.ige_decrypt(encrypted_answer, tmp_aes_key, tmp_aes_iv)
+ answer_with_hash = AES.ige256_decrypt(encrypted_answer, tmp_aes_key, tmp_aes_iv)
answer = answer_with_hash[20:]
server_dh_inner_data = Object.read(BytesIO(answer))
@@ -192,7 +192,7 @@ class Auth:
sha = sha1(data).digest()
padding = urandom(- (len(data) + len(sha)) % 16)
data_with_hash = sha + data + padding
- encrypted_data = AES.ige_encrypt(data_with_hash, tmp_aes_key, tmp_aes_iv)
+ encrypted_data = AES.ige256_encrypt(data_with_hash, tmp_aes_key, tmp_aes_iv)
log.debug("Send set_client_DH_params")
set_client_dh_params_answer = self.send(
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index f8cdcc19..2564b7d1 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -222,14 +222,14 @@ class Session:
msg_key = msg_key_large[8:24]
aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
- return self.auth_key_id + msg_key + AES.ige_encrypt(data + padding, aes_key, aes_iv)
+ return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
def unpack(self, b: BytesIO) -> Message:
assert b.read(8) == self.auth_key_id, b.getvalue()
msg_key = b.read(16)
aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
- data = BytesIO(AES.ige_decrypt(b.read(), aes_key, aes_iv))
+ data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
data.read(8)
# https://core.telegram.org/mtproto/security_guidelines#checking-session-id
From c5911a6f6b53b838f698a206866932e58369a5bd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 19 May 2018 15:36:38 +0200
Subject: [PATCH 010/145] Reorganize AES module
---
pyrogram/client/client.py | 8 ++-
pyrogram/crypto/aes.py | 141 ++++++++++++++++++++++++--------------
2 files changed, 96 insertions(+), 53 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 24a09a5c..209488f7 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1213,11 +1213,13 @@ class Client(Methods, BaseClient):
chunk = r2.bytes
# https://core.telegram.org/cdn#decrypting-files
- decrypted_chunk = AES.ctr_decrypt(
+ decrypted_chunk = AES.ctr256_decrypt(
chunk,
r.encryption_key,
- r.encryption_iv,
- offset
+ bytearray(
+ r.encryption_iv[:-4]
+ + (offset // 16).to_bytes(4, "big")
+ )
)
hashes = session.send(
diff --git a/pyrogram/crypto/aes.py b/pyrogram/crypto/aes.py
index 19eec9a1..f16688c4 100644
--- a/pyrogram/crypto/aes.py
+++ b/pyrogram/crypto/aes.py
@@ -22,72 +22,113 @@ log = logging.getLogger(__name__)
try:
import tgcrypto
+
+ log.info("Using TgCrypto")
+
+
+ class AES:
+ @classmethod
+ def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
+ return tgcrypto.ige256_encrypt(data, key, iv)
+
+ @classmethod
+ def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
+ return tgcrypto.ige256_decrypt(data, key, iv)
+
+ @staticmethod
+ def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
+ return tgcrypto.ctr256_encrypt(data, key, iv, state or bytearray(1))
+
+ @staticmethod
+ def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
+ return tgcrypto.ctr256_decrypt(data, key, iv, state or bytearray(1))
+
+ @staticmethod
+ def xor(a: bytes, b: bytes) -> bytes:
+ return int.to_bytes(
+ int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
+ len(a),
+ "big",
+ )
except ImportError:
+ import pyaes
+
log.warning(
"TgCrypto is missing! "
"Pyrogram will work the same, but at a much slower speed. "
"More info: https://docs.pyrogram.ml/resources/TgCrypto"
)
- is_fast = False
- import pyaes
-else:
- log.info("Using TgCrypto")
- is_fast = True
-# TODO: Ugly IFs
-class AES:
- @classmethod
- def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
- if is_fast:
- return tgcrypto.ige256_encrypt(data, key, iv)
- else:
+ class AES:
+ @classmethod
+ def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
return cls.ige(data, key, iv, True)
- @classmethod
- def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
- if is_fast:
- return tgcrypto.ige256_decrypt(data, key, iv)
- else:
+ @classmethod
+ def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
return cls.ige(data, key, iv, False)
- @staticmethod
- def ctr256_encrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes:
- if is_fast:
- return tgcrypto.ctr256_decrypt(data, key, iv, state)
- else:
- ctr = pyaes.AESModeOfOperationCTR(key)
- ctr._counter._counter = list(iv)
- return ctr.decrypt(data)
+ @classmethod
+ def ctr256_encrypt(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
+ return cls.ctr(data, key, iv, state or bytearray(1))
- @staticmethod
- def ctr256_decrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes:
- return AES.ctr256_encrypt(data, key, iv, state)
+ @classmethod
+ def ctr256_decrypt(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
+ return cls.ctr(data, key, iv, state or bytearray(1))
- @staticmethod
- def xor(a: bytes, b: bytes) -> bytes:
- return int.to_bytes(
- int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
- len(a),
- "big",
- )
+ @staticmethod
+ def xor(a: bytes, b: bytes) -> bytes:
+ return int.to_bytes(
+ int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
+ len(a),
+ "big",
+ )
- @classmethod
- def ige(cls, data: bytes, key: bytes, iv: bytes, encrypt: bool) -> bytes:
- cipher = pyaes.AES(key)
+ @classmethod
+ def ige(cls, data: bytes, key: bytes, iv: bytes, encrypt: bool) -> bytes:
+ cipher = pyaes.AES(key)
- iv_1 = iv[:16]
- iv_2 = iv[16:]
+ iv_1 = iv[:16]
+ iv_2 = iv[16:]
- data = [data[i: i + 16] for i in range(0, len(data), 16)]
+ data = [data[i: i + 16] for i in range(0, len(data), 16)]
- if encrypt:
- for i, chunk in enumerate(data):
- iv_1 = data[i] = cls.xor(cipher.encrypt(cls.xor(chunk, iv_1)), iv_2)
- iv_2 = chunk
- else:
- for i, chunk in enumerate(data):
- iv_2 = data[i] = cls.xor(cipher.decrypt(cls.xor(chunk, iv_2)), iv_1)
- iv_1 = chunk
+ if encrypt:
+ for i, chunk in enumerate(data):
+ iv_1 = data[i] = cls.xor(cipher.encrypt(cls.xor(chunk, iv_1)), iv_2)
+ iv_2 = chunk
+ else:
+ for i, chunk in enumerate(data):
+ iv_2 = data[i] = cls.xor(cipher.decrypt(cls.xor(chunk, iv_2)), iv_1)
+ iv_1 = chunk
- return b"".join(data)
+ return b"".join(data)
+
+ @classmethod
+ def ctr(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray) -> bytes:
+ cipher = pyaes.AES(key)
+
+ out = bytearray(data)
+ chunk = cipher.encrypt(iv)
+
+ for i in range(0, len(data), 16):
+ for j in range(0, min(len(data) - i, 16)):
+ out[i + j] ^= chunk[state[0]]
+
+ state[0] += 1
+
+ if state[0] >= 16:
+ state[0] = 0
+
+ if state[0] == 0:
+ for k in range(15, -1, -1):
+ try:
+ iv[k] += 1
+ break
+ except ValueError:
+ iv[k] = 0
+
+ chunk = cipher.encrypt(iv)
+
+ return out
From 1cd7e28b50f8f9abb51df48b64a09431d4233141 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 19 May 2018 15:50:10 +0200
Subject: [PATCH 011/145] Rename TCP protocol impl files
---
pyrogram/connection/connection.py | 8 ++++----
pyrogram/connection/transport/tcp/__init__.py | 6 +++---
.../transport/tcp/{abridged.py => tcp_abridged.py} | 2 +-
.../connection/transport/tcp/{full.py => tcp_full.py} | 2 +-
.../tcp/{intermediate.py => tcp_intermediate.py} | 4 ++--
5 files changed, 11 insertions(+), 11 deletions(-)
rename pyrogram/connection/transport/tcp/{abridged.py => tcp_abridged.py} (98%)
rename pyrogram/connection/transport/tcp/{full.py => tcp_full.py} (99%)
rename pyrogram/connection/transport/tcp/{intermediate.py => tcp_intermediate.py} (96%)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 4b9cf6a8..118f0d83 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -27,15 +27,15 @@ log = logging.getLogger(__name__)
class Connection:
MODES = {
- 0: Full,
- 1: Abridged,
- 2: Intermediate
+ 0: TCPFull,
+ 1: TCPAbridged,
+ 2: TCPIntermediate
}
def __init__(self, address: tuple, proxy: dict, mode: int = 1):
self.address = address
self.proxy = proxy
- self.mode = self.MODES.get(mode, Abridged)
+ self.mode = self.MODES.get(mode, TCPAbridged)
self.lock = threading.Lock()
self.connection = None
diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py
index 0298e04b..d1daff63 100644
--- a/pyrogram/connection/transport/tcp/__init__.py
+++ b/pyrogram/connection/transport/tcp/__init__.py
@@ -16,6 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .abridged import Abridged
-from .full import Full
-from .intermediate import Intermediate
+from .tcp_abridged import TCPAbridged
+from .tcp_full import TCPFull
+from .tcp_intermediate import TCPIntermediate
diff --git a/pyrogram/connection/transport/tcp/abridged.py b/pyrogram/connection/transport/tcp/tcp_abridged.py
similarity index 98%
rename from pyrogram/connection/transport/tcp/abridged.py
rename to pyrogram/connection/transport/tcp/tcp_abridged.py
index 076badad..472f4799 100644
--- a/pyrogram/connection/transport/tcp/abridged.py
+++ b/pyrogram/connection/transport/tcp/tcp_abridged.py
@@ -23,7 +23,7 @@ from .tcp import TCP
log = logging.getLogger(__name__)
-class Abridged(TCP):
+class TCPAbridged(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
diff --git a/pyrogram/connection/transport/tcp/full.py b/pyrogram/connection/transport/tcp/tcp_full.py
similarity index 99%
rename from pyrogram/connection/transport/tcp/full.py
rename to pyrogram/connection/transport/tcp/tcp_full.py
index 5707cdfb..1b131678 100644
--- a/pyrogram/connection/transport/tcp/full.py
+++ b/pyrogram/connection/transport/tcp/tcp_full.py
@@ -25,7 +25,7 @@ from .tcp import TCP
log = logging.getLogger(__name__)
-class Full(TCP):
+class TCPFull(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
self.seq_no = None
diff --git a/pyrogram/connection/transport/tcp/intermediate.py b/pyrogram/connection/transport/tcp/tcp_intermediate.py
similarity index 96%
rename from pyrogram/connection/transport/tcp/intermediate.py
rename to pyrogram/connection/transport/tcp/tcp_intermediate.py
index 46546d1d..4b2e2596 100644
--- a/pyrogram/connection/transport/tcp/intermediate.py
+++ b/pyrogram/connection/transport/tcp/tcp_intermediate.py
@@ -19,12 +19,12 @@
import logging
from struct import pack, unpack
-from .abridged import TCP
+from .tcp import TCP
log = logging.getLogger(__name__)
-class Intermediate(TCP):
+class TCPIntermediate(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
From 5b300ef83cdbd5cc088abe694d46dc33b4d0189e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 20 May 2018 12:45:37 +0200
Subject: [PATCH 012/145] Fix some GIF not having video attributes
---
pyrogram/client/ext/utils.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index dc2b1f28..724b554d 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -415,7 +415,7 @@ def parse_messages(
date=doc.date
)
elif types.DocumentAttributeAnimated in attributes:
- video_attributes = attributes[types.DocumentAttributeVideo]
+ video_attributes = attributes.get(types.DocumentAttributeVideo, None)
gif = pyrogram_types.GIF(
file_id=encode(
@@ -427,9 +427,9 @@ def parse_messages(
doc.access_hash
)
),
- width=video_attributes.w,
- height=video_attributes.h,
- duration=video_attributes.duration,
+ width=getattr(video_attributes, "w", 0),
+ height=getattr(video_attributes, "h", 0),
+ duration=getattr(video_attributes, "duration", 0),
thumb=parse_thumb(doc.thumb),
mime_type=doc.mime_type,
file_size=doc.size,
From 43526876a4bf39d10c1b2c4b09be81137f311275 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 20 May 2018 12:53:00 +0200
Subject: [PATCH 013/145] Split handlers in files
---
pyrogram/client/handlers/__init__.py | 4 +-
.../client/handlers/callback_query_handler.py | 51 +++++++++++++++
pyrogram/client/handlers/message_handler.py | 52 +++++++++++++++
.../{handlers.py => raw_update_handler.py} | 65 -------------------
4 files changed, 106 insertions(+), 66 deletions(-)
create mode 100644 pyrogram/client/handlers/callback_query_handler.py
create mode 100644 pyrogram/client/handlers/message_handler.py
rename pyrogram/client/handlers/{handlers.py => raw_update_handler.py} (54%)
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index ed330b21..52fe40b3 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -16,4 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .handlers import MessageHandler, CallbackQueryHandler, RawUpdateHandler
+from .callback_query_handler import CallbackQueryHandler
+from .message_handler import MessageHandler
+from .raw_update_handler import RawUpdateHandler
diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/client/handlers/callback_query_handler.py
new file mode 100644
index 00000000..c0bba510
--- /dev/null
+++ b/pyrogram/client/handlers/callback_query_handler.py
@@ -0,0 +1,51 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from .handler import Handler
+
+
+class CallbackQueryHandler(Handler):
+ """The CallbackQuery handler class. Used to handle callback queries coming from inline buttons.
+ It is intended to be used with :meth:`add_handler() `
+
+ Args:
+ callback (``callable``):
+ Pass a function that will be called when a new CallbackQuery arrives. It takes *(client, callback_query)*
+ as positional arguments (look at the section below for a detailed description).
+
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of callback queries to be passed
+ in your callback function.
+
+ Other parameters:
+ client (:obj:`Client `):
+ The Client itself, useful when you want to call other API methods inside the message handler.
+
+ callback_query (:obj:`CallbackQuery `):
+ The received callback query.
+ """
+
+ def __init__(self, callback: callable, filters=None):
+ super().__init__(callback, filters)
+
+ def check(self, callback_query):
+ return (
+ self.filters(callback_query)
+ if self.filters
+ else True
+ )
diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/client/handlers/message_handler.py
new file mode 100644
index 00000000..6aae27de
--- /dev/null
+++ b/pyrogram/client/handlers/message_handler.py
@@ -0,0 +1,52 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from .handler import Handler
+
+
+class MessageHandler(Handler):
+ """The Message handler class. Used to handle text, media and service messages coming from
+ any chat (private, group, channel). It is intended to be used with
+ :meth:`add_handler() `
+
+ Args:
+ callback (``callable``):
+ Pass a function that will be called when a new Message arrives. It takes *(client, message)*
+ as positional arguments (look at the section below for a detailed description).
+
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of messages to be passed
+ in your callback function.
+
+ Other parameters:
+ client (:obj:`Client `):
+ The Client itself, useful when you want to call other API methods inside the message handler.
+
+ message (:obj:`Message `):
+ The received message.
+ """
+
+ def __init__(self, callback: callable, filters=None):
+ super().__init__(callback, filters)
+
+ def check(self, message):
+ return (
+ self.filters(message)
+ if self.filters
+ else True
+ )
diff --git a/pyrogram/client/handlers/handlers.py b/pyrogram/client/handlers/raw_update_handler.py
similarity index 54%
rename from pyrogram/client/handlers/handlers.py
rename to pyrogram/client/handlers/raw_update_handler.py
index c50e6725..8a1e0a03 100644
--- a/pyrogram/client/handlers/handlers.py
+++ b/pyrogram/client/handlers/raw_update_handler.py
@@ -19,71 +19,6 @@
from .handler import Handler
-class MessageHandler(Handler):
- """The Message handler class. Used to handle text, media and service messages coming from
- any chat (private, group, channel). It is intended to be used with
- :meth:`add_handler() `
-
- Args:
- callback (``callable``):
- Pass a function that will be called when a new Message arrives. It takes *(client, message)*
- as positional arguments (look at the section below for a detailed description).
-
- filters (:obj:`Filters `):
- Pass one or more filters to allow only a subset of messages to be passed
- in your callback function.
-
- Other parameters:
- client (:obj:`Client `):
- The Client itself, useful when you want to call other API methods inside the message handler.
-
- message (:obj:`Message `):
- The received message.
- """
-
- def __init__(self, callback: callable, filters=None):
- super().__init__(callback, filters)
-
- def check(self, message):
- return (
- self.filters(message)
- if self.filters
- else True
- )
-
-
-class CallbackQueryHandler(Handler):
- """The CallbackQuery handler class. Used to handle callback queries coming from inline buttons.
- It is intended to be used with :meth:`add_handler() `
-
- Args:
- callback (``callable``):
- Pass a function that will be called when a new CallbackQuery arrives. It takes *(client, callback_query)*
- as positional arguments (look at the section below for a detailed description).
-
- filters (:obj:`Filters `):
- Pass one or more filters to allow only a subset of callback queries to be passed
- in your callback function.
-
- Other parameters:
- client (:obj:`Client `):
- The Client itself, useful when you want to call other API methods inside the message handler.
-
- callback_query (:obj:`CallbackQuery `):
- The received callback query.
- """
-
- def __init__(self, callback: callable, filters=None):
- super().__init__(callback, filters)
-
- def check(self, callback_query):
- return (
- self.filters(callback_query)
- if self.filters
- else True
- )
-
-
class RawUpdateHandler(Handler):
"""The Raw Update handler class. Used to handle raw updates. It is intended to be used with
:meth:`add_handler() `
From 28310cb0a74b5dc13c7e05a8bfea6bff62475033 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 20 May 2018 14:03:16 +0200
Subject: [PATCH 014/145] Add GIFs to media filter
---
pyrogram/client/filters/filters.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index ecd6e8c2..e2a177b8 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -253,6 +253,7 @@ class Filters:
or Filters.photo(m)
or Filters.sticker(m)
or Filters.video(m)
+ or Filters.gif(m)
or Filters.voice(m)
or Filters.video_note(m)
or Filters.contact(m)
From b451ced0fe86528343001e6a0267df37e7160cc0 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 21 May 2018 09:27:56 +0200
Subject: [PATCH 015/145] Revert back to previous tgcrypto function names
---
pyrogram/crypto/aes.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/pyrogram/crypto/aes.py b/pyrogram/crypto/aes.py
index f16688c4..e4fb94b1 100644
--- a/pyrogram/crypto/aes.py
+++ b/pyrogram/crypto/aes.py
@@ -27,21 +27,22 @@ try:
class AES:
+ # TODO: Use new tgcrypto function names
@classmethod
def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
- return tgcrypto.ige256_encrypt(data, key, iv)
+ return tgcrypto.ige_encrypt(data, key, iv)
@classmethod
def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes:
- return tgcrypto.ige256_decrypt(data, key, iv)
+ return tgcrypto.ige_decrypt(data, key, iv)
@staticmethod
def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
- return tgcrypto.ctr256_encrypt(data, key, iv, state or bytearray(1))
+ return tgcrypto.ctr_encrypt(data, key, iv, state or bytearray(1))
@staticmethod
def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
- return tgcrypto.ctr256_decrypt(data, key, iv, state or bytearray(1))
+ return tgcrypto.ctr_decrypt(data, key, iv, state or bytearray(1))
@staticmethod
def xor(a: bytes, b: bytes) -> bytes:
From 49414799e2fd6b21021ae5171706de1ee8b88096 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 21 May 2018 13:59:31 +0200
Subject: [PATCH 016/145] Update dev version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 87689ebd..636e52bf 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès
Date: Tue, 22 May 2018 16:16:28 +0200
Subject: [PATCH 017/145] Allow FloodWait to be raised in case of
non-interactive sign-ins
---
pyrogram/client/client.py | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 209488f7..8721f925 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -399,8 +399,11 @@ class Client(Methods, BaseClient):
print(e.MESSAGE)
self.phone_number = None
except FloodWait as e:
- print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ if phone_number_invalid_raises:
+ raise
+ else:
+ print(e.MESSAGE.format(x=e.x))
+ time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
else:
@@ -493,16 +496,22 @@ class Client(Methods, BaseClient):
print(e.MESSAGE)
self.password = None
except FloodWait as e:
- print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ if password_hash_invalid_raises:
+ raise
+ else:
+ print(e.MESSAGE.format(x=e.x))
+ time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
else:
break
break
except FloodWait as e:
- print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ if phone_code_invalid_raises or first_name_invalid_raises:
+ raise
+ else:
+ print(e.MESSAGE.format(x=e.x))
+ time.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
else:
From 9001ccd11ff2875fb760be1e1ced1afa46df1c60 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 23 May 2018 14:27:17 +0200
Subject: [PATCH 018/145] Add DisconnectHandler
---
pyrogram/__init__.py | 2 +-
pyrogram/client/__init__.py | 5 +++-
pyrogram/client/client.py | 11 +++++--
pyrogram/client/ext/base_client.py | 2 ++
pyrogram/client/handlers/__init__.py | 1 +
.../client/handlers/disconnect_handler.py | 25 ++++++++++++++++
.../client/methods/decorators/__init__.py | 3 +-
.../methods/decorators/on_disconnect.py | 30 +++++++++++++++++++
pyrogram/session/session.py | 6 ++++
9 files changed, 80 insertions(+), 5 deletions(-)
create mode 100644 pyrogram/client/handlers/disconnect_handler.py
create mode 100644 pyrogram/client/methods/decorators/on_disconnect.py
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 636e52bf..5581b969 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -39,5 +39,5 @@ from .client.types.reply_markup import (
from .client import (
Client, ChatAction, ParseMode, Emoji,
MessageHandler, CallbackQueryHandler, RawUpdateHandler,
- Filters
+ DisconnectHandler, Filters
)
diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py
index aac1b9e0..21bde533 100644
--- a/pyrogram/client/__init__.py
+++ b/pyrogram/client/__init__.py
@@ -19,4 +19,7 @@
from .client import Client
from .ext import BaseClient, ChatAction, Emoji, ParseMode
from .filters import Filters
-from .handlers import MessageHandler, CallbackQueryHandler, RawUpdateHandler
+from .handlers import (
+ MessageHandler, CallbackQueryHandler,
+ RawUpdateHandler, DisconnectHandler
+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 8721f925..75bb082f 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -43,6 +43,7 @@ from pyrogram.api.errors import (
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid)
+from pyrogram.client.handlers import DisconnectHandler
from pyrogram.crypto import AES
from pyrogram.session import Auth, Session
from .dispatcher import Dispatcher
@@ -290,7 +291,10 @@ class Client(Methods, BaseClient):
Returns:
A tuple of (handler, group)
"""
- self.dispatcher.add_handler(handler, group)
+ if isinstance(handler, DisconnectHandler):
+ self.disconnect_handler = handler.callback
+ else:
+ self.dispatcher.add_handler(handler, group)
return handler, group
@@ -308,7 +312,10 @@ class Client(Methods, BaseClient):
group (``int``, *optional*):
The group identifier, defaults to 0.
"""
- self.dispatcher.remove_handler(handler, group)
+ if isinstance(handler, DisconnectHandler):
+ self.disconnect_handler = None
+ else:
+ self.dispatcher.remove_handler(handler, group)
def authorize_bot(self):
try:
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index ce3d5591..9c0fb26b 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -75,6 +75,8 @@ class BaseClient:
self.download_queue = Queue()
self.download_workers_list = []
+ self.disconnect_handler = None
+
def send(self, data: Object):
pass
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index 52fe40b3..38a8aeeb 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -17,5 +17,6 @@
# along with Pyrogram. If not, see .
from .callback_query_handler import CallbackQueryHandler
+from .disconnect_handler import DisconnectHandler
from .message_handler import MessageHandler
from .raw_update_handler import RawUpdateHandler
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
new file mode 100644
index 00000000..67d0ae02
--- /dev/null
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -0,0 +1,25 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from .handler import Handler
+
+
+class DisconnectHandler(Handler):
+ # TODO: Documentation
+ def __init__(self, callback: callable):
+ super().__init__(callback)
diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/client/methods/decorators/__init__.py
index 89645906..6ece61ff 100644
--- a/pyrogram/client/methods/decorators/__init__.py
+++ b/pyrogram/client/methods/decorators/__init__.py
@@ -17,9 +17,10 @@
# along with Pyrogram. If not, see .
from .on_callback_query import OnCallbackQuery
+from .on_disconnect import OnDisconnect
from .on_message import OnMessage
from .on_raw_update import OnRawUpdate
-class Decorators(OnMessage, OnCallbackQuery, OnRawUpdate):
+class Decorators(OnMessage, OnCallbackQuery, OnRawUpdate, OnDisconnect):
pass
diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py
new file mode 100644
index 00000000..230a361c
--- /dev/null
+++ b/pyrogram/client/methods/decorators/on_disconnect.py
@@ -0,0 +1,30 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+import pyrogram
+from ...ext import BaseClient
+
+
+class OnDisconnect(BaseClient):
+ def on_disconnect(self):
+ # TODO: Documentation
+ def decorator(func):
+ self.add_handler(pyrogram.DisconnectHandler(func))
+ return func
+
+ return decorator
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 2564b7d1..1da0fdd7 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -207,6 +207,12 @@ class Session:
for i in self.results.values():
i.event.set()
+ if self.client and callable(self.client.disconnect_handler):
+ try:
+ self.client.disconnect_handler(self.client)
+ except Exception as e:
+ log.error(e, exc_info=True)
+
log.debug("Session stopped")
def restart(self):
From 65c209000cb2279588f3d1ad4015add4f48a7417 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 24 May 2018 21:19:57 +0200
Subject: [PATCH 019/145] Connection refactoring
---
pyrogram/client/client.py | 2 --
pyrogram/connection/transport/tcp/tcp.py | 12 ++++++------
pyrogram/session/auth.py | 5 ++++-
pyrogram/session/session.py | 8 +++++++-
4 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 75bb082f..813d7e74 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -843,8 +843,6 @@ class Client(Methods, BaseClient):
if self.proxy:
self.proxy["enabled"] = True
- self.proxy["username"] = self.proxy.get("username", None)
- self.proxy["password"] = self.proxy.get("password", None)
else:
self.proxy = {}
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 38005e57..5df8aacb 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -41,15 +41,15 @@ class TCP(socks.socksocket):
if proxy and self.proxy_enabled:
self.set_proxy(
proxy_type=socks.SOCKS5,
- addr=proxy["hostname"],
- port=proxy["port"],
- username=proxy["username"],
- password=proxy["password"]
+ addr=proxy.get("hostname", None),
+ port=proxy.get("port", None),
+ username=proxy.get("username", None),
+ password=proxy.get("password", None)
)
log.info("Using proxy {}:{}".format(
- proxy["hostname"],
- proxy["port"]
+ proxy.get("hostname", None),
+ proxy.get("port", None)
))
def close(self):
diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py
index 888d3a4d..80956187 100644
--- a/pyrogram/session/auth.py
+++ b/pyrogram/session/auth.py
@@ -49,8 +49,9 @@ class Auth:
def __init__(self, dc_id: int, test_mode: bool, proxy: dict):
self.dc_id = dc_id
self.test_mode = test_mode
+ self.proxy = proxy
- self.connection = Connection(DataCenter(dc_id, test_mode), proxy)
+ self.connection = None
@staticmethod
def pack(data: Object) -> bytes:
@@ -83,6 +84,8 @@ class Auth:
# The server may close the connection at any time, causing the auth key creation to fail.
# If that happens, just try again up to MAX_RETRIES times.
while True:
+ self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
+
try:
log.info("Start creating a new auth key on DC{}".format(self.dc_id))
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 1da0fdd7..7e90cfff 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -96,11 +96,15 @@ class Session:
print("Licensed under the terms of the " + __license__, end="\n\n")
Session.notice_displayed = True
- self.connection = Connection(DataCenter(dc_id, test_mode), proxy)
+ self.dc_id = dc_id
+ self.test_mode = test_mode
+ self.proxy = proxy
self.api_id = api_id
self.is_cdn = is_cdn
self.client = client
+ self.connection = None
+
self.auth_key = auth_key
self.auth_key_id = sha1(auth_key).digest()[-8:]
@@ -126,6 +130,8 @@ class Session:
def start(self):
while True:
+ self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
+
try:
self.connection.connect()
From 00b983ccc3a726052b1c0287f2326620eeed9ec6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 25 May 2018 11:52:40 +0200
Subject: [PATCH 020/145] Fix proxy not being correctly updated
---
pyrogram/client/client.py | 52 +++++++++++++++++++++++----------------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 813d7e74..3ec22181 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -144,7 +144,8 @@ class Client(Methods, BaseClient):
self.session_name = session_name
self.api_id = int(api_id) if api_id else None
self.api_hash = api_hash
- self.proxy = proxy
+ # TODO: Make code consistent, use underscore for private/protected fields
+ self._proxy = proxy
self.test_mode = test_mode
self.phone_number = phone_number
self.phone_code = phone_code
@@ -158,6 +159,15 @@ class Client(Methods, BaseClient):
self.dispatcher = Dispatcher(self, workers)
+ @property
+ def proxy(self):
+ return self._proxy
+
+ @proxy.setter
+ def proxy(self, value):
+ self._proxy["enabled"] = True
+ self._proxy.update(value)
+
def start(self, debug: bool = False):
"""Use this method to start the Client after creating it.
Requires no parameters.
@@ -183,7 +193,7 @@ class Client(Methods, BaseClient):
self.session = Session(
self.dc_id,
self.test_mode,
- self.proxy,
+ self._proxy,
self.auth_key,
self.api_id,
client=self
@@ -331,12 +341,12 @@ class Client(Methods, BaseClient):
self.session.stop()
self.dc_id = e.x
- self.auth_key = Auth(self.dc_id, self.test_mode, self.proxy).create()
+ self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
self.dc_id,
self.test_mode,
- self.proxy,
+ self._proxy,
self.auth_key,
self.api_id,
client=self
@@ -379,12 +389,12 @@ class Client(Methods, BaseClient):
self.session.stop()
self.dc_id = e.x
- self.auth_key = Auth(self.dc_id, self.test_mode, self.proxy).create()
+ self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
self.dc_id,
self.test_mode,
- self.proxy,
+ self._proxy,
self.auth_key,
self.api_id,
client=self
@@ -841,17 +851,17 @@ class Client(Methods, BaseClient):
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
)
- if self.proxy:
- self.proxy["enabled"] = True
+ if self._proxy:
+ self._proxy["enabled"] = True
else:
- self.proxy = {}
+ self._proxy = {}
if parser.has_section("proxy"):
- self.proxy["enabled"] = parser.getboolean("proxy", "enabled")
- self.proxy["hostname"] = parser.get("proxy", "hostname")
- self.proxy["port"] = parser.getint("proxy", "port")
- self.proxy["username"] = parser.get("proxy", "username", fallback=None) or None
- self.proxy["password"] = parser.get("proxy", "password", fallback=None) or None
+ self._proxy["enabled"] = parser.getboolean("proxy", "enabled")
+ self._proxy["hostname"] = parser.get("proxy", "hostname")
+ self._proxy["port"] = parser.getint("proxy", "port")
+ self._proxy["username"] = parser.get("proxy", "username", fallback=None) or None
+ self._proxy["password"] = parser.get("proxy", "password", fallback=None) or None
def load_session(self):
try:
@@ -860,7 +870,7 @@ class Client(Methods, BaseClient):
except FileNotFoundError:
self.dc_id = 1
self.date = 0
- self.auth_key = Auth(self.dc_id, self.test_mode, self.proxy).create()
+ self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
else:
self.dc_id = s["dc_id"]
self.test_mode = s["test_mode"]
@@ -1012,7 +1022,7 @@ class Client(Methods, BaseClient):
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
- session = Session(self.dc_id, self.test_mode, self.proxy, self.auth_key, self.api_id)
+ session = Session(self.dc_id, self.test_mode, self._proxy, self.auth_key, self.api_id)
session.start()
try:
@@ -1099,8 +1109,8 @@ class Client(Methods, BaseClient):
session = Session(
dc_id,
self.test_mode,
- self.proxy,
- Auth(dc_id, self.test_mode, self.proxy).create(),
+ self._proxy,
+ Auth(dc_id, self.test_mode, self._proxy).create(),
self.api_id
)
@@ -1118,7 +1128,7 @@ class Client(Methods, BaseClient):
session = Session(
dc_id,
self.test_mode,
- self.proxy,
+ self._proxy,
self.auth_key,
self.api_id
)
@@ -1188,8 +1198,8 @@ class Client(Methods, BaseClient):
cdn_session = Session(
r.dc_id,
self.test_mode,
- self.proxy,
- Auth(r.dc_id, self.test_mode, self.proxy).create(),
+ self._proxy,
+ Auth(r.dc_id, self.test_mode, self._proxy).create(),
self.api_id,
is_cdn=True
)
From 81d3d5956c405767d3682bff6880eced7dc3650f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 25 May 2018 12:37:03 +0200
Subject: [PATCH 021/145] Don't try to indefinitely reconnect at Connection
layer
---
pyrogram/connection/connection.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 118f0d83..5e86c8aa 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -26,6 +26,8 @@ log = logging.getLogger(__name__)
class Connection:
+ MAX_RETRIES = 5
+
MODES = {
0: TCPFull,
1: TCPAbridged,
@@ -40,7 +42,7 @@ class Connection:
self.connection = None
def connect(self):
- while True:
+ for i in range(Connection.MAX_RETRIES):
self.connection = self.mode(self.proxy)
try:
@@ -51,6 +53,8 @@ class Connection:
time.sleep(1)
else:
break
+ else:
+ raise TimeoutError
def close(self):
self.connection.close()
From b04bce9dba3b9ceb970c9efd5405bc0761f5568b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 25 May 2018 14:26:01 +0200
Subject: [PATCH 022/145] Lower connection retries to 3
---
pyrogram/connection/connection.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 5e86c8aa..2b29743e 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
class Connection:
- MAX_RETRIES = 5
+ MAX_RETRIES = 3
MODES = {
0: TCPFull,
From 93218a6ed703d2c4ac2c247b0bc0aa7f72f57135 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 26 May 2018 18:04:17 +0200
Subject: [PATCH 023/145] Remove handlers lock
---
pyrogram/client/dispatcher/dispatcher.py | 73 +++++++++++-------------
1 file changed, 34 insertions(+), 39 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 5558a2fd..f62cbfd1 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -50,8 +50,6 @@ class Dispatcher:
self.updates = Queue()
self.groups = OrderedDict()
- self._handler_lock = threading.Lock()
-
def start(self):
for i in range(self.workers):
self.workers_list.append(
@@ -73,52 +71,49 @@ class Dispatcher:
self.workers_list.clear()
def add_handler(self, handler, group: int):
- with self._handler_lock:
- if group not in self.groups:
- self.groups[group] = []
- self.groups = OrderedDict(sorted(self.groups.items()))
+ if group not in self.groups:
+ self.groups[group] = []
+ self.groups = OrderedDict(sorted(self.groups.items()))
- self.groups[group].append(handler)
+ self.groups[group].append(handler)
def remove_handler(self, handler, group: int):
- with self._handler_lock:
- if group not in self.groups:
- raise ValueError("Group {} does not exist. "
- "Handler was not removed.".format(group))
- self.groups[group].remove(handler)
+ if group not in self.groups:
+ raise ValueError("Group {} does not exist. "
+ "Handler was not removed.".format(group))
+ self.groups[group].remove(handler)
def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool = False):
- with self._handler_lock:
- for group in self.groups.values():
- for handler in group:
- if is_raw:
- if not isinstance(handler, RawUpdateHandler):
+ for group in self.groups.values():
+ for handler in group:
+ if is_raw:
+ if not isinstance(handler, RawUpdateHandler):
+ continue
+
+ args = (self.client, update, users, chats)
+ else:
+ message = (update.message
+ or update.channel_post
+ or update.edited_message
+ or update.edited_channel_post)
+
+ callback_query = update.callback_query
+
+ if message and isinstance(handler, MessageHandler):
+ if not handler.check(message):
continue
- args = (self.client, update, users, chats)
+ args = (self.client, message)
+ elif callback_query and isinstance(handler, CallbackQueryHandler):
+ if not handler.check(callback_query):
+ continue
+
+ args = (self.client, callback_query)
else:
- message = (update.message
- or update.channel_post
- or update.edited_message
- or update.edited_channel_post)
+ continue
- callback_query = update.callback_query
-
- if message and isinstance(handler, MessageHandler):
- if not handler.check(message):
- continue
-
- args = (self.client, message)
- elif callback_query and isinstance(handler, CallbackQueryHandler):
- if not handler.check(callback_query):
- continue
-
- args = (self.client, callback_query)
- else:
- continue
-
- handler.callback(*args)
- break
+ handler.callback(*args)
+ break
def update_worker(self):
name = threading.current_thread().name
From d8dbcb5b4ead3d5a94e5c2dc79b62342fc0a519c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 27 May 2018 20:16:30 +0200
Subject: [PATCH 024/145] Add Empty parse mode
---
pyrogram/client/ext/parse_mode.py | 3 +++
pyrogram/client/style/__init__.py | 1 +
pyrogram/client/style/empty.py | 26 ++++++++++++++++++++++++++
3 files changed, 30 insertions(+)
create mode 100644 pyrogram/client/style/empty.py
diff --git a/pyrogram/client/ext/parse_mode.py b/pyrogram/client/ext/parse_mode.py
index 817bccb0..209b8cde 100644
--- a/pyrogram/client/ext/parse_mode.py
+++ b/pyrogram/client/ext/parse_mode.py
@@ -27,3 +27,6 @@ class ParseMode:
MARKDOWN = "markdown"
"""Set the parse mode to Markdown style"""
+
+ EMPTY = "empty"
+ """Disable the parse mode"""
diff --git a/pyrogram/client/style/__init__.py b/pyrogram/client/style/__init__.py
index e60b4da1..0c318fef 100644
--- a/pyrogram/client/style/__init__.py
+++ b/pyrogram/client/style/__init__.py
@@ -16,5 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+from .empty import Empty
from .html import HTML
from .markdown import Markdown
diff --git a/pyrogram/client/style/empty.py b/pyrogram/client/style/empty.py
new file mode 100644
index 00000000..28df2055
--- /dev/null
+++ b/pyrogram/client/style/empty.py
@@ -0,0 +1,26 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+
+class Empty:
+ @staticmethod
+ def parse(text):
+ return dict(
+ message=text,
+ entities=[]
+ )
From e1e6e4bd70a90721785585d1abe2ac5805d598b1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 27 May 2018 20:24:42 +0200
Subject: [PATCH 025/145] Make send_message recognise the Empty parse mode
---
pyrogram/client/methods/messages/send_message.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index 44acaa2e..c6a459ab 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -19,6 +19,7 @@
from pyrogram.api import functions, types
from pyrogram.client import types as pyrogram_types
from ...ext import utils, BaseClient
+from ...style import Empty
class SendMessage(BaseClient):
@@ -67,7 +68,13 @@ class SendMessage(BaseClient):
Raises:
:class:`Error `
"""
- style = self.html if parse_mode.lower() == "html" else self.markdown
+ parse_mode = parse_mode.lower()
+
+ style = (
+ Empty if parse_mode == "empty"
+ else self.html if parse_mode == "html"
+ else self.markdown
+ )
r = self.send(
functions.messages.SendMessage(
From 78aa7aea2a9d3032d3b1aa376e3e3945b3d47995 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 28 May 2018 19:57:57 +0200
Subject: [PATCH 026/145] Add TCP Abridged obfuscated protocol
---
.../transport/tcp/tcp_abridged_o.py | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 pyrogram/connection/transport/tcp/tcp_abridged_o.py
diff --git a/pyrogram/connection/transport/tcp/tcp_abridged_o.py b/pyrogram/connection/transport/tcp/tcp_abridged_o.py
new file mode 100644
index 00000000..bba88e34
--- /dev/null
+++ b/pyrogram/connection/transport/tcp/tcp_abridged_o.py
@@ -0,0 +1,93 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+import logging
+import os
+
+from .tcp import TCP
+from ....crypto.aes import AES
+
+log = logging.getLogger(__name__)
+
+
+class TCPAbridgedO(TCP):
+ RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
+
+ def __init__(self, proxy: dict):
+ super().__init__(proxy)
+ self.encrypt = None
+ self.decrypt = None
+
+ def connect(self, address: tuple):
+ super().connect(address)
+
+ while True:
+ nonce = bytearray(os.urandom(64))
+
+ if (nonce[0] != b"\xef"
+ and nonce[:4] not in self.RESERVED
+ and nonce[4:4] != b"\x00" * 4):
+ nonce[56] = nonce[57] = nonce[58] = nonce[59] = 0xef
+ break
+
+ temp = bytearray(nonce[55:7:-1])
+
+ self.encrypt = (nonce[8:40], nonce[40:56], bytearray(1))
+ self.decrypt = (temp[0:32], temp[32:48], bytearray(1))
+
+ nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64]
+
+ super().sendall(nonce)
+
+ log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
+
+ def sendall(self, data: bytes, *args):
+ length = len(data) // 4
+
+ super().sendall(
+ AES.ctr256_encrypt(
+ (bytes([length])
+ if length <= 126
+ else b"\x7f" + length.to_bytes(3, "little"))
+ + data,
+ *self.encrypt
+ )
+ )
+
+ def recvall(self, length: int = 0) -> bytes or None:
+ length = super().recvall(1)
+
+ if length is None:
+ return None
+
+ length = AES.ctr256_decrypt(length, *self.decrypt)
+
+ if length == b"\x7f":
+ length = super().recvall(3)
+
+ if length is None:
+ return None
+
+ length = AES.ctr256_decrypt(length, *self.decrypt)
+
+ data = super().recvall(int.from_bytes(length, "little") * 4)
+
+ if data is None:
+ return None
+
+ return AES.ctr256_decrypt(data, *self.decrypt)
From 0866dfa1dd7f1eb0ef72e703959046b3750789f3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 28 May 2018 19:58:36 +0200
Subject: [PATCH 027/145] Make TCPAbridgedO importable
---
pyrogram/connection/transport/tcp/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py
index d1daff63..f6b85c25 100644
--- a/pyrogram/connection/transport/tcp/__init__.py
+++ b/pyrogram/connection/transport/tcp/__init__.py
@@ -17,5 +17,6 @@
# along with Pyrogram. If not, see .
from .tcp_abridged import TCPAbridged
+from .tcp_abridged_o import TCPAbridgedO
from .tcp_full import TCPFull
from .tcp_intermediate import TCPIntermediate
From 55010e4f1fcdbc88fa4e4d94a87bc97c2e3f3335 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 29 May 2018 12:20:42 +0200
Subject: [PATCH 028/145] Add TCPAbridgedO to Connection modes
---
pyrogram/connection/connection.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 2b29743e..01b322e8 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -31,7 +31,8 @@ class Connection:
MODES = {
0: TCPFull,
1: TCPAbridged,
- 2: TCPIntermediate
+ 2: TCPIntermediate,
+ 3: TCPAbridgedO
}
def __init__(self, address: tuple, proxy: dict, mode: int = 1):
From 98ebad34281aa082cab414027e0e46740452d885 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 30 May 2018 19:29:03 +0200
Subject: [PATCH 029/145] Add TCP Intermediate obfuscated protocol
---
pyrogram/connection/transport/tcp/__init__.py | 1 +
.../transport/tcp/tcp_intermediate_o.py | 81 +++++++++++++++++++
2 files changed, 82 insertions(+)
create mode 100644 pyrogram/connection/transport/tcp/tcp_intermediate_o.py
diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py
index f6b85c25..ce662e61 100644
--- a/pyrogram/connection/transport/tcp/__init__.py
+++ b/pyrogram/connection/transport/tcp/__init__.py
@@ -20,3 +20,4 @@ from .tcp_abridged import TCPAbridged
from .tcp_abridged_o import TCPAbridgedO
from .tcp_full import TCPFull
from .tcp_intermediate import TCPIntermediate
+from .tcp_intermediate_o import TCPIntermediateO
diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py
new file mode 100644
index 00000000..df79352a
--- /dev/null
+++ b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py
@@ -0,0 +1,81 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+import logging
+import os
+from struct import pack, unpack
+
+from .tcp import TCP
+from ....crypto.aes import AES
+
+log = logging.getLogger(__name__)
+
+
+class TCPIntermediateO(TCP):
+ RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
+
+ def __init__(self, proxy: dict):
+ super().__init__(proxy)
+ self.encrypt = None
+ self.decrypt = None
+
+ def connect(self, address: tuple):
+ super().connect(address)
+
+ while True:
+ nonce = bytearray(os.urandom(64))
+
+ if (nonce[0] != b"\xef"
+ and nonce[:4] not in self.RESERVED
+ and nonce[4:4] != b"\x00" * 4):
+ nonce[56] = nonce[57] = nonce[58] = nonce[59] = 0xee
+ break
+
+ temp = bytearray(nonce[55:7:-1])
+
+ self.encrypt = (nonce[8:40], nonce[40:56], bytearray(1))
+ self.decrypt = (temp[0:32], temp[32:48], bytearray(1))
+
+ nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64]
+
+ super().sendall(nonce)
+
+ log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
+
+ def sendall(self, data: bytes, *args):
+ super().sendall(
+ AES.ctr256_encrypt(
+ pack(" bytes or None:
+ length = super().recvall(4)
+
+ if length is None:
+ return None
+
+ length = AES.ctr256_decrypt(length, *self.decrypt)
+
+ data = super().recvall(unpack("
Date: Wed, 30 May 2018 19:29:45 +0200
Subject: [PATCH 030/145] Add TCPIntermediateO to Connection modes
---
pyrogram/connection/connection.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 01b322e8..a53295ce 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -32,7 +32,8 @@ class Connection:
0: TCPFull,
1: TCPAbridged,
2: TCPIntermediate,
- 3: TCPAbridgedO
+ 3: TCPAbridgedO,
+ 4: TCPIntermediateO
}
def __init__(self, address: tuple, proxy: dict, mode: int = 1):
From 73c101b49d116f9cb568f9658459cae1e4cc98ef Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 31 May 2018 13:03:20 +0200
Subject: [PATCH 031/145] Revert "Add Empty parse mode"
This reverts commit d8dbcb5
---
pyrogram/client/ext/parse_mode.py | 3 ---
pyrogram/client/style/__init__.py | 1 -
pyrogram/client/style/empty.py | 26 --------------------------
3 files changed, 30 deletions(-)
delete mode 100644 pyrogram/client/style/empty.py
diff --git a/pyrogram/client/ext/parse_mode.py b/pyrogram/client/ext/parse_mode.py
index 209b8cde..817bccb0 100644
--- a/pyrogram/client/ext/parse_mode.py
+++ b/pyrogram/client/ext/parse_mode.py
@@ -27,6 +27,3 @@ class ParseMode:
MARKDOWN = "markdown"
"""Set the parse mode to Markdown style"""
-
- EMPTY = "empty"
- """Disable the parse mode"""
diff --git a/pyrogram/client/style/__init__.py b/pyrogram/client/style/__init__.py
index 0c318fef..e60b4da1 100644
--- a/pyrogram/client/style/__init__.py
+++ b/pyrogram/client/style/__init__.py
@@ -16,6 +16,5 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .empty import Empty
from .html import HTML
from .markdown import Markdown
diff --git a/pyrogram/client/style/empty.py b/pyrogram/client/style/empty.py
deleted file mode 100644
index 28df2055..00000000
--- a/pyrogram/client/style/empty.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-
-class Empty:
- @staticmethod
- def parse(text):
- return dict(
- message=text,
- entities=[]
- )
From 0dc5ecf28c125f60dc9cb192a1c33cee14ba34fb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 31 May 2018 13:03:28 +0200
Subject: [PATCH 032/145] Revert "Make send_message recognise the Empty parse
mode"
This reverts commit e1e6e4b
---
pyrogram/client/methods/messages/send_message.py | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index c6a459ab..44acaa2e 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -19,7 +19,6 @@
from pyrogram.api import functions, types
from pyrogram.client import types as pyrogram_types
from ...ext import utils, BaseClient
-from ...style import Empty
class SendMessage(BaseClient):
@@ -68,13 +67,7 @@ class SendMessage(BaseClient):
Raises:
:class:`Error `
"""
- parse_mode = parse_mode.lower()
-
- style = (
- Empty if parse_mode == "empty"
- else self.html if parse_mode == "html"
- else self.markdown
- )
+ style = self.html if parse_mode.lower() == "html" else self.markdown
r = self.send(
functions.messages.SendMessage(
From 118cd04a73c0fd23ddcbd9ac8ce8947fe8b2b37b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 31 May 2018 13:13:38 +0200
Subject: [PATCH 033/145] Document DisconnectHandler
---
pyrogram/client/handlers/disconnect_handler.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
index 67d0ae02..71123248 100644
--- a/pyrogram/client/handlers/disconnect_handler.py
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -20,6 +20,19 @@ from .handler import Handler
class DisconnectHandler(Handler):
- # TODO: Documentation
+ """The Disconnect handler class. Used to handle disconnections. It is intended to be used with
+ :meth:`add_handler() `
+
+
+ Args:
+ callback (``callable``):
+ Pass a function that will be called when a disconnection occurs. It takes *(client)*
+ as positional argument (look at the section below for a detailed description).
+
+ Other parameters:
+ client (:obj:`Client `):
+ The Client itself. Useful, for example, when you want to change the proxy before a new connection
+ is established.
+ """
def __init__(self, callback: callable):
super().__init__(callback)
From dacc0173f1294a53ccc3123fd17c3294b4954cd9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 31 May 2018 13:15:47 +0200
Subject: [PATCH 034/145] Document on_disconnect
---
pyrogram/client/methods/decorators/on_disconnect.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py
index 230a361c..d1d03723 100644
--- a/pyrogram/client/methods/decorators/on_disconnect.py
+++ b/pyrogram/client/methods/decorators/on_disconnect.py
@@ -22,7 +22,11 @@ from ...ext import BaseClient
class OnDisconnect(BaseClient):
def on_disconnect(self):
- # TODO: Documentation
+ """Use this decorator to automatically register a function for handling
+ disconnections. This does the same thing as :meth:`add_handler` using the
+ DisconnectHandler.
+ """
+
def decorator(func):
self.add_handler(pyrogram.DisconnectHandler(func))
return func
From b4a2490da275ed16d0e04c7f2edf33a007221185 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 1 Jun 2018 19:27:05 +0200
Subject: [PATCH 035/145] Use getpass instead of input
---
pyrogram/client/client.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 3ec22181..e38d752e 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -18,6 +18,7 @@
import base64
import binascii
+import getpass
import json
import logging
import math
@@ -498,7 +499,7 @@ class Client(Methods, BaseClient):
if self.password is None:
print("Hint: {}".format(r.hint))
- self.password = input("Enter password: ") # TODO: Use getpass
+ self.password = getpass.getpass("Enter password: ")
if type(self.password) is str:
self.password = r.current_salt + self.password.encode() + r.current_salt
From dc7fe93aeb02a0aa3b4a2adf336091e57331b7e6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 2 Jun 2018 20:52:16 +0200
Subject: [PATCH 036/145] Clean up code
---
pyrogram/client/client.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index e38d752e..24b1b5fe 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1272,9 +1272,6 @@ class Client(Methods, BaseClient):
break
except Exception as e:
raise e
- finally:
- pass # Don't stop sessions, they are now cached and kept online
- # cdn_session.stop() TODO: Remove this branch
except Exception as e:
log.error(e, exc_info=True)
@@ -1286,6 +1283,3 @@ class Client(Methods, BaseClient):
return ""
else:
return file_name
- finally:
- pass # Don't stop sessions, they are now cached and kept online
- # session.stop() TODO: Remove this branch
From 91cf103783a2e78f258b0aa2e769bbaf748881be Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 2 Jun 2018 20:52:46 +0200
Subject: [PATCH 037/145] Remove a bunch of useless TODOs
---
pyrogram/api/core/primitives/int.py | 2 --
pyrogram/client/client.py | 2 --
2 files changed, 4 deletions(-)
diff --git a/pyrogram/api/core/primitives/int.py b/pyrogram/api/core/primitives/int.py
index 6379c2ad..0985367f 100644
--- a/pyrogram/api/core/primitives/int.py
+++ b/pyrogram/api/core/primitives/int.py
@@ -35,8 +35,6 @@ class Int(Object):
class Long(Int):
SIZE = 8
- # TODO: PyCharm can't infer types when overriding parent's __new__ and is showing unnecessary warnings.
- # Add this to shut warnings down
def __new__(cls, *args):
return super().__new__(cls, *args)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 24b1b5fe..73f45966 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1008,7 +1008,6 @@ class Client(Methods, BaseClient):
except (KeyError, ValueError):
raise PeerIdInvalid
- # TODO: Improvements for the new API
def save_file(self,
path: str,
file_id: int = None,
@@ -1084,7 +1083,6 @@ class Client(Methods, BaseClient):
finally:
session.stop()
- # TODO: Improvements for the new API
def get_file(self,
dc_id: int,
id: int = None,
From 29dcdbdc927b9669e56526a82bd3c1cebe98e4be Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 17:14:15 +0200
Subject: [PATCH 038/145] Add reply_text convenience method to Message objects
---
pyrogram/client/types/message.py | 62 ++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index ca095f1d..4d9e6147 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -309,3 +309,65 @@ class Message(Object):
self.matches = matches
self.command = command
self.reply_markup = reply_markup
+
+ def reply_text(self,
+ text: str,
+ quote: bool = None,
+ parse_mode: str = "",
+ disable_web_page_preview: bool = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
+ """Use this method as a shortcut for::
+
+ app.send_message(message.chat.id, ...)
+
+ Args:
+ text (``str``):
+ Text of the message to be sent.
+
+ quote (``bool``, *optional*):
+ If ``True``, the message will be sent as a reply to this message.
+ If *reply_to_message_id* is passed, this parameter will be ignored.
+ Defaults to ``True`` in group chats and ``False`` in private chats.
+
+ parse_mode (``str``, *optional*):
+ Use :obj:`MARKDOWN ` or :obj:`HTML `
+ if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
+ Defaults to Markdown.
+
+ disable_web_page_preview (``bool``, *optional*):
+ Disables link previews for links in this message.
+
+ disable_notification (``bool``, *optional*):
+ Sends the message silently.
+ Users will receive a notification with no sound.
+
+ reply_to_message_id (``int``, *optional*):
+ If the message is a reply, ID of the original message.
+
+ reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
+ Additional interface options. An object for an inline keyboard, custom reply keyboard,
+ instructions to remove reply keyboard or to force a reply from the user.
+
+ Returns:
+ On success, the sent Message is returned.
+
+ Raises:
+ :class:`Error `
+ """
+ if quote is None:
+ quote = self.chat.type != "private"
+
+ if reply_to_message_id is None and quote:
+ reply_to_message_id = self.message_id
+
+ return self.client.send_message(
+ chat_id=self.chat.id,
+ text=text,
+ parse_mode=parse_mode,
+ disable_web_page_preview=disable_web_page_preview,
+ disable_notification=disable_notification,
+ reply_to_message_id=reply_to_message_id,
+ reply_markup=reply_markup
+ )
From 131d792bad795d7898b30aef1fb14f7df2c4f069 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 17:40:28 +0200
Subject: [PATCH 039/145] Add forward convenience method to Message objects
---
pyrogram/client/types/message.py | 42 ++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 4d9e6147..a6f099bb 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -371,3 +371,45 @@ class Message(Object):
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
+
+ def forward(self,
+ chat_id: int or str,
+ disable_notification: bool = None):
+ """Use this method as a shortcut for:
+
+ .. code-block:: python
+
+ client.forward_messages(
+ chat_id=chat_id,
+ from_chat_id=message.chat.id,
+ message_ids=message.message_id,
+ )
+
+ Example:
+ .. code-block:: python
+
+ message.forward(chat_id)
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For your personal cloud (Saved Messages) you can simply use "me" or "self".
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ disable_notification (``bool``, *optional*):
+ Sends the message silently.
+ Users will receive a notification with no sound.
+
+ Returns:
+ On success, the forwarded Message is returned.
+
+ Raises:
+ :class:`Error `
+ """
+ return self.client.forward_messages(
+ chat_id=chat_id,
+ from_chat_id=self.chat.id,
+ message_ids=self.message_id,
+ disable_notification=disable_notification
+ )
From e94520b7bc8564b788448a025eaede0cd798b752 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 17:40:59 +0200
Subject: [PATCH 040/145] Fix reply_text docstrings and add the Example section
---
pyrogram/client/types/message.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index a6f099bb..1ffab8ed 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -318,9 +318,20 @@ class Message(Object):
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None):
- """Use this method as a shortcut for::
+ """Use this method as a shortcut for:
- app.send_message(message.chat.id, ...)
+ .. code-block:: python
+
+ client.send_message(
+ chat_id=message.chat.id,
+ text="hello",
+ reply_to_message_id=message.message_id
+ )
+
+ Example:
+ .. code-block:: python
+
+ message.reply_text("hello", quote=True)
Args:
text (``str``):
From 7752aef33855d1fe317d907288342493726d2c1a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 17:50:24 +0200
Subject: [PATCH 041/145] Add delete convenience method to Message objects
---
pyrogram/client/types/message.py | 36 ++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 1ffab8ed..a2a1ceab 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -424,3 +424,39 @@ class Message(Object):
message_ids=self.message_id,
disable_notification=disable_notification
)
+
+ def delete(self, revoke: bool = True):
+ """Use this method as a shortcut for:
+
+ .. code-block:: python
+
+ client.delete_messages(
+ chat_id=chat_id,
+ message_ids=message.message_id
+ )
+
+ Example:
+ .. code-block:: python
+
+ message.delete()
+
+ Args:
+ revoke (``bool``, *optional*):
+ Deletes messages on both parts.
+ This is only for private cloud chats and normal groups, messages on
+ channels and supergroups are always revoked (i.e.: deleted for everyone).
+ Defaults to True.
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+ self.client.delete_messages(
+ chat_id=self.chat.id,
+ message_ids=self.message_id,
+ revoke=revoke
+ )
+
+ return True
From 745049bda33c4e9495b80089ea4ce0a2033f43f4 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 17:54:57 +0200
Subject: [PATCH 042/145] Protect client by renaming the property to _client
---
pyrogram/client/ext/utils.py | 4 ++--
pyrogram/client/types/message.py | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 724b554d..1feac5a8 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -583,10 +583,10 @@ def parse_messages(
)
if m.text:
- m.text.init(m.client, m.entities or [])
+ m.text.init(m._client, m.entities or [])
if m.caption:
- m.caption.init(m.client, m.caption_entities or [])
+ m.caption.init(m._client, m.caption_entities or [])
if message.reply_to_msg_id and replies:
while True:
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index a2a1ceab..74f2a0a6 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -260,7 +260,7 @@ class Message(Object):
reply_markup=None,
):
self.message_id = message_id # int
- self.client = client
+ self._client = client
self.date = date # int
self.chat = chat # Chat
self.from_user = from_user # flags.0?User
@@ -373,7 +373,7 @@ class Message(Object):
if reply_to_message_id is None and quote:
reply_to_message_id = self.message_id
- return self.client.send_message(
+ return self._client.send_message(
chat_id=self.chat.id,
text=text,
parse_mode=parse_mode,
@@ -418,7 +418,7 @@ class Message(Object):
Raises:
:class:`Error `
"""
- return self.client.forward_messages(
+ return self._client.forward_messages(
chat_id=chat_id,
from_chat_id=self.chat.id,
message_ids=self.message_id,
@@ -453,7 +453,7 @@ class Message(Object):
Raises:
:class:`Error `
"""
- self.client.delete_messages(
+ self._client.delete_messages(
chat_id=self.chat.id,
message_ids=self.message_id,
revoke=revoke
From b3ffa1e86c2b262b175ec06b9b2030cb25f76a7c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 18:04:16 +0200
Subject: [PATCH 043/145] Update auth key generation TL scheme
---
compiler/api/source/auth_key.tl | 2 ++
1 file changed, 2 insertions(+)
diff --git a/compiler/api/source/auth_key.tl b/compiler/api/source/auth_key.tl
index e0af9dcd..dad176fe 100644
--- a/compiler/api/source/auth_key.tl
+++ b/compiler/api/source/auth_key.tl
@@ -7,7 +7,9 @@
resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes server_public_key_fingerprints:Vector = ResPQ;
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_dc#a9f55f95 pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 dc: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;
+p_q_inner_data_temp_dc#56fddf88 pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;
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;
From d67dfd39da8d714a536a3f2c377e25dd781d956c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 18:07:04 +0200
Subject: [PATCH 044/145] Update system messages TL scheme
---
compiler/api/source/sys_msgs.tl | 11 ++++++++---
pyrogram/session/internals/msg_factory.py | 4 ++--
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/compiler/api/source/sys_msgs.tl b/compiler/api/source/sys_msgs.tl
index cd00cd2d..067ab91e 100644
--- a/compiler/api/source/sys_msgs.tl
+++ b/compiler/api/source/sys_msgs.tl
@@ -42,9 +42,16 @@ new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long =
// msg_copy#e06046b2 orig_message:Message = MessageCopy; // Not used
// gzip_packed#3072cfa1 packed_data:string = Object; // Parsed manually
+http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
+
//// 0xd433ad73 = hex(crc32(b"ipPort ipv4:int port:int = IpPort"))
+// ipPort ipv4:int port:int = IpPort;
+// help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple;
+
ipPort#d433ad73 ipv4:int port:int = IpPort;
-help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple;
+ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
+accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule;
+help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple;
---functions---
@@ -58,5 +65,3 @@ ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
destroy_session#e7512126 session_id:long = DestroySessionRes;
contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool;
-
-http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
diff --git a/pyrogram/session/internals/msg_factory.py b/pyrogram/session/internals/msg_factory.py
index f599cd6f..76a35458 100644
--- a/pyrogram/session/internals/msg_factory.py
+++ b/pyrogram/session/internals/msg_factory.py
@@ -17,8 +17,8 @@
# along with Pyrogram. If not, see .
from pyrogram.api.core import Message, MsgContainer, Object
-from pyrogram.api.functions import Ping, HttpWait
-from pyrogram.api.types import MsgsAck
+from pyrogram.api.functions import Ping
+from pyrogram.api.types import MsgsAck, HttpWait
from .msg_id import MsgId
from .seq_no import SeqNo
From 7e5dcb9f6056cde2e7518cb6f9aae5fd58c47dc5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Jun 2018 20:10:57 +0200
Subject: [PATCH 045/145] Update API scheme to Layer 79
---
compiler/api/source/main_api.tl | 48 ++++++++++++++++-----------------
1 file changed, 23 insertions(+), 25 deletions(-)
diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl
index 9ede3e28..2919520e 100644
--- a/compiler/api/source/main_api.tl
+++ b/compiler/api/source/main_api.tl
@@ -97,7 +97,7 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
-channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
+channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull;
@@ -173,18 +173,10 @@ auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorizat
inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
inputNotifyUsers#193b4417 = InputNotifyPeer;
inputNotifyChats#4a95e84e = InputNotifyPeer;
-inputNotifyAll#a429b886 = InputNotifyPeer;
-inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents;
-inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents;
+inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
-inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings;
-
-peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
-peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
-
-peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
-peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
+peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
@@ -338,9 +330,9 @@ photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File;
-dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption;
+dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
-config#86b5778e flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
+config#eb7bb160 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -385,7 +377,6 @@ help.support#17c6b5f6 phone_number:string user:User = help.Support;
notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
notifyUsers#b4c83b4c = NotifyPeer;
notifyChats#c007cec3 = NotifyPeer;
-notifyAll#74d07c60 = NotifyPeer;
sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
@@ -438,7 +429,7 @@ documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
messages.stickersNotModified#f1749a22 = messages.Stickers;
-messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers;
+messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers;
stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack;
@@ -567,7 +558,7 @@ messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs;
inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
-inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
@@ -579,7 +570,7 @@ inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:Input
botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
-botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
@@ -718,6 +709,8 @@ webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vect
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument;
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
+inputWebFileGeoPointLocation#66275a62 geo_point:InputGeoPoint w:int h:int zoom:int scale:int = InputWebFileLocation;
+inputWebFileGeoMessageLocation#553f32eb peer:InputPeer msg_id:int w:int h:int zoom:int scale:int = InputWebFileLocation;
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
@@ -773,7 +766,7 @@ langPackDifference#f385c1f6 lang_code:string from_version:int version:int string
langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage;
-channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights;
+channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights;
channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights;
@@ -832,15 +825,19 @@ messages.foundStickerSets#5108d648 hash:int sets:Vector = mes
fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
+inputClientProxy#75588b3f address:string port:int = InputClientProxy;
+
+help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
+help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData;
+
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X;
-initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X;
+initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
-auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone;
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
@@ -943,7 +940,7 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da
messages.receivedQueue#55a5bb66 max_qts:int = Vector;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages;
-messages.getStickers#85cb5182 flags:# exclude_featured:flags.0?true emoticon:string hash:string = messages.Stickers;
+messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
@@ -967,8 +964,8 @@ messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_p
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
-messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates;
-messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool;
+messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates;
+messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs;
@@ -1030,10 +1027,11 @@ help.saveAppLog#6f02f748 events:Vector = Bool;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
-help.getTermsOfService#350170f3 = help.TermsOfService;
+help.getTermsOfService#8e59b7e7 country_iso2:string = help.TermsOfService;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
+help.getProxyData#3d7758e1 = help.ProxyData;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages;
@@ -1097,4 +1095,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector;
-// LAYER 76
+// LAYER 79
From 36a1015ec9939414f1368dd19b601215bc229365 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 09:11:58 +0200
Subject: [PATCH 046/145] Hide _client when printing pyrogram object
---
pyrogram/api/core/object.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/api/core/object.py b/pyrogram/api/core/object.py
index 21bd7c3f..d54d0327 100644
--- a/pyrogram/api/core/object.py
+++ b/pyrogram/api/core/object.py
@@ -78,7 +78,7 @@ class Encoder(JSONEncoder):
if o is not None:
if o.startswith("pyrogram.client"):
r = remove_none(OrderedDict([("_", name)] + [i for i in content.items()]))
- r.pop("client", None)
+ r.pop("_client", None)
return r
else:
From 2125415f8f065207081ac7e0261218520cea790a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 10:13:11 +0200
Subject: [PATCH 047/145] Allow empty and multi-character prefixes in
Filters.command
---
pyrogram/client/filters/filters.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index e2a177b8..d2dfb9a5 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -155,8 +155,9 @@ class Filters:
def f(_, m):
if m.text and m.text.startswith(_.p):
- c = m.text[1:].split(_.s)[0]
- m.command = ([c] + m.text.split(_.s)[1:]) if c in _.c else None
+ t = m.text.split(_.s)
+ c, a = t[0][len(_.p):], t[1:]
+ m.command = ([c] + a) if c in _.c else None
return bool(m.command)
From 62d4b2aeee45953f226e6ce76ba2f6b36fa17f87 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 11:35:38 +0200
Subject: [PATCH 048/145] Allow defining case sensitive commands with
Filters.command
---
pyrogram/client/filters/filters.py | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index d2dfb9a5..e92948b6 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -134,7 +134,10 @@ class Filters:
# TODO: Add filters for reply markups
@staticmethod
- def command(command: str or list, prefix: str = "/", separator: str = " "):
+ def command(command: str or list,
+ prefix: str = "/",
+ separator: str = " ",
+ case_sensitive: bool = False):
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
Args:
@@ -144,26 +147,40 @@ class Filters:
a command arrives, the command itself and its arguments will be stored in the *command*
field of the :class:`Message `.
- prefix (``str``):
- The command prefix. Defaults to "/".
+ prefix (``str``, *optional*):
+ The command prefix. Defaults to "/" (slash).
Examples: /start, .help, !settings.
- separator (``str``):
+ separator (``str``, *optional*):
The command arguments separator. Defaults to " " (white space).
Examples: /start first second, /start-first-second, /start.first.second.
+
+ case_sensitive (``bool``, *optional*):
+ Pass True if you want your command(s) to be case sensitive. Defaults to False.
+ Examples: when True, command="Start" would trigger /Start but not /start.
"""
def f(_, m):
if m.text and m.text.startswith(_.p):
t = m.text.split(_.s)
c, a = t[0][len(_.p):], t[1:]
+ c = c if _.cs else c.lower()
m.command = ([c] + a) if c in _.c else None
return bool(m.command)
return build(
- "Command", f, c={command} if not isinstance(command, list) else {c for c in command},
- p=prefix, s=separator
+ "Command",
+ f,
+ c={command if case_sensitive
+ else command.lower()}
+ if not isinstance(command, list)
+ else {c if case_sensitive
+ else c.lower()
+ for c in command},
+ p=prefix,
+ s=separator,
+ cs=case_sensitive
)
@staticmethod
From bbfc5334171f8bf5d6734e4b6b31836934123914 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 11:40:54 +0200
Subject: [PATCH 049/145] Add DisconnectHandler to docs
---
docs/source/pyrogram/handlers/DisconnectHandler.rst | 6 ++++++
docs/source/pyrogram/handlers/index.rst | 3 ++-
2 files changed, 8 insertions(+), 1 deletion(-)
create mode 100644 docs/source/pyrogram/handlers/DisconnectHandler.rst
diff --git a/docs/source/pyrogram/handlers/DisconnectHandler.rst b/docs/source/pyrogram/handlers/DisconnectHandler.rst
new file mode 100644
index 00000000..594081f1
--- /dev/null
+++ b/docs/source/pyrogram/handlers/DisconnectHandler.rst
@@ -0,0 +1,6 @@
+DisconnectHandler
+=================
+
+.. autoclass:: pyrogram.DisconnectHandler
+ :members:
+ :undoc-members:
diff --git a/docs/source/pyrogram/handlers/index.rst b/docs/source/pyrogram/handlers/index.rst
index bbd55542..191d4eff 100644
--- a/docs/source/pyrogram/handlers/index.rst
+++ b/docs/source/pyrogram/handlers/index.rst
@@ -6,4 +6,5 @@ Handlers
.. toctree::
MessageHandler
CallbackQueryHandler
- RawUpdateHandler
\ No newline at end of file
+ RawUpdateHandler
+ DisconnectHandler
\ No newline at end of file
From c22cf3d89ad0d9e34acb68c0e47c06c7465a5b8d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 11:41:43 +0200
Subject: [PATCH 050/145] Add custom Makefile to be used with local venv
---
docs/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Makefile b/docs/Makefile
index c647eb13..cb346f83 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -3,7 +3,7 @@
# You can set these variables from the command line.
SPHINXOPTS =
-SPHINXBUILD = sphinx-build
+SPHINXBUILD = ~/PycharmProjects/pyrogram/venv/bin/sphinx-build
SPHINXPROJ = Pyrogram
SOURCEDIR = source
BUILDDIR = build
From c88ca2e4f56c423129de66a070e4875a2f5136f9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 11:58:22 +0200
Subject: [PATCH 051/145] Add namespaces when printing Object types
---
pyrogram/api/core/object.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pyrogram/api/core/object.py b/pyrogram/api/core/object.py
index d54d0327..a1e20726 100644
--- a/pyrogram/api/core/object.py
+++ b/pyrogram/api/core/object.py
@@ -77,11 +77,14 @@ class Encoder(JSONEncoder):
if o is not None:
if o.startswith("pyrogram.client"):
- r = remove_none(OrderedDict([("_", name)] + [i for i in content.items()]))
+ r = remove_none(OrderedDict([("_", "pyrogram:" + name)] + [i for i in content.items()]))
r.pop("_client", None)
return r
else:
- return OrderedDict([("_", o)] + [i for i in content.items()])
+ return OrderedDict(
+ [("_", o.replace("pyrogram.api.types.", "telegram:"))]
+ + [i for i in content.items()]
+ )
else:
return None
From 0f9b4c6ac62b01a8f3d9b69e93df702479458fcd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:07:42 +0200
Subject: [PATCH 052/145] Add kick_chat_member.py
---
.../client/methods/chats/kick_chat_member.py | 87 +++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 pyrogram/client/methods/chats/kick_chat_member.py
diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/client/methods/chats/kick_chat_member.py
new file mode 100644
index 00000000..6275718c
--- /dev/null
+++ b/pyrogram/client/methods/chats/kick_chat_member.py
@@ -0,0 +1,87 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from pyrogram.api import functions, types
+from ...ext import BaseClient
+
+
+class KickChatMember(BaseClient):
+ def kick_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ until_date: int = 0):
+ """Use this method to kick a user from a group, a supergroup or a channel.
+ In the case of supergroups and channels, the user will not be able to return to the group on their own using
+ invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must
+ have the appropriate admin rights.
+
+ Note:
+ In regular groups (non-supergroups), this method will only work if the "All Members Are Admins" setting is
+ off in the target group. Otherwise members may only be removed by the group's creator or by the member
+ that added them.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ user_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target user.
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+
+ until_date (``int``, *optional*):
+ Date when the user will be unbanned, unix time.
+ If user is banned for more than 366 days or less than 30 seconds from the current time they are
+ considered to be banned forever. Defaults to 0 (ban forever).
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+ chat_peer = self.resolve_peer(chat_id)
+ user_peer = self.resolve_peer(user_id)
+
+ if isinstance(chat_peer, types.InputPeerChannel):
+ self.send(
+ functions.channels.EditBanned(
+ channel=chat_peer,
+ user_id=user_peer,
+ banned_rights=types.ChannelBannedRights(
+ until_date=until_date,
+ view_messages=True,
+ send_messages=True,
+ send_media=True,
+ send_stickers=True,
+ send_gifs=True,
+ send_games=True,
+ send_inline=True,
+ embed_links=True
+ )
+ )
+ )
+ else:
+ self.send(
+ functions.messages.DeleteChatUser(
+ chat_id=abs(chat_id),
+ user_id=user_peer
+ )
+ )
+
+ return True
From ea282a74dd64804b952030f7ce01c9391d91b1b9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:20:41 +0200
Subject: [PATCH 053/145] Add unban_chat_member.py
---
.../client/methods/chats/unban_chat_member.py | 56 +++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 pyrogram/client/methods/chats/unban_chat_member.py
diff --git a/pyrogram/client/methods/chats/unban_chat_member.py b/pyrogram/client/methods/chats/unban_chat_member.py
new file mode 100644
index 00000000..b0916eb4
--- /dev/null
+++ b/pyrogram/client/methods/chats/unban_chat_member.py
@@ -0,0 +1,56 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from pyrogram.api import functions, types
+from ...ext import BaseClient
+
+
+class UnbanChatMember(BaseClient):
+ def unban_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str):
+ """Use this method to unban a previously kicked user in a supergroup or channel.
+ The user will **not** return to the group or channel automatically, but will be able to join via link, etc.
+ You must be an administrator for this to work.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ user_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target user.
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+ self.send(
+ functions.channels.EditBanned(
+ channel=self.resolve_peer(chat_id),
+ user_id=self.resolve_peer(user_id),
+ banned_rights=types.ChannelBannedRights(
+ until_date=0
+ )
+ )
+ )
+
+ return True
From f611a92f90ae1ab4bbf90822db381c0d555c0c2f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:21:02 +0200
Subject: [PATCH 054/145] Add restrict_chat_member.py
---
.../methods/chats/restrict_chat_member.py | 113 ++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 pyrogram/client/methods/chats/restrict_chat_member.py
diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py
new file mode 100644
index 00000000..ae1e4d9c
--- /dev/null
+++ b/pyrogram/client/methods/chats/restrict_chat_member.py
@@ -0,0 +1,113 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from pyrogram.api import functions, types
+from ...ext import BaseClient
+
+
+class RestrictChatMember(BaseClient):
+ def restrict_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ until_date: int = 0,
+ can_send_messages: bool = False,
+ can_send_media_messages: bool = False,
+ can_send_other_messages: bool = False,
+ can_add_web_page_previews: bool = False):
+ """Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for
+ this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift
+ restrictions from a user.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ user_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target user.
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+
+ until_date (``int``, *optional*):
+ Date when the user will be unbanned, unix time.
+ If user is banned for more than 366 days or less than 30 seconds from the current time they are
+ considered to be banned forever. Defaults to 0 (ban forever).
+
+ can_send_messages (``bool``, *optional*):
+ Pass True, if the user can send text messages, contacts, locations and venues.
+
+ can_send_media_messages (``bool``, *optional*):
+ Pass True, if the user can send audios, documents, photos, videos, video notes and voice notes,
+ implies can_send_messages.
+
+ can_send_other_messages (``bool``, *optional*):
+ Pass True, if the user can send animations, games, stickers and use inline bots,
+ implies can_send_media_messages.
+
+ can_add_web_page_previews (``bool``, *optional*):
+ Pass True, if the user may add web page previews to their messages, implies can_send_media_messages
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+ send_messages = True
+ send_media = True
+ send_stickers = True
+ send_gifs = True
+ send_games = True
+ send_inline = True
+ embed_links = True
+
+ if can_send_messages:
+ send_messages = None
+
+ if can_send_media_messages:
+ send_messages = None
+ send_media = None
+
+ if can_send_other_messages:
+ send_media = None
+ send_stickers = None
+ send_gifs = None
+ send_games = None
+ send_inline = None
+
+ if can_add_web_page_previews:
+ send_media = None
+ embed_links = None
+
+ self.send(
+ functions.channels.EditBanned(
+ channel=self.resolve_peer(chat_id),
+ user_id=self.resolve_peer(user_id),
+ banned_rights=types.ChannelBannedRights(
+ until_date=until_date,
+ send_messages=send_messages,
+ send_media=send_media,
+ send_stickers=send_stickers,
+ send_gifs=send_gifs,
+ send_games=send_games,
+ send_inline=send_inline,
+ embed_links=embed_links
+ )
+ )
+ )
+
+ return True
From 5bf912640f5a219a70412212aa9091e166548852 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:21:14 +0200
Subject: [PATCH 055/145] Add promote_chat_member.py
---
.../methods/chats/promote_chat_member.py | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 pyrogram/client/methods/chats/promote_chat_member.py
diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/client/methods/chats/promote_chat_member.py
new file mode 100644
index 00000000..eb70578a
--- /dev/null
+++ b/pyrogram/client/methods/chats/promote_chat_member.py
@@ -0,0 +1,99 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from pyrogram.api import functions, types
+from ...ext import BaseClient
+
+
+class PromoteChatMember(BaseClient):
+ def promote_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ can_change_info: bool = True,
+ can_post_messages: bool = True,
+ can_edit_messages: bool = True,
+ can_delete_messages: bool = True,
+ can_invite_users: bool = True,
+ can_restrict_members: bool = True,
+ can_pin_messages: bool = True,
+ can_promote_members: bool = False):
+ """Use this method to promote or demote a user in a supergroup or a channel.
+ You must be an administrator in the chat for this to work and must have the appropriate admin rights.
+ Pass False for all boolean parameters to demote a user.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ user_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target user.
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+
+ can_change_info (``bool``, *optional*):
+ Pass True, if the administrator can change chat title, photo and other settings.
+
+ can_post_messages (``bool``, *optional*):
+ Pass True, if the administrator can create channel posts, channels only.
+
+ can_edit_messages (``bool``, *optional*):
+ Pass True, if the administrator can edit messages of other users and can pin messages, channels only.
+
+ can_delete_messages (``bool``, *optional*):
+ Pass True, if the administrator can delete messages of other users.
+
+ can_invite_users (``bool``, *optional*):
+ Pass True, if the administrator can invite new users to the chat.
+
+ can_restrict_members (``bool``, *optional*):
+ Pass True, if the administrator can restrict, ban or unban chat members.
+
+ can_pin_messages (``bool``, *optional*):
+ Pass True, if the administrator can pin messages, supergroups only.
+
+ can_promote_members (``bool``, *optional*):
+ Pass True, if the administrator can add new administrators with a subset of his own privileges or
+ demote administrators that he has promoted, directly or indirectly (promoted by administrators that
+ were appointed by him).
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+ self.send(
+ functions.channels.EditAdmin(
+ channel=self.resolve_peer(chat_id),
+ user_id=self.resolve_peer(user_id),
+ admin_rights=types.ChannelAdminRights(
+ change_info=can_change_info or None,
+ post_messages=can_post_messages or None,
+ edit_messages=can_edit_messages or None,
+ delete_messages=can_delete_messages or None,
+ ban_users=can_restrict_members or None,
+ invite_users=can_invite_users or None,
+ invite_link=can_invite_users or None,
+ pin_messages=can_pin_messages or None,
+ add_admins=can_promote_members or None,
+ manage_call=None
+ )
+ )
+ )
+
+ return True
From 0b2efd2b7ae82ff78cc9f28ee6deb608fbe39468 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:21:48 +0200
Subject: [PATCH 056/145] Register the new chat administration methods
---
pyrogram/client/methods/chats/__init__.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/client/methods/chats/__init__.py
index f32e474e..9c887ef5 100644
--- a/pyrogram/client/methods/chats/__init__.py
+++ b/pyrogram/client/methods/chats/__init__.py
@@ -19,13 +19,21 @@
from .export_chat_invite_link import ExportChatInviteLink
from .get_chat import GetChat
from .join_chat import JoinChat
+from .kick_chat_member import KickChatMember
from .leave_chat import LeaveChat
+from .promote_chat_member import PromoteChatMember
+from .restrict_chat_member import RestrictChatMember
+from .unban_chat_member import UnbanChatMember
class Chats(
GetChat,
ExportChatInviteLink,
LeaveChat,
- JoinChat
+ JoinChat,
+ KickChatMember,
+ UnbanChatMember,
+ RestrictChatMember,
+ PromoteChatMember
):
pass
From dafbe31a60c5f9dcf3d00d709516553dd4dd2c3c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Jun 2018 12:21:58 +0200
Subject: [PATCH 057/145] Add chat administration methods to docs
---
docs/source/pyrogram/Client.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index e879db71..fbab4ecc 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -49,6 +49,10 @@ Client
enable_cloud_password
change_cloud_password
remove_cloud_password
+ kick_chat_member
+ unban_chat_member
+ restrict_chat_member
+ promote_chat_member
add_contacts
get_contacts
delete_contacts
From 4a69e5c64bb07f9ce19f59650fe173d09e93fe03 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:27:48 +0200
Subject: [PATCH 058/145] Don't add undocumented stuff in ChatAction doc page
---
docs/source/pyrogram/ChatAction.rst | 1 -
1 file changed, 1 deletion(-)
diff --git a/docs/source/pyrogram/ChatAction.rst b/docs/source/pyrogram/ChatAction.rst
index a7d5975d..dfa56945 100644
--- a/docs/source/pyrogram/ChatAction.rst
+++ b/docs/source/pyrogram/ChatAction.rst
@@ -3,4 +3,3 @@ ChatAction
.. autoclass:: pyrogram.ChatAction
:members:
- :undoc-members:
From 6d7de359f086d4d35a05d781e0ea2f185b229d6d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:28:14 +0200
Subject: [PATCH 059/145] Add a link to available methods in docs
---
docs/source/pyrogram/Client.rst | 2 +
.../messages/media/send_media_group.py | 171 +-----------------
2 files changed, 3 insertions(+), 170 deletions(-)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index fbab4ecc..3e65b0f6 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -7,6 +7,8 @@ Client
:inherited-members:
:members:
+ .. _available-methods:
+
**Available methods**
.. autosummary::
diff --git a/pyrogram/client/methods/messages/media/send_media_group.py b/pyrogram/client/methods/messages/media/send_media_group.py
index 6d004d9f..e7d73509 100644
--- a/pyrogram/client/methods/messages/media/send_media_group.py
+++ b/pyrogram/client/methods/messages/media/send_media_group.py
@@ -1,170 +1 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-import binascii
-import mimetypes
-import os
-import struct
-
-from pyrogram.api import functions, types
-from pyrogram.api.errors import FileIdInvalid
-from pyrogram.client import types as pyrogram_types
-from ....ext import BaseClient, utils
-
-
-class SendMediaGroup(BaseClient):
- # TODO: Add progress parameter
- # TODO: Return new Message object
- # TODO: Figure out how to send albums using URLs
- def send_media_group(self,
- chat_id: int or str,
- media: list,
- disable_notification: bool = None,
- reply_to_message_id: int = None):
- """Use this method to send a group of photos or videos as an album.
- On success, an Update containing the sent Messages is returned.
-
- Args:
- chat_id (``int`` | ``str``):
- Unique identifier (int) or username (str) of the target chat.
- For your personal cloud (Saved Messages) you can simply use "me" or "self".
- For a contact that exists in your Telegram address book you can use his phone number (str).
- For a private channel/supergroup you can use its *t.me/joinchat/* link.
-
- media (``list``):
- A list containing either :obj:`InputMediaPhoto ` or
- :obj:`InputMediaVideo ` objects
- describing photos and videos to be sent, must include 2–10 items.
-
- disable_notification (``bool``, *optional*):
- Sends the message silently.
- Users will receive a notification with no sound.
-
- reply_to_message_id (``int``, *optional*):
- If the message is a reply, ID of the original message.
- """
- multi_media = []
-
- for i in media:
- style = self.html if i.parse_mode.lower() == "html" else self.markdown
-
- if isinstance(i, pyrogram_types.InputMediaPhoto):
- if os.path.exists(i.media):
- media = self.send(
- functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
- media=types.InputMediaUploadedPhoto(
- file=self.save_file(i.media)
- )
- )
- )
-
- media = types.InputMediaPhoto(
- id=types.InputPhoto(
- id=media.photo.id,
- access_hash=media.photo.access_hash
- )
- )
- else:
- try:
- decoded = utils.decode(i.media)
- fmt = " 24 else " 24 else "
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
import binascii
import mimetypes
import os
import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid
from pyrogram.client import types as pyrogram_types
from ....ext import BaseClient, utils
class SendMediaGroup(BaseClient):
# TODO: Add progress parameter
# TODO: Return new Message object
# TODO: Figure out how to send albums using URLs
def send_media_group(self,
chat_id: int or str,
media: list,
disable_notification: bool = None,
reply_to_message_id: int = None):
"""Use this method to send a group of photos or videos as an album.
On success, an Update containing the sent Messages is returned.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
media (``list``):
A list containing either :obj:`InputMediaPhoto ` or
:obj:`InputMediaVideo ` objects
describing photos and videos to be sent, must include 2–10 items.
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
"""
multi_media = []
for i in media:
style = self.html if i.parse_mode.lower() == "html" else self.markdown
if isinstance(i, pyrogram_types.InputMediaPhoto):
if os.path.exists(i.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedPhoto(
file=self.save_file(i.media)
)
)
)
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=media.photo.id,
access_hash=media.photo.access_hash
)
)
else:
try:
decoded = utils.decode(i.media)
fmt = " 24 else " 24 else "
Date: Tue, 5 Jun 2018 16:35:54 +0200
Subject: [PATCH 060/145] Update docs index
---
docs/source/index.rst | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index fced42bb..61394d7b 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -75,11 +75,11 @@ To get started, press the Next button.
.. toctree::
:hidden:
- :caption: Getting Started
+ :caption: Quick Start
- start/QuickInstallation
- start/ProjectSetup
- start/BasicUsage
+ start/Installation
+ start/Setup
+ start/Usage
.. toctree::
:hidden:
@@ -107,5 +107,4 @@ To get started, press the Next button.
types/index
.. _`Telegram`: https://telegram.org/
-
-.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto/
+.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto/
\ No newline at end of file
From 95e16c2e6cf7c9721a14189b73a89a8be09a406f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:36:37 +0200
Subject: [PATCH 061/145] Rename and rework Installation docs page
---
docs/source/start/Installation.rst | 50 +++++++++++++++++++
docs/source/start/QuickInstallation.rst | 37 --------------
pyrogram/api/errors/__init__.py | 2 +-
.../client/handlers/disconnect_handler.py | 1 +
pyrogram/client/types/__init__.py | 2 +-
5 files changed, 53 insertions(+), 39 deletions(-)
create mode 100644 docs/source/start/Installation.rst
delete mode 100644 docs/source/start/QuickInstallation.rst
diff --git a/docs/source/start/Installation.rst b/docs/source/start/Installation.rst
new file mode 100644
index 00000000..8aea16de
--- /dev/null
+++ b/docs/source/start/Installation.rst
@@ -0,0 +1,50 @@
+Installation
+============
+
+Being a Python library, Pyrogram requires Python to be installed in your system.
+We recommend using the latest version of Python 3 and pip.
+
+Get Python 3 from https://www.python.org/downloads/ or with your package manager and pip
+by following the instructions at https://pip.pypa.io/en/latest/installing/.
+
+Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
+
+Install Pyrogram
+----------------
+
+- The easiest way to install and upgrade Pyrogram is by using **pip**:
+
+ .. code-block:: bash
+
+ $ pip3 install --upgrade pyrogram
+
+- or, with TgCrypto_ (recommended):
+
+ .. code-block:: bash
+
+ $ pip3 install --upgrade pyrogram[tgcrypto]
+
+Bleeding Edge
+-------------
+
+If you want the latest development version of Pyrogram, you can install it straight from the develop_
+branch using this command:
+
+.. code-block:: bash
+
+ $ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git
+
+Verifying
+---------
+
+To verify that Pyrogram is correctly installed, open a Python shell and import it.
+If no error shows up you are good to go.
+
+.. code-block:: bash
+
+ >>> import pyrogram
+ >>> pyrogram.__version__
+ '0.7.5'
+
+.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
+.. _develop: http://github.com/pyrogram/pyrogram
\ No newline at end of file
diff --git a/docs/source/start/QuickInstallation.rst b/docs/source/start/QuickInstallation.rst
deleted file mode 100644
index f0400207..00000000
--- a/docs/source/start/QuickInstallation.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-Quick Installation
-==================
-
-- The easiest way to install and upgrade Pyrogram is by using **pip**:
-
- .. code-block:: bash
-
- $ pip3 install --upgrade pyrogram
-
-- or, with TgCrypto_ (recommended):
-
- .. code-block:: bash
-
- $ pip3 install --upgrade pyrogram[tgcrypto]
-
-Bleeding Edge
--------------
-
-If you want the latest development version of the library, you can install it with:
-
-.. code-block:: bash
-
- $ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git
-
-Verifying
----------
-
-To verify that Pyrogram is correctly installed, open a Python shell and import it.
-If no error shows up you are good to go.
-
-.. code-block:: bash
-
- >>> import pyrogram
- >>> pyrogram.__version__
- '0.7.4'
-
-.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
\ No newline at end of file
diff --git a/pyrogram/api/errors/__init__.py b/pyrogram/api/errors/__init__.py
index 0ed04e02..3f7961dd 100644
--- a/pyrogram/api/errors/__init__.py
+++ b/pyrogram/api/errors/__init__.py
@@ -16,5 +16,5 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .exceptions import *
from .error import UnknownError
+from .exceptions import *
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
index 71123248..9ad4ffbc 100644
--- a/pyrogram/client/handlers/disconnect_handler.py
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -34,5 +34,6 @@ class DisconnectHandler(Handler):
The Client itself. Useful, for example, when you want to change the proxy before a new connection
is established.
"""
+
def __init__(self, callback: callable):
super().__init__(callback)
diff --git a/pyrogram/client/types/__init__.py b/pyrogram/client/types/__init__.py
index 5431b89e..acd001dd 100644
--- a/pyrogram/client/types/__init__.py
+++ b/pyrogram/client/types/__init__.py
@@ -30,6 +30,7 @@ from .input_phone_contact import InputPhoneContact
from .location import Location
from .message import Message
from .message_entity import MessageEntity
+from .messages import Messages
from .photo_size import PhotoSize
from .reply_markup import (
ForceReply, InlineKeyboardButton, InlineKeyboardMarkup,
@@ -43,4 +44,3 @@ from .venue import Venue
from .video import Video
from .video_note import VideoNote
from .voice import Voice
-from .messages import Messages
From 2a792438418c7a7f621f9da8d86e1e9dbd821e20 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:37:57 +0200
Subject: [PATCH 062/145] Rename and rework Setup docs page
---
.../start/{ProjectSetup.rst => Setup.rst} | 18 ++++++++++--------
pyrogram/api/errors/__init__.py | 2 +-
2 files changed, 11 insertions(+), 9 deletions(-)
rename docs/source/start/{ProjectSetup.rst => Setup.rst} (84%)
diff --git a/docs/source/start/ProjectSetup.rst b/docs/source/start/Setup.rst
similarity index 84%
rename from docs/source/start/ProjectSetup.rst
rename to docs/source/start/Setup.rst
index 05d46810..dc837a86 100644
--- a/docs/source/start/ProjectSetup.rst
+++ b/docs/source/start/Setup.rst
@@ -1,8 +1,9 @@
-Project Setup
-=============
+Setup
+=====
-This section provides all the information you need to setup your project with Pyrogram.
-There are a few steps you have to follow before you can actually use the library to make API calls.
+Once you successfully installed_ Pyrogram, you will have to follow a few steps before you can actually use
+the library to make API calls. This section provides all the information you need in order to set up a project
+with Pyrogram.
API Keys
--------
@@ -45,7 +46,7 @@ There are two ways to configure a Pyrogram application project, and you can choo
)
.. note:: The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
- and *api_hash* parameters usage.
+and *api_hash* parameters usage.
User Authorization
------------------
@@ -75,14 +76,14 @@ After successfully authorizing yourself, a new file called ``my_account.session`
Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app,
and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
-.. important:: Your *.session file(s) must be kept secret.
+.. important:: Your ``*.session`` file(s) must be kept secret.
Bot Authorization
-----------------
Being written entirely from the ground up, Pyrogram is also able to authorize Bots.
-Bots are a special kind of users which also make use of MTProto. This means that you can use Pyrogram to
-execute API calls with a Bot identity.
+Bots are a special kind of users which also make use of MTProto, the underlying Telegram protocol.
+This means that you can use Pyrogram to execute API calls with a Bot identity.
Instead of phone numbers, Bots are authorized via their tokens which are created by BotFather_:
@@ -96,5 +97,6 @@ Instead of phone numbers, Bots are authorized via their tokens which are created
That's all, no further action is needed. The session file will be named after the Bot user_id, which is
``123456.session`` for the example above.
+.. _installed: Installation.html
.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes
.. _BotFather: https://t.me/botfather
\ No newline at end of file
diff --git a/pyrogram/api/errors/__init__.py b/pyrogram/api/errors/__init__.py
index 3f7961dd..0ed04e02 100644
--- a/pyrogram/api/errors/__init__.py
+++ b/pyrogram/api/errors/__init__.py
@@ -16,5 +16,5 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .error import UnknownError
from .exceptions import *
+from .error import UnknownError
From ea08a2af6ac0cb5bcfd3f5f365b155ce4528449d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:38:12 +0200
Subject: [PATCH 063/145] Rename and rework Usage docs page
---
docs/source/start/BasicUsage.rst | 97 ---------------------------
docs/source/start/Usage.rst | 110 +++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+), 97 deletions(-)
delete mode 100644 docs/source/start/BasicUsage.rst
create mode 100644 docs/source/start/Usage.rst
diff --git a/docs/source/start/BasicUsage.rst b/docs/source/start/BasicUsage.rst
deleted file mode 100644
index 94dfd00c..00000000
--- a/docs/source/start/BasicUsage.rst
+++ /dev/null
@@ -1,97 +0,0 @@
-Basic Usage
-===========
-
-.. note::
-
- All the snippets below assume you have successfully created and started a :class:`Client `
- instance. You also must be authorized, that is, a valid *.session file does exist in your working directory.
-
-Simple API Access
------------------
-
-The easiest way to interact with the Telegram API is via the :class:`Client ` class, which
-exposes `Bot API-like`_ methods:
-
-- Get information about the authorized user:
-
- .. code-block:: python
-
- print(app.get_me())
-
-- Send a message to yourself (Saved Messages):
-
- .. code-block:: python
-
- app.send_message("me", "Hi there! I'm using Pyrogram")
-
-- Upload a new photo (with caption):
-
- .. code-block:: python
-
- app.send_photo("me", "/home/dan/perla.jpg", "Cute!")
-
-.. seealso:: For a complete list of the available methods and an exhaustive description for each of them, have a look
- at the :class:`Client ` class.
-
-.. _using-raw-functions:
-
-Using Raw Functions
--------------------
-
-If you want **complete**, low-level access to the Telegram API you have to use the raw
-:mod:`functions ` and :mod:`types ` exposed by the ``pyrogram.api``
-package and call any Telegram API method you wish using the :meth:`send() ` method provided by
-the Client class.
-
-Here some examples:
-
-- Update first name, last name and bio:
-
- .. code-block:: python
-
- from pyrogram.api import functions
-
- ...
-
- app.send(
- functions.account.UpdateProfile(
- first_name="Dan", last_name="Tès",
- about="Bio written from Pyrogram"
- )
- )
-
-- Share your Last Seen time only with your contacts:
-
- .. code-block:: python
-
- from pyrogram.api import functions, types
-
- ...
-
- app.send(
- functions.account.SetPrivacy(
- key=types.InputPrivacyKeyStatusTimestamp(),
- rules=[types.InputPrivacyValueAllowContacts()]
- )
- )
-
-- Invite users to your channel/supergroup:
-
- .. code-block:: python
-
- from pyrogram.api import functions, types
-
- ...
-
- app.send(
- functions.channels.InviteToChannel(
- channel=app.resolve_peer(123456789), # ID or Username
- users=[ # The users you want to invite
- app.resolve_peer(23456789), # By ID
- app.resolve_peer("username"), # By username
- app.resolve_peer("393281234567"), # By phone number
- ]
- )
- )
-
-.. _`Bot API-like`: https://core.telegram.org/bots/api#available-methods
\ No newline at end of file
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
new file mode 100644
index 00000000..8b93df53
--- /dev/null
+++ b/docs/source/start/Usage.rst
@@ -0,0 +1,110 @@
+Usage
+=====
+
+Having your `project set up`_ and your account authorized_, it's time to play with the API.
+In this section, you'll be shown two ways of communicating with Telegram using Pyrogram. Let's start!
+
+High-level API
+--------------
+
+The easiest and recommended way to interact with Telegram is via the high-level Pyrogram methods_ and types_, which are
+named after the `Telegram Bot API`_.
+
+.. hint:: If you can't find a method you want to use, chances are it's not implemented yet. In this case, you must use
+ the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you're in trouble or want to propose a
+ new method!
+
+Examples:
+
+- Get information about the authorized user:
+
+ .. code-block:: python
+
+ print(app.get_me())
+
+- Send a message to yourself (Saved Messages):
+
+ .. code-block:: python
+
+ app.send_message("me", "Hi there! I'm using Pyrogram")
+
+- Upload a new photo (with caption):
+
+ .. code-block:: python
+
+ app.send_photo("me", "/home/dan/perla.jpg", "Cute!")
+
+.. _using-raw-functions:
+
+Using Raw Functions
+-------------------
+
+If you can't find a high-level method for your needs or want complete, low-level access to the whole Telegram API,
+you have to use the raw :mod:`functions ` and :mod:`types ` exposed by the
+``pyrogram.api`` package and call any Telegram API method you wish using the :meth:`send() `
+method provided by the Client class.
+
+.. hint:: Every high-level method mentioned in the section above is built on top of these raw functions.
+ Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already
+ re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
+ If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
+
+Examples:
+
+- Update first name, last name and bio:
+
+ .. code-block:: python
+
+ from pyrogram.api import functions
+
+ ...
+
+ app.send(
+ functions.account.UpdateProfile(
+ first_name="Dan", last_name="Tès",
+ about="Bio written from Pyrogram"
+ )
+ )
+
+- Share your Last Seen time only with your contacts:
+
+ .. code-block:: python
+
+ from pyrogram.api import functions, types
+
+ ...
+
+ app.send(
+ functions.account.SetPrivacy(
+ key=types.InputPrivacyKeyStatusTimestamp(),
+ rules=[types.InputPrivacyValueAllowContacts()]
+ )
+ )
+
+- Invite users to your channel/supergroup:
+
+ .. code-block:: python
+
+ from pyrogram.api import functions, types
+
+ ...
+
+ app.send(
+ functions.channels.InviteToChannel(
+ channel=app.resolve_peer(123456789), # ID or Username
+ users=[ # The users you want to invite
+ app.resolve_peer(23456789), # By ID
+ app.resolve_peer("username"), # By username
+ app.resolve_peer("393281234567"), # By phone number
+ ]
+ )
+ )
+
+.. _methods: ../pyrogram/Client.html#available-methods
+.. _plenty of them: ../pyrogram/Client.html#available-methods
+.. _types: ../pyrogram/types/index.html
+.. _Raw Functions: Usage.html#using-raw-functions
+.. _Community: https://t.me/PyrogramChat
+.. _project set up: Setup.html
+.. _authorized: Setup.html#user-authorization
+.. _Telegram Bot API: https://core.telegram.org/bots/api
\ No newline at end of file
From 64ff6fa07b96efc481879a6a6feb999429f2e356 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 16:59:17 +0200
Subject: [PATCH 064/145] Add the old Makefile
---
docs/Makefile_ | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 docs/Makefile_
diff --git a/docs/Makefile_ b/docs/Makefile_
new file mode 100644
index 00000000..c647eb13
--- /dev/null
+++ b/docs/Makefile_
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SPHINXPROJ = Pyrogram
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
\ No newline at end of file
From 901b1517182649c84c9dbff881daa77aa6068831 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 5 Jun 2018 17:08:05 +0200
Subject: [PATCH 065/145] Fix wrong line separator
---
.../messages/media/send_media_group.py | 171 +++++++++++++++++-
1 file changed, 170 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/media/send_media_group.py b/pyrogram/client/methods/messages/media/send_media_group.py
index e7d73509..6d004d9f 100644
--- a/pyrogram/client/methods/messages/media/send_media_group.py
+++ b/pyrogram/client/methods/messages/media/send_media_group.py
@@ -1 +1,170 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
import binascii
import mimetypes
import os
import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid
from pyrogram.client import types as pyrogram_types
from ....ext import BaseClient, utils
class SendMediaGroup(BaseClient):
# TODO: Add progress parameter
# TODO: Return new Message object
# TODO: Figure out how to send albums using URLs
def send_media_group(self,
chat_id: int or str,
media: list,
disable_notification: bool = None,
reply_to_message_id: int = None):
"""Use this method to send a group of photos or videos as an album.
On success, an Update containing the sent Messages is returned.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
media (``list``):
A list containing either :obj:`InputMediaPhoto ` or
:obj:`InputMediaVideo ` objects
describing photos and videos to be sent, must include 2–10 items.
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
"""
multi_media = []
for i in media:
style = self.html if i.parse_mode.lower() == "html" else self.markdown
if isinstance(i, pyrogram_types.InputMediaPhoto):
if os.path.exists(i.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedPhoto(
file=self.save_file(i.media)
)
)
)
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=media.photo.id,
access_hash=media.photo.access_hash
)
)
else:
try:
decoded = utils.decode(i.media)
fmt = " 24 else " 24 else "
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+import binascii
+import mimetypes
+import os
+import struct
+
+from pyrogram.api import functions, types
+from pyrogram.api.errors import FileIdInvalid
+from pyrogram.client import types as pyrogram_types
+from ....ext import BaseClient, utils
+
+
+class SendMediaGroup(BaseClient):
+ # TODO: Add progress parameter
+ # TODO: Return new Message object
+ # TODO: Figure out how to send albums using URLs
+ def send_media_group(self,
+ chat_id: int or str,
+ media: list,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None):
+ """Use this method to send a group of photos or videos as an album.
+ On success, an Update containing the sent Messages is returned.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For your personal cloud (Saved Messages) you can simply use "me" or "self".
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ media (``list``):
+ A list containing either :obj:`InputMediaPhoto ` or
+ :obj:`InputMediaVideo ` objects
+ describing photos and videos to be sent, must include 2–10 items.
+
+ disable_notification (``bool``, *optional*):
+ Sends the message silently.
+ Users will receive a notification with no sound.
+
+ reply_to_message_id (``int``, *optional*):
+ If the message is a reply, ID of the original message.
+ """
+ multi_media = []
+
+ for i in media:
+ style = self.html if i.parse_mode.lower() == "html" else self.markdown
+
+ if isinstance(i, pyrogram_types.InputMediaPhoto):
+ if os.path.exists(i.media):
+ media = self.send(
+ functions.messages.UploadMedia(
+ peer=self.resolve_peer(chat_id),
+ media=types.InputMediaUploadedPhoto(
+ file=self.save_file(i.media)
+ )
+ )
+ )
+
+ media = types.InputMediaPhoto(
+ id=types.InputPhoto(
+ id=media.photo.id,
+ access_hash=media.photo.access_hash
+ )
+ )
+ else:
+ try:
+ decoded = utils.decode(i.media)
+ fmt = " 24 else " 24 else "
Date: Wed, 6 Jun 2018 12:28:25 +0200
Subject: [PATCH 066/145] Fix callback query id not being a string
---
pyrogram/client/ext/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 1feac5a8..d9956ca5 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -801,7 +801,7 @@ def parse_callback_query(client, callback_query, users):
peer_id = int("-100" + str(peer.channel_id))
return pyrogram_types.CallbackQuery(
- id=callback_query.query_id,
+ id=str(callback_query.query_id),
from_user=parse_user(users[callback_query.user_id]),
message=client.get_messages(peer_id, callback_query.msg_id),
chat_instance=str(callback_query.chat_instance),
From e3bd7d57a24b0a1789536bd9a5c783122efb1745 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 6 Jun 2018 12:28:36 +0200
Subject: [PATCH 067/145] Remove TODO
---
pyrogram/client/ext/utils.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index d9956ca5..2d43757f 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -807,7 +807,6 @@ def parse_callback_query(client, callback_query, users):
chat_instance=str(callback_query.chat_instance),
data=callback_query.data.decode(),
game_short_name=callback_query.game_short_name
- # TODO: add inline_message_id
)
From 6238f984b4a15bb03134d5dacca644ae86ad55eb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 6 Jun 2018 12:29:05 +0200
Subject: [PATCH 068/145] Add dedicated parse function for inline callback
queries
---
pyrogram/client/ext/utils.py | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 2d43757f..d7a09ee1 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -810,6 +810,24 @@ def parse_callback_query(client, callback_query, users):
)
+def parse_inline_callback_query(callback_query, users):
+ return pyrogram_types.CallbackQuery(
+ id=str(callback_query.query_id),
+ from_user=parse_user(users[callback_query.user_id]),
+ chat_instance=str(callback_query.chat_instance),
+ inline_message_id=b64encode(
+ pack(
+ "
Date: Wed, 6 Jun 2018 12:29:21 +0200
Subject: [PATCH 069/145] Dispatch inline bot callback queries
---
pyrogram/client/dispatcher/dispatcher.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index f62cbfd1..51be2ebb 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -169,6 +169,14 @@ class Dispatcher:
)
)
)
+ elif isinstance(update, types.UpdateInlineBotCallbackQuery):
+ self.dispatch(
+ pyrogram.Update(
+ callback_query=utils.parse_inline_callback_query(
+ update, users
+ )
+ )
+ )
else:
continue
except Exception as e:
From c8bcdf30d7bda659a6805cb652b29a5c16e9ffbc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 7 Jun 2018 10:54:19 +0200
Subject: [PATCH 070/145] Update docs
---
docs/source/start/Usage.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 8b93df53..7750db3f 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -11,7 +11,7 @@ The easiest and recommended way to interact with Telegram is via the high-level
named after the `Telegram Bot API`_.
.. hint:: If you can't find a method you want to use, chances are it's not implemented yet. In this case, you must use
- the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you're in trouble or want to propose a
+ the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you're stuck or want to propose a
new method!
Examples:
From 244b4f15ce5b4c0042aa336fffe5b957eb5b7c91 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 7 Jun 2018 10:54:45 +0200
Subject: [PATCH 071/145] Remove duplicate parameter
---
pyrogram/client/types/video_note.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/pyrogram/client/types/video_note.py b/pyrogram/client/types/video_note.py
index 2421436b..7f0b6736 100644
--- a/pyrogram/client/types/video_note.py
+++ b/pyrogram/client/types/video_note.py
@@ -35,9 +35,6 @@ class VideoNote(Object):
thumb (:obj:`PhotoSize `, *optional*):
Video thumbnail.
- file_size (``int``, *optional*):
- File size.
-
file_name (``str``, *optional*):
Video note file name.
From 8e2aec4d3acdcf8853709240e3b9622d7adb3056 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 7 Jun 2018 12:54:23 +0200
Subject: [PATCH 072/145] Show TOS on sign-ins
---
pyrogram/client/client.py | 2 ++
pyrogram/client/ext/base_client.py | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 73f45966..b148c307 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -204,6 +204,8 @@ class Client(Methods, BaseClient):
self.is_started = True
if self.user_id is None:
+ print(self.TOS)
+
if self.token is None:
self.authorize_user()
else:
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 9c0fb26b..8d2f4860 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -26,6 +26,16 @@ from ...session.internals import MsgId
class BaseClient:
+ TOS = (
+ "By using Pyrogram you accept Telegram's Terms of Service (https://telegram.org/tos) and agree not to:\n\n"
+
+ "- Use the library to send spam or scam users.\n"
+ "- Promote violence on publicly viewable Telegram bots, groups or channels.\n"
+ "- Post illegal pornographic content on publicly viewable Telegram bots, groups or channels.\n\n"
+
+ "We reserve the right to update these Terms of Service later.\n"
+ )
+
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:t\.me/joinchat/)([\w-]+)$")
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100
From 2944181b388aa687cf7af7083c888e574fafb248 Mon Sep 17 00:00:00 2001
From: YoilyL
Date: Wed, 13 Jun 2018 17:54:48 +0300
Subject: [PATCH 073/145] fixed session mistake
use new session when uploading files instead of main session
---
pyrogram/client/client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 73f45966..5e6324fc 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1051,7 +1051,7 @@ class Client(Methods, BaseClient):
bytes=chunk
)
- assert self.send(rpc), "Couldn't upload file"
+ assert session.send(rpc), "Couldn't upload file"
if is_missing_part:
return
From 329bac6ab00ede9f4b677ca412bb537ba19be5b1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 13 Jun 2018 20:53:31 +0200
Subject: [PATCH 074/145] Better invite link regex pattern
---
pyrogram/client/ext/base_client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 9c0fb26b..578cf168 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -26,7 +26,7 @@ from ...session.internals import MsgId
class BaseClient:
- INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:t\.me/joinchat/)([\w-]+)$")
+ INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100
UPDATES_WORKERS = 1
From e6c6bd839c2ceff278bfac3ef0e8a59f9e9c7eb7 Mon Sep 17 00:00:00 2001
From: Vitali
Date: Tue, 19 Jun 2018 11:18:12 -0300
Subject: [PATCH 075/145] Add Handler to deleted messages update
---
pyrogram/__init__.py | 4 +-
pyrogram/client/__init__.py | 5 +-
pyrogram/client/dispatcher/dispatcher.py | 31 ++++++++++-
pyrogram/client/ext/utils.py | 16 ++++++
pyrogram/client/filters/filters.py | 6 +--
pyrogram/client/handlers/__init__.py | 1 +
.../handlers/deleted_messages_handler.py | 52 +++++++++++++++++++
.../client/methods/decorators/__init__.py | 3 +-
.../methods/decorators/on_deleted_messages.py | 42 +++++++++++++++
pyrogram/client/types/update.py | 10 ++++
10 files changed, 161 insertions(+), 9 deletions(-)
create mode 100644 pyrogram/client/handlers/deleted_messages_handler.py
create mode 100644 pyrogram/client/methods/decorators/on_deleted_messages.py
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 5581b969..531da722 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -38,6 +38,6 @@ from .client.types.reply_markup import (
)
from .client import (
Client, ChatAction, ParseMode, Emoji,
- MessageHandler, CallbackQueryHandler, RawUpdateHandler,
- DisconnectHandler, Filters
+ MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
+ RawUpdateHandler, DisconnectHandler, Filters
)
diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py
index 21bde533..b345de94 100644
--- a/pyrogram/client/__init__.py
+++ b/pyrogram/client/__init__.py
@@ -20,6 +20,7 @@ from .client import Client
from .ext import BaseClient, ChatAction, Emoji, ParseMode
from .filters import Filters
from .handlers import (
- MessageHandler, CallbackQueryHandler,
- RawUpdateHandler, DisconnectHandler
+ MessageHandler, DeletedMessagesHandler,
+ CallbackQueryHandler, RawUpdateHandler,
+ DisconnectHandler
)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 51be2ebb..ffff16bd 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -25,7 +25,7 @@ from threading import Thread
import pyrogram
from pyrogram.api import types
from ..ext import utils
-from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler
+from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler
log = logging.getLogger(__name__)
@@ -41,6 +41,11 @@ class Dispatcher:
types.UpdateEditChannelMessage
)
+ DELETE_MESSAGE_UPDATES = (
+ types.UpdateDeleteMessages,
+ types.UpdateDeleteChannelMessages
+ )
+
MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES
def __init__(self, client, workers):
@@ -97,6 +102,9 @@ class Dispatcher:
or update.edited_message
or update.edited_channel_post)
+ deleted_messages = (update.deleted_channel_posts
+ or update.deleted_messages)
+
callback_query = update.callback_query
if message and isinstance(handler, MessageHandler):
@@ -104,6 +112,11 @@ class Dispatcher:
continue
args = (self.client, message)
+ elif deleted_messages and isinstance(handler, DeletedMessagesHandler):
+ if not handler.check(deleted_messages):
+ continue
+
+ args = (self.client, deleted_messages)
elif callback_query and isinstance(handler, CallbackQueryHandler):
if not handler.check(callback_query):
continue
@@ -161,6 +174,22 @@ class Dispatcher:
else None)
)
)
+
+ elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES):
+ is_channel = hasattr(update, 'channel_id')
+
+ messages = utils.parse_deleted_messages(
+ update.messages,
+ (update.channel_id if is_channel else None)
+ )
+
+ self.dispatch(
+ pyrogram.Update(
+ deleted_messages=(messages if not is_channel else None),
+ deleted_channel_posts=(messages if is_channel else None)
+ )
+ )
+
elif isinstance(update, types.UpdateBotCallbackQuery):
self.dispatch(
pyrogram.Update(
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index d7a09ee1..26017c90 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -711,6 +711,22 @@ def parse_messages(
return parsed_messages if is_list else parsed_messages[0]
+def parse_deleted_messages(
+ messages: list,
+ channel_id: int
+) -> pyrogram_types.Messages:
+ parsed_messages = []
+
+ for message in messages:
+ m = pyrogram_types.Message(
+ message_id=message,
+ chat=(pyrogram_types.Chat(id=channel_id, type="channel") if channel_id is not None else None)
+ )
+ parsed_messages.append(m)
+
+ return pyrogram_types.Messages(len(parsed_messages), parsed_messages)
+
+
def get_peer_id(input_peer) -> int:
return (
input_peer.user_id if isinstance(input_peer, types.InputPeerUser)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index e92948b6..26aa84c8 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -89,13 +89,13 @@ class Filters:
venue = build("Venue", lambda _, m: bool(m.venue))
"""Filter messages that contain :obj:`Venue ` objects."""
- private = build("Private", lambda _, m: bool(m.chat.type == "private"))
+ private = build("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
"""Filter messages sent in private chats."""
- group = build("Group", lambda _, m: bool(m.chat.type in {"group", "supergroup"}))
+ group = build("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
"""Filter messages sent in group or supergroup chats."""
- channel = build("Channel", lambda _, m: bool(m.chat.type == "channel"))
+ channel = build("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
"""Filter messages sent in channels."""
new_chat_members = build("NewChatMembers", lambda _, m: bool(m.new_chat_members))
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index 38a8aeeb..d06b2a76 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -19,4 +19,5 @@
from .callback_query_handler import CallbackQueryHandler
from .disconnect_handler import DisconnectHandler
from .message_handler import MessageHandler
+from .deleted_messages_handler import DeletedMessagesHandler
from .raw_update_handler import RawUpdateHandler
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
new file mode 100644
index 00000000..2f90d5da
--- /dev/null
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -0,0 +1,52 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from .handler import Handler
+
+
+class DeletedMessagesHandler(Handler):
+ """The Deleted Message handler class. Used to handle deleted messages coming from any chat
+ (private, group, channel). It is intended to be used with
+ :meth:`add_handler() `
+
+ Args:
+ callback (``callable``):
+ Pass a function that will be called when a new Message arrives. It takes *(client, message)*
+ as positional arguments (look at the section below for a detailed description).
+
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of messages to be passed
+ in your callback function.
+
+ Other parameters:
+ client (:obj:`Client `):
+ The Client itself, useful when you want to call other API methods inside the message handler.
+
+ message (:obj:`Message `):
+ The received message.
+ """
+
+ def __init__(self, callback: callable, filters=None):
+ super().__init__(callback, filters)
+
+ def check(self, messages):
+ return (
+ self.filters(messages.messages[0])
+ if self.filters
+ else True
+ )
diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/client/methods/decorators/__init__.py
index 6ece61ff..f84a922c 100644
--- a/pyrogram/client/methods/decorators/__init__.py
+++ b/pyrogram/client/methods/decorators/__init__.py
@@ -19,8 +19,9 @@
from .on_callback_query import OnCallbackQuery
from .on_disconnect import OnDisconnect
from .on_message import OnMessage
+from .on_deleted_messages import OnDeletedMessages
from .on_raw_update import OnRawUpdate
-class Decorators(OnMessage, OnCallbackQuery, OnRawUpdate, OnDisconnect):
+class Decorators(OnMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, OnDisconnect):
pass
diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py
new file mode 100644
index 00000000..4cc2d904
--- /dev/null
+++ b/pyrogram/client/methods/decorators/on_deleted_messages.py
@@ -0,0 +1,42 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+import pyrogram
+from ...ext import BaseClient
+
+
+class OnDeletedMessages(BaseClient):
+ def on_deleted_messages(self, filters=None, group: int = 0):
+ """Use this decorator to automatically register a function for handling
+ deleted messages. This does the same thing as :meth:`add_handler` using the
+ DeletedMessagesHandler.
+
+ Args:
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of messages to be passed
+ in your function.
+
+ group (``int``, *optional*):
+ The group identifier, defaults to 0.
+ """
+
+ def decorator(func):
+ self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group)
+ return func
+
+ return decorator
diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py
index edd5d85c..05295285 100644
--- a/pyrogram/client/types/update.py
+++ b/pyrogram/client/types/update.py
@@ -30,12 +30,18 @@ class Update(Object):
edited_message (:obj:`Message `, *optional*):
New version of a message that is known to the bot and was edited.
+ deleted_messages (:obj:`Message `, *optional*):
+ Deleted messages.
+
channel_post (:obj:`Message `, *optional*):
New incoming channel post of any kind — text, photo, sticker, etc.
edited_channel_post (:obj:`Message `, *optional*):
New version of a channel post that is known to the bot and was edited.
+ deleted_channel_posts (:obj:`Message `, *optional*):
+ Deleted channel posts.
+
inline_query (:obj:`InlineQuery `, *optional*):
New incoming inline query.
@@ -60,8 +66,10 @@ class Update(Object):
self,
message=None,
edited_message=None,
+ deleted_messages=None,
channel_post=None,
edited_channel_post=None,
+ deleted_channel_posts=None,
inline_query=None,
chosen_inline_result=None,
callback_query=None,
@@ -70,8 +78,10 @@ class Update(Object):
):
self.message = message
self.edited_message = edited_message
+ self.deleted_messages = deleted_messages
self.channel_post = channel_post
self.edited_channel_post = edited_channel_post
+ self.deleted_channel_posts = deleted_channel_posts
self.inline_query = inline_query
self.chosen_inline_result = chosen_inline_result
self.callback_query = callback_query
From 872f4f865a281da0ba978b0a5e2ea683c48810b6 Mon Sep 17 00:00:00 2001
From: Vitali
Date: Tue, 19 Jun 2018 11:27:34 -0300
Subject: [PATCH 076/145] Fix comments
---
pyrogram/client/handlers/deleted_messages_handler.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index 2f90d5da..29bed259 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -37,8 +37,8 @@ class DeletedMessagesHandler(Handler):
client (:obj:`Client `):
The Client itself, useful when you want to call other API methods inside the message handler.
- message (:obj:`Message `):
- The received message.
+ messages (:obj:`Message `):
+ The received messages.
"""
def __init__(self, callback: callable, filters=None):
From c5fb0d60790125997602e3fe8a3d9ef59c0b9d9e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 20 Jun 2018 12:15:55 +0200
Subject: [PATCH 077/145] Use -100 prefix for channel ids
---
pyrogram/client/ext/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 26017c90..6dda20b7 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -720,7 +720,7 @@ def parse_deleted_messages(
for message in messages:
m = pyrogram_types.Message(
message_id=message,
- chat=(pyrogram_types.Chat(id=channel_id, type="channel") if channel_id is not None else None)
+ chat=(pyrogram_types.Chat(id=int("-100" + str(channel_id)), type="channel") if channel_id is not None else None)
)
parsed_messages.append(m)
From afc0c87cd3e1d1cac3b92524f27e3d9456b48d4a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 20 Jun 2018 12:19:32 +0200
Subject: [PATCH 078/145] Fix DeletedMessagesHandler docstrings
---
pyrogram/client/handlers/deleted_messages_handler.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index 29bed259..6a1f7689 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -20,14 +20,14 @@ from .handler import Handler
class DeletedMessagesHandler(Handler):
- """The Deleted Message handler class. Used to handle deleted messages coming from any chat
+ """The Deleted Messages handler class. Used to handle deleted messages coming from any chat
(private, group, channel). It is intended to be used with
:meth:`add_handler() `
Args:
callback (``callable``):
- Pass a function that will be called when a new Message arrives. It takes *(client, message)*
- as positional arguments (look at the section below for a detailed description).
+ Pass a function that will be called when one or more Messages have been deleted.
+ It takes *(client, messages)* as positional arguments (look at the section below for a detailed description).
filters (:obj:`Filters `):
Pass one or more filters to allow only a subset of messages to be passed
@@ -37,8 +37,8 @@ class DeletedMessagesHandler(Handler):
client (:obj:`Client `):
The Client itself, useful when you want to call other API methods inside the message handler.
- messages (:obj:`Message `):
- The received messages.
+ messages (:obj:`Messages `):
+ The deleted messages.
"""
def __init__(self, callback: callable, filters=None):
From 1c4047f2c6d2b4a255d12c74f54d4c349e8a978a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 20 Jun 2018 12:20:48 +0200
Subject: [PATCH 079/145] Fix Update docstrings
---
pyrogram/client/types/update.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py
index 05295285..c8959708 100644
--- a/pyrogram/client/types/update.py
+++ b/pyrogram/client/types/update.py
@@ -30,7 +30,7 @@ class Update(Object):
edited_message (:obj:`Message `, *optional*):
New version of a message that is known to the bot and was edited.
- deleted_messages (:obj:`Message `, *optional*):
+ deleted_messages (:obj:`Messages `, *optional*):
Deleted messages.
channel_post (:obj:`Message `, *optional*):
@@ -39,7 +39,7 @@ class Update(Object):
edited_channel_post (:obj:`Message `, *optional*):
New version of a channel post that is known to the bot and was edited.
- deleted_channel_posts (:obj:`Message `, *optional*):
+ deleted_channel_posts (:obj:`Messages `, *optional*):
Deleted channel posts.
inline_query (:obj:`InlineQuery `, *optional*):
From ff915965f158025aa3aac5f34fb4ab62fa70977f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 21 Jun 2018 15:33:30 +0200
Subject: [PATCH 080/145] Minor style fixes
---
pyrogram/client/ext/utils.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 6dda20b7..2913c38b 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -718,11 +718,14 @@ def parse_deleted_messages(
parsed_messages = []
for message in messages:
- m = pyrogram_types.Message(
- message_id=message,
- chat=(pyrogram_types.Chat(id=int("-100" + str(channel_id)), type="channel") if channel_id is not None else None)
+ parsed_messages.append(
+ pyrogram_types.Message(
+ message_id=message,
+ chat=(pyrogram_types.Chat(id=int("-100" + str(channel_id)), type="channel")
+ if channel_id is not None
+ else None)
+ )
)
- parsed_messages.append(m)
return pyrogram_types.Messages(len(parsed_messages), parsed_messages)
From 896d0844d18173583b17adaf57eb14073da61839 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 12:29:14 +0200
Subject: [PATCH 081/145] Rename venv to venv3.6
---
docs/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Makefile b/docs/Makefile
index cb346f83..c01e3d3d 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -3,7 +3,7 @@
# You can set these variables from the command line.
SPHINXOPTS =
-SPHINXBUILD = ~/PycharmProjects/pyrogram/venv/bin/sphinx-build
+SPHINXBUILD = ~/PycharmProjects/pyrogram/venv3.6/bin/sphinx-build
SPHINXPROJ = Pyrogram
SOURCEDIR = source
BUILDDIR = build
From 2f80a0ba7fe9a006ebc343a5cd9f4ead042c2479 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 12:46:04 +0200
Subject: [PATCH 082/145] Add DeletedMessagesHandler to docs
---
docs/source/pyrogram/handlers/DeletedMessagesHandler.rst | 6 ++++++
docs/source/pyrogram/handlers/index.rst | 3 ++-
2 files changed, 8 insertions(+), 1 deletion(-)
create mode 100644 docs/source/pyrogram/handlers/DeletedMessagesHandler.rst
diff --git a/docs/source/pyrogram/handlers/DeletedMessagesHandler.rst b/docs/source/pyrogram/handlers/DeletedMessagesHandler.rst
new file mode 100644
index 00000000..128bc656
--- /dev/null
+++ b/docs/source/pyrogram/handlers/DeletedMessagesHandler.rst
@@ -0,0 +1,6 @@
+DeletedMessagesHandler
+======================
+
+.. autoclass:: pyrogram.DeletedMessagesHandler
+ :members:
+ :undoc-members:
diff --git a/docs/source/pyrogram/handlers/index.rst b/docs/source/pyrogram/handlers/index.rst
index 191d4eff..272e529f 100644
--- a/docs/source/pyrogram/handlers/index.rst
+++ b/docs/source/pyrogram/handlers/index.rst
@@ -5,6 +5,7 @@ Handlers
.. toctree::
MessageHandler
+ DeletedMessagesHandler
CallbackQueryHandler
+ DisconnectHandler
RawUpdateHandler
- DisconnectHandler
\ No newline at end of file
From ac47ffad8f39201f68c3cde9fe57fa70dad1993f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 12:46:35 +0200
Subject: [PATCH 083/145] Hint about decorators on handlers' docstrings
---
pyrogram/client/handlers/callback_query_handler.py | 3 +++
pyrogram/client/handlers/deleted_messages_handler.py | 5 ++++-
pyrogram/client/handlers/disconnect_handler.py | 2 ++
pyrogram/client/handlers/message_handler.py | 3 +++
pyrogram/client/handlers/raw_update_handler.py | 3 +++
5 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/client/handlers/callback_query_handler.py
index c0bba510..c5346519 100644
--- a/pyrogram/client/handlers/callback_query_handler.py
+++ b/pyrogram/client/handlers/callback_query_handler.py
@@ -23,6 +23,9 @@ class CallbackQueryHandler(Handler):
"""The CallbackQuery handler class. Used to handle callback queries coming from inline buttons.
It is intended to be used with :meth:`add_handler() `
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_callback_query() ` decorator.
+
Args:
callback (``callable``):
Pass a function that will be called when a new CallbackQuery arrives. It takes *(client, callback_query)*
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index 6a1f7689..55d5715f 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -20,10 +20,13 @@ from .handler import Handler
class DeletedMessagesHandler(Handler):
- """The Deleted Messages handler class. Used to handle deleted messages coming from any chat
+ """The deleted Messages handler class. Used to handle deleted messages coming from any chat
(private, group, channel). It is intended to be used with
:meth:`add_handler() `
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_deleted_messages() ` decorator.
+
Args:
callback (``callable``):
Pass a function that will be called when one or more Messages have been deleted.
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
index 9ad4ffbc..a8b800a8 100644
--- a/pyrogram/client/handlers/disconnect_handler.py
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -23,6 +23,8 @@ class DisconnectHandler(Handler):
"""The Disconnect handler class. Used to handle disconnections. It is intended to be used with
:meth:`add_handler() `
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_disconnect() ` decorator.
Args:
callback (``callable``):
diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/client/handlers/message_handler.py
index 6aae27de..1b4770b3 100644
--- a/pyrogram/client/handlers/message_handler.py
+++ b/pyrogram/client/handlers/message_handler.py
@@ -24,6 +24,9 @@ class MessageHandler(Handler):
any chat (private, group, channel). It is intended to be used with
:meth:`add_handler() `
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_message() ` decorator.
+
Args:
callback (``callable``):
Pass a function that will be called when a new Message arrives. It takes *(client, message)*
diff --git a/pyrogram/client/handlers/raw_update_handler.py b/pyrogram/client/handlers/raw_update_handler.py
index 8a1e0a03..5a8913b6 100644
--- a/pyrogram/client/handlers/raw_update_handler.py
+++ b/pyrogram/client/handlers/raw_update_handler.py
@@ -23,6 +23,9 @@ class RawUpdateHandler(Handler):
"""The Raw Update handler class. Used to handle raw updates. It is intended to be used with
:meth:`add_handler() `
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_raw_update() ` decorator.
+
Args:
callback (``callable``):
A function that will be called when a new update is received from the server. It takes
From 6be8f1aae326c9efd1d159b6de974bc206e97daf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 12:46:58 +0200
Subject: [PATCH 084/145] Cross reference Handler classes on decorators'
docstrings
---
pyrogram/client/methods/decorators/on_callback_query.py | 2 +-
pyrogram/client/methods/decorators/on_deleted_messages.py | 2 +-
pyrogram/client/methods/decorators/on_disconnect.py | 2 +-
pyrogram/client/methods/decorators/on_message.py | 2 +-
pyrogram/client/methods/decorators/on_raw_update.py | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py
index 3bafc94d..5f22fc92 100644
--- a/pyrogram/client/methods/decorators/on_callback_query.py
+++ b/pyrogram/client/methods/decorators/on_callback_query.py
@@ -24,7 +24,7 @@ class OnCallbackQuery(BaseClient):
def on_callback_query(self, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
callback queries. This does the same thing as :meth:`add_handler` using the
- CallbackQueryHandler.
+ :class:`CallbackQueryHandler`.
Args:
filters (:obj:`Filters `):
diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py
index 4cc2d904..3f603c41 100644
--- a/pyrogram/client/methods/decorators/on_deleted_messages.py
+++ b/pyrogram/client/methods/decorators/on_deleted_messages.py
@@ -24,7 +24,7 @@ class OnDeletedMessages(BaseClient):
def on_deleted_messages(self, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
deleted messages. This does the same thing as :meth:`add_handler` using the
- DeletedMessagesHandler.
+ :class:`DeletedMessagesHandler`.
Args:
filters (:obj:`Filters `):
diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py
index d1d03723..4bc593e3 100644
--- a/pyrogram/client/methods/decorators/on_disconnect.py
+++ b/pyrogram/client/methods/decorators/on_disconnect.py
@@ -24,7 +24,7 @@ class OnDisconnect(BaseClient):
def on_disconnect(self):
"""Use this decorator to automatically register a function for handling
disconnections. This does the same thing as :meth:`add_handler` using the
- DisconnectHandler.
+ :class:`DisconnectHandler`.
"""
def decorator(func):
diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py
index 43c6f9f8..0011e083 100644
--- a/pyrogram/client/methods/decorators/on_message.py
+++ b/pyrogram/client/methods/decorators/on_message.py
@@ -24,7 +24,7 @@ class OnMessage(BaseClient):
def on_message(self, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
messages. This does the same thing as :meth:`add_handler` using the
- MessageHandler.
+ :class:`MessageHandler`.
Args:
filters (:obj:`Filters `):
diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py
index ca1c9d9b..902d9854 100644
--- a/pyrogram/client/methods/decorators/on_raw_update.py
+++ b/pyrogram/client/methods/decorators/on_raw_update.py
@@ -24,7 +24,7 @@ class OnRawUpdate(BaseClient):
def on_raw_update(self, group: int = 0):
"""Use this decorator to automatically register a function for handling
raw updates. This does the same thing as :meth:`add_handler` using the
- RawUpdateHandler.
+ :class:`RawUpdateHandler`.
Args:
group (``int``, *optional*):
From 7c97efd2a134523109835a30f115c2833ac48230 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 12:55:52 +0200
Subject: [PATCH 085/145] Update docs
---
docs/source/start/Setup.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/start/Setup.rst b/docs/source/start/Setup.rst
index dc837a86..e9105cde 100644
--- a/docs/source/start/Setup.rst
+++ b/docs/source/start/Setup.rst
@@ -1,7 +1,7 @@
Setup
=====
-Once you successfully installed_ Pyrogram, you will have to follow a few steps before you can actually use
+Once you successfully `installed Pyrogram`_, you will still have to follow a few steps before you can actually use
the library to make API calls. This section provides all the information you need in order to set up a project
with Pyrogram.
@@ -46,7 +46,7 @@ There are two ways to configure a Pyrogram application project, and you can choo
)
.. note:: The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
-and *api_hash* parameters usage.
+ and *api_hash* parameters usage.
User Authorization
------------------
@@ -97,6 +97,6 @@ Instead of phone numbers, Bots are authorized via their tokens which are created
That's all, no further action is needed. The session file will be named after the Bot user_id, which is
``123456.session`` for the example above.
-.. _installed: Installation.html
+.. _installed Pyrogram: Installation.html
.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes
.. _BotFather: https://t.me/botfather
\ No newline at end of file
From dab0a05f16641200c22e4368c9db9cc76c6bcdcb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:08:01 +0200
Subject: [PATCH 086/145] Move idle() and signal_handler() definitions near
stop()
---
pyrogram/client/client.py | 44 +++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 5e6324fc..2cd31dc9 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -285,6 +285,28 @@ class Client(Methods, BaseClient):
self.is_started = False
self.session.stop()
+ def signal_handler(self, *args):
+ self.is_idle = False
+
+ def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
+ """Blocks the program execution until one of the signals are received,
+ then gently stop the Client by closing the underlying connection.
+
+ Args:
+ stop_signals (``tuple``, *optional*):
+ Iterable containing signals the signal handler will listen to.
+ Defaults to (SIGINT, SIGTERM, SIGABRT).
+ """
+ for s in stop_signals:
+ signal(s, self.signal_handler)
+
+ self.is_idle = True
+
+ while self.is_idle:
+ time.sleep(1)
+
+ self.stop()
+
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
@@ -790,28 +812,6 @@ class Client(Methods, BaseClient):
log.debug("{} stopped".format(name))
- def signal_handler(self, *args):
- self.is_idle = False
-
- def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
- """Blocks the program execution until one of the signals are received,
- then gently stop the Client by closing the underlying connection.
-
- Args:
- stop_signals (``tuple``, *optional*):
- Iterable containing signals the signal handler will listen to.
- Defaults to (SIGINT, SIGTERM, SIGABRT).
- """
- for s in stop_signals:
- signal(s, self.signal_handler)
-
- self.is_idle = True
-
- while self.is_idle:
- time.sleep(1)
-
- self.stop()
-
def send(self, data: Object):
"""Use this method to send Raw Function queries.
From ffd67ed40839d82c133b6abc5529305385a74a4e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:08:27 +0200
Subject: [PATCH 087/145] Remove debug docstrings
---
pyrogram/client/client.py | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 2cd31dc9..f8309b88 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -169,15 +169,10 @@ class Client(Methods, BaseClient):
self._proxy["enabled"] = True
self._proxy.update(value)
- def start(self, debug: bool = False):
+ def start(self):
"""Use this method to start the Client after creating it.
Requires no parameters.
- Args:
- debug (``bool``, *optional*):
- Enable or disable debug mode. When enabled, extra logging
- lines will be printed out on your console.
-
Raises:
:class:`Error `
"""
From e3299bb3b7fd08b4224d1d2280c9922ecbd3d93f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:10:09 +0200
Subject: [PATCH 088/145] Add run() method
---
pyrogram/client/client.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index f8309b88..49b1c898 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -302,6 +302,16 @@ class Client(Methods, BaseClient):
self.stop()
+ def run(self):
+ """Use this method to automatically :meth:`start` and :meth:`idle` a Client.
+ Requires no parameters.
+
+ Raises:
+ :class:`Error `
+ """
+ self.start()
+ self.idle()
+
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
From 8748ff97ef1eb5d6c00f8816c114aa465b425f95 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:10:14 +0200
Subject: [PATCH 089/145] Update docs
---
docs/source/resources/UpdateHandling.rst | 1 +
docs/source/start/Usage.rst | 8 ++++----
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst
index 4373433b..e4db3574 100644
--- a/docs/source/resources/UpdateHandling.rst
+++ b/docs/source/resources/UpdateHandling.rst
@@ -6,6 +6,7 @@ and are handled by registering one or more callback functions with an Handler. T
from, one for each kind of update:
- `MessageHandler <../pyrogram/handlers/MessageHandler.html>`_
+- `DeletedMessagesHandler <../pyrogram/handlers/DeletedMessagesHandler.html>`_
- `CallbackQueryHandler <../pyrogram/handlers/CallbackQueryHandler.html>`_
- `RawUpdateHandler <../pyrogram/handlers/RawUpdateHandler.html>`_
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 7750db3f..2a213eb9 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -10,9 +10,9 @@ High-level API
The easiest and recommended way to interact with Telegram is via the high-level Pyrogram methods_ and types_, which are
named after the `Telegram Bot API`_.
-.. hint:: If you can't find a method you want to use, chances are it's not implemented yet. In this case, you must use
- the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you're stuck or want to propose a
- new method!
+.. hint:: If you can't find an high-level method you want to use, chances are it's not implemented yet.
+ In this case, you must use the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you get stuck
+ or want to propose a new method!
Examples:
@@ -39,7 +39,7 @@ Examples:
Using Raw Functions
-------------------
-If you can't find a high-level method for your needs or want complete, low-level access to the whole Telegram API,
+If you can't find a high-level method for your needs or if want complete, low-level access to the whole Telegram API,
you have to use the raw :mod:`functions ` and :mod:`types ` exposed by the
``pyrogram.api`` package and call any Telegram API method you wish using the :meth:`send() `
method provided by the Client class.
From c067b42bf273f15d8b1a793c63f636642d4ffd53 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:10:33 +0200
Subject: [PATCH 090/145] Add run() method to docs
---
docs/source/pyrogram/Client.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index 3e65b0f6..0448c3cb 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -17,6 +17,7 @@ Client
start
stop
idle
+ run
on_message
on_callback_query
on_raw_update
From 82a0c965ba9a7193c202e2e156b365ed4e2717fd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:12:31 +0200
Subject: [PATCH 091/145] Don't make start and idle clickable
---
pyrogram/client/client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 49b1c898..6db22fa4 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -303,7 +303,7 @@ class Client(Methods, BaseClient):
self.stop()
def run(self):
- """Use this method to automatically :meth:`start` and :meth:`idle` a Client.
+ """Use this method to automatically start and idle a Client.
Requires no parameters.
Raises:
From b8e6fc2e6a893cce3d81c10215d1dc462facd053 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:17:39 +0200
Subject: [PATCH 092/145] Update welcome example
---
docs/source/index.rst | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 61394d7b..414e47dd 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -44,12 +44,11 @@ Welcome to Pyrogram
@app.on_message(Filters.private)
def hello(client, message):
- client.send_message(
- message.chat.id, "Hello {}".format(message.from_user.first_name))
+ message.reply_text(
+ "Hello {}".format(message.from_user.first_name))
- app.start()
- app.idle()
+ app.run()
Welcome to Pyrogram's Documentation! Here you can find resources for learning how to use the library.
Contents are organized by topic and can be accessed from the sidebar, or by following them one by one using the Next
From 478f757689fe8b747b4de21846672b8cda9d8879 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:19:04 +0200
Subject: [PATCH 093/145] Update Setup page
---
docs/source/start/Setup.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/start/Setup.rst b/docs/source/start/Setup.rst
index e9105cde..8b7c0597 100644
--- a/docs/source/start/Setup.rst
+++ b/docs/source/start/Setup.rst
@@ -40,7 +40,7 @@ There are two ways to configure a Pyrogram application project, and you can choo
from pyrogram import Client
app = Client(
- session_name="my_account",
+ "my_account",
api_id=12345,
api_hash="0123456789abcdef0123456789abcdef"
)
@@ -61,7 +61,7 @@ the :class:`Client ` class by passing to it a ``session_name``
from pyrogram import Client
app = Client("my_account")
- app.start()
+ app.run()
This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_)
and the **phone code** you will receive:
@@ -92,7 +92,7 @@ Instead of phone numbers, Bots are authorized via their tokens which are created
from pyrogram import Client
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
- app.start()
+ app.run()
That's all, no further action is needed. The session file will be named after the Bot user_id, which is
``123456.session`` for the example above.
From fa65abf2763aa6c49932e92c9796f3053a88a6a5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:27:43 +0200
Subject: [PATCH 094/145] Update Usage page
---
docs/source/start/Usage.rst | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 2a213eb9..d9cb8fe1 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -14,7 +14,7 @@ named after the `Telegram Bot API`_.
In this case, you must use the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you get stuck
or want to propose a new method!
-Examples:
+Examples (more on `GitHub `_):
- Get information about the authorized user:
@@ -49,15 +49,17 @@ method provided by the Client class.
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
-Examples:
+Examples (more on `GitHub `_):
- Update first name, last name and bio:
.. code-block:: python
+ from pyrogram import Client
from pyrogram.api import functions
- ...
+ app = Client("my_account")
+ app.start()
app.send(
functions.account.UpdateProfile(
@@ -66,13 +68,17 @@ Examples:
)
)
+ app.stop()
+
- Share your Last Seen time only with your contacts:
.. code-block:: python
+ from pyrogram import Client
from pyrogram.api import functions, types
- ...
+ app = Client("my_account")
+ app.start()
app.send(
functions.account.SetPrivacy(
@@ -81,13 +87,17 @@ Examples:
)
)
+ app.stop()
+
- Invite users to your channel/supergroup:
.. code-block:: python
+ from pyrogram import Client
from pyrogram.api import functions, types
- ...
+ app = Client("my_account")
+ app.start()
app.send(
functions.channels.InviteToChannel(
@@ -100,6 +110,8 @@ Examples:
)
)
+ app.stop()
+
.. _methods: ../pyrogram/Client.html#available-methods
.. _plenty of them: ../pyrogram/Client.html#available-methods
.. _types: ../pyrogram/types/index.html
From 142a27f52ac910d8a5afed247c6da493c64c3993 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:30:18 +0200
Subject: [PATCH 095/145] Use app.run() in the examples
---
examples/callback_query_handler.py | 3 +--
examples/echo_bot.py | 3 +--
examples/get_history.py | 4 ++--
examples/get_participants.py | 4 ++--
examples/get_participants2.py | 5 ++---
examples/raw_update_handler.py | 3 +--
examples/welcome_bot.py | 3 +--
7 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/examples/callback_query_handler.py b/examples/callback_query_handler.py
index 6b76edd8..999c2686 100644
--- a/examples/callback_query_handler.py
+++ b/examples/callback_query_handler.py
@@ -34,5 +34,4 @@ def answer(client, callback_query):
)
-app.start()
-app.idle()
+app.run() # Automatically start() and idle()
diff --git a/examples/echo_bot.py b/examples/echo_bot.py
index ed2d4df5..adda52c7 100644
--- a/examples/echo_bot.py
+++ b/examples/echo_bot.py
@@ -36,5 +36,4 @@ def echo(client, message):
)
-app.start()
-app.idle()
+app.run() # Automatically start() and idle()
diff --git a/examples/get_history.py b/examples/get_history.py
index d53bed96..433d127c 100644
--- a/examples/get_history.py
+++ b/examples/get_history.py
@@ -24,12 +24,12 @@ from pyrogram.api.errors import FloodWait
"""This example shows how to retrieve the full message history of a chat"""
app = Client("my_account")
-app.start()
-
target = "me" # "me" refers to your own chat (Saved Messages)
messages = [] # List that will contain all the messages of the target chat
offset_id = 0 # ID of the last message of the chunk
+app.start()
+
while True:
try:
m = app.get_history(target, offset_id=offset_id)
diff --git a/examples/get_participants.py b/examples/get_participants.py
index d10710ba..fd5257fb 100644
--- a/examples/get_participants.py
+++ b/examples/get_participants.py
@@ -28,13 +28,13 @@ Refer to get_participants2.py for more than 10.000 users.
"""
app = Client("my_account")
-app.start()
-
target = "pyrogramchat" # Target channel/supergroup
users = [] # List that will contain all the users of the target chat
limit = 200 # Amount of users to retrieve for each API call
offset = 0 # Offset starts at 0
+app.start()
+
while True:
try:
participants = app.send(
diff --git a/examples/get_participants2.py b/examples/get_participants2.py
index dfad315b..a70afb74 100644
--- a/examples/get_participants2.py
+++ b/examples/get_participants2.py
@@ -33,15 +33,14 @@ as some user names may not contain ascii letters at all.
"""
app = Client("my_account")
-app.start()
-
target = "pyrogramchat" # Target channel/supergroup username or id
users = {} # To ensure uniqueness, users will be stored in a dictionary with user_id as key
limit = 200 # Amount of users to retrieve for each API call (200 is the maximum)
-
# "" + "0123456789" + "abcdefghijklmnopqrstuvwxyz" (as list)
queries = [""] + [str(i) for i in range(10)] + list(ascii_lowercase)
+app.start()
+
for q in queries:
print("Searching for '{}'".format(q))
offset = 0 # For each query, offset restarts from 0
diff --git a/examples/raw_update_handler.py b/examples/raw_update_handler.py
index eb417c24..c7195761 100644
--- a/examples/raw_update_handler.py
+++ b/examples/raw_update_handler.py
@@ -28,5 +28,4 @@ def raw(client, update, users, chats):
print(update)
-app.start()
-app.idle()
+app.run() # Automatically start() and idle()
diff --git a/examples/welcome_bot.py b/examples/welcome_bot.py
index 8e087728..5fd93293 100644
--- a/examples/welcome_bot.py
+++ b/examples/welcome_bot.py
@@ -49,5 +49,4 @@ def welcome(client, message):
)
-app.start()
-app.idle()
+app.run() # Automatically start() and idle()
From dd156e0f7abf968c069c090d2a19ef6a6462e7d2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:32:55 +0200
Subject: [PATCH 096/145] Update UpdateHandling page
---
docs/source/resources/UpdateHandling.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst
index e4db3574..ffa01be9 100644
--- a/docs/source/resources/UpdateHandling.rst
+++ b/docs/source/resources/UpdateHandling.rst
@@ -32,8 +32,7 @@ We shall examine the :obj:`MessageHandler `, which will
print(message)
- app.start()
- app.idle()
+ app.run()
- If you prefer not to use decorators, there is an alternative way for registering Handlers.
This is useful, for example, when you want to keep your callback functions in separate files.
@@ -51,8 +50,7 @@ We shall examine the :obj:`MessageHandler `, which will
app.add_handler(MessageHandler(my_handler))
- app.start()
- app.idle()
+ app.run()
Using Filters
-------------
From 1aa02cb63f63514a61300edabd188db711073d90 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:36:22 +0200
Subject: [PATCH 097/145] Update AutoAuthorization page
---
docs/source/resources/AutoAuthorization.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/source/resources/AutoAuthorization.rst b/docs/source/resources/AutoAuthorization.rst
index 46f0809d..73504f80 100644
--- a/docs/source/resources/AutoAuthorization.rst
+++ b/docs/source/resources/AutoAuthorization.rst
@@ -35,6 +35,7 @@ ask you to input the phone code manually.
app.start()
print(app.get_me())
+ app.stop()
Sign Up
-------
@@ -61,4 +62,5 @@ Telegram account in case the phone number you passed is not registered yet.
)
app.start()
- print(app.get_me())
\ No newline at end of file
+ print(app.get_me())
+ app.stop()
\ No newline at end of file
From 6c976a37082ef9f4a82b77145052af2c00b32841 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:41:06 +0200
Subject: [PATCH 098/145] Update README.rst
---
README.rst | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/README.rst b/README.rst
index 67dbd3a5..eb49c635 100644
--- a/README.rst
+++ b/README.rst
@@ -12,12 +12,11 @@ Pyrogram |twitter|
@app.on_message(Filters.private)
def hello(client, message):
- client.send_message(
- message.chat.id, "Hello {}".format(message.from_user.first_name))
+ message.reply_text(
+ "Hello {}".format(message.from_user.first_name))
- app.start()
- app.idle()
+ app.run()
**Pyrogram** is a brand new Telegram_ Client Library written from the ground up in Python and C. It can be used for building
custom Telegram applications that interact with the MTProto API as both User and Bot.
From 8074ef1368259a20c5d6d9b01dfa87436ed0da20 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 10:34:20 +0200
Subject: [PATCH 099/145] Make methods directory structure simple
---
pyrogram/client/methods/bots/__init__.py | 12 +++--
.../answer_callback_query.py | 2 +-
.../methods/bots/callback_query/__init__.py | 25 ----------
.../{inline => }/get_inline_bot_results.py | 2 +-
.../client/methods/bots/inline/__init__.py | 27 -----------
.../{inline => }/send_inline_bot_result.py | 2 +-
pyrogram/client/methods/messages/__init__.py | 44 +++++++++++++----
.../methods/messages/action/__init__.py | 25 ----------
.../messages/{update => }/delete_messages.py | 2 +-
.../{update => }/edit_message_caption.py | 2 +-
.../{update => }/edit_message_reply_markup.py | 2 +-
.../{update => }/edit_message_text.py | 2 +-
.../client/methods/messages/media/__init__.py | 47 -------------------
.../messages/{media => }/send_audio.py | 2 +-
.../messages/{action => }/send_chat_action.py | 2 +-
.../messages/{media => }/send_contact.py | 2 +-
.../messages/{media => }/send_document.py | 2 +-
.../methods/messages/{media => }/send_gif.py | 2 +-
.../messages/{media => }/send_location.py | 2 +-
.../messages/{media => }/send_media_group.py | 2 +-
.../messages/{media => }/send_photo.py | 2 +-
.../messages/{media => }/send_sticker.py | 2 +-
.../messages/{media => }/send_venue.py | 2 +-
.../messages/{media => }/send_video.py | 2 +-
.../messages/{media => }/send_video_note.py | 2 +-
.../messages/{media => }/send_voice.py | 2 +-
.../methods/messages/update/__init__.py | 31 ------------
27 files changed, 64 insertions(+), 187 deletions(-)
rename pyrogram/client/methods/bots/{callback_query => }/answer_callback_query.py (98%)
delete mode 100644 pyrogram/client/methods/bots/callback_query/__init__.py
rename pyrogram/client/methods/bots/{inline => }/get_inline_bot_results.py (98%)
delete mode 100644 pyrogram/client/methods/bots/inline/__init__.py
rename pyrogram/client/methods/bots/{inline => }/send_inline_bot_result.py (98%)
delete mode 100644 pyrogram/client/methods/messages/action/__init__.py
rename pyrogram/client/methods/messages/{update => }/delete_messages.py (98%)
rename pyrogram/client/methods/messages/{update => }/edit_message_caption.py (98%)
rename pyrogram/client/methods/messages/{update => }/edit_message_reply_markup.py (98%)
rename pyrogram/client/methods/messages/{update => }/edit_message_text.py (98%)
delete mode 100644 pyrogram/client/methods/messages/media/__init__.py
rename pyrogram/client/methods/messages/{media => }/send_audio.py (99%)
rename pyrogram/client/methods/messages/{action => }/send_chat_action.py (98%)
rename pyrogram/client/methods/messages/{media => }/send_contact.py (98%)
rename pyrogram/client/methods/messages/{media => }/send_document.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_gif.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_location.py (98%)
rename pyrogram/client/methods/messages/{media => }/send_media_group.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_photo.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_sticker.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_venue.py (98%)
rename pyrogram/client/methods/messages/{media => }/send_video.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_video_note.py (99%)
rename pyrogram/client/methods/messages/{media => }/send_voice.py (99%)
delete mode 100644 pyrogram/client/methods/messages/update/__init__.py
diff --git a/pyrogram/client/methods/bots/__init__.py b/pyrogram/client/methods/bots/__init__.py
index 62e0eb61..2d89c2fb 100644
--- a/pyrogram/client/methods/bots/__init__.py
+++ b/pyrogram/client/methods/bots/__init__.py
@@ -16,12 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .callback_query import CallbackQuery
-from .inline import Inline
+from .answer_callback_query import AnswerCallbackQuery
+from .get_inline_bot_results import GetInlineBotResults
+from .request_callback_answer import RequestCallbackAnswer
+from .send_inline_bot_result import SendInlineBotResult
class Bots(
- CallbackQuery,
- Inline
+ AnswerCallbackQuery,
+ GetInlineBotResults,
+ RequestCallbackAnswer,
+ SendInlineBotResult
):
pass
diff --git a/pyrogram/client/methods/bots/callback_query/answer_callback_query.py b/pyrogram/client/methods/bots/answer_callback_query.py
similarity index 98%
rename from pyrogram/client/methods/bots/callback_query/answer_callback_query.py
rename to pyrogram/client/methods/bots/answer_callback_query.py
index a4baa166..64951692 100644
--- a/pyrogram/client/methods/bots/callback_query/answer_callback_query.py
+++ b/pyrogram/client/methods/bots/answer_callback_query.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions
-from ....ext import BaseClient
+from pyrogram.client.ext import BaseClient
class AnswerCallbackQuery(BaseClient):
diff --git a/pyrogram/client/methods/bots/callback_query/__init__.py b/pyrogram/client/methods/bots/callback_query/__init__.py
deleted file mode 100644
index 76575724..00000000
--- a/pyrogram/client/methods/bots/callback_query/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-from .answer_callback_query import AnswerCallbackQuery
-
-
-class CallbackQuery(
- AnswerCallbackQuery
-):
- pass
diff --git a/pyrogram/client/methods/bots/inline/get_inline_bot_results.py b/pyrogram/client/methods/bots/get_inline_bot_results.py
similarity index 98%
rename from pyrogram/client/methods/bots/inline/get_inline_bot_results.py
rename to pyrogram/client/methods/bots/get_inline_bot_results.py
index 52c3b005..a43eb6c1 100644
--- a/pyrogram/client/methods/bots/inline/get_inline_bot_results.py
+++ b/pyrogram/client/methods/bots/get_inline_bot_results.py
@@ -18,7 +18,7 @@
from pyrogram.api import functions, types
from pyrogram.api.errors import UnknownError
-from ....ext import BaseClient
+from pyrogram.client.ext import BaseClient
class GetInlineBotResults(BaseClient):
diff --git a/pyrogram/client/methods/bots/inline/__init__.py b/pyrogram/client/methods/bots/inline/__init__.py
deleted file mode 100644
index af88c57e..00000000
--- a/pyrogram/client/methods/bots/inline/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-from .get_inline_bot_results import GetInlineBotResults
-from .send_inline_bot_result import SendInlineBotResult
-
-
-class Inline(
- SendInlineBotResult,
- GetInlineBotResults
-):
- pass
diff --git a/pyrogram/client/methods/bots/inline/send_inline_bot_result.py b/pyrogram/client/methods/bots/send_inline_bot_result.py
similarity index 98%
rename from pyrogram/client/methods/bots/inline/send_inline_bot_result.py
rename to pyrogram/client/methods/bots/send_inline_bot_result.py
index 947433cd..c194298a 100644
--- a/pyrogram/client/methods/bots/inline/send_inline_bot_result.py
+++ b/pyrogram/client/methods/bots/send_inline_bot_result.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions
-from ....ext import BaseClient
+from pyrogram.client.ext import BaseClient
class SendInlineBotResult(BaseClient):
diff --git a/pyrogram/client/methods/messages/__init__.py b/pyrogram/client/methods/messages/__init__.py
index c2ff2400..e2c2462e 100644
--- a/pyrogram/client/methods/messages/__init__.py
+++ b/pyrogram/client/methods/messages/__init__.py
@@ -16,22 +16,50 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .action import Action
+from .delete_messages import DeleteMessages
+from .edit_message_caption import EditMessageCaption
+from .edit_message_reply_markup import EditMessageReplyMarkup
+from .edit_message_text import EditMessageText
from .forward_messages import ForwardMessages
from .get_history import GetHistory
from .get_messages import GetMessages
-from .media import Media
+from .send_audio import SendAudio
+from .send_chat_action import SendChatAction
+from .send_contact import SendContact
+from .send_document import SendDocument
+from .send_gif import SendGIF
+from .send_location import SendLocation
+from .send_media_group import SendMediaGroup
from .send_message import SendMessage
-from .update import Update
+from .send_photo import SendPhoto
+from .send_sticker import SendSticker
+from .send_venue import SendVenue
+from .send_video import SendVideo
+from .send_video_note import SendVideoNote
+from .send_voice import SendVoice
class Messages(
+ DeleteMessages,
+ EditMessageCaption,
+ EditMessageReplyMarkup,
+ EditMessageText,
+ ForwardMessages,
GetHistory,
GetMessages,
- Action,
- Media,
- Update,
- ForwardMessages,
- SendMessage
+ SendAudio,
+ SendChatAction,
+ SendContact,
+ SendDocument,
+ SendGIF,
+ SendLocation,
+ SendMediaGroup,
+ SendMessage,
+ SendPhoto,
+ SendSticker,
+ SendVenue,
+ SendVideo,
+ SendVideoNote,
+ SendVoice
):
pass
diff --git a/pyrogram/client/methods/messages/action/__init__.py b/pyrogram/client/methods/messages/action/__init__.py
deleted file mode 100644
index 639405f2..00000000
--- a/pyrogram/client/methods/messages/action/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-from .send_chat_action import SendChatAction
-
-
-class Action(
- SendChatAction
-):
- pass
diff --git a/pyrogram/client/methods/messages/update/delete_messages.py b/pyrogram/client/methods/messages/delete_messages.py
similarity index 98%
rename from pyrogram/client/methods/messages/update/delete_messages.py
rename to pyrogram/client/methods/messages/delete_messages.py
index 3d29bf55..a4c97c76 100644
--- a/pyrogram/client/methods/messages/update/delete_messages.py
+++ b/pyrogram/client/methods/messages/delete_messages.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient
+from pyrogram.client.ext import BaseClient
class DeleteMessages(BaseClient):
diff --git a/pyrogram/client/methods/messages/update/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py
similarity index 98%
rename from pyrogram/client/methods/messages/update/edit_message_caption.py
rename to pyrogram/client/methods/messages/edit_message_caption.py
index 90bf26f7..25276dc2 100644
--- a/pyrogram/client/methods/messages/update/edit_message_caption.py
+++ b/pyrogram/client/methods/messages/edit_message_caption.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class EditMessageCaption(BaseClient):
diff --git a/pyrogram/client/methods/messages/update/edit_message_reply_markup.py b/pyrogram/client/methods/messages/edit_message_reply_markup.py
similarity index 98%
rename from pyrogram/client/methods/messages/update/edit_message_reply_markup.py
rename to pyrogram/client/methods/messages/edit_message_reply_markup.py
index 295eb258..b840adab 100644
--- a/pyrogram/client/methods/messages/update/edit_message_reply_markup.py
+++ b/pyrogram/client/methods/messages/edit_message_reply_markup.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class EditMessageReplyMarkup(BaseClient):
diff --git a/pyrogram/client/methods/messages/update/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py
similarity index 98%
rename from pyrogram/client/methods/messages/update/edit_message_text.py
rename to pyrogram/client/methods/messages/edit_message_text.py
index be7b380c..741c0890 100644
--- a/pyrogram/client/methods/messages/update/edit_message_text.py
+++ b/pyrogram/client/methods/messages/edit_message_text.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class EditMessageText(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/__init__.py b/pyrogram/client/methods/messages/media/__init__.py
deleted file mode 100644
index b0e287c5..00000000
--- a/pyrogram/client/methods/messages/media/__init__.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-from .send_audio import SendAudio
-from .send_contact import SendContact
-from .send_document import SendDocument
-from .send_gif import SendGIF
-from .send_location import SendLocation
-from .send_media_group import SendMediaGroup
-from .send_photo import SendPhoto
-from .send_sticker import SendSticker
-from .send_venue import SendVenue
-from .send_video import SendVideo
-from .send_video_note import SendVideoNote
-from .send_voice import SendVoice
-
-
-class Media(
- SendContact,
- SendVenue,
- SendLocation,
- SendMediaGroup,
- SendVideoNote,
- SendVoice,
- SendVideo,
- SendGIF,
- SendSticker,
- SendDocument,
- SendAudio,
- SendPhoto
-):
- pass
diff --git a/pyrogram/client/methods/messages/media/send_audio.py b/pyrogram/client/methods/messages/send_audio.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_audio.py
rename to pyrogram/client/methods/messages/send_audio.py
index 41f4457f..7d590b79 100644
--- a/pyrogram/client/methods/messages/media/send_audio.py
+++ b/pyrogram/client/methods/messages/send_audio.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendAudio(BaseClient):
diff --git a/pyrogram/client/methods/messages/action/send_chat_action.py b/pyrogram/client/methods/messages/send_chat_action.py
similarity index 98%
rename from pyrogram/client/methods/messages/action/send_chat_action.py
rename to pyrogram/client/methods/messages/send_chat_action.py
index 4b34dd40..49625b48 100644
--- a/pyrogram/client/methods/messages/action/send_chat_action.py
+++ b/pyrogram/client/methods/messages/send_chat_action.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions
-from ....ext import BaseClient, ChatAction
+from pyrogram.client.ext import BaseClient, ChatAction
class SendChatAction(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_contact.py b/pyrogram/client/methods/messages/send_contact.py
similarity index 98%
rename from pyrogram/client/methods/messages/media/send_contact.py
rename to pyrogram/client/methods/messages/send_contact.py
index eb1bb6c4..fc0abdd5 100644
--- a/pyrogram/client/methods/messages/media/send_contact.py
+++ b/pyrogram/client/methods/messages/send_contact.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendContact(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_document.py b/pyrogram/client/methods/messages/send_document.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_document.py
rename to pyrogram/client/methods/messages/send_document.py
index 1092147f..b2b5c532 100644
--- a/pyrogram/client/methods/messages/media/send_document.py
+++ b/pyrogram/client/methods/messages/send_document.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendDocument(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_gif.py b/pyrogram/client/methods/messages/send_gif.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_gif.py
rename to pyrogram/client/methods/messages/send_gif.py
index 0d4bb4b9..a4a14d84 100644
--- a/pyrogram/client/methods/messages/media/send_gif.py
+++ b/pyrogram/client/methods/messages/send_gif.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendGIF(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_location.py b/pyrogram/client/methods/messages/send_location.py
similarity index 98%
rename from pyrogram/client/methods/messages/media/send_location.py
rename to pyrogram/client/methods/messages/send_location.py
index 08dac02b..a3db2561 100644
--- a/pyrogram/client/methods/messages/media/send_location.py
+++ b/pyrogram/client/methods/messages/send_location.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendLocation(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_media_group.py
rename to pyrogram/client/methods/messages/send_media_group.py
index 6d004d9f..297d8f83 100644
--- a/pyrogram/client/methods/messages/media/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -24,7 +24,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid
from pyrogram.client import types as pyrogram_types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendMediaGroup(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_photo.py b/pyrogram/client/methods/messages/send_photo.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_photo.py
rename to pyrogram/client/methods/messages/send_photo.py
index 52e98ff1..a6264bf3 100644
--- a/pyrogram/client/methods/messages/media/send_photo.py
+++ b/pyrogram/client/methods/messages/send_photo.py
@@ -22,7 +22,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendPhoto(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_sticker.py
rename to pyrogram/client/methods/messages/send_sticker.py
index 639e3600..fbf7a205 100644
--- a/pyrogram/client/methods/messages/media/send_sticker.py
+++ b/pyrogram/client/methods/messages/send_sticker.py
@@ -22,7 +22,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendSticker(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_venue.py b/pyrogram/client/methods/messages/send_venue.py
similarity index 98%
rename from pyrogram/client/methods/messages/media/send_venue.py
rename to pyrogram/client/methods/messages/send_venue.py
index d65ea43b..50946e86 100644
--- a/pyrogram/client/methods/messages/media/send_venue.py
+++ b/pyrogram/client/methods/messages/send_venue.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendVenue(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_video.py b/pyrogram/client/methods/messages/send_video.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_video.py
rename to pyrogram/client/methods/messages/send_video.py
index a4cc0309..b86b4702 100644
--- a/pyrogram/client/methods/messages/media/send_video.py
+++ b/pyrogram/client/methods/messages/send_video.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendVideo(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_video_note.py
rename to pyrogram/client/methods/messages/send_video_note.py
index d7b417d5..a266e5dd 100644
--- a/pyrogram/client/methods/messages/media/send_video_note.py
+++ b/pyrogram/client/methods/messages/send_video_note.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendVideoNote(BaseClient):
diff --git a/pyrogram/client/methods/messages/media/send_voice.py b/pyrogram/client/methods/messages/send_voice.py
similarity index 99%
rename from pyrogram/client/methods/messages/media/send_voice.py
rename to pyrogram/client/methods/messages/send_voice.py
index ae21de6d..f4fe4229 100644
--- a/pyrogram/client/methods/messages/media/send_voice.py
+++ b/pyrogram/client/methods/messages/send_voice.py
@@ -23,7 +23,7 @@ import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
-from ....ext import BaseClient, utils
+from pyrogram.client.ext import BaseClient, utils
class SendVoice(BaseClient):
diff --git a/pyrogram/client/methods/messages/update/__init__.py b/pyrogram/client/methods/messages/update/__init__.py
deleted file mode 100644
index cc913e23..00000000
--- a/pyrogram/client/methods/messages/update/__init__.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2018 Dan Tès
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram. If not, see .
-
-from .delete_messages import DeleteMessages
-from .edit_message_caption import EditMessageCaption
-from .edit_message_reply_markup import EditMessageReplyMarkup
-from .edit_message_text import EditMessageText
-
-
-class Update(
- DeleteMessages,
- EditMessageReplyMarkup,
- EditMessageCaption,
- EditMessageText
-):
- pass
From 6404862b878ba7c6deff3046d236d71c0ff26946 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 10:36:29 +0200
Subject: [PATCH 100/145] Add reply_keyboard and inline_keyboard filters
---
pyrogram/client/filters/filters.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index 26aa84c8..133ab6c2 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -19,6 +19,7 @@
import re
from .filter import Filter
+from ..types.reply_markup import InlineKeyboardMarkup, ReplyKeyboardMarkup
def build(name: str, func: callable, **kwargs) -> type:
@@ -131,7 +132,11 @@ class Filters:
pinned_message = build("PinnedMessage", lambda _, m: bool(m.pinned_message))
"""Filter service messages for pinned messages."""
- # TODO: Add filters for reply markups
+ reply_keyboard = build("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
+ """Filter messages containing reply keyboard markups"""
+
+ inline_keyboard = build("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
+ """Filter messages containing inline keyboard markups"""
@staticmethod
def command(command: str or list,
From 2ee7cf5124c43d5ad8cd0840dbe8b144db0395fc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 12:29:40 +0200
Subject: [PATCH 101/145] Add request_callback_answer method
---
.../methods/bots/request_callback_answer.py | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 pyrogram/client/methods/bots/request_callback_answer.py
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
new file mode 100644
index 00000000..5bc31efd
--- /dev/null
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -0,0 +1,51 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# This file is part of Pyrogram.
+#
+# Pyrogram is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pyrogram is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
+
+from pyrogram.api import functions
+from pyrogram.client.ext import BaseClient
+
+
+class RequestCallbackAnswer(BaseClient):
+ def request_callback_answer(self,
+ chat_id: int or str,
+ message_id: int,
+ callback_data: str):
+ """Use this method to request a callback answer from bots. This is the equivalent of clicking an inline button
+ containing callback data. The answer contains info useful for clients to display a notification at the top of
+ the chat screen or as an alert.
+
+ Args:
+ chat_id (``int`` | ``str``):
+ Unique identifier (int) or username (str) of the target chat.
+ For your personal cloud (Saved Messages) you can simply use "me" or "self".
+ For a contact that exists in your Telegram address book you can use his phone number (str).
+ For a private channel/supergroup you can use its *t.me/joinchat/* link.
+
+ message_id (``int``):
+ The message id the inline keyboard is attached on.
+
+ callback_data (``str``):
+ Callback data associated with the inline button you want to get the answer from.
+ """
+ return self.send(
+ functions.messages.GetBotCallbackAnswer(
+ peer=self.resolve_peer(chat_id),
+ msg_id=message_id,
+ data=callback_data.encode()
+ )
+ )
From d95086163e4b68b3431d8327a77c37c9c4473c60 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:09:07 +0200
Subject: [PATCH 102/145] Add click() bound method to Message
---
pyrogram/client/types/message.py | 113 +++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 74f2a0a6..43eaba2a 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -17,6 +17,7 @@
# along with Pyrogram. If not, see .
from pyrogram.api.core import Object
+from .reply_markup import InlineKeyboardMarkup, ReplyKeyboardMarkup
class Message(Object):
@@ -460,3 +461,115 @@ class Message(Object):
)
return True
+
+ def click(self, x: int or str, y: int = None, quote: bool = None):
+ """Use this method to click a button attached to the message.
+ It's a shortcut for:
+
+ - Clicking inline buttons:
+
+ .. code-block:: python
+
+ client.request_callback_answer(
+ chat_id=message.chat.id,
+ message_id=message.message_id,
+ callback_data=message.reply_markup[i][j].callback_data
+ )
+
+ - Clicking normal buttons:
+
+ .. code-block:: python
+
+ client.send_message(
+ chat_id=message.chat.id,
+ text=message.reply_markup[i][j].text
+ )
+
+ This method can be used in three different ways:
+
+ 1. Pass one integer argument only (e.g.: ``.click(2)``, to click a button at index 2).
+ Buttons are counted left to right, starting from the top.
+
+ 2. Pass two integer arguments (e.g.: ``.click(1, 0)``, to click a button at position (1, 0)).
+ The origin (0, 0) is top-left.
+
+ 3. Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
+ Only the first matching button will be pressed.
+
+ Args:
+ x (``int`` | ``str``):
+ Used as integer index, integer abscissa (in pair with y) or as string label.
+
+ y (``int``, *optional*):
+ Used as ordinate only (in pair with x).
+
+ quote (``bool``, *optional*):
+ Useful for normal buttons only, where pressing it will result in a new message sent.
+ If ``True``, the message will be sent as a reply to this message.
+ Defaults to ``True`` in group chats and ``False`` in private chats.
+
+ Returns:
+ - The result of *request_callback_answer()* in case of inline callback button clicks.
+ - The result of *reply_text()* in case of normal button clicks.
+ - A string in case the inline button is an URL, switch_inline_query or switch_inline_query_current_chat
+ button.
+
+ Raises:
+ :class:`Error `
+ ``ValueError``: If the provided index or position is out of range or the button label was not found.
+ """
+ if isinstance(self.reply_markup, ReplyKeyboardMarkup):
+ if quote is None:
+ quote = self.chat.type != "private"
+
+ return self.reply_text(x, quote=quote)
+ elif isinstance(self.reply_markup, InlineKeyboardMarkup):
+ if isinstance(x, int) and y is None:
+ try:
+ button = [
+ button
+ for row in self.reply_markup.inline_keyboard
+ for button in row
+ ][x]
+ except IndexError:
+ raise ValueError("The button at index {} doesn't exist".format(x)) from None
+ elif isinstance(x, int) and isinstance(y, int):
+ try:
+ button = self.reply_markup.inline_keyboard[y][x]
+ except IndexError:
+ raise ValueError("The button at position ({}, {}) doesn't exist".format(x, y)) from None
+ elif isinstance(x, str):
+ x = x.encode("utf-16", "surrogatepass").decode("utf-16")
+
+ try:
+ button = [
+ button
+ for row in self.reply_markup.inline_keyboard
+ for button in row
+ if x == button.text
+ ][0]
+ except IndexError:
+ raise ValueError(
+ "The button with label '{}' doesn't exists".format(
+ x.encode("unicode_escape").decode()
+ )
+ ) from None
+ else:
+ raise ValueError("Invalid arguments")
+
+ if button.callback_data:
+ return self._client.request_callback_answer(
+ chat_id=self.chat.id,
+ message_id=self.message_id,
+ data=button.callback_data
+ )
+ elif button.url:
+ return button.url
+ elif button.switch_inline_query:
+ return button.switch_inline_query
+ elif button.switch_inline_query_current_chat:
+ return button.switch_inline_query_current_chat
+ else:
+ raise ValueError("This button is not supported yet")
+ else:
+ raise ValueError("The message doesn't contain any keyboard")
From 03a17dd8dbd9b5081113341a142c340694635b34 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:24:31 +0200
Subject: [PATCH 103/145] Rename reply_text() to reply() Is shorter and looks
nicer. When more methods like reply_audio(), reply_photo(), etc. will be
implemented, I can consider adding reply_text() back again, maybe.
---
pyrogram/client/types/message.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 43eaba2a..8f677a2d 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -311,14 +311,14 @@ class Message(Object):
self.command = command
self.reply_markup = reply_markup
- def reply_text(self,
- text: str,
- quote: bool = None,
- parse_mode: str = "",
- disable_web_page_preview: bool = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ def reply(self,
+ text: str,
+ quote: bool = None,
+ parse_mode: str = "",
+ disable_web_page_preview: bool = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method as a shortcut for:
.. code-block:: python
@@ -510,7 +510,7 @@ class Message(Object):
Returns:
- The result of *request_callback_answer()* in case of inline callback button clicks.
- - The result of *reply_text()* in case of normal button clicks.
+ - The result of *reply()* in case of normal button clicks.
- A string in case the inline button is an URL, switch_inline_query or switch_inline_query_current_chat
button.
@@ -522,7 +522,7 @@ class Message(Object):
if quote is None:
quote = self.chat.type != "private"
- return self.reply_text(x, quote=quote)
+ return self.reply(x, quote=quote)
elif isinstance(self.reply_markup, InlineKeyboardMarkup):
if isinstance(x, int) and y is None:
try:
From 25a09d1c9b281c2d1f617df1517eb24ccbab088b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:25:19 +0200
Subject: [PATCH 104/145] Update docs welcome example
---
docs/source/index.rst | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 414e47dd..c52e239b 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -44,8 +44,7 @@ Welcome to Pyrogram
@app.on_message(Filters.private)
def hello(client, message):
- message.reply_text(
- "Hello {}".format(message.from_user.first_name))
+ message.reply("Hello {}".format(message.from_user.first_name))
app.run()
From 69ca31b12ec98b9ba09782a8274a67fb9e876835 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:26:23 +0200
Subject: [PATCH 105/145] Update README.rst
---
README.rst | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.rst b/README.rst
index eb49c635..b1015db2 100644
--- a/README.rst
+++ b/README.rst
@@ -12,8 +12,7 @@ Pyrogram |twitter|
@app.on_message(Filters.private)
def hello(client, message):
- message.reply_text(
- "Hello {}".format(message.from_user.first_name))
+ message.reply("Hello {}".format(message.from_user.first_name))
app.run()
From fe0744a23fcfa585cb2ad83b6245e013efb17cdc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:42:04 +0200
Subject: [PATCH 106/145] Remove requirements_extras.txt There's only an extra
requirement: TgCrypto. Let's not keep a whole file just for that.
---
requirements_extras.txt | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 requirements_extras.txt
diff --git a/requirements_extras.txt b/requirements_extras.txt
deleted file mode 100644
index 1d101a7e..00000000
--- a/requirements_extras.txt
+++ /dev/null
@@ -1 +0,0 @@
-tgcrypto>=1.0.4
\ No newline at end of file
From 2b94f46728982f77eb3e6fb4ad36106e7abc6853 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:42:26 +0200
Subject: [PATCH 107/145] Add TgCrypto as extra requirement in setup.py
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index ef703729..00f9be63 100644
--- a/setup.py
+++ b/setup.py
@@ -85,5 +85,5 @@ setup(
packages=find_packages(exclude=["compiler*"]),
zip_safe=False,
install_requires=read("requirements.txt"),
- extras_require={"tgcrypto": read("requirements_extras.txt")}
+ extras_require={"tgcrypto": ["tgcrypto>=1.0.4"]}
)
From 7f11f85c8fd57c972043547d3f760a810597ec98 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 15:45:48 +0200
Subject: [PATCH 108/145] Move signal handler inside idle
---
pyrogram/client/client.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 6db22fa4..24bf09eb 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -280,9 +280,6 @@ class Client(Methods, BaseClient):
self.is_started = False
self.session.stop()
- def signal_handler(self, *args):
- self.is_idle = False
-
def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
"""Blocks the program execution until one of the signals are received,
then gently stop the Client by closing the underlying connection.
@@ -292,8 +289,11 @@ class Client(Methods, BaseClient):
Iterable containing signals the signal handler will listen to.
Defaults to (SIGINT, SIGTERM, SIGABRT).
"""
+ def signal_handler(*args):
+ self.is_idle = False
+
for s in stop_signals:
- signal(s, self.signal_handler)
+ signal(s, signal_handler)
self.is_idle = True
From f701ee46f64823a158fe01a4fbfe76dd6f799de6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 16:04:34 +0200
Subject: [PATCH 109/145] Update scheme to Layer 81
---
compiler/api/source/main_api.tl | 82 +++++++++++++++++++++++++++++----
1 file changed, 74 insertions(+), 8 deletions(-)
diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl
index 2919520e..d1f2fa33 100644
--- a/compiler/api/source/main_api.tl
+++ b/compiler/api/source/main_api.tl
@@ -60,6 +60,7 @@ inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
+inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
@@ -149,6 +150,8 @@ messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDis
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#abe9affe domain:string = MessageAction;
+messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction;
+messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction;
dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
@@ -164,7 +167,7 @@ geoPoint#2049d70c long:double lat:double = GeoPoint;
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
-auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
+auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode;
auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
@@ -452,12 +455,12 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s
account.authorizations#1250abde authorizations:Vector = account.Authorizations;
-account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password;
-account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password;
+account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password;
+account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password;
-account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings;
+account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings;
-account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings;
+account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
@@ -545,7 +548,7 @@ channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant;
-help.termsOfService#f1ee3e90 text:string = help.TermsOfService;
+help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService;
foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
@@ -830,6 +833,56 @@ inputClientProxy#75588b3f address:string port:int = InputClientProxy;
help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData;
+help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate;
+help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate;
+
+inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile;
+inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile;
+
+secureFileEmpty#64199744 = SecureFile;
+secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile;
+
+secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData;
+
+securePlainPhone#7d6099dd phone:string = SecurePlainData;
+securePlainEmail#21ec5a5f email:string = SecurePlainData;
+
+secureValueTypePersonalDetails#9d2a81e3 = SecureValueType;
+secureValueTypePassport#3dac6a00 = SecureValueType;
+secureValueTypeDriverLicense#6e425c4 = SecureValueType;
+secureValueTypeIdentityCard#a0d0744b = SecureValueType;
+secureValueTypeInternalPassport#99a48f23 = SecureValueType;
+secureValueTypeAddress#cbe31e26 = SecureValueType;
+secureValueTypeUtilityBill#fc36954e = SecureValueType;
+secureValueTypeBankStatement#89137c0d = SecureValueType;
+secureValueTypeRentalAgreement#8b883488 = SecureValueType;
+secureValueTypePassportRegistration#99e3806a = SecureValueType;
+secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType;
+secureValueTypePhone#b320aadb = SecureValueType;
+secureValueTypeEmail#8e3ca7ee = SecureValueType;
+
+secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
+
+inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue;
+
+secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;
+
+secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError;
+secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError;
+
+secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;
+
+account.authorizationForm#cb976d53 flags:# selfie_required:flags.1?true required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm;
+
+account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;
+
+help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
+help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo;
+
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -885,9 +938,20 @@ account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPass
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
account.resetWebAuthorization#2d01b9ef hash:long = Bool;
account.resetWebAuthorizations#682d2594 = Bool;
+account.getAllSecureValues#b288bc7d = Vector;
+account.getSecureValue#73665bc2 types:Vector = Vector;
+account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue;
+account.deleteSecureValue#b880bc4b types:Vector = Bool;
+account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
+account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool;
+account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
+account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
+account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
+account.verifyEmail#ecba39db email:string code:string = Bool;
users.getUsers#d91a548 id:Vector = Vector;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
+users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool;
contacts.getStatuses#c4a353ee = Vector;
contacts.getContacts#c023849f hash:int = contacts.Contacts;
@@ -1027,11 +1091,13 @@ help.saveAppLog#6f02f748 events:Vector = Bool;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
-help.getTermsOfService#8e59b7e7 country_iso2:string = help.TermsOfService;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
help.getProxyData#3d7758e1 = help.ProxyData;
+help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
+help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
+help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages;
@@ -1095,4 +1161,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector;
-// LAYER 79
+// LAYER 81
From fc541221eddbb4f29b3fba13f5a533c8c8514279 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 16:08:28 +0200
Subject: [PATCH 110/145] Accept terms of service after successfully signing in
---
pyrogram/client/client.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 24bf09eb..17833310 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -456,6 +456,7 @@ class Client(Methods, BaseClient):
phone_registered = r.phone_registered
phone_code_hash = r.phone_code_hash
+ terms_of_service = r.terms_of_service
if self.force_sms:
self.send(
@@ -562,6 +563,8 @@ class Client(Methods, BaseClient):
else:
break
+ assert self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
+
self.password = None
self.user_id = r.user.id
From 602f4581c6e446720dfd0bb5cb42dce827fb20d1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 16:15:09 +0200
Subject: [PATCH 111/145] Remove custom TOS
---
pyrogram/client/ext/base_client.py | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index a3279157..578cf168 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -26,16 +26,6 @@ from ...session.internals import MsgId
class BaseClient:
- TOS = (
- "By using Pyrogram you accept Telegram's Terms of Service (https://telegram.org/tos) and agree not to:\n\n"
-
- "- Use the library to send spam or scam users.\n"
- "- Promote violence on publicly viewable Telegram bots, groups or channels.\n"
- "- Post illegal pornographic content on publicly viewable Telegram bots, groups or channels.\n\n"
-
- "We reserve the right to update these Terms of Service later.\n"
- )
-
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100
From 0cd479531815cdc744732a462faaa1462a60f225 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 16:15:44 +0200
Subject: [PATCH 112/145] Use TOS provided by Telegram
---
pyrogram/client/client.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index a6250d74..4787c7af 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -199,8 +199,6 @@ class Client(Methods, BaseClient):
self.is_started = True
if self.user_id is None:
- print(self.TOS)
-
if self.token is None:
self.authorize_user()
else:
@@ -460,6 +458,9 @@ class Client(Methods, BaseClient):
phone_code_hash = r.phone_code_hash
terms_of_service = r.terms_of_service
+ if terms_of_service:
+ print("\n" + terms_of_service.text + "\n")
+
if self.force_sms:
self.send(
functions.auth.ResendCode(
@@ -565,7 +566,8 @@ class Client(Methods, BaseClient):
else:
break
- assert self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
+ if terms_of_service:
+ assert self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
self.password = None
self.user_id = r.user.id
From 8e5ec7165a580ca406c6c8c3db3e904c7766f771 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 14:22:50 +0200
Subject: [PATCH 113/145] Update README.rst
---
README.rst | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/README.rst b/README.rst
index b1015db2..e704d46a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
|header|
-Pyrogram |twitter|
-==================
+Pyrogram
+========
.. code-block:: python
@@ -26,8 +26,8 @@ Features
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
-- **Updated** to the latest Telegram API version, currently Layer 76 running on MTProto 2.0.
-- **Documented**: Pyrogram API methods are documented and resemble the Telegram Bot API.
+- **Updated** to the latest Telegram API version, currently Layer 79 on top of MTProto 2.0.
+- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
Requirements
@@ -54,7 +54,7 @@ Getting Started
Contributing
------------
-Pyrogram is brand new! **You are welcome to try it and help make it better** by either submitting pull
+Pyrogram is brand new, and **you are welcome to try it and help make it even better** by either submitting pull
requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code
and documentation. Any help is appreciated!
@@ -100,28 +100,25 @@ Copyright & License
-
+
-
-.. |twitter| image:: https://media.pyrogram.ml/images/twitter.svg
- :target: https://twitter.com/intent/tweet?text=Build%20custom%20Telegram%20applications%20with%20Pyrogram&url=https://github.com/pyrogram/pyrogram&hashtags=Telegram,MTProto,Python
-
.. |logo| image:: https://pyrogram.ml/images/logo.png
:target: https://pyrogram.ml
:alt: Pyrogram
.. |description| replace:: **Telegram MTProto API Client Library for Python**
-.. |scheme| image:: https://www.pyrogram.ml/images/scheme.svg
+.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2079-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
:target: compiler/api/source/main_api.tl
- :alt: Scheme Layer 76
+ :alt: Scheme Layer
-.. |tgcrypto| image:: https://www.pyrogram.ml/images/tgcrypto.svg
+.. |tgcrypto| image:: "https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
:target: https://github.com/pyrogram/tgcrypto
:alt: TgCrypto
From 24572fcb65a33567b9e0040e28e1b87d33142d0f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 14:26:52 +0200
Subject: [PATCH 114/145] Remove requirements_extras.txt from MANIFEST.in
---
MANIFEST.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index a1d19d94..f818e13a 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,5 @@
## Include
-include COPYING COPYING.lesser NOTICE requirements.txt requirements_extras.txt
+include COPYING COPYING.lesser NOTICE requirements.txt
recursive-include compiler *.py *.tl *.tsv *.txt
## Exclude
From 66f91b1b63ac54f1fd06fe7f869790315ea6fef8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 14:31:06 +0200
Subject: [PATCH 115/145] Update dev version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 531da722..dce17c91 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès
Date: Sun, 24 Jun 2018 16:11:22 +0200
Subject: [PATCH 116/145] Pass the phone number when calling the phone_code
callback function
---
pyrogram/client/client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 24bf09eb..91bdc1a6 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -469,7 +469,7 @@ class Client(Methods, BaseClient):
self.phone_code = (
input("Enter phone code: ") if self.phone_code is None
else self.phone_code if type(self.phone_code) is str
- else str(self.phone_code())
+ else str(self.phone_code(self.phone_number))
)
try:
From 44f71f096fe9e90fffca098ad9b37d54d025bbd0 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 16:53:07 +0200
Subject: [PATCH 117/145] Better docs for phone_code argument
---
pyrogram/client/client.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 91bdc1a6..2312d6dd 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -93,8 +93,8 @@ class Client(Methods, BaseClient):
entering it manually. Only applicable for new sessions.
phone_code (``str`` | ``callable``, *optional*):
- Pass the phone code as string (for test numbers only), or pass a callback function
- which must return the correct phone code as string (e.g., "12345").
+ Pass the phone code as string (for test numbers only), or pass a callback function which accepts
+ a single positional argument *(phone_number)* and must return the correct phone code (e.g., "12345").
Only applicable for new sessions.
password (``str``, *optional*):
From 50ab50eb529c88932aa2e3a1b1c0cfa62f7d65c6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 17:13:17 +0200
Subject: [PATCH 118/145] Update AutoAuthorization page
---
docs/source/resources/AutoAuthorization.rst | 24 ++++++++++++++-------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/docs/source/resources/AutoAuthorization.rst b/docs/source/resources/AutoAuthorization.rst
index 73504f80..d7a099fe 100644
--- a/docs/source/resources/AutoAuthorization.rst
+++ b/docs/source/resources/AutoAuthorization.rst
@@ -14,27 +14,31 @@ Log In
To automate the **Log In** process, pass your ``phone_number`` and ``password`` (if you have one) in the Client parameters.
If you want to retrieve the phone code programmatically, pass a callback function in the ``phone_code`` field — this
-function must return the correct phone code as string (e.g., "12345") — otherwise, ignore this parameter, Pyrogram will
-ask you to input the phone code manually.
+function accepts a single positional argument (phone_number) and must return the correct phone code (e.g., "12345")
+— otherwise, ignore this parameter, Pyrogram will ask you to input the phone code manually.
+
+Example:
.. code-block:: python
from pyrogram import Client
- def phone_code_callback():
+ def phone_code_callback(phone_number):
code = ... # Get your code programmatically
- return code # Must be string, e.g., "12345"
+ return code # e.g., "12345"
app = Client(
session_name="example",
phone_number="39**********",
- phone_code=phone_code_callback,
+ phone_code=phone_code_callback, # Note the missing parentheses
password="password" # (if you have one)
)
app.start()
+
print(app.get_me())
+
app.stop()
Sign Up
@@ -44,23 +48,27 @@ To automate the **Sign Up** process (i.e., automatically create a new Telegram a
``first_name`` and ``last_name`` fields alongside the other parameters; they will be used to automatically create a new
Telegram account in case the phone number you passed is not registered yet.
+Example:
+
.. code-block:: python
from pyrogram import Client
- def phone_code_callback():
+ def phone_code_callback(phone_number):
code = ... # Get your code programmatically
- return code # Must be string, e.g., "12345"
+ return code # e.g., "12345"
app = Client(
session_name="example",
phone_number="39**********",
- phone_code=phone_code_callback,
+ phone_code=phone_code_callback, # Note the missing parentheses
first_name="Pyrogram",
last_name="" # Can be an empty string
)
app.start()
+
print(app.get_me())
+
app.stop()
\ No newline at end of file
From 69d1432251c15a150d639d2a547729b5d3ee105a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 17:47:29 +0200
Subject: [PATCH 119/145] Allow user-defined values for retries and timeout
---
pyrogram/client/client.py | 10 ++++++++--
pyrogram/client/ext/base_client.py | 3 ++-
pyrogram/session/session.py | 10 +++++-----
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 2312d6dd..1897e8d3 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -817,7 +817,7 @@ class Client(Methods, BaseClient):
log.debug("{} stopped".format(name))
- def send(self, data: Object):
+ def send(self, data: Object, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT):
"""Use this method to send Raw Function queries.
This method makes possible to manually call every single Telegram API method in a low-level manner.
@@ -828,13 +828,19 @@ class Client(Methods, BaseClient):
data (``Object``):
The API Scheme function filled with proper arguments.
+ retries (``int``):
+ Number of retries.
+
+ timeout (``float``):
+ Timeout in seconds.
+
Raises:
:class:`Error `
"""
if not self.is_started:
raise ConnectionError("Client has not been started")
- r = self.session.send(data)
+ r = self.session.send(data, retries, timeout)
self.fetch_peers(getattr(r, "users", []))
self.fetch_peers(getattr(r, "chats", []))
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 578cf168..d8e30283 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -23,6 +23,7 @@ from threading import Lock
from ..style import Markdown, HTML
from ...api.core import Object
from ...session.internals import MsgId
+from ...session import Session
class BaseClient:
@@ -77,7 +78,7 @@ class BaseClient:
self.disconnect_handler = None
- def send(self, data: Object):
+ def send(self, data: Object, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT):
pass
def resolve_peer(self, peer_id: int or str):
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 7e90cfff..d8c8651d 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -391,7 +391,7 @@ class Session:
log.debug("RecvThread stopped")
- def _send(self, data: Object, wait_response: bool = True):
+ def _send(self, data: Object, wait_response: bool = True, timeout: float = WAIT_TIMEOUT):
message = self.msg_factory(data)
msg_id = message.msg_id
@@ -407,7 +407,7 @@ class Session:
raise e
if wait_response:
- self.results[msg_id].event.wait(self.WAIT_TIMEOUT)
+ self.results[msg_id].event.wait(timeout)
result = self.results.pop(msg_id).value
if result is None:
@@ -422,11 +422,11 @@ class Session:
else:
return result
- def send(self, data: Object, retries: int = MAX_RETRIES):
+ def send(self, data: Object, retries: int = MAX_RETRIES, timeout: float = WAIT_TIMEOUT):
self.is_connected.wait(self.WAIT_TIMEOUT)
try:
- return self._send(data)
+ return self._send(data, timeout=timeout)
except (OSError, TimeoutError, InternalServerError) as e:
if retries == 0:
raise e from None
@@ -437,4 +437,4 @@ class Session:
datetime.now(), type(data)))
time.sleep(0.5)
- return self.send(data, retries - 1)
+ return self.send(data, retries - 1, timeout)
From 166b3646ac5d862968e53ffb2608d1e01f8210f7 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 17:48:33 +0200
Subject: [PATCH 120/145] Make request_callback_answer try only once with a
timeout of 10 seconds
---
pyrogram/client/methods/bots/request_callback_answer.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
index 5bc31efd..e5871dd8 100644
--- a/pyrogram/client/methods/bots/request_callback_answer.py
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -47,5 +47,7 @@ class RequestCallbackAnswer(BaseClient):
peer=self.resolve_peer(chat_id),
msg_id=message_id,
data=callback_data.encode()
- )
+ ),
+ retries=0,
+ timeout=10
)
From 56f616c753228653214c1a848348226182f66206 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 17:50:30 +0200
Subject: [PATCH 121/145] Mention timeout and retries in docs for
request_callback_answer
---
.../client/methods/bots/request_callback_answer.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
index e5871dd8..52dab58c 100644
--- a/pyrogram/client/methods/bots/request_callback_answer.py
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -25,9 +25,8 @@ class RequestCallbackAnswer(BaseClient):
chat_id: int or str,
message_id: int,
callback_data: str):
- """Use this method to request a callback answer from bots. This is the equivalent of clicking an inline button
- containing callback data. The answer contains info useful for clients to display a notification at the top of
- the chat screen or as an alert.
+ """Use this method to request a callback answer from bots. This is the equivalent of clicking an
+ inline button containing callback data.
Args:
chat_id (``int`` | ``str``):
@@ -41,6 +40,14 @@ class RequestCallbackAnswer(BaseClient):
callback_data (``str``):
Callback data associated with the inline button you want to get the answer from.
+
+ Returns:
+ The answer containing info useful for clients to display a notification at the top of the chat screen
+ or as an alert.
+
+ Raises:
+ :class:`Error `
+ ``TimeoutError``: If the bot fails to answer within 10 seconds
"""
return self.send(
functions.messages.GetBotCallbackAnswer(
From f4c0793a0b67713f74571d1971b26e1790f4b32f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 18:26:11 +0200
Subject: [PATCH 122/145] Make session leaner by removing some redundant
parameters Related to #86
---
pyrogram/client/client.py | 38 ++++++++---------------
pyrogram/client/ext/base_client.py | 19 +++++++++++-
pyrogram/session/session.py | 48 ++++++++++--------------------
3 files changed, 47 insertions(+), 58 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 1897e8d3..dde583dc 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -187,12 +187,9 @@ class Client(Methods, BaseClient):
self.load_session()
self.session = Session(
+ self,
self.dc_id,
- self.test_mode,
- self._proxy,
- self.auth_key,
- self.api_id,
- client=self
+ self.auth_key
)
self.session.start()
@@ -372,12 +369,9 @@ class Client(Methods, BaseClient):
self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
+ self,
self.dc_id,
- self.test_mode,
- self._proxy,
- self.auth_key,
- self.api_id,
- client=self
+ self.auth_key
)
self.session.start()
@@ -420,12 +414,9 @@ class Client(Methods, BaseClient):
self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
+ self,
self.dc_id,
- self.test_mode,
- self._proxy,
- self.auth_key,
- self.api_id,
- client=self
+ self.auth_key
)
self.session.start()
@@ -1033,7 +1024,7 @@ class Client(Methods, BaseClient):
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
- session = Session(self.dc_id, self.test_mode, self._proxy, self.auth_key, self.api_id)
+ session = Session(self, self.dc_id, self.auth_key, is_media=True)
session.start()
try:
@@ -1117,11 +1108,10 @@ class Client(Methods, BaseClient):
)
session = Session(
+ self,
dc_id,
- self.test_mode,
- self._proxy,
Auth(dc_id, self.test_mode, self._proxy).create(),
- self.api_id
+ is_media=True
)
session.start()
@@ -1136,11 +1126,10 @@ class Client(Methods, BaseClient):
)
else:
session = Session(
+ self,
dc_id,
- self.test_mode,
- self._proxy,
self.auth_key,
- self.api_id
+ is_media=True
)
session.start()
@@ -1206,11 +1195,10 @@ class Client(Methods, BaseClient):
if cdn_session is None:
cdn_session = Session(
+ self,
r.dc_id,
- self.test_mode,
- self._proxy,
Auth(r.dc_id, self.test_mode, self._proxy).create(),
- self.api_id,
+ is_media=True,
is_cdn=True
)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index d8e30283..cd54570d 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -16,17 +16,34 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import platform
import re
from queue import Queue
from threading import Lock
+from pyrogram import __version__
from ..style import Markdown, HTML
from ...api.core import Object
-from ...session.internals import MsgId
from ...session import Session
+from ...session.internals import MsgId
class BaseClient:
+ APP_VERSION = "Pyrogram \U0001f525 {}".format(__version__)
+
+ DEVICE_MODEL = "{} {}".format(
+ platform.python_implementation(),
+ platform.python_version()
+ )
+
+ SYSTEM_VERSION = "{} {}".format(
+ platform.system(),
+ platform.release()
+ )
+
+ SYSTEM_LANG_CODE = "en"
+ LANG_CODE = "en"
+
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index d8c8651d..b643650b 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -17,7 +17,6 @@
# along with Pyrogram. If not, see .
import logging
-import platform
import threading
import time
from datetime import timedelta, datetime
@@ -47,19 +46,6 @@ class Result:
class Session:
- VERSION = __version__
- APP_VERSION = "Pyrogram \U0001f525 {}".format(VERSION)
-
- DEVICE_MODEL = "{} {}".format(
- platform.python_implementation(),
- platform.python_version()
- )
-
- SYSTEM_VERSION = "{} {}".format(
- platform.system(),
- platform.release()
- )
-
INITIAL_SALT = 0x616e67656c696361
NET_WORKERS = 1
WAIT_TIMEOUT = 15
@@ -84,28 +70,24 @@ class Session:
}
def __init__(self,
+ client: pyrogram,
dc_id: int,
- test_mode: bool,
- proxy: dict,
auth_key: bytes,
- api_id: int,
- is_cdn: bool = False,
- client: pyrogram = None):
+ is_media: bool = False,
+ is_cdn: bool = False):
if not Session.notice_displayed:
print("Pyrogram v{}, {}".format(__version__, __copyright__))
print("Licensed under the terms of the " + __license__, end="\n\n")
Session.notice_displayed = True
- self.dc_id = dc_id
- self.test_mode = test_mode
- self.proxy = proxy
- self.api_id = api_id
- self.is_cdn = is_cdn
self.client = client
+ self.dc_id = dc_id
+ self.auth_key = auth_key
+ self.is_media = is_media
+ self.is_cdn = is_cdn
self.connection = None
- self.auth_key = auth_key
self.auth_key_id = sha1(auth_key).digest()[-8:]
self.session_id = Long(MsgId())
@@ -130,7 +112,7 @@ class Session:
def start(self):
while True:
- self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
+ self.connection = Connection(DataCenter(self.dc_id, self.client.test_mode), self.client.proxy)
try:
self.connection.connect()
@@ -159,12 +141,14 @@ class Session:
functions.InvokeWithLayer(
layer,
functions.InitConnection(
- self.api_id,
- self.DEVICE_MODEL,
- self.SYSTEM_VERSION,
- self.APP_VERSION,
- "en", "", "en",
- functions.help.GetConfig(),
+ api_id=self.client.api_id,
+ device_model=self.client.DEVICE_MODEL,
+ system_version=self.client.SYSTEM_VERSION,
+ app_version=self.client.APP_VERSION,
+ system_lang_code=self.client.SYSTEM_LANG_CODE,
+ lang_code=self.client.LANG_CODE,
+ lang_pack="",
+ query=functions.help.GetConfig(),
)
)
)
From 55ef4abb2737a3e829c7693d927cd6bcfb5075b5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 18:47:49 +0200
Subject: [PATCH 123/145] Allow user-defined session properties. Related to #86
This commit adds five 5 extra parameters to the Client class: app_version,
device_model, system_version, system_lang_code, lang_code
---
pyrogram/client/client.py | 72 +++++++++++++++++++++++++++++++++++++
pyrogram/session/session.py | 10 +++---
2 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index dde583dc..e2fe648e 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -129,6 +129,11 @@ class Client(Methods, BaseClient):
session_name: str,
api_id: int or str = None,
api_hash: str = None,
+ app_version: str = None,
+ device_model: str = None,
+ system_version: str = None,
+ system_lang_code: str = None,
+ lang_code: str = None,
proxy: dict = None,
test_mode: bool = False,
phone_number: str = None,
@@ -145,6 +150,11 @@ class Client(Methods, BaseClient):
self.session_name = session_name
self.api_id = int(api_id) if api_id else None
self.api_hash = api_hash
+ self.app_version = app_version
+ self.device_model = device_model
+ self.system_version = system_version
+ self.system_lang_code = system_lang_code
+ self.lang_code = lang_code
# TODO: Make code consistent, use underscore for private/protected fields
self._proxy = proxy
self.test_mode = test_mode
@@ -854,6 +864,68 @@ class Client(Methods, BaseClient):
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
)
+ # TODO: Woah! Some redundant code down here
+
+ if self.app_version:
+ pass
+ else:
+ self.app_version = Client.APP_VERSION
+
+ if parser.has_section("pyrogram"):
+ self.app_version = parser.get(
+ "pyrogram",
+ "app_version",
+ fallback=Client.APP_VERSION
+ )
+
+ if self.device_model:
+ pass
+ else:
+ self.device_model = Client.DEVICE_MODEL
+
+ if parser.has_section("pyrogram"):
+ self.device_model = parser.get(
+ "pyrogram",
+ "device_model",
+ fallback=Client.DEVICE_MODEL
+ )
+
+ if self.system_version:
+ pass
+ else:
+ self.system_version = Client.SYSTEM_VERSION
+
+ if parser.has_section("pyrogram"):
+ self.system_version = parser.get(
+ "pyrogram",
+ "system_version",
+ fallback=Client.SYSTEM_VERSION
+ )
+
+ if self.system_lang_code:
+ pass
+ else:
+ self.system_lang_code = Client.SYSTEM_LANG_CODE
+
+ if parser.has_section("pyrogram"):
+ self.system_lang_code = parser.get(
+ "pyrogram",
+ "system_lang_code",
+ fallback=Client.SYSTEM_LANG_CODE
+ )
+
+ if self.lang_code:
+ pass
+ else:
+ self.lang_code = Client.LANG_CODE
+
+ if parser.has_section("pyrogram"):
+ self.lang_code = parser.get(
+ "pyrogram",
+ "lang_code",
+ fallback=Client.LANG_CODE
+ )
+
if self._proxy:
self._proxy["enabled"] = True
else:
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index b643650b..77188156 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -142,11 +142,11 @@ class Session:
layer,
functions.InitConnection(
api_id=self.client.api_id,
- device_model=self.client.DEVICE_MODEL,
- system_version=self.client.SYSTEM_VERSION,
- app_version=self.client.APP_VERSION,
- system_lang_code=self.client.SYSTEM_LANG_CODE,
- lang_code=self.client.LANG_CODE,
+ app_version=self.client.app_version,
+ device_model=self.client.device_model,
+ system_version=self.client.system_version,
+ system_lang_code=self.client.system_lang_code,
+ lang_code=self.client.lang_code,
lang_pack="",
query=functions.help.GetConfig(),
)
From 9a012077cc11edaffa79680ae6cc5ac5f4db5f3a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 18:54:47 +0200
Subject: [PATCH 124/145] Remove some redundant code. Related to #86
---
pyrogram/client/client.py | 59 ++++++++-------------------------------
1 file changed, 11 insertions(+), 48 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index e2fe648e..be6d5385 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -864,55 +864,18 @@ class Client(Methods, BaseClient):
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
)
- # TODO: Woah! Some redundant code down here
+ for option in {"app_version", "device_model", "system_version", "system_lang_code", "lang_code"}:
+ if getattr(self, option):
+ pass
+ else:
+ setattr(self, option, Client.APP_VERSION)
- if self.app_version:
- pass
- else:
- self.app_version = Client.APP_VERSION
-
- if parser.has_section("pyrogram"):
- self.app_version = parser.get(
- "pyrogram",
- "app_version",
- fallback=Client.APP_VERSION
- )
-
- if self.device_model:
- pass
- else:
- self.device_model = Client.DEVICE_MODEL
-
- if parser.has_section("pyrogram"):
- self.device_model = parser.get(
- "pyrogram",
- "device_model",
- fallback=Client.DEVICE_MODEL
- )
-
- if self.system_version:
- pass
- else:
- self.system_version = Client.SYSTEM_VERSION
-
- if parser.has_section("pyrogram"):
- self.system_version = parser.get(
- "pyrogram",
- "system_version",
- fallback=Client.SYSTEM_VERSION
- )
-
- if self.system_lang_code:
- pass
- else:
- self.system_lang_code = Client.SYSTEM_LANG_CODE
-
- if parser.has_section("pyrogram"):
- self.system_lang_code = parser.get(
- "pyrogram",
- "system_lang_code",
- fallback=Client.SYSTEM_LANG_CODE
- )
+ if parser.has_section("pyrogram"):
+ setattr(self, option, parser.get(
+ "pyrogram",
+ option,
+ fallback=getattr(Client, option.upper())
+ ))
if self.lang_code:
pass
From 9c420bb73b4ac297377e8a94dff125e91cbb11cf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 19:08:52 +0200
Subject: [PATCH 125/145] Document the new parameters. Closes #86
---
pyrogram/client/client.py | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index be6d5385..519823a0 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -77,6 +77,26 @@ class Client(Methods, BaseClient):
The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef"
This is an alternative way to pass it if you don't want to use the *config.ini* file.
+ app_version (``str``, *optional*):
+ Application version. Defaults to "Pyrogram \U0001f525 vX.Y.Z"
+ This is an alternative way to set it if you don't want to use the *config.ini* file.
+
+ device_model (``str``, *optional*):
+ Device model. Defaults to *platform.python_implementation() + " " + platform.python_version()*
+ This is an alternative way to set it if you don't want to use the *config.ini* file.
+
+ system_version (``str``, *optional*):
+ Operating System version. Defaults to *platform.system() + " " + platform.release()*
+ This is an alternative way to set it if you don't want to use the *config.ini* file.
+
+ system_lang_code (``str``, *optional*):
+ Code of the language used on the system, in ISO 639-1 standard. Defaults to "en".
+ This is an alternative way to set it if you don't want to use the *config.ini* file.
+
+ lang_code (``str``, *optional*):
+ Code of the language used on the client, in ISO 639-1 standard. Defaults to "en".
+ This is an alternative way to set it if you don't want to use the *config.ini* file.
+
proxy (``dict``, *optional*):
Your SOCKS5 Proxy settings as dict,
e.g.: *dict(hostname="11.22.33.44", port=1080, username="user", password="pass")*.
From fa7b7d0ce353f6f66efd4da0ebd3b7bfa08714ee Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 19:09:22 +0200
Subject: [PATCH 126/145] Cleanup Client class
---
pyrogram/client/client.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 519823a0..366ab4b2 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -51,9 +51,6 @@ from .dispatcher import Dispatcher
from .ext import utils, Syncer, BaseClient
from .methods import Methods
-# Custom format for nice looking log lines
-LOG_FORMAT = "[%(asctime)s.%(msecs)03d] %(filename)s:%(lineno)s %(levelname)s: %(message)s"
-
log = logging.getLogger(__name__)
@@ -316,6 +313,7 @@ class Client(Methods, BaseClient):
Iterable containing signals the signal handler will listen to.
Defaults to (SIGINT, SIGTERM, SIGABRT).
"""
+
def signal_handler(*args):
self.is_idle = False
From c7d60ef8a69eea7f38504871643f69e6bae15dc4 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 19:29:12 +0200
Subject: [PATCH 127/145] Fix disconnect handler callback being called on every
session
---
pyrogram/session/session.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 77188156..7bafd71f 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -197,7 +197,7 @@ class Session:
for i in self.results.values():
i.event.set()
- if self.client and callable(self.client.disconnect_handler):
+ if not self.is_media and callable(self.client.disconnect_handler):
try:
self.client.disconnect_handler(self.client)
except Exception as e:
From a04b08f245f6ee31eb5c9a457f43b3d592b275a6 Mon Sep 17 00:00:00 2001
From: YoilyL
Date: Sun, 24 Jun 2018 22:58:17 +0300
Subject: [PATCH 128/145] Fixed tiny typo
---
pyrogram/client/types/message.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 8f677a2d..ce6d158f 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -332,7 +332,7 @@ class Message(Object):
Example:
.. code-block:: python
- message.reply_text("hello", quote=True)
+ message.reply("hello", quote=True)
Args:
text (``str``):
From 355281f081d9d047650ba572771043b8306641db Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 25 Jun 2018 00:49:01 +0200
Subject: [PATCH 129/145] Update README.rst
---
README.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.rst b/README.rst
index e704d46a..0b9efb76 100644
--- a/README.rst
+++ b/README.rst
@@ -26,7 +26,7 @@ Features
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
-- **Updated** to the latest Telegram API version, currently Layer 79 on top of MTProto 2.0.
+- **Updated** to the latest Telegram API version, currently Layer 81 on top of MTProto 2.0.
- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
@@ -100,7 +100,7 @@ Copyright & License
-
@@ -115,7 +115,7 @@ Copyright & License
.. |description| replace:: **Telegram MTProto API Client Library for Python**
-.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2079-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
+.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2081-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
:target: compiler/api/source/main_api.tl
:alt: Scheme Layer
From 04a86054b09ea2589703aea274907c4836a69b4f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 25 Jun 2018 00:53:45 +0200
Subject: [PATCH 130/145] Update to dev version 0.7.5.dev5
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index dce17c91..daddb08f 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès
Date: Mon, 25 Jun 2018 18:06:00 +0200
Subject: [PATCH 131/145] Add CustomizeSessions page
---
docs/source/index.rst | 1 +
docs/source/resources/CustomizeSessions.rst | 68 +++++++++++++++++++++
2 files changed, 69 insertions(+)
create mode 100644 docs/source/resources/CustomizeSessions.rst
diff --git a/docs/source/index.rst b/docs/source/index.rst
index c52e239b..cffa851d 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -89,6 +89,7 @@ To get started, press the Next button.
resources/AutoAuthorization
resources/TextFormatting
resources/BotsInteraction
+ resources/CustomizeSessions
resources/ErrorHandling
.. toctree::
diff --git a/docs/source/resources/CustomizeSessions.rst b/docs/source/resources/CustomizeSessions.rst
new file mode 100644
index 00000000..4564eaf0
--- /dev/null
+++ b/docs/source/resources/CustomizeSessions.rst
@@ -0,0 +1,68 @@
+Customize Sessions
+==================
+
+As you may probably know, Telegram allows Users (and Bots) having more than one session (authorizations) registered
+in the system at the same time.
+
+Briefly explaining, sessions are simply new logins in your account and can be reviewed in the settings of an official
+app or by invoking `GetAuthorizations <../functions/account/GetAuthorizations>`_ with Pyrogram.
+
+
+.. figure:: https://i.imgur.com/lzGPCdZ.png
+ :width: 70%
+ :align: center
+
+ A Pyrogram session running on Linux, Python 3.6.
+
+That's how a session looks like on the Android app, showing the three main pieces of information.
+
+- ``app_version``: **Pyrogram 🔥 0.7.5**
+- ``device_model``: **CPython 3.6.5**
+- ``system_version``: **Linux 4.15.0-23-generic**
+
+Set Custom Values
+-----------------
+
+To set custom values, you can either make use of the ``config.ini`` file, this way:
+
+.. code-block:: ini
+
+ [pyrogram]
+ app_version = 1.2.3
+ device_model = PC
+ system_version = Linux
+
+Or, pass the arguments directly in the Client's constructor.
+
+.. code-block:: python
+
+ app = Client(
+ "my_account",
+ app_version="1.2.3",
+ device_model="PC",
+ system_version="Linux"
+ )
+
+Set Custom Languages
+--------------------
+
+These are two extra parameters you can change: ``system_lang_code`` (OS language) and ``lang_code`` (Client language).
+They exist to tell Telegram in which language it should speak to you (terms of service, service messages, ...) and are
+usually both set to the same value, in `ISO 639-1 `_ standard.
+Pyrogram uses "en" (English) for both by default.
+
+With the following code we make Telegram know we want it to speak in Italian (it):
+
+.. code-block:: ini
+
+ [pyrogram]
+ system_lang_code = it
+ lang_code = it
+
+.. code-block:: python
+
+ app = Client(
+ "my_account",
+ system_lang_code="it",
+ lang_code="it",
+ )
\ No newline at end of file
From 9d31673f2c4a3ba5bc82c4672d11f8ee8a94d3dc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 25 Jun 2018 18:06:15 +0200
Subject: [PATCH 132/145] Make example more readable
---
docs/source/resources/BotsInteraction.rst | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/docs/source/resources/BotsInteraction.rst b/docs/source/resources/BotsInteraction.rst
index cbbe23c1..de7925a2 100644
--- a/docs/source/resources/BotsInteraction.rst
+++ b/docs/source/resources/BotsInteraction.rst
@@ -28,8 +28,12 @@ Inline Bots
.. code-block:: python
- # Send the first result (bot_results.results[0]) to your own chat (Saved Messages)
- app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id)
+ # Send the first result to your own chat
+ app.send_inline_bot_result(
+ "me",
+ bot_results.query_id,
+ bot_results.results[0].id
+ )
.. figure:: https://i.imgur.com/wwxr7B7.png
:width: 90%
From 1510bc12a8eaf47fb1dbdf97eafff57917f71737 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 25 Jun 2018 18:27:30 +0200
Subject: [PATCH 133/145] Cleanup docs
---
docs/source/resources/UpdateHandling.rst | 1 +
docs/source/start/Setup.rst | 2 +-
docs/source/start/Usage.rst | 6 ++----
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst
index ffa01be9..0aa6457f 100644
--- a/docs/source/resources/UpdateHandling.rst
+++ b/docs/source/resources/UpdateHandling.rst
@@ -9,6 +9,7 @@ from, one for each kind of update:
- `DeletedMessagesHandler <../pyrogram/handlers/DeletedMessagesHandler.html>`_
- `CallbackQueryHandler <../pyrogram/handlers/CallbackQueryHandler.html>`_
- `RawUpdateHandler <../pyrogram/handlers/RawUpdateHandler.html>`_
+- `DisconnectHandler <../pyrogram/handlers/DisconnectHandler.html>`_
Registering an Handler
----------------------
diff --git a/docs/source/start/Setup.rst b/docs/source/start/Setup.rst
index 8b7c0597..417d62d8 100644
--- a/docs/source/start/Setup.rst
+++ b/docs/source/start/Setup.rst
@@ -54,7 +54,7 @@ User Authorization
In order to use the API, Telegram requires that Users be authorized via their phone numbers.
Pyrogram automatically manages this access, all you need to do is create an instance of
the :class:`Client ` class by passing to it a ``session_name`` of your choice
-(e.g.: "my_account") and call the :meth:`start() ` method:
+(e.g.: "my_account") and call the :meth:`run() ` method:
.. code-block:: python
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index d9cb8fe1..531e997f 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -10,10 +10,6 @@ High-level API
The easiest and recommended way to interact with Telegram is via the high-level Pyrogram methods_ and types_, which are
named after the `Telegram Bot API`_.
-.. hint:: If you can't find an high-level method you want to use, chances are it's not implemented yet.
- In this case, you must use the `Raw Functions`_. Meanwhile, feel free to join our Community_ if you get stuck
- or want to propose a new method!
-
Examples (more on `GitHub `_):
- Get information about the authorized user:
@@ -45,8 +41,10 @@ you have to use the raw :mod:`functions ` and :mod:`type
method provided by the Client class.
.. hint:: Every high-level method mentioned in the section above is built on top of these raw functions.
+
Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
+
If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
Examples (more on `GitHub `_):
From 1cc66c898d3b47601e2e3b1ad4b840afffe1b121 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 26 Jun 2018 14:05:45 +0200
Subject: [PATCH 134/145] Fix request_callback_answer call with wrong kwarg
---
pyrogram/client/types/message.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index ce6d158f..d80c657d 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -561,7 +561,7 @@ class Message(Object):
return self._client.request_callback_answer(
chat_id=self.chat.id,
message_id=self.message_id,
- data=button.callback_data
+ callback_data=button.callback_data
)
elif button.url:
return button.url
From fc1c653c05717e55cd2a237b0c40532d309293b3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 26 Jun 2018 16:16:10 +0200
Subject: [PATCH 135/145] Add TimeoutError on possible raises of
Message.click()
---
pyrogram/client/types/message.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index d80c657d..b969865c 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -516,7 +516,8 @@ class Message(Object):
Raises:
:class:`Error `
- ``ValueError``: If the provided index or position is out of range or the button label was not found.
+ ``ValueError``: If the provided index or position is out of range or the button label was not found
+ ``TimeoutError``: If, after clicking an inline button, the bot fails to answer within 10 seconds
"""
if isinstance(self.reply_markup, ReplyKeyboardMarkup):
if quote is None:
From ef69dbd396934e669bc0a73e54aed98e29a63fce Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 00:02:54 +0200
Subject: [PATCH 136/145] Use shields.io badges
---
docs/source/index.rst | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index cffa851d..fb7022ab 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -26,11 +26,11 @@ Welcome to Pyrogram
-
+
-
@@ -56,7 +56,7 @@ button at the end of each page. But first, here's a brief overview of what is th
About
-----
-Pyrogram is a brand new Telegram_ Client Library written from the ground up in Python and C. It can be used for building
+**Pyrogram** is a brand new Telegram_ Client Library written from the ground up in Python and C. It can be used for building
custom Telegram applications that interact with the MTProto API as both User and Bot.
Features
@@ -65,8 +65,8 @@ Features
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
-- **Updated** to the latest Telegram API version, currently Layer 76 running on MTProto 2.0.
-- **Documented**: Pyrogram API methods are documented and resemble the Telegram Bot API.
+- **Updated** to the latest Telegram API version, currently Layer 81 on top of MTProto 2.0.
+- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
To get started, press the Next button.
From 36519cb3ca9f373a2d5cde6ac297bbae2e0bbaa9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 00:11:53 +0200
Subject: [PATCH 137/145] Sort Resources
---
docs/source/index.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index fb7022ab..4143cfee 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -84,12 +84,12 @@ To get started, press the Next button.
:caption: Resources
resources/UpdateHandling
- resources/SOCKS5Proxy
- resources/TgCrypto
resources/AutoAuthorization
- resources/TextFormatting
- resources/BotsInteraction
resources/CustomizeSessions
+ resources/TgCrypto
+ resources/TextFormatting
+ resources/SOCKS5Proxy
+ resources/BotsInteraction
resources/ErrorHandling
.. toctree::
From 27020ca1bb594492ac4edb9b6390be0b045cc355 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 00:12:09 +0200
Subject: [PATCH 138/145] Rename Raw Functions section
---
docs/source/start/Usage.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 531e997f..6c20decd 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -30,10 +30,8 @@ Examples (more on `GitHub ` and :mod:`types ` exposed by the
From ecaba45523170f4d4de4c8c386a24d3fa95a98f8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 00:42:32 +0200
Subject: [PATCH 139/145] Keep only lang_code
---
pyrogram/client/client.py | 8 +-------
pyrogram/session/session.py | 2 +-
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 2cb153db..f21d2ef2 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -86,10 +86,6 @@ class Client(Methods, BaseClient):
Operating System version. Defaults to *platform.system() + " " + platform.release()*
This is an alternative way to set it if you don't want to use the *config.ini* file.
- system_lang_code (``str``, *optional*):
- Code of the language used on the system, in ISO 639-1 standard. Defaults to "en".
- This is an alternative way to set it if you don't want to use the *config.ini* file.
-
lang_code (``str``, *optional*):
Code of the language used on the client, in ISO 639-1 standard. Defaults to "en".
This is an alternative way to set it if you don't want to use the *config.ini* file.
@@ -149,7 +145,6 @@ class Client(Methods, BaseClient):
app_version: str = None,
device_model: str = None,
system_version: str = None,
- system_lang_code: str = None,
lang_code: str = None,
proxy: dict = None,
test_mode: bool = False,
@@ -170,7 +165,6 @@ class Client(Methods, BaseClient):
self.app_version = app_version
self.device_model = device_model
self.system_version = system_version
- self.system_lang_code = system_lang_code
self.lang_code = lang_code
# TODO: Make code consistent, use underscore for private/protected fields
self._proxy = proxy
@@ -889,7 +883,7 @@ class Client(Methods, BaseClient):
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
)
- for option in {"app_version", "device_model", "system_version", "system_lang_code", "lang_code"}:
+ for option in {"app_version", "device_model", "system_version", "lang_code"}:
if getattr(self, option):
pass
else:
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 7bafd71f..ef7b565c 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -145,7 +145,7 @@ class Session:
app_version=self.client.app_version,
device_model=self.client.device_model,
system_version=self.client.system_version,
- system_lang_code=self.client.system_lang_code,
+ system_lang_code=self.client.lang_code,
lang_code=self.client.lang_code,
lang_pack="",
query=functions.help.GetConfig(),
From 7ed9cd6759dd18cabf037fe5014f669c81a19e9a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 14:42:04 +0200
Subject: [PATCH 140/145] Add "Login successful" message upon login
---
pyrogram/client/client.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index f21d2ef2..20a3e50c 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -585,6 +585,8 @@ class Client(Methods, BaseClient):
self.password = None
self.user_id = r.user.id
+ print("Login successful")
+
def fetch_peers(self, entities: list):
for entity in entities:
if isinstance(entity, types.User):
From c0ad63f72cec666f98c0c3f52dd0d31bef2a6448 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 14:45:56 +0200
Subject: [PATCH 141/145] Update CustomizeSessions page
---
docs/source/resources/CustomizeSessions.rst | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/docs/source/resources/CustomizeSessions.rst b/docs/source/resources/CustomizeSessions.rst
index 4564eaf0..498003d4 100644
--- a/docs/source/resources/CustomizeSessions.rst
+++ b/docs/source/resources/CustomizeSessions.rst
@@ -4,8 +4,9 @@ Customize Sessions
As you may probably know, Telegram allows Users (and Bots) having more than one session (authorizations) registered
in the system at the same time.
-Briefly explaining, sessions are simply new logins in your account and can be reviewed in the settings of an official
-app or by invoking `GetAuthorizations <../functions/account/GetAuthorizations>`_ with Pyrogram.
+Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official
+app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations>`_ with Pyrogram) and store some useful
+information about the client who generated them.
.. figure:: https://i.imgur.com/lzGPCdZ.png
@@ -46,23 +47,20 @@ Or, pass the arguments directly in the Client's constructor.
Set Custom Languages
--------------------
-These are two extra parameters you can change: ``system_lang_code`` (OS language) and ``lang_code`` (Client language).
-They exist to tell Telegram in which language it should speak to you (terms of service, service messages, ...) and are
-usually both set to the same value, in `ISO 639-1 `_ standard.
-Pyrogram uses "en" (English) for both by default.
+To tell Telegram in which language should speak to you (terms of service, bots, service messages, ...) you can
+set ``lang_code`` in `ISO 639-1 `_ standard (defaults to "en",
+English).
With the following code we make Telegram know we want it to speak in Italian (it):
.. code-block:: ini
[pyrogram]
- system_lang_code = it
lang_code = it
.. code-block:: python
app = Client(
"my_account",
- system_lang_code="it",
lang_code="it",
)
\ No newline at end of file
From c1cd8ec12dee39b8153d6f670518090b4dda3c53 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 14:52:13 +0200
Subject: [PATCH 142/145] Tiny fix
---
docs/source/index.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 4143cfee..051b5af8 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -26,7 +26,7 @@ Welcome to Pyrogram
-
From ec667035cd53c407cdb912f320af01019dfc57bf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 15:27:15 +0200
Subject: [PATCH 143/145] Sort docs entries alphabetically
---
compiler/docs/compiler.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py
index 494697de..73b5a578 100644
--- a/compiler/docs/compiler.py
+++ b/compiler/docs/compiler.py
@@ -77,7 +77,8 @@ def generate(source_path, base):
build(source_path)
- for k, v in all_entities.items():
+ for k, v in sorted(all_entities.items()):
+ v = sorted(v)
entities = []
for i in v:
From a65376a52be0c26c2e5cab6bea5589bbd5d754be Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 15:46:38 +0200
Subject: [PATCH 144/145] Fix broken link
---
docs/source/resources/CustomizeSessions.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/resources/CustomizeSessions.rst b/docs/source/resources/CustomizeSessions.rst
index 498003d4..e98792b7 100644
--- a/docs/source/resources/CustomizeSessions.rst
+++ b/docs/source/resources/CustomizeSessions.rst
@@ -5,7 +5,7 @@ As you may probably know, Telegram allows Users (and Bots) having more than one
in the system at the same time.
Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official
-app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations>`_ with Pyrogram) and store some useful
+app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram) and store some useful
information about the client who generated them.
From 37aae4382e67c45b27eec33250d8934999ec2465 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Jun 2018 16:38:41 +0200
Subject: [PATCH 145/145] Update to v0.7.5
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index daddb08f..96fb4a76 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -23,7 +23,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès