Rubka 2.11.9__tar.gz → 3.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {rubka-2.11.9 → rubka-3.2.5}/PKG-INFO +1 -1
  2. {rubka-2.11.9 → rubka-3.2.5}/Rubka.egg-info/PKG-INFO +1 -1
  3. rubka-3.2.5/Rubka.egg-info/SOURCES.txt +39 -0
  4. rubka-3.2.5/rubka/adaptorrubka/__init__.py +4 -0
  5. rubka-3.2.5/rubka/adaptorrubka/client/__init__.py +1 -0
  6. rubka-3.2.5/rubka/adaptorrubka/client/client.py +60 -0
  7. rubka-3.2.5/rubka/adaptorrubka/crypto/__init__.py +1 -0
  8. rubka-3.2.5/rubka/adaptorrubka/crypto/crypto.py +82 -0
  9. rubka-3.2.5/rubka/adaptorrubka/enums.py +36 -0
  10. rubka-3.2.5/rubka/adaptorrubka/exceptions.py +22 -0
  11. rubka-3.2.5/rubka/adaptorrubka/methods/__init__.py +1 -0
  12. rubka-3.2.5/rubka/adaptorrubka/methods/methods.py +90 -0
  13. rubka-3.2.5/rubka/adaptorrubka/network/__init__.py +3 -0
  14. rubka-3.2.5/rubka/adaptorrubka/network/helper.py +22 -0
  15. rubka-3.2.5/rubka/adaptorrubka/network/network.py +221 -0
  16. rubka-3.2.5/rubka/adaptorrubka/network/socket.py +16 -0
  17. rubka-3.2.5/rubka/adaptorrubka/sessions/__init__.py +1 -0
  18. rubka-3.2.5/rubka/adaptorrubka/sessions/sessions.py +72 -0
  19. rubka-3.2.5/rubka/adaptorrubka/types/__init__.py +1 -0
  20. rubka-3.2.5/rubka/adaptorrubka/types/socket/__init__.py +1 -0
  21. rubka-3.2.5/rubka/adaptorrubka/types/socket/message.py +187 -0
  22. rubka-3.2.5/rubka/adaptorrubka/utils/__init__.py +2 -0
  23. rubka-3.2.5/rubka/adaptorrubka/utils/configs.py +18 -0
  24. rubka-3.2.5/rubka/adaptorrubka/utils/utils.py +251 -0
  25. {rubka-2.11.9 → rubka-3.2.5}/rubka/api.py +21 -9
  26. {rubka-2.11.9 → rubka-3.2.5}/setup.py +1 -1
  27. rubka-2.11.9/Rubka.egg-info/SOURCES.txt +0 -18
  28. {rubka-2.11.9 → rubka-3.2.5}/README.md +0 -0
  29. {rubka-2.11.9 → rubka-3.2.5}/Rubka.egg-info/dependency_links.txt +0 -0
  30. {rubka-2.11.9 → rubka-3.2.5}/Rubka.egg-info/requires.txt +0 -0
  31. {rubka-2.11.9 → rubka-3.2.5}/Rubka.egg-info/top_level.txt +0 -0
  32. {rubka-2.11.9 → rubka-3.2.5}/rubka/__init__.py +0 -0
  33. {rubka-2.11.9 → rubka-3.2.5}/rubka/config.py +0 -0
  34. {rubka-2.11.9 → rubka-3.2.5}/rubka/context.py +0 -0
  35. {rubka-2.11.9 → rubka-3.2.5}/rubka/decorators.py +0 -0
  36. {rubka-2.11.9 → rubka-3.2.5}/rubka/exceptions.py +0 -0
  37. {rubka-2.11.9 → rubka-3.2.5}/rubka/jobs.py +0 -0
  38. {rubka-2.11.9 → rubka-3.2.5}/rubka/keyboards.py +0 -0
  39. {rubka-2.11.9 → rubka-3.2.5}/rubka/keypad.py +0 -0
  40. {rubka-2.11.9 → rubka-3.2.5}/rubka/logger.py +0 -0
  41. {rubka-2.11.9 → rubka-3.2.5}/rubka/utils.py +0 -0
  42. {rubka-2.11.9 → rubka-3.2.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 2.11.9
3
+ Version: 3.2.5
4
4
  Summary: A Python library for interacting with Rubika Bot API.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/Rubka/archive/refs/tags/v0.1.0.tar.gz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 2.11.9
3
+ Version: 3.2.5
4
4
  Summary: A Python library for interacting with Rubika Bot API.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/Rubka/archive/refs/tags/v0.1.0.tar.gz
@@ -0,0 +1,39 @@
1
+ README.md
2
+ setup.py
3
+ Rubka.egg-info/PKG-INFO
4
+ Rubka.egg-info/SOURCES.txt
5
+ Rubka.egg-info/dependency_links.txt
6
+ Rubka.egg-info/requires.txt
7
+ Rubka.egg-info/top_level.txt
8
+ rubka/__init__.py
9
+ rubka/api.py
10
+ rubka/config.py
11
+ rubka/context.py
12
+ rubka/decorators.py
13
+ rubka/exceptions.py
14
+ rubka/jobs.py
15
+ rubka/keyboards.py
16
+ rubka/keypad.py
17
+ rubka/logger.py
18
+ rubka/utils.py
19
+ rubka/adaptorrubka/__init__.py
20
+ rubka/adaptorrubka/enums.py
21
+ rubka/adaptorrubka/exceptions.py
22
+ rubka/adaptorrubka/client/__init__.py
23
+ rubka/adaptorrubka/client/client.py
24
+ rubka/adaptorrubka/crypto/__init__.py
25
+ rubka/adaptorrubka/crypto/crypto.py
26
+ rubka/adaptorrubka/methods/__init__.py
27
+ rubka/adaptorrubka/methods/methods.py
28
+ rubka/adaptorrubka/network/__init__.py
29
+ rubka/adaptorrubka/network/helper.py
30
+ rubka/adaptorrubka/network/network.py
31
+ rubka/adaptorrubka/network/socket.py
32
+ rubka/adaptorrubka/sessions/__init__.py
33
+ rubka/adaptorrubka/sessions/sessions.py
34
+ rubka/adaptorrubka/types/__init__.py
35
+ rubka/adaptorrubka/types/socket/__init__.py
36
+ rubka/adaptorrubka/types/socket/message.py
37
+ rubka/adaptorrubka/utils/__init__.py
38
+ rubka/adaptorrubka/utils/configs.py
39
+ rubka/adaptorrubka/utils/utils.py
@@ -0,0 +1,4 @@
1
+ from .client import Client
2
+
3
+ __version__ = "3.6.0"
4
+ __author__ = "Ali Ganji zadeh"
@@ -0,0 +1 @@
1
+ from .client import Client
@@ -0,0 +1,60 @@
1
+ from ..methods import Methods
2
+
3
+ class Client(object):
4
+
5
+ def __init__(
6
+ self,
7
+ session:str=None,
8
+ auth:str=None,
9
+ private:str=None,
10
+ platform:str="web",
11
+ api_version:int=6,
12
+ proxy:str=None,
13
+ time_out:int=10,
14
+ show_progress_bar:bool=True
15
+ ) -> None:
16
+
17
+ self.session = session
18
+ self.platform = platform
19
+ self.apiVersion = api_version
20
+ self.proxy = proxy
21
+ self.timeOut = time_out
22
+
23
+ if(session):
24
+ from ..sessions import Sessions
25
+ self.sessions = Sessions(self)
26
+
27
+ if(self.sessions.cheackSessionExists()):
28
+ self.sessionData = self.sessions.loadSessionData()
29
+ else:
30
+ self.sessionData = self.sessions.createSession()
31
+ else:
32
+ from ..utils import Utils
33
+ self.sessionData = {
34
+ "auth": auth,
35
+ "private_key": Utils.privateParse(private=private)
36
+ }
37
+
38
+ self.methods = Methods(
39
+ sessionData=self.sessionData,
40
+ platform=platform,
41
+ apiVersion=api_version,
42
+ proxy=proxy,
43
+ timeOut=time_out,
44
+ showProgressBar=show_progress_bar
45
+ )
46
+
47
+ def send_code(self, phone_number:str, pass_key:str=None) -> dict:
48
+ return self.methods.sendCode(phoneNumber=phone_number, passKey=pass_key)
49
+
50
+ def sign_in(self, phone_number:str, phone_code_hash:str, phone_code:str) -> dict:
51
+ return self.methods.signIn(phoneNumber=phone_number, phoneCodeHash=phone_code_hash, phoneCode=phone_code)
52
+
53
+ def register_device(self, device_model:str) -> dict:
54
+ return self.methods.registerDevice(deviceModel=device_model)
55
+
56
+ def logout(self) -> dict:
57
+ return self.methods.logout()
58
+
59
+ def get_all_members(self, object_guid:str, search_text:str=None, start_id:str=None, just_get_guids:bool=False) -> dict:
60
+ return self.methods.getChatAllMembers(objectGuid=object_guid, searchText=search_text, startId=start_id, justGetGuids=just_get_guids)
@@ -0,0 +1 @@
1
+ from .crypto import Cryption
@@ -0,0 +1,82 @@
1
+ from Crypto.Util.Padding import pad, unpad
2
+ from base64 import b64encode as b64e, urlsafe_b64decode as b64d, b64decode
3
+ from Crypto.Cipher import AES
4
+ from Crypto.PublicKey import RSA
5
+ from Crypto.Hash import SHA256
6
+ from Crypto.Signature import pkcs1_15
7
+ from Crypto.Cipher import PKCS1_OAEP
8
+
9
+ class Cryption:
10
+
11
+ def __init__(self, auth:str, private_key:str=None):
12
+ self.auth = auth
13
+
14
+ if auth:
15
+ self.key = bytearray(self.secret(auth), 'UTF-8')
16
+ self.iv = bytearray.fromhex('0' * 32)
17
+
18
+ if private_key:
19
+ self.keypair = RSA.import_key(private_key.encode('UTF-8'))
20
+
21
+ def replaceCharAt(self, e, t, i):
22
+ return e[0:t] + i + e[t + len(i):]
23
+
24
+ def secret(self, e):
25
+ t = e[0:8]
26
+ i = e[8:16]
27
+ n = e[16:24] + t + e[24:32] + i
28
+ s = 0
29
+ while s < len(n):
30
+ e = n[s]
31
+ if e >= '0' and e <= '9':
32
+ t = chr((ord(e[0]) - ord('0') + 5) % 10 + ord('0'))
33
+ n = self.replaceCharAt(n, s, t)
34
+ else:
35
+ t = chr((ord(e[0]) - ord('a') + 9) % 26 + ord('a'))
36
+ n = self.replaceCharAt(n, s, t)
37
+ s += 1
38
+ return n
39
+
40
+ def encrypt(self, text):
41
+ raw = pad(text.encode('UTF-8'), AES.block_size)
42
+ aes = AES.new(self.key, AES.MODE_CBC, self.iv)
43
+ enc = aes.encrypt(raw)
44
+ result = b64e(enc).decode('UTF-8')
45
+ return result
46
+
47
+ def decrypt(self, text):
48
+ aes = AES.new(self.key, AES.MODE_CBC, self.iv)
49
+ dec = aes.decrypt(b64d(text.encode('UTF-8')))
50
+ result = unpad(dec, AES.block_size).decode('UTF-8')
51
+ return result
52
+
53
+ def makeSignFromData(self, data_enc:str):
54
+ sha_data = SHA256.new(data_enc.encode('UTF-8'))
55
+ signature = pkcs1_15.new(self.keypair).sign(sha_data)
56
+ return b64e(signature).decode('UTF-8')
57
+
58
+ def decryptRsaOaep(private:str, data_enc:str):
59
+ keyPair = RSA.import_key(private.encode('UTF-8'))
60
+ return PKCS1_OAEP.new(keyPair).decrypt(b64decode(data_enc)).decode('UTF-8')
61
+
62
+ def changeAuthType(self, auth_enc):
63
+ n = ''
64
+ lowercase = 'abcdefghijklmnopqrstuvwxyz'
65
+ uppercase = 'abcdefghijklmnopqrstuvwxyz'.upper()
66
+ digits = '0123456789'
67
+ for s in auth_enc:
68
+ if s in lowercase:
69
+ n += chr(((32 - (ord(s) - 97)) % 26) + 97)
70
+ elif s in uppercase:
71
+ n += chr(((29- (ord(s) - 65)) % 26) + 65)
72
+ elif s in digits:
73
+ n += chr(((13 - (ord(s)- 48)) % 10) + 48)
74
+ else:
75
+ n += s
76
+ return n
77
+
78
+ def rsaKeyGenrate(self):
79
+ keyPair = RSA.generate(1024)
80
+ public = self.changeAuthType(b64e(keyPair.publickey().export_key()).decode('UTF-8'))
81
+ privarte = keyPair.export_key().decode('UTF-8')
82
+ return public, privarte
@@ -0,0 +1,36 @@
1
+ class SetAdminAccessList:
2
+ set_admin:str = "SetAdmin"
3
+ ban_member:str = "BanMember"
4
+ change_info:str = "ChangeInfo"
5
+ pin_messages:str = "PinMessages"
6
+ delete_messages:str = "DeleteGlobalAllMessages"
7
+ edit_messages:str = "EditMessages"
8
+ set_join_link:str = "SetJoinLink"
9
+ set_member_access:str = "SetMemberAccess"
10
+ delete_global_all_messages:str = "DeleteGlobalAllMessages"
11
+
12
+ class SetGroupDefaultAccessList:
13
+ send_messages:str = "SendMessages"
14
+ add_member:str = "AddMember"
15
+ view_admins:str = "ViewAdmins"
16
+ view_members:str = "ViewMembers"
17
+
18
+ class ChatActivities:
19
+ typing:str = "Typing"
20
+ recording:str = "Recording"
21
+ uploading:str = "Uploading"
22
+
23
+ class Filters:
24
+ user:str = "User"
25
+ group:str = "Group"
26
+ channel:str = "Channel"
27
+ bot:str = "Bot"
28
+ service:str = "Service"
29
+ media:str = "Media"
30
+ file:str = "File"
31
+ image:str = "Image"
32
+ video:str = "Video"
33
+ gif:str = "Gif"
34
+ music:str = "Music"
35
+ voice:str = "Voice"
36
+ sticker:str = "Sticker"
@@ -0,0 +1,22 @@
1
+ class ClientException(Exception):
2
+ pass
3
+
4
+ class InvalidAuth(ClientException):
5
+
6
+ def __init__(self, message:str="You don't have access to request this method!"):
7
+ super().__init__(message)
8
+
9
+ class NotRegistered(ClientException):
10
+
11
+ def __init__(self, message:str="The account used is invalid or not registered!"):
12
+ super().__init__(message)
13
+
14
+ class InvalidInput(ClientException):
15
+
16
+ def __init__(self, message:str="Some input given to the method is invalid!"):
17
+ super().__init__(message)
18
+
19
+ class TooRequests(ClientException):
20
+
21
+ def __init__(self, message:str="You won't be able to use this method for a while!"):
22
+ super().__init__(message)
@@ -0,0 +1 @@
1
+ from .methods import Methods
@@ -0,0 +1,90 @@
1
+ from random import randint
2
+ from ..network import Network, Socket
3
+ from ..crypto import Cryption
4
+ from ..utils import Utils
5
+ from time import sleep
6
+
7
+
8
+ class Methods:
9
+
10
+ def __init__(self, sessionData:dict, platform:str, apiVersion:int, proxy:str, timeOut:int, showProgressBar:bool) -> None:
11
+ self.platform = platform.lower()
12
+ if not self.platform in ["android", "web", "rubx", "rubikax", "rubino"]:
13
+ print("The \"{}\" is not a valid platform. Choose these one -> (web, android, rubx)".format(platform))
14
+ exit()
15
+ self.apiVersion = apiVersion
16
+ self.proxy = proxy
17
+ self.timeOut = timeOut
18
+ self.showProgressBar = showProgressBar
19
+ self.sessionData = sessionData
20
+ self.crypto = Cryption(
21
+ auth=sessionData["auth"],
22
+ private_key=sessionData["private_key"]
23
+ ) if sessionData else Cryption(auth=Utils.randomTmpSession())
24
+ self.network = Network(methods=self)
25
+ self.socket = Socket(methods=self)
26
+
27
+
28
+ def sendCode(self, phoneNumber:str, passKey:str=None, sendInternal:bool=False) -> dict:
29
+ input:dict = {
30
+ "phone_number": f"98{Utils.phoneNumberParse(phoneNumber)}",
31
+ "send_type": "Internal" if sendInternal else "SMS",
32
+ }
33
+
34
+ if passKey:
35
+ input["pass_key"] = passKey
36
+
37
+ return self.network.request(
38
+ method="sendCode",
39
+ input=input,
40
+ tmpSession=True
41
+ )
42
+
43
+ def signIn(self, phoneNumber, phoneCodeHash, phoneCode) -> dict:
44
+ publicKey, privateKey = self.crypto.rsaKeyGenrate()
45
+
46
+ data = self.network.request(
47
+ method="signIn",
48
+ input={
49
+ "phone_number": f"98{Utils.phoneNumberParse(phoneNumber)}",
50
+ "phone_code_hash": phoneCodeHash,
51
+ "phone_code": phoneCode,
52
+ "public_key": publicKey
53
+ },
54
+ tmpSession=True
55
+ )
56
+
57
+ data["private_key"] = privateKey
58
+
59
+ return data
60
+
61
+ def registerDevice(self, deviceModel) -> dict:
62
+ return self.network.request(
63
+ method="registerDevice",
64
+ input={
65
+ "app_version": "WB_4.3.3" if self.platform == "web" else "MA_3.4.3",
66
+ "device_hash": Utils.randomDeviceHash(),
67
+ "device_model": deviceModel,
68
+ "is_multi_account": False,
69
+ "lang_code": "fa",
70
+ "system_version": "Windows 11" if self.platform == "web" else "SDK 28",
71
+ "token": "",
72
+ "token_type": "Web" if self.platform == "web" else "Firebase"
73
+ }
74
+ )
75
+
76
+ def getChatAllMembers(self, objectGuid:str, searchText:str, startId:str, justGetGuids:bool=False) -> dict:
77
+ chatType:str = Utils.getChatTypeByGuid(objectGuid=objectGuid)
78
+
79
+ data = self.network.request(
80
+ method=f"get{chatType}AllMembers",
81
+ input={
82
+ f"{chatType.lower()}_guid": objectGuid,
83
+ "search_text": searchText.replace("@", "") if searchText else searchText,
84
+ "start_id": startId
85
+ }
86
+ )
87
+
88
+ if justGetGuids: return [i["member_guid"] for i in data["in_chat_members"]]
89
+
90
+ return data
@@ -0,0 +1,3 @@
1
+ from .network import Network
2
+ from .socket import Socket
3
+ from .helper import Helper
@@ -0,0 +1,22 @@
1
+ from urllib3 import PoolManager
2
+ from json import loads
3
+ from random import randint, choice
4
+
5
+ class Helper:
6
+
7
+ @classmethod
8
+ def getDcmess(self) -> dict:
9
+ return loads(
10
+ PoolManager().request(
11
+ "GET",
12
+ "https://getdcmess.iranlms.ir/"
13
+ ).data.decode()
14
+ )["data"]
15
+
16
+ @classmethod
17
+ def getApiServer(self) -> str:
18
+ return f"https://messengerg2c{randint(2, 3)}.iranlms.ir"
19
+
20
+ @classmethod
21
+ def getSocketServer(self) -> str:
22
+ return choice(list(self.getDcmess()["socket"].values()))
@@ -0,0 +1,221 @@
1
+ from json import dumps, loads
2
+ from tqdm import tqdm
3
+ from urllib3 import PoolManager, ProxyManager
4
+ from ..utils import Configs
5
+ from ..exceptions import *
6
+ from .helper import Helper
7
+
8
+ class Network:
9
+
10
+ def __init__(self, methods:object) -> None:
11
+ self.methods = methods
12
+ self.sessionData = methods.sessionData
13
+ self.crypto = methods.crypto
14
+ self.http = ProxyManager(methods.proxy) if methods.proxy else PoolManager()
15
+
16
+ def request(self, method:str, input:dict={}, tmpSession:bool=False, attempt:int = 0, maxAttempt:int=2):
17
+ url:str = Helper.getApiServer()
18
+ platform:str = self.methods.platform.lower()
19
+ apiVersion:int = self.methods.apiVersion
20
+
21
+ if platform in ["rubx", "rubikax"]:
22
+ client:dict = Configs.clients["android"]
23
+ client["package"] = "ir.rubx.bapp"
24
+
25
+ elif platform in ["android"]:
26
+ client:dict = Configs.clients["android"]
27
+
28
+ else:
29
+ client:dict = Configs.clients["web"]
30
+
31
+ data = {
32
+ "api_version": str(apiVersion),
33
+ "tmp_session" if tmpSession else
34
+ "auth": self.crypto.auth if tmpSession else
35
+ self.crypto.changeAuthType(self.sessionData["auth"]) if apiVersion > 5 else
36
+ self.sessionData["auth"],
37
+ "data_enc": self.crypto.encrypt(
38
+ dumps({
39
+ "method": method,
40
+ "input": input,
41
+ "client": client
42
+ })
43
+ )
44
+ }
45
+
46
+ headers:dict = {
47
+ "Referer": "https://web.rubika.ir/",
48
+ "Content-Type": "application/json; charset=utf-8"
49
+ }
50
+
51
+ if not tmpSession and apiVersion > 5:
52
+ data["sign"] = self.crypto.makeSignFromData(data["data_enc"])
53
+
54
+ while True:
55
+ result = self.http.request(
56
+ method="POST",
57
+ url=url,
58
+ headers=headers,
59
+ body = dumps(data).encode(),
60
+ timeout=self.methods.timeOut
61
+ )
62
+
63
+ try:
64
+ result = loads(self.crypto.decrypt(loads(result.data.decode("UTF-8"))["data_enc"]))
65
+ except:
66
+ attempt += 1
67
+
68
+ if attempt > maxAttempt:
69
+ raise
70
+
71
+ continue
72
+
73
+ if result["status"] == "OK":
74
+ if tmpSession:
75
+ result["data"]["tmp_session"] = self.crypto.auth
76
+
77
+ return result["data"]
78
+
79
+ else:
80
+ raise {
81
+ "INVALID_AUTH": InvalidAuth(),
82
+ "NOT_REGISTERED": NotRegistered(),
83
+ "INVALID_INPUT": InvalidInput(),
84
+ "TOO_REQUESTS": TooRequests()
85
+ }[result["status_det"]]
86
+
87
+ def upload(self, file:str, fileName:str=None, chunkSize:int=131072):
88
+ from ..utils import Utils
89
+
90
+ if isinstance(file, str):
91
+ if Utils.checkLink(url=file):
92
+ file:bytes = self.http.request(method="GET", url=file).data
93
+ mime:str = Utils.getMimeFromByte(bytes=file)
94
+ fileName = fileName or Utils.generateFileName(mime=mime)
95
+ else:
96
+ fileName = fileName or file
97
+ mime = file.split(".")[-1]
98
+ file = open(file, "rb").read()
99
+
100
+ elif not isinstance(file, bytes):
101
+ raise FileNotFoundError("Enter a valid path or url or bytes of file.")
102
+ else:
103
+ mime = Utils.getMimeFromByte(bytes=file)
104
+ fileName = fileName or Utils.generateFileName(mime=mime)
105
+
106
+ def send_chunk(data, maxAttempts=2):
107
+ for attempt in range(maxAttempts):
108
+ try:
109
+ response = self.http.request(
110
+ "POST",
111
+ url=requestSendFileData["upload_url"],
112
+ headers=header,
113
+ body=data
114
+ )
115
+ return loads(response.data.decode("UTF-8"))
116
+ except Exception:
117
+ print(f"\nError uploading file! (Attempt {attempt + 1}/{maxAttempts})")
118
+
119
+ print("\nFailed to upload the file!")
120
+
121
+ requestSendFileData:dict = self.methods.requestSendFile(
122
+ fileName = fileName,
123
+ mime = mime,
124
+ size = len(file)
125
+ )
126
+
127
+ header = {
128
+ "auth": self.sessionData["auth"],
129
+ "access-hash-send": requestSendFileData["access_hash_send"],
130
+ "file-id": requestSendFileData["id"],
131
+ }
132
+
133
+ totalParts = (len(file) + chunkSize - 1) // chunkSize
134
+
135
+ if self.methods.showProgressBar:
136
+ processBar = tqdm(
137
+ desc=f"Uploading {fileName}",
138
+ total=len(file),
139
+ unit="B",
140
+ unit_scale=True,
141
+ unit_divisor=1024,
142
+ )
143
+
144
+ for partNumber in range(1, totalParts + 1):
145
+ startIdx = (partNumber - 1) * chunkSize
146
+ endIdx = min(startIdx + chunkSize, len(file))
147
+ header["chunk-size"] = str(endIdx - startIdx)
148
+ header["part-number"] = str(partNumber)
149
+ header["total-part"] = str(totalParts)
150
+ data = file[startIdx:endIdx]
151
+ hashFileReceive = send_chunk(data)
152
+
153
+ if self.methods.showProgressBar:
154
+ processBar.update(len(data))
155
+
156
+ if not hashFileReceive:
157
+ return
158
+
159
+ if partNumber == totalParts:
160
+
161
+ if not hashFileReceive["data"]:
162
+ return
163
+
164
+ requestSendFileData["file"] = file
165
+ requestSendFileData["access_hash_rec"] = hashFileReceive["data"]["access_hash_rec"]
166
+ requestSendFileData["file_name"] = fileName
167
+ requestSendFileData["mime"] = mime
168
+ requestSendFileData["size"] = len(file)
169
+ return requestSendFileData
170
+
171
+ def download(self, accessHashRec:str, fileId:str, dcId:str, size:int, fileName:str, chunkSize:int=262143, attempt:int=0, maxAttempts:int=2):
172
+ headers:dict = {
173
+ "auth": self.sessionData["auth"],
174
+ "access-hash-rec": accessHashRec,
175
+ "dc-id": dcId,
176
+ "file-id": fileId,
177
+ "Host": f"messenger{dcId}.iranlms.ir",
178
+ "client-app-name": "Main",
179
+ "client-app-version": "3.5.7",
180
+ "client-package": "app.rbmain.a",
181
+ "client-platform": "Android",
182
+ "Connection": "Keep-Alive",
183
+ "Content-Type": "application/json",
184
+ "User-Agent": "okhttp/3.12.1"
185
+ }
186
+
187
+
188
+ response = self.http.request(
189
+ "POST",
190
+ url=f"https://messenger{dcId}.iranlms.ir/GetFile.ashx",
191
+ headers=headers,
192
+ preload_content=False
193
+ )
194
+
195
+ data:bytes = b""
196
+
197
+ if self.methods.showProgressBar:
198
+ processBar = tqdm(
199
+ desc=f"Downloading {fileName}",
200
+ total=size,
201
+ unit="B",
202
+ unit_scale=True,
203
+ unit_divisor=1024,
204
+ )
205
+
206
+ for downloadedData in response.stream(chunkSize):
207
+ try:
208
+ if downloadedData:
209
+ data += downloadedData
210
+ if self.methods.showProgressBar:
211
+ processBar.update(len(downloadedData))
212
+
213
+ if len(data) >= size:
214
+ return data
215
+ except Exception:
216
+ if attempt <= maxAttempts:
217
+ attempt += 1
218
+ print(f"\nError downloading file! (Attempt {attempt}/{maxAttempts})")
219
+ continue
220
+
221
+ raise TimeoutError("Failed to download the file!")
@@ -0,0 +1,16 @@
1
+ from websocket import WebSocketApp
2
+ from .helper import Helper
3
+ from json import dumps, loads
4
+ from threading import Thread
5
+ from ..types import Message
6
+ from ..exceptions import NotRegistered, TooRequests
7
+ from ..utils import Utils
8
+ from re import match
9
+ from time import sleep
10
+
11
+ class Socket:
12
+ def __init__(self, methods) -> None:
13
+ self.methods = methods
14
+ self.handlers = {}
15
+
16
+ ...
@@ -0,0 +1 @@
1
+ from .sessions import Sessions