├── .gitignore ├── README.rst ├── bots ├── __init__.py ├── ftp_bot.py ├── history_bot.py └── wiki_bot.py ├── config.py ├── dev-requirements.txt ├── elbot ├── __init__.py ├── app.py ├── bots │ ├── GoogleBot.py │ ├── LyricBot.py │ ├── YouTubeBot.py │ └── __init__.py └── domain │ ├── __init__.py │ ├── group.py │ ├── keyboard.py │ ├── message.py │ ├── update.py │ └── user.py ├── python_bot.py ├── requirements.txt └── ser_bot.py /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | ### Virtualenv template 62 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 63 | .Python 64 | [Bb]in 65 | [Ii]nclude 66 | [Ll]ib 67 | [Ll]ib64 68 | [Ll]ocal 69 | [Ss]hare 70 | pyvenv.cfg 71 | .venv 72 | pip-selfcheck.json 73 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ELBot 2 | ============================================================================== 3 | - `Introduction`_ 4 | 5 | Introduction 6 | ------------------------------------------------------------------------------ 7 | This is a telegram bot platform is written in python, it runs as a 8 | standalone telegram bot and 9 | uses `telegram bot API `_ for doing its job :smile:. 10 | 11 | If you want to have some automated replies on your telegram user, 12 | you must use somethings like `Telegram CLI `_ and 13 | run your scripts on top of it. 14 | -------------------------------------------------------------------------------- /bots/__init__.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : __init__.py 4 | # 5 | # [] Creation Date : 27-07-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | -------------------------------------------------------------------------------- /bots/ftp_bot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : file.py 4 | # 5 | # [] Creation Date : 27-07-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import os 12 | import bots.abstract_bot 13 | import tgl 14 | 15 | 16 | class FTPBot(bots.abstract_bot.AbstractBot): 17 | bot_name = 'ftp' 18 | authorize_users = ['parham_alvani'] 19 | 20 | def __init__(self): 21 | self.msg = None 22 | self.peer = None 23 | 24 | def run_query(self, query: str, msg: tgl.Msg, peer: tgl.Peer): 25 | self.msg = msg 26 | self.peer = peer 27 | if self.msg.src.username in FTPBot.authorize_users: 28 | command = query.split(' ')[0] 29 | try: 30 | method = getattr(self, 'do_' + command) 31 | except AttributeError: 32 | method = None 33 | if not method: 34 | self.peer.send_msg("Error: Command not found [{}]".format(command), reply=self.msg.id) 35 | return 36 | method(query[len(command):].strip()) 37 | else: 38 | self.peer.send_msg("You don not have permission on FTP server", reply=self.msg.id) 39 | 40 | def do_ls(self, query: str): 41 | path = query.lstrip() 42 | if not os.path.exists(path): 43 | self.peer.send_msg("Error: Path not found [{}]".format(path), reply=self.msg.id) 44 | return 45 | reply = "" 46 | for file in os.listdir(path): 47 | if not os.path.isdir(os.path.join(path, file)): 48 | reply += "{1}[{0} B]\n".format(os.lstat(os.path.join(path, file)).st_size, file) 49 | else: 50 | reply += "{0}[-]\n".format(file) 51 | self.peer.send_msg(reply, reply=self.msg.id) 52 | 53 | def do_get(self, query: str): 54 | path = query.lstrip() 55 | if not os.path.exists(path): 56 | self.peer.send_msg("Error: Path not found [{}]".format(path), reply=self.msg.id) 57 | return 58 | if os.path.isdir(path): 59 | self.peer.send_msg("Error: Cannot send directory [{}]".format(path), reply=self.msg.id) 60 | return 61 | self.peer.send_document(path) 62 | -------------------------------------------------------------------------------- /bots/history_bot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : history_bot.py 4 | # 5 | # [] Creation Date : 27-07-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import tgl 12 | import bots.abstract_bot 13 | import functools 14 | import time 15 | 16 | 17 | class HistoryBot(bots.abstract_bot.AbstractBot): 18 | bot_name = 'history' 19 | 20 | def __init__(self): 21 | self.peer = None 22 | self.history = [] 23 | 24 | def run_query(self, query: str, msg: tgl.Msg, peer: tgl.Peer): 25 | self.peer = peer 26 | 27 | # Get all the history, 100 msgs at a time 28 | self.peer.history(0, 100, functools.partial(self.history_callback, 100)) 29 | 30 | def history_callback(self, msg_count, success, msgs: tgl.Msg): 31 | self.history.extend(msgs) 32 | if len(msgs) == msg_count: 33 | self.peer.history(len(self.history), msg_count, 34 | functools.partial(self.history_callback, msg_count)) 35 | else: 36 | output = open("history_" + self.peer.name + ".txt", "w") 37 | self.history.reverse() 38 | for msg in self.history: 39 | line = "[{0}] |{1}| {2} --> {3} >> {4}\n".format(msg.id, time.strftime("%c", msg.date.timetuple()), 40 | msg.src.name.replace("_", " "), 41 | msg.dest.name.replace("_", " "), msg.text) 42 | output.write(line) 43 | -------------------------------------------------------------------------------- /bots/wiki_bot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : wiki.py 4 | # 5 | # [] Creation Date : 27-07-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import urllib.request 12 | import tgl 13 | import bots.abstract_bot 14 | 15 | 16 | class WikiBot(bots.abstract_bot.AbstractBot): 17 | bot_name = 'wiki' 18 | 19 | def run_query(self, query: str, msg: tgl.Msg, peer: tgl.Peer): 20 | """ 21 | Returns a wiki link and the first paragraph of the page 22 | Telegram usage: wiki 23 | :param query: search term 24 | """ 25 | 26 | main_page = 'http://en.wikipedia.org/wiki/Main_Page' 27 | 28 | search_term = query.replace(' ', '_') 29 | 30 | if len(search_term) < 1: 31 | url = main_page 32 | else: 33 | url = 'http://en.wikipedia.org/wiki/' + search_term 34 | try: 35 | urllib.request.urlopen(url) 36 | except urllib.request.HTTPError: 37 | url = main_page 38 | 39 | peer.send_msg(url, reply=msg.id) 40 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # This is ELBot configurations, these configuraitons 3 | # include Bot Token and list of your required bots. 4 | 5 | # Bot Token 6 | token = "" 7 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | flake8 3 | pep8-naming 4 | -------------------------------------------------------------------------------- /elbot/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | elbot_log_format = ( 4 | 'ELBot: [%(asctime)s] %(levelname)-8s %(name)-12s %(thread)-8s %(message)s' 5 | ) 6 | 7 | elbot_log_formatter = logging.Formatter(elbot_log_format) 8 | elbot_log_handler = logging.StreamHandler() 9 | elbot_log_handler.setLevel(logging.DEBUG) 10 | elbot_log_handler.setFormatter(elbot_log_formatter) 11 | logger = logging.getLogger('ELBot') 12 | logger.setLevel(logging.DEBUG) 13 | logger.addHandler(elbot_log_handler) 14 | -------------------------------------------------------------------------------- /elbot/app.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : app.py 4 | # 5 | # [] Creation Date : 11-10-2016 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | import time 10 | import requests 11 | import json 12 | import threading 13 | import re 14 | import logging 15 | 16 | from .domain.update import Update, UpdateDictDecoder 17 | from .domain.keyboard import ReplyKeyboardMarkup, \ 18 | ReplyKeyboardMarkdownJSONEncoder 19 | 20 | 21 | logger = logging.getLogger('ELBot.app') 22 | 23 | 24 | class ELBot: 25 | ''' 26 | ELBot represents core application module for creating a bot, 27 | define your handlers and use ELBot as a helper for sending things, 28 | You are done :D 29 | ''' 30 | def __init__(self, hash_id: str): 31 | self.hash_id = hash_id 32 | self.base_url = 'https://api.telegram.org/bot' + self.hash_id + '/' 33 | self.message_handlers = {} 34 | 35 | def send_message(self, chat_id: int, text: str, 36 | disable_web_page_preview: bool = False, 37 | reply_to_message_id: int = 0, 38 | reply_markup: ReplyKeyboardMarkup = None, 39 | parse_mode: str = ""): 40 | ''' 41 | Use this method to send text messages. 42 | On success, the sent Message is returned. 43 | :param chat_id: Unique identifier for the message recipient — 44 | User or GroupChat id 45 | :param text: Text of the message to be sent 46 | :param disable_web_page_preview: Disables link previews for 47 | links in this message 48 | :param reply_to_message_id: If the message is a reply, 49 | ID of the original message 50 | :param reply_markup: Additional interface options. A JSON-serialized 51 | object for a custom reply keyboard, 52 | instructions to hide keyboard or to force a reply 53 | from the user. 54 | :param parse_mode: Send Markdown, if you want Telegram apps to show 55 | bold, italic and inline URLs in your 56 | bot's message. For the moment, 57 | only Telegram for Android supports this. 58 | :return: None 59 | ''' 60 | params = { 61 | 'chat_id': str(chat_id), 62 | 'text': text, 63 | 'disable_web_page_preview': disable_web_page_preview, 64 | } 65 | 66 | if reply_to_message_id != 0: 67 | params['reply_to_message_id'] = reply_to_message_id 68 | 69 | if reply_markup is not None and isinstance(reply_markup, 70 | ReplyKeyboardMarkup): 71 | params['reply_markup'] = \ 72 | json.dumps(reply_markup, 73 | cls=ReplyKeyboardMarkdownJSONEncoder) 74 | 75 | if parse_mode is not None: 76 | params['parse_mode'] = parse_mode 77 | 78 | requests.post(url=self.base_url + 'sendMessage', data=params, 79 | headers={ 80 | 'content-type': 'application/x-www-form-urlencoded'}) 81 | 82 | def get_updates(self, offset: int = 0, limit: int = 0, 83 | timeout: int = 0) -> [Update]: 84 | ''' 85 | Use this method to receive incoming updates using long polling. 86 | An Array of Update objects is returned. 87 | :param offset: Identifier of the first update to be returned. 88 | Must be greater by one than the highest among the 89 | identifiers of previously received updates. 90 | By default, updates starting with the earliest 91 | unconfirmed update are returned. 92 | An update is considered confirmed as soon as getUpdates 93 | is called with an offset higher than 94 | its update_id. 95 | :param limit: Limits the number of updates to be retrieved. 96 | Values between 1—100 are accepted. Defaults to 100 97 | :param timeout: Timeout in seconds for long polling. Defaults to 0, 98 | i.e. usual short polling 99 | :return: list[Update] 100 | ''' 101 | updates = [] 102 | params = {} 103 | if offset != 0: 104 | params['offset'] = offset 105 | if limit != 0: 106 | params['limit'] = limit 107 | if timeout != 0: 108 | params['timeout'] = timeout 109 | response = requests.get(url=self.base_url + 'getUpdates', 110 | params=params) 111 | response = json.loads(response.text) 112 | if response['ok']: 113 | for obj in response['result']: 114 | update = UpdateDictDecoder.decode(obj) 115 | updates.append(update) 116 | else: 117 | print("We get error at {}".format(response['result'])) 118 | return updates 119 | 120 | def message(self, message: str): 121 | def _message(fn): 122 | pattern = re.compile(message) 123 | self.message_handlers[pattern] = fn 124 | return fn 125 | return _message 126 | 127 | def run(self): 128 | print(' * 18.20 at Sep 07 2016 7:20 IR721') 129 | print(" * ELBot at %s" % self.hash_id) 130 | update_id = 0 131 | while True: 132 | try: 133 | updates = self.get_updates(offset=update_id) 134 | if len(updates) != 0: 135 | update_id = updates[-1].id + 1 136 | for update in updates: 137 | message = update.message 138 | if message is None: 139 | continue 140 | for pattern in self.message_handlers: 141 | if pattern.match(message.text) is not None: 142 | logger.info('Handling: %s' % message.text) 143 | threading.Thread( 144 | target=self.message_handlers[pattern], 145 | args=(message,), daemon=True).start() 146 | except Exception as ex: 147 | print("Error: {}".format(ex)) 148 | raise ex 149 | time.sleep(10) 150 | -------------------------------------------------------------------------------- /elbot/bots/GoogleBot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : GoogleBot.py 4 | # 5 | # [] Creation Date : 09-09-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import json 12 | import urllib.parse 13 | import urllib.request 14 | 15 | from elbot.core.AbstractBot import AbstractBot 16 | from elbot.core.BotFather import BotFather 17 | from elbot.domain.Message import Message 18 | 19 | 20 | class GoogleBot(AbstractBot): 21 | bot_name = 'google' 22 | 23 | def run_query(self, message: Message, father: BotFather): 24 | father.send_message(chat_id=message.chat.id, text=GoogleBot.search_google(message.text), 25 | reply_to_message_id=message.message_id) 26 | 27 | @staticmethod 28 | def search_google(terms): 29 | """ 30 | Returns the link and the description of the first result from a google search 31 | Telegram usage: google 32 | :param terms: 33 | :return: 34 | """ 35 | 36 | query = terms 37 | query = urllib.parse.urlencode({'q': query}) 38 | request = urllib.request.urlopen('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&' + query).read() 39 | request = str(request, 'UTF-8') 40 | response = json.loads(request) 41 | results = response['responseData']['results'] 42 | retval = "" 43 | for result in results: 44 | title = result['title'] 45 | url = result['url'] # was URL in the original and that threw a name error exception 46 | title = title.translate({ord(k): None for k in u''}) 47 | title = title.translate({ord(k): None for k in u''}) 48 | retval += title + ' : ' + url + '\n' 49 | return retval 50 | -------------------------------------------------------------------------------- /elbot/bots/LyricBot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : LyricBot.py 4 | # 5 | # [] Creation Date : 26-07-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import suds.client 12 | 13 | from elbot.core.AbstractBot import AbstractBot 14 | from elbot.core.BotFather import BotFather 15 | from elbot.domain.Message import Message 16 | 17 | 18 | class LyricBot(AbstractBot): 19 | bot_name = 'lyric' 20 | 21 | def run_query(self, message: Message, father: BotFather): 22 | father.send_message(chat_id=message.chat.id, 23 | text=LyricBot.get_lyric(message.text.split(',')[0], message.text.split(',')[1]), 24 | reply_to_message_id=message.message_id, 25 | disable_web_page_preview=True) 26 | 27 | @staticmethod 28 | def get_lyric(artist, song): 29 | client = suds.client.Client('http://lyrics.wikia.com/server.php?wsdl') 30 | 31 | retval = '404 Not Found' 32 | response = client.service.checkSongExists(artist, song) 33 | if response: 34 | response = client.service.getSongResult(artist, song) 35 | retval = """ 36 | {0:#^54} 37 | {1} 38 | {3:=^54} 39 | {2} 40 | {3:=^54} 41 | Please note that currently, the API only returns a small portion of the lyrics (about 1/7th of them). 42 | This is because of the licensing restrictions 43 | """.format(' ' + response.artist + ' : ' + response.song + ' ', str(response.lyrics.encode("ISO-8859-1"), 'UTF-8'), 44 | response.url, "") 45 | return retval 46 | 47 | 48 | # Just for test :-) 49 | if __name__ == '__main__': 50 | print(LyricBot.get_lyric('Poets of the Fall', 'Daze')) 51 | -------------------------------------------------------------------------------- /elbot/bots/YouTubeBot.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : YouTubeBot.py 4 | # 5 | # [] Creation Date : 10/29/15 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | __author__ = 'Parham Alvani' 10 | 11 | import os 12 | 13 | from pytube import YouTube 14 | 15 | from elbot.core.AbstractBot import AbstractBot 16 | from elbot.core.BotFather import BotFather 17 | from elbot.domain.Message import Message 18 | 19 | 20 | class YouTubeBot(AbstractBot): 21 | bot_name = 'ytdl' 22 | 23 | def run_query(self, message: Message, father: BotFather): 24 | father.send_chat_action(message.chat.id, 'upload_video') 25 | for (path, name) in self.youtube_download(message.text): 26 | father.send_video(video=path, chat_id=message.chat.id, 27 | caption=name) 28 | father.send_chat_action(message.chat.id, 'upload_video') 29 | 30 | @staticmethod 31 | def youtube_download(video_ids): 32 | video_ids = video_ids.split('\n') 33 | for video_id in video_ids: 34 | yt = YouTube('https://www.youtube.com/watch?v=' + video_id) 35 | video = yt.get('mp4') 36 | name = yt.filename 37 | if not os.path.isfile('res/' + name + 'mp4'): 38 | video.download('res/') 39 | yield ('res/' + name + '.mp4', name) 40 | -------------------------------------------------------------------------------- /elbot/bots/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1995parham/ELBoT/454509aa698fed57c95d51a9f734246add971b1d/elbot/bots/__init__.py -------------------------------------------------------------------------------- /elbot/domain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1995parham/ELBoT/454509aa698fed57c95d51a9f734246add971b1d/elbot/domain/__init__.py -------------------------------------------------------------------------------- /elbot/domain/group.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : group.py 4 | # 5 | # [] Creation Date : 26-08-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | import json 10 | 11 | 12 | class GroupChat: 13 | """ 14 | This object represents a group chat. 15 | :type title: str 16 | :type group_id: int 17 | """ 18 | 19 | def __init__(self, title, group_id): 20 | self.title = title 21 | self.id = group_id 22 | 23 | 24 | class GroupChatJSONEncoder(json.JSONEncoder): 25 | def default(self, obj: GroupChat): 26 | if isinstance(obj, GroupChat): 27 | return { 28 | 'id': str(obj.id), 29 | 'title': obj.title 30 | } 31 | else: 32 | raise TypeError( 33 | "GroupChatJsonEncoder got {} instead of GroupChat.".format( 34 | type(obj))) 35 | 36 | 37 | class GroupChatDictDecoder: 38 | @staticmethod 39 | def decode(obj: dict) -> GroupChat: 40 | return GroupChat(group_id=int(obj['id']), title=obj['title']) 41 | -------------------------------------------------------------------------------- /elbot/domain/keyboard.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : keyboard.py 4 | # 5 | # [] Creation Date : 09-09-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | import json 10 | 11 | 12 | class ReplyKeyboardMarkup: 13 | """ 14 | This object represents a custom keyboard with reply options 15 | (see Introduction to bots for details and examples). 16 | :type keyboard: list[list[str]] 17 | :type resize_keyboard: bool 18 | :type one_time_keyboard: bool 19 | :type selective: bool 20 | """ 21 | 22 | def __init__(self, keyboard, resize_keyboard=False, 23 | one_time_keyboard=False, selective=False): 24 | self.keyboard = keyboard 25 | self.resize_keyboard = resize_keyboard 26 | self.one_time_keyboard = one_time_keyboard 27 | self.selective = selective 28 | 29 | 30 | class ReplyKeyboardMarkdownJSONEncoder(json.JSONEncoder): 31 | def default(self, obj: ReplyKeyboardMarkup): 32 | if isinstance(obj, ReplyKeyboardMarkup): 33 | return { 34 | 'keyboard': json.dumps(obj.keyboard), 35 | 'resize_keyboard': 'true' if obj.resize_keyboard else 'false', 36 | 'one_time_keyboard': 'true' if obj.one_time_keyboard else 37 | 'false', 38 | 'selective': 'true' if obj.selective else 'false' 39 | } 40 | else: 41 | raise TypeError( 42 | "ReplayKeyboardMarkdownJsonEncoder got {}" 43 | " instead of ReplyKeyboardMarkup.".format(type(obj))) 44 | -------------------------------------------------------------------------------- /elbot/domain/message.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : message.py 4 | # 5 | # [] Creation Date : 27-08-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | 10 | import datetime 11 | 12 | from .group import GroupChatDictDecoder 13 | from .user import UserDictDecoder 14 | 15 | 16 | class Message: 17 | """ 18 | This object represents a message. 19 | :type message_id: int 20 | :type src: User 21 | :type date: datetime.datetime 22 | :type chat: User or GroupChat 23 | :type text: str 24 | :type forward_from: User 25 | :type forward_date: datetime.datetime 26 | :type reply_to_message: Message 27 | """ 28 | 29 | def __init__(self, message_id, src, date, chat, text='', forward_from=None, 30 | forward_date=None, 31 | reply_to_message=None): 32 | self.id = message_id 33 | self.src = src 34 | self.date = date 35 | self.chat = chat 36 | self.text = text 37 | self.forward_from = forward_from 38 | self.forward_date = forward_date 39 | self.reply_to_message = reply_to_message 40 | 41 | 42 | class MessageDictDecoder: 43 | @staticmethod 44 | def decode(obj: dict) -> Message: 45 | # Message.text 46 | text = obj.get('text', '') 47 | 48 | # Message.forward_from 49 | if obj.get('forward_from', None): 50 | forward_from = UserDictDecoder.decode(obj['forward_from']) 51 | else: 52 | forward_from = None 53 | 54 | # Message.forward_date 55 | if obj.get('forward_date', None): 56 | forward_date = datetime.datetime.fromtimestamp(obj['forward_date']) 57 | else: 58 | forward_date = None 59 | 60 | # Message.reply_to_message 61 | if obj.get('reply_to_message', None): 62 | reply_to_message = MessageDictDecoder.decode( 63 | obj['reply_to_message']) 64 | else: 65 | reply_to_message = None 66 | 67 | # Message.chat 68 | type = obj['chat']['type'] 69 | if type == 'private': 70 | chat = UserDictDecoder.decode(obj['chat']) 71 | elif type == 'group': 72 | chat = GroupChatDictDecoder.decode(obj['chat']) 73 | 74 | return Message(message_id=int(obj['message_id']), 75 | src=UserDictDecoder.decode(obj['from']), 76 | date=datetime.datetime.fromtimestamp(obj['date']), 77 | chat=chat, text=text, 78 | forward_from=forward_from, forward_date=forward_date, 79 | reply_to_message=reply_to_message) 80 | -------------------------------------------------------------------------------- /elbot/domain/update.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : update.py 4 | # 5 | # [] Creation Date : 27-08-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | 10 | from .message import Message, MessageDictDecoder 11 | 12 | 13 | class Update: 14 | """ 15 | This object represents an incoming update. 16 | :type update_id: int 17 | :type message: Message 18 | """ 19 | 20 | def __init__(self, update_id: int, message: Message=None): 21 | self.id = update_id 22 | self.message = message 23 | 24 | 25 | class UpdateDictDecoder: 26 | @staticmethod 27 | def decode(obj: dict) -> Update: 28 | return Update(update_id=int(obj['update_id']), 29 | message=MessageDictDecoder.decode( 30 | obj['message']) if 'message' in obj else None) 31 | -------------------------------------------------------------------------------- /elbot/domain/user.py: -------------------------------------------------------------------------------- 1 | # In The Name Of God 2 | # ======================================== 3 | # [] File Name : user.py 4 | # 5 | # [] Creation Date : 26-08-2015 6 | # 7 | # [] Created By : Parham Alvani (parham.alvani@gmail.com) 8 | # ======================================= 9 | import json 10 | 11 | 12 | class User: 13 | """ 14 | This object represents a Telegram user or bot. 15 | :type username: str 16 | :type first_name: str 17 | :type last_name: str 18 | :type id: int 19 | """ 20 | 21 | def __init__(self, username, first_name, last_name, user_id): 22 | self.username = username 23 | self.first_name = first_name 24 | self.last_name = last_name 25 | self.id = user_id 26 | 27 | 28 | class UserJSONEncoder(json.JSONEncoder): 29 | def default(self, obj: User): 30 | if isinstance(obj, User): 31 | return { 32 | 'id': str(obj.id), 33 | 'first_name': obj.first_name, 34 | 'last_name': obj.last_name, 35 | 'username': obj.username 36 | } 37 | else: 38 | raise TypeError( 39 | "UserJsonEncoder got {} instead of User.".format(type(obj))) 40 | 41 | 42 | class UserDictDecoder: 43 | @staticmethod 44 | def decode(obj: dict) -> User: 45 | return User(user_id=int(obj['id']), username=obj.get('username', ''), 46 | first_name=obj['first_name'], 47 | last_name=obj.get('last_name', '')) 48 | -------------------------------------------------------------------------------- /python_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from elbot.app import ELBot 4 | from elbot.domain.message import Message 5 | 6 | 7 | elbot = ELBot('152389518:AAHW5iTAkK-3UqHV70PGd--bLQDdv3SnyQk') 8 | 9 | 10 | @elbot.message(r'^/python') 11 | def python_handler(message: Message): 12 | elbot.send_message( 13 | text=str(interpret(message.text.split(' ', maxsplit=1)[1])), 14 | chat_id=message.chat.id, 15 | reply_to_message_id=message.id 16 | ) 17 | 18 | 19 | def interpret(query): 20 | safe_list = ['math', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 21 | 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 22 | 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 23 | 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 24 | 'sinh', 'sqrt', 'tan', 'tanh'] 25 | # use the list to filter the local namespace 26 | safe_dict = dict([(k, locals().get(k)) for k in safe_list]) 27 | safe_dict = dict([(k, globals().get(k)) for k in safe_list]) 28 | # add any needed builtins back in. 29 | safe_dict['abs'] = abs 30 | safe_dict['len'] = len 31 | try: 32 | result = eval(query, {'__builtins__': None}, safe_dict) 33 | except Exception as exception: 34 | result = exception.args[0] 35 | return result 36 | 37 | elbot.run() 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /ser_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from elbot.app import ELBot 4 | from elbot.domain.message import Message 5 | 6 | 7 | elbot = ELBot('152389518:AAHW5iTAkK-3UqHV70PGd--bLQDdv3SnyQk') 8 | 9 | 10 | @elbot.message(r'^/ser') 11 | def ser_handler(m: Message): 12 | print("seriously wanted from %s" % m.src.first_name) 13 | elbot.send_message(m.chat.id, 'seriously') 14 | 15 | elbot.run() 16 | --------------------------------------------------------------------------------