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 ADDED
Binary file
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,9 @@
1
+ README.md
2
+ setup.py
3
+ osonbot/__init__.py
4
+ osonbot/bot.py
5
+ osonbot.egg-info/PKG-INFO
6
+ osonbot.egg-info/SOURCES.txt
7
+ osonbot.egg-info/dependency_links.txt
8
+ osonbot.egg-info/requires.txt
9
+ osonbot.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ httpx
@@ -0,0 +1 @@
1
+ osonbot
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
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
+ )