├── .gitignore ├── LICENSE ├── README.md ├── bot.py └── config.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 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 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 mcfx0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # telegram_pipebot 2 | Connect other bots as pipes. 3 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import threading, traceback 2 | 3 | import telebot 4 | from telebot import apihelper 5 | from telebot import types 6 | 7 | from pyrogram import Client, Filters 8 | 9 | import config 10 | 11 | bot = telebot.AsyncTeleBot(config.bot_token) 12 | print('bot init ok') 13 | 14 | app = Client(config.profile_name, config.api_id, config.api_hash) 15 | app.start() 16 | print('client init ok') 17 | 18 | bot_conds = {} 19 | bot_replys = {} 20 | 21 | banned_system_bots = ['spambot'] 22 | 23 | def is_bot(username): 24 | if username.lower() in banned_system_bots: 25 | return False 26 | if username[-3:].lower() != 'bot': 27 | return False 28 | u = app.get_users(username) 29 | return u.is_bot 30 | 31 | @app.on_message(Filters.text & Filters.private) 32 | def process_message(client, message): 33 | username = message.from_user.username 34 | if username in bot_conds: 35 | co = bot_conds[username] 36 | co.acquire() 37 | bot_replys[username] = message.text 38 | co.notify() 39 | co.release() 40 | 41 | def get_single_reply(username, command): 42 | bot_conds[username].acquire() 43 | app.send_message(username, command) 44 | if not bot_conds[username].wait(3): 45 | bot_conds[username].release() 46 | return False 47 | res = bot_replys[username] 48 | bot_conds[username].release() 49 | return res 50 | 51 | def get_reply(username, command): 52 | if not is_bot(username): return False 53 | if username not in bot_conds: 54 | bot_conds[username] = threading.Condition() 55 | bot_replys[username] = '' 56 | get_single_reply(username, '/start') 57 | return get_single_reply(username, command) 58 | 59 | help_text = '''This is a bot to connect other bots as pipes. 60 | 61 | Basic usage: Botn Bot(n-1) ... Bot2 Bot1 message 62 | Example: @pipe2bot @kongebot @bullshitsaysbot test 63 | You can also use /pipe command. 64 | 65 | In addition, you can add parameters to each bot call. 66 | There are currently 3 parameters: 67 | 68 | [x]@bot - The x-th result of the inline query will be used. If x is not given, the first(0-th) result will be used. 69 | [pm]@bot - I will pm the bot and send the message. The first reply is used as the result. 70 | /command@bot - I will PM the bot and send the command. The first reply is used as the result. 71 | 72 | Examples: 73 | @pipe2bot @kongebot [1]@xiaobbot /ranwen@ranwen_quote_bot 74 | @pipe2bot @kongebot [pm]@bullshitsaysbot /ranwen@ranwen_quote_bot''' 75 | 76 | @bot.message_handler(commands=['start', 'help']) 77 | def send_help(message): 78 | bot.reply_to(message, help_text) 79 | 80 | def get_piped_text(s): 81 | funcs = [] 82 | while s[0] == '@' or s[0] == '/' or s[0] == '[': 83 | p = s.find(' ') 84 | if p == -1: 85 | p = len(s) 86 | assert p != 1 87 | funcs.append(s[:p]) 88 | if p == len(s): 89 | s = '' 90 | break 91 | s = s[p + 1:] 92 | print(funcs, s) 93 | res = 'message' 94 | for i in reversed(funcs): 95 | print(i) 96 | res = '%s(%s)' % (i, res) 97 | if i[0] == '@': 98 | s = app.get_inline_bot_results(i[1:], s) 99 | s = s['results'][0]['send_message']['message'] 100 | elif i[0] == '/': 101 | assert '@' in i 102 | a, b = i.split('@', 1) 103 | s = get_reply(b, a + ' ' + s) 104 | assert s 105 | elif i[0] == '[': 106 | assert ']' in i 107 | a, b = i[1:].split(']', 1) 108 | assert b[0] == '@' 109 | if a.lower() == 'pm': 110 | s = get_reply(b[1:], s) 111 | assert s 112 | else: 113 | a = int(a) 114 | s = app.get_inline_bot_results(b[1:], s) 115 | s = s['results'][a]['send_message']['message'] 116 | print(s) 117 | return res, s 118 | 119 | @bot.message_handler(commands=['pipe']) 120 | def send_pipe(message): 121 | try: 122 | msg = message.text.split(' ', 1)[1] 123 | bot.reply_to(message, get_piped_text(msg)[1]) 124 | except Exception as e: 125 | #print(e) 126 | traceback.print_exc() 127 | 128 | @bot.inline_handler(lambda query: query.query != "") 129 | def query_text(inline_query): 130 | qtext = inline_query.query.strip() 131 | if qtext == "": 132 | return 133 | try: 134 | res, s = get_piped_text(qtext) 135 | r = types.InlineQueryResultArticle('1', res, types.InputTextMessageContent(s)) 136 | bot.answer_inline_query(inline_query.id, [r], cache_time=1) 137 | except Exception as e: 138 | #print(e) 139 | traceback.print_exc() 140 | 141 | bot.polling(True) 142 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | bot_token = 'your bot token' 2 | 3 | api_id = your api id 4 | api_hash = your api hash 5 | 6 | profile_name = 'test' --------------------------------------------------------------------------------