osonbot 1.0.0__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.
- osonbot-1.0.0/PKG-INFO +0 -0
- osonbot-1.0.0/README.md +0 -0
- osonbot-1.0.0/osonbot/__init__.py +8 -0
- osonbot-1.0.0/osonbot/bot.py +329 -0
- osonbot-1.0.0/osonbot.egg-info/PKG-INFO +0 -0
- osonbot-1.0.0/osonbot.egg-info/SOURCES.txt +9 -0
- osonbot-1.0.0/osonbot.egg-info/dependency_links.txt +1 -0
- osonbot-1.0.0/osonbot.egg-info/requires.txt +1 -0
- osonbot-1.0.0/osonbot.egg-info/top_level.txt +1 -0
- osonbot-1.0.0/setup.cfg +4 -0
- osonbot-1.0.0/setup.py +20 -0
osonbot-1.0.0/PKG-INFO
ADDED
|
Binary file
|
osonbot-1.0.0/README.md
ADDED
|
Binary file
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .bot import Bot, Photo, Video, Audio, Voice, Sticker, KeyboardButton, RemoveKeyboardButton, InlineKeyboardButton, URLKeyboardButton, CreateTable
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"Bot",
|
|
5
|
+
"Photo", "Video", "Audio", "Voice", "Sticker",
|
|
6
|
+
"KeyboardButton", "RemoveKeyboardButton", "InlineKeyboardButton", "URLKeyboardButton",
|
|
7
|
+
"CreateTable"
|
|
8
|
+
]
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import httpx
|
|
4
|
+
import sqlite3
|
|
5
|
+
|
|
6
|
+
def create_table(table_name: str, **columns):
|
|
7
|
+
if not columns:
|
|
8
|
+
raise ValueError("You must provide at least one column.")
|
|
9
|
+
|
|
10
|
+
type_map = {
|
|
11
|
+
int: "INTEGER",
|
|
12
|
+
str: "TEXT",
|
|
13
|
+
float: "REAL",
|
|
14
|
+
bool: "INTEGER"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
cols = []
|
|
18
|
+
for name, py_type in columns.items():
|
|
19
|
+
sqlite_type = type_map.get(py_type, "TEXT")
|
|
20
|
+
cols.append(f"{name} {sqlite_type}")
|
|
21
|
+
|
|
22
|
+
columns_def = ", ".join(cols)
|
|
23
|
+
query = f"CREATE TABLE IF NOT EXISTS {table_name} ({columns_def});"
|
|
24
|
+
|
|
25
|
+
with sqlite3.connect("example.db") as conn:
|
|
26
|
+
cur = conn.cursor()
|
|
27
|
+
cur.execute(query)
|
|
28
|
+
|
|
29
|
+
# def add_data(table_name: str, username: )
|
|
30
|
+
|
|
31
|
+
def add_data2(table_name, **data):
|
|
32
|
+
if not data:
|
|
33
|
+
raise ValueError("You must provide at least one column and value.")
|
|
34
|
+
|
|
35
|
+
columns = ", ".join(data.keys())
|
|
36
|
+
placeholders = ", ".join("?" for _ in data)
|
|
37
|
+
values = tuple(data.values())
|
|
38
|
+
|
|
39
|
+
query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders});"
|
|
40
|
+
|
|
41
|
+
with sqlite3.connect("DB_NAME") as conn:
|
|
42
|
+
cur = conn.cursor()
|
|
43
|
+
cur.execute(query, values)
|
|
44
|
+
print("✅ Data inserted successfully!")
|
|
45
|
+
|
|
46
|
+
# Exception
|
|
47
|
+
class FileNotFoundOrInvalidURLError(Exception):
|
|
48
|
+
"""Raised when a file does not exist or the provided URL is invalid."""
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# For sendinng media and handling
|
|
53
|
+
class Photo:
|
|
54
|
+
def __init__(self, url, caption=""):
|
|
55
|
+
self.url = url
|
|
56
|
+
self.caption = caption
|
|
57
|
+
|
|
58
|
+
class Video:
|
|
59
|
+
def __init__(self, url, caption=""):
|
|
60
|
+
self.url = url
|
|
61
|
+
self.caption = caption
|
|
62
|
+
|
|
63
|
+
class Audio:
|
|
64
|
+
def __init__(self, url, caption=""):
|
|
65
|
+
self.url = url
|
|
66
|
+
self.caption = caption
|
|
67
|
+
|
|
68
|
+
class Voice:
|
|
69
|
+
def __init__(self, url, caption=""):
|
|
70
|
+
self.url = url
|
|
71
|
+
self.caption = caption
|
|
72
|
+
|
|
73
|
+
class Sticker:
|
|
74
|
+
def __init__(self, file_id):
|
|
75
|
+
self.file_id = file_id
|
|
76
|
+
|
|
77
|
+
def setup_logger(name: str):
|
|
78
|
+
logger = logging.getLogger(name)
|
|
79
|
+
logger.setLevel(logging.INFO)
|
|
80
|
+
|
|
81
|
+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s", "%Y-%m-%d %H:%M:%S")
|
|
82
|
+
|
|
83
|
+
stream_handler = logging.StreamHandler()
|
|
84
|
+
stream_handler.setFormatter(formatter)
|
|
85
|
+
|
|
86
|
+
logger.addHandler(stream_handler)
|
|
87
|
+
|
|
88
|
+
return logger
|
|
89
|
+
|
|
90
|
+
# Bot
|
|
91
|
+
class Bot:
|
|
92
|
+
def __init__(self, token, create_db=True):
|
|
93
|
+
self.api_url = f"https://api.telegram.org/bot{token}/"
|
|
94
|
+
self.handlers = {}
|
|
95
|
+
self.callback_handlers = {}
|
|
96
|
+
self.logger = setup_logger("osonbot")
|
|
97
|
+
self.create_db = create_db
|
|
98
|
+
|
|
99
|
+
def when(self, condition: str | list[str], text: str, parse_mode: str = None, reply_markup: str = None):
|
|
100
|
+
if condition:
|
|
101
|
+
if self.create_db:
|
|
102
|
+
create_table("users", username=str, user_id=int)
|
|
103
|
+
if isinstance(condition, list):
|
|
104
|
+
for cond in condition:
|
|
105
|
+
self.handlers[cond] = {"text": text, 'parse_mode': parse_mode, 'reply_markup': reply_markup}
|
|
106
|
+
else:
|
|
107
|
+
self.handlers[condition] = {"text": text, 'parse_mode': parse_mode, 'reply_markup': reply_markup}
|
|
108
|
+
|
|
109
|
+
def c_when(self, condition: str | list[str], text: str, parse_mode: str = None, reply_markup: str = None):
|
|
110
|
+
if condition:
|
|
111
|
+
if isinstance(condition, list):
|
|
112
|
+
for cond in condition:
|
|
113
|
+
self.callback_handlers[cond] = {"text": text, 'parse_mode': parse_mode, 'reply_markup': reply_markup}
|
|
114
|
+
else:
|
|
115
|
+
self.callback_handlers[condition] = {'text': text, "parse_mode": parse_mode, "reply_markup": reply_markup}
|
|
116
|
+
|
|
117
|
+
def get_updates(self, offset: int):
|
|
118
|
+
return httpx.get(self.api_url+"getUpdates", params={'offset': offset}).json()
|
|
119
|
+
|
|
120
|
+
def send_message(self, chat_id, text: str, parse_mode: str = None, reply_markup: list[list[str]] = None):
|
|
121
|
+
params = {'chat_id': chat_id, "text": text}
|
|
122
|
+
if parse_mode:
|
|
123
|
+
params['parse_mode'] = parse_mode
|
|
124
|
+
if reply_markup:
|
|
125
|
+
params['reply_markup'] = reply_markup
|
|
126
|
+
httpx.post(self.api_url+"sendMessage", json=params)
|
|
127
|
+
|
|
128
|
+
def send_photo(self, chat_id, photo: str, caption, reply_markup: list[list[str]] = None, parse_mode: str = None):
|
|
129
|
+
# try:
|
|
130
|
+
if os.path.exists(photo):
|
|
131
|
+
data = {"chat_id": chat_id, 'caption': caption}
|
|
132
|
+
if reply_markup:
|
|
133
|
+
data['reply_markup'] = reply_markup
|
|
134
|
+
if parse_mode:
|
|
135
|
+
data['parse_mode'] = parse_mode
|
|
136
|
+
with open(photo, 'rb') as p:
|
|
137
|
+
httpx.post(self.api_url+"sendPhoto", data=data, files={"photo": p})
|
|
138
|
+
elif "https://" in photo or "http://" in photo:
|
|
139
|
+
json = {"chat_id": chat_id, "photo": photo, 'caption': caption}
|
|
140
|
+
if reply_markup:
|
|
141
|
+
json['reply_markup'] = reply_markup
|
|
142
|
+
if parse_mode:
|
|
143
|
+
json['parse_mode'] = parse_mode
|
|
144
|
+
httpx.post(self.api_url+"sendPhoto", json=json)
|
|
145
|
+
else:
|
|
146
|
+
raise FileNotFoundOrInvalidURLError(f"Photo not found or invalid URL: {photo}")
|
|
147
|
+
# except:
|
|
148
|
+
# raise FileNotFoundOrInvalidURLError(f"Photo not found or invalid URL: {photo}")
|
|
149
|
+
|
|
150
|
+
def send_video(self, chat_id, video: str, caption, reply_markup: list[list[str]] = None, parse_mode: str = None):
|
|
151
|
+
# try:
|
|
152
|
+
if os.path.exists(video):
|
|
153
|
+
data = {"chat_id": chat_id, 'caption': caption}
|
|
154
|
+
if reply_markup:
|
|
155
|
+
data['reply_markup'] = reply_markup
|
|
156
|
+
if parse_mode:
|
|
157
|
+
data['parse_mode'] = parse_mode
|
|
158
|
+
with open(video, 'rb') as v:
|
|
159
|
+
httpx.post(self.api_url+"sendVideo", data=data, files={"video": v})
|
|
160
|
+
elif "https://" in video or "http://" in video:
|
|
161
|
+
json = {"chat_id": chat_id, "video": video, 'caption': caption}
|
|
162
|
+
if reply_markup:
|
|
163
|
+
json['reply_markup'] = reply_markup
|
|
164
|
+
if parse_mode:
|
|
165
|
+
json['parse_mode'] = parse_mode
|
|
166
|
+
httpx.post(self.api_url+"sendVideo", json=json)
|
|
167
|
+
else:
|
|
168
|
+
raise FileNotFoundOrInvalidURLError(f"Video not found or invalid URL: {video}")
|
|
169
|
+
# except:
|
|
170
|
+
# raise FileNotFoundOrInvalidURLError(f"Video not found or invalid URL: {video}")
|
|
171
|
+
|
|
172
|
+
def send_audio(self, chat_id, audio: str, caption, reply_markup: list[list[str]] = None, parse_mode: str = None):
|
|
173
|
+
# try:
|
|
174
|
+
if os.path.exists(audio):
|
|
175
|
+
data = {"chat_id": chat_id, 'caption': caption}
|
|
176
|
+
if reply_markup:
|
|
177
|
+
data['reply_markup'] = reply_markup
|
|
178
|
+
if parse_mode:
|
|
179
|
+
data['parse_mode'] = parse_mode
|
|
180
|
+
with open(audio, 'rb') as a:
|
|
181
|
+
httpx.post(self.api_url+"sendAudio", data=data, files={"audio": a})
|
|
182
|
+
elif "https://" in audio or "http://" in audio:
|
|
183
|
+
json = {"chat_id": chat_id, "audio": audio, 'caption': caption, 'reply_markup': reply_markup}
|
|
184
|
+
if reply_markup:
|
|
185
|
+
json['reply_markup'] = reply_markup
|
|
186
|
+
if parse_mode:
|
|
187
|
+
json['parse_mode'] = parse_mode
|
|
188
|
+
httpx.post(self.api_url+"sendAudio", json=json)
|
|
189
|
+
else:
|
|
190
|
+
raise FileNotFoundOrInvalidURLError(f"Audio not found or invalid URL: {audio}")
|
|
191
|
+
# except:
|
|
192
|
+
# raise FileNotFoundOrInvalidURLError(f"Audio not found or invalid URL: {audio}")
|
|
193
|
+
|
|
194
|
+
def send_voice(self, chat_id, voice: str, caption, reply_markup: list[list[str]] = None, parse_mode: str = None):
|
|
195
|
+
# try:
|
|
196
|
+
if os.path.exists(voice):
|
|
197
|
+
data = {"chat_id": chat_id, 'caption': caption}
|
|
198
|
+
if reply_markup:
|
|
199
|
+
data['reply_markup'] = reply_markup
|
|
200
|
+
if parse_mode:
|
|
201
|
+
data['parse_mode'] = parse_mode
|
|
202
|
+
with open(voice, 'rb') as v:
|
|
203
|
+
httpx.post(self.api_url+"sendVoice", data=data, files={"voice": v})
|
|
204
|
+
else:
|
|
205
|
+
raise FileNotFoundError(f"file {voice} not found. Make sure it exists")
|
|
206
|
+
# except:
|
|
207
|
+
# raise FileNotFoundOrInvalidURLError(f"Audio not found or invalid URL: {voice}")
|
|
208
|
+
|
|
209
|
+
def send_sticker(self, chat_id, sticker: str, reply_markup: dict = None):
|
|
210
|
+
params = {"chat_id": chat_id, "sticker": sticker}
|
|
211
|
+
if reply_markup:
|
|
212
|
+
params['reply_markup'] = reply_markup
|
|
213
|
+
httpx.post(self.api_url + "sendSticker", json=params)
|
|
214
|
+
|
|
215
|
+
def formatter(self, text: str, message):
|
|
216
|
+
try:
|
|
217
|
+
return text.format(
|
|
218
|
+
first_name=message['from']['first_name'],
|
|
219
|
+
last_name=message['from']['last_name'],
|
|
220
|
+
full_name=f"{message['from']['first_name']} {message['from']['last_name']}",
|
|
221
|
+
message_text=message['text'],
|
|
222
|
+
user_id=message['from']['id'],
|
|
223
|
+
message_id=message['message_id']
|
|
224
|
+
)
|
|
225
|
+
except:
|
|
226
|
+
return text.format(
|
|
227
|
+
first_name=message['chat']['first_name'],
|
|
228
|
+
last_name=message['chat']['last_name'],
|
|
229
|
+
full_name=f"{message['chat']['first_name']} {message['chat']['last_name']}",
|
|
230
|
+
message_text=message['text'],
|
|
231
|
+
user_id=message['from']['id'],
|
|
232
|
+
message_id=message['message_id']
|
|
233
|
+
)
|
|
234
|
+
def get_me(self):
|
|
235
|
+
return httpx.get(self.api_url + "getMe").json()
|
|
236
|
+
|
|
237
|
+
def process_callback(self, callback):
|
|
238
|
+
message = callback.get("message", {})
|
|
239
|
+
data = callback.get('data')
|
|
240
|
+
chat_id = message['chat']['id']
|
|
241
|
+
handled = self.callback_handlers.get(data)
|
|
242
|
+
|
|
243
|
+
if not handled:
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
self.send_message(chat_id, self.formatter(handled['text'], message))
|
|
247
|
+
|
|
248
|
+
def process_messages(self, message):
|
|
249
|
+
chat_id = message['from']['id']
|
|
250
|
+
if "text" in message:
|
|
251
|
+
text = message.get("text", "")
|
|
252
|
+
chat_id = message['chat']['id']
|
|
253
|
+
handled = self.handlers.get(text) or self.handlers.get("*")
|
|
254
|
+
|
|
255
|
+
if not handled:
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
if callable(handled['text']):
|
|
259
|
+
handled['text'](message)
|
|
260
|
+
|
|
261
|
+
if isinstance(handled['text'], Photo):
|
|
262
|
+
self.send_photo(chat_id, handled['text'].url, caption=self.formatter(handled['text'].caption, message), reply_markup=handled['reply_markup'], parse_mode=handled['parse_mode'])
|
|
263
|
+
elif isinstance(handled['text'], Video):
|
|
264
|
+
self.send_video(chat_id, handled['text'].url, caption=self.formatter(handled['text'].caption, message), reply_markup=handled['reply_markup'], parse_mode=handled['parse_mode'])
|
|
265
|
+
elif isinstance(handled['text'], Audio):
|
|
266
|
+
self.send_audio(chat_id, handled['text'].url, caption=self.formatter(handled['text'].caption, message), reply_markup=handled['reply_markup'], parse_mode=handled['parse_mode'])
|
|
267
|
+
elif isinstance(handled['text'], Voice):
|
|
268
|
+
self.send_voice(chat_id, handled['text'].url, caption=self.formatter(handled['text'].caption, message), reply_markup=handled['reply_markup'], parse_mode=handled['parse_mode'])
|
|
269
|
+
elif isinstance(handled['text'], Sticker):
|
|
270
|
+
self.send_sticker(chat_id, handled['text'].file_id, reply_markup=handled['reply_markup'])
|
|
271
|
+
elif isinstance(handled['text'], str):
|
|
272
|
+
self.send_message(chat_id, self.formatter(handled['text'], message), parse_mode=handled['parse_mode'], reply_markup=handled['reply_markup'])
|
|
273
|
+
|
|
274
|
+
elif "photo" in message:
|
|
275
|
+
hv = self.handlers.get(Photo)
|
|
276
|
+
self.send_message(chat_id, hv['text'], parse_mode=hv['parse_mode'], reply_markup=hv['reply_markup'])
|
|
277
|
+
|
|
278
|
+
elif "video" in message:
|
|
279
|
+
hv = self.handlers.get(Video)
|
|
280
|
+
self.send_message(chat_id, hv['text'], parse_mode=hv['parse_mode'], reply_markup=hv['reply_markup'])
|
|
281
|
+
|
|
282
|
+
elif "sticker" in message:
|
|
283
|
+
hv = self.handlers.get(Sticker)
|
|
284
|
+
self.send_message(chat_id, hv['text'], parse_mode=hv['parse_mode'], reply_markup=hv['reply_markup'])
|
|
285
|
+
|
|
286
|
+
def run(self):
|
|
287
|
+
getme = self.get_me()
|
|
288
|
+
self.logger.info(f"[@{getme['result']['username']} - id={getme['result']['id']}] successfully started")
|
|
289
|
+
offset = 0
|
|
290
|
+
while True:
|
|
291
|
+
try:
|
|
292
|
+
for update in self.get_updates(offset).get("result", []):
|
|
293
|
+
offset = update['update_id'] + 1
|
|
294
|
+
|
|
295
|
+
self.when("/admin")
|
|
296
|
+
|
|
297
|
+
if "callback_query" in update:
|
|
298
|
+
self.process_callback(update['callback_query'])
|
|
299
|
+
elif "message" in update:
|
|
300
|
+
self.process_messages(update['message'])
|
|
301
|
+
|
|
302
|
+
except Exception as e:
|
|
303
|
+
self.logger.error("Error occured", exc_info=True)
|
|
304
|
+
|
|
305
|
+
def KeyboardButton(*rows: list[str], resize_keyboard: bool = True, one_time_keyborad: bool = False):
|
|
306
|
+
return {
|
|
307
|
+
"keyboard": list(rows),
|
|
308
|
+
'resize_keyboard': resize_keyboard,
|
|
309
|
+
'one_time_keyboard': one_time_keyborad
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
def InlineKeyboardButton(*rows: list[list[str, str]]) -> dict[str, list]:
|
|
313
|
+
keyboard = []
|
|
314
|
+
for row in rows:
|
|
315
|
+
keyboard_row = [{"text": text, "callback_data": data} for text, data in row]
|
|
316
|
+
keyboard.append(keyboard_row)
|
|
317
|
+
return {"inline_keyboard": keyboard}
|
|
318
|
+
|
|
319
|
+
def URLKeyboardButton(*rows: list[list[str, str]]) -> dict[str, list]:
|
|
320
|
+
keyboard = []
|
|
321
|
+
for row in rows:
|
|
322
|
+
keyboard_row = [{"text": text, "url": data} for text, data in row]
|
|
323
|
+
keyboard.append(keyboard_row)
|
|
324
|
+
return {"inline_keyboard": keyboard}
|
|
325
|
+
|
|
326
|
+
def RemoveKeyboardButton():
|
|
327
|
+
return {
|
|
328
|
+
'remove_keyboard': True
|
|
329
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
httpx
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
osonbot
|
osonbot-1.0.0/setup.cfg
ADDED
osonbot-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="osonbot",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
requires=['httpx'],
|
|
8
|
+
author="https://t.me/jackson_rodger",
|
|
9
|
+
description="A simple and lightweight Telegram bot framework",
|
|
10
|
+
long_description=open("README.md").read(),
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
url="https://github.com/sinofarmonov323/osonbot",
|
|
13
|
+
classifiers=[
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
],
|
|
18
|
+
python_requires=">=3.10",
|
|
19
|
+
install_requires=["httpx"]
|
|
20
|
+
)
|