minline 0.1.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.
minline-0.1.0/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Minline License (Non-Commercial)
2
+
3
+ Copyright (c) 2025 Bakirullit
4
+
5
+ Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, and distribute the Software for **personal, educational, or non-commercial purposes**, subject to the following conditions:
6
+
7
+ 1. **Commercial use is strictly prohibited**. This includes use in paid products, SaaS platforms, enterprise software, or any application where the software contributes to generating revenue.
8
+
9
+ 2. Redistribution of modified versions must include attribution to the original author.
10
+
11
+ 3. The above copyright notice and this license must be included in all copies or substantial portions of the Software.
12
+
13
+ The Software is provided "as is", without warranty of any kind, express or implied.
14
+
15
+ For commercial licensing inquiries, contact: bakirullit@gmail.com
minline-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: minline
3
+ Version: 0.1.0
4
+ Summary: Menu-inline framework for Telegram bots
5
+ Author: bakirullit
6
+ Author-email: Bakdaulet <bakirullit@gmail.com>
7
+ License: MIT
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: aiogram>=3.3
12
+ Requires-Dist: redis>=5.0.0
13
+ Dynamic: author
14
+ Dynamic: license-file
15
+ Dynamic: requires-python
16
+
17
+ # minline
18
+
19
+ **Menu-inline framework for Telegram bots**
20
+
21
+ Build Telegram inline menu systems with localized rendering, button logic separation, and extensible components.
@@ -0,0 +1,5 @@
1
+ # minline
2
+
3
+ **Menu-inline framework for Telegram bots**
4
+
5
+ Build Telegram inline menu systems with localized rendering, button logic separation, and extensible components.
@@ -0,0 +1,13 @@
1
+ # Minline - Custom Telegram Menu Framework
2
+ # Copyright (c) 2025 Bakirullit
3
+ # License: Minline License (Non-Commercial) – see LICENSE file for details
4
+
5
+
6
+ from .app import MinlineApp
7
+ from .components.buttons.button import Button
8
+ from .components.activity.menu import Menu
9
+ from .runtime import *
10
+
11
+ __all__ = ["MinlineApp", "Menu", "Button",
12
+ "LanguageManager", "RedisSessionManager",
13
+ "render_menu", "RenderedMenu"]
@@ -0,0 +1,152 @@
1
+ # Minline - Custom Telegram Menu Framework
2
+ # Copyright (c) 2025 Bakirullit
3
+ # License: Minline License (Non-Commercial) – see LICENSE file for details
4
+
5
+ from aiogram import Bot, Dispatcher, Router
6
+ from aiogram.types import Message, CallbackQuery
7
+ from aiogram.filters import CommandStart
8
+ from aiogram.fsm.storage.memory import MemoryStorage
9
+ import asyncio
10
+ from typing import Callable, Awaitable
11
+ from .session.redis_manager import RedisSessionManager
12
+ from .runtime.language_manager import LanguageManager
13
+ from .components.buttons.button import Button # assuming your Menu and Button classes are here
14
+ from .components.activity.menu import Menu
15
+
16
+ class MinlineApp:
17
+ def __init__(self, token: str, *, language_dir: str = "languages", default_lang: str = "en"):
18
+ self.token = token
19
+ self.dp = Dispatcher(storage=MemoryStorage())
20
+ self.bot = Bot(token=self.token)
21
+ self.router = Router()
22
+ self.default_lang = default_lang
23
+ self.menu_registry = {}
24
+ self.action_commands: dict[str, Callable[[CallbackQuery, str], Awaitable]] = {}
25
+ self.lang = LanguageManager(language_dir)
26
+ self.session = RedisSessionManager()
27
+ self.router.message(CommandStart())(self._menu_handler)
28
+ self.router.message()(self._delete_unknown)
29
+ self._register_callbacks()
30
+ self.dp.include_router(self.router)
31
+
32
+ def action(self, name: str):
33
+ def decorator(func):
34
+ self.action_commands[name] = func
35
+ return func
36
+ return decorator
37
+
38
+ def menu(self, path: str):
39
+ def decorator(fn):
40
+ menu_instance = fn()
41
+ menu_instance.menu_id = path
42
+ if path != "/":
43
+ back_button = Button("back", f"#route://")
44
+ menu_instance.controls.insert(0, [back_button])
45
+ self.menu_registry[path] = menu_instance
46
+ return menu_instance
47
+ return decorator
48
+
49
+ async def _menu_handler(self, message: Message):
50
+ user_id = message.from_user.id
51
+ chat_id = message.chat.id
52
+ lang = self.default_lang
53
+ state = await self.session.get_state(user_id)
54
+ if state:
55
+ old_chat_id = state.get("chat_id")
56
+ old_message_id = state.get("message_id")
57
+ if old_chat_id and old_message_id:
58
+ try:
59
+ await self.bot.delete_message(old_chat_id, old_message_id)
60
+ except Exception:
61
+ pass
62
+ menu = self.menu_registry.get("/")
63
+ if not menu:
64
+ await self.bot.send_message(chat_id, "Menu '/' not found.")
65
+ return
66
+ _, _, message_id = await menu.render(chat_id, None, self.bot, lang)
67
+ await self.session.set_state(user_id, {
68
+ "chat_id": chat_id,
69
+ "message_id": message_id,
70
+ "lang": lang,
71
+ "menu_path": "/"
72
+ })
73
+
74
+ try:
75
+ await message.delete()
76
+ except Exception:
77
+ pass
78
+
79
+ def _register_callbacks(self):
80
+ @self.router.callback_query()
81
+ async def callback_handler(callback: CallbackQuery):
82
+ user_id = callback.from_user.id
83
+ data = callback.data
84
+ if not data or ":" not in data:
85
+ return
86
+
87
+ parts = data.split(":", maxsplit=3)
88
+ if len(parts) < 3:
89
+ return
90
+
91
+ lang, current_path, command = parts[0], parts[1], parts[2]
92
+ arg = parts[3] if len(parts) > 3 else ""
93
+ print(f"Callback received: lang={lang}, path={current_path}, command={command}, arg={arg}", parts)
94
+
95
+ if not command.startswith("#"):
96
+ return
97
+
98
+ if (command == "#route"):
99
+ state = await self.session.get_state(user_id)
100
+ if not state:
101
+ return
102
+
103
+ chat_id = state["chat_id"]
104
+ message_id = state["message_id"]
105
+
106
+ if arg == "//":
107
+ path_parts = current_path.rstrip("/").split("/")
108
+ new_path = "/" if len(path_parts) <= 2 else "/".join(path_parts[:-1])
109
+ else:
110
+ new_path = current_path.rstrip("/") + "/" + arg
111
+ menu = self.menu_registry.get(new_path)
112
+ if not menu:
113
+ await callback.answer("Menu not found", show_alert=True)
114
+ return
115
+
116
+ _, _, new_msg_id = await menu.render(chat_id, message_id, self.bot, lang)
117
+ await self.session.set_state(user_id, {
118
+ "chat_id": chat_id,
119
+ "message_id": new_msg_id,
120
+ "lang": lang,
121
+ "menu_path": new_path
122
+ })
123
+
124
+ await callback.answer()
125
+ return
126
+
127
+ if command in self.action_commands:
128
+ await self.action_commands[command](callback, command)
129
+ return
130
+
131
+ await callback.answer("Unknown action", show_alert=True)
132
+
133
+ async def _open_menu(self, user_id: int, menu: Menu, path: str):
134
+ state = await self.session.get_state(user_id)
135
+ if not state:
136
+ return
137
+
138
+ chat_id = state["chat_id"]
139
+ message_id = state["message_id"]
140
+ lang = state.get("lang", self.default_lang)
141
+ menu.lang = lang
142
+ await menu.render(chat_id, message_id, self.bot)
143
+
144
+ state["menu_path"] = path
145
+ await self.session.set_state(user_id, state)
146
+
147
+ async def _delete_unknown(self, message: Message):
148
+ await message.delete()
149
+
150
+ def run(self):
151
+ asyncio.run(self.dp.start_polling(self.bot))
152
+
File without changes
@@ -0,0 +1,7 @@
1
+ from aiogram.types import InlineKeyboardButton
2
+
3
+ class Button:
4
+ def __init__(self, text_id: str, action: str, data: dict = None):
5
+ self.text_id = text_id
6
+ self.action = action
7
+ self.data = data or {}
File without changes
@@ -0,0 +1,26 @@
1
+ import os
2
+ import json
3
+
4
+ class LanguageManager:
5
+ _languages: dict[str, dict[str, str]] = {}
6
+
7
+ def __init__(self, directory: str = "languages"):
8
+ self.directory = directory
9
+ self.load_languages(directory)
10
+
11
+ @classmethod
12
+ def load_languages(cls, folder_path: str = "languages"):
13
+ for filename in os.listdir(folder_path):
14
+ if filename.endswith(".json"):
15
+ lang_code = filename.split(".")[0]
16
+ full_path = os.path.join(folder_path, filename)
17
+ with open(full_path, "r", encoding="utf-8") as f:
18
+ cls._languages[lang_code] = json.load(f)
19
+
20
+ @classmethod
21
+ def get(cls, lang: str, key: str) -> str:
22
+ return cls._languages.get(lang, {}).get(key, key)
23
+
24
+
25
+ # Load on import
26
+ LanguageManager.load_languages()
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: minline
3
+ Version: 0.1.0
4
+ Summary: Menu-inline framework for Telegram bots
5
+ Author: bakirullit
6
+ Author-email: Bakdaulet <bakirullit@gmail.com>
7
+ License: MIT
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: aiogram>=3.3
12
+ Requires-Dist: redis>=5.0.0
13
+ Dynamic: author
14
+ Dynamic: license-file
15
+ Dynamic: requires-python
16
+
17
+ # minline
18
+
19
+ **Menu-inline framework for Telegram bots**
20
+
21
+ Build Telegram inline menu systems with localized rendering, button logic separation, and extensible components.
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ minline/__init__.py
6
+ minline/app.py
7
+ minline.egg-info/PKG-INFO
8
+ minline.egg-info/SOURCES.txt
9
+ minline.egg-info/dependency_links.txt
10
+ minline.egg-info/requires.txt
11
+ minline.egg-info/top_level.txt
12
+ minline/components/__init__.py
13
+ minline/components/buttons/button.py
14
+ minline/runtime/__init__.py
15
+ minline/runtime/language_manager.py
@@ -0,0 +1,2 @@
1
+ aiogram>=3.3
2
+ redis>=5.0.0
@@ -0,0 +1 @@
1
+ minline
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "minline"
3
+ version = "0.1.0"
4
+ description = "Menu-inline framework for Telegram bots"
5
+ authors = [
6
+ { name="Bakdaulet", email="bakirullit@gmail.com" }
7
+ ]
8
+ readme = "README.md"
9
+ license = { text = "MIT" }
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "aiogram>=3.3",
13
+ "redis>=5.0.0"
14
+ ]
15
+
16
+ [build-system]
17
+ requires = ["setuptools", "wheel"]
18
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
minline-0.1.0/setup.py ADDED
@@ -0,0 +1,15 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="minline",
5
+ version="0.1.0",
6
+ description="Menu-inline framework for Telegram bots",
7
+ author="bakirullit",
8
+ packages=find_packages(),
9
+ include_package_data=True,
10
+ install_requires=[
11
+ "aiogram>=3.3",
12
+ "redis>=5.0.0"
13
+ ],
14
+ python_requires=">=3.10",
15
+ )