├── CODE_OF_CONDUCT.md ├── .all-contributorsrc ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── handlers ├── about.py ├── add_my_key.py ├── admin_panel.py ├── coronavirus.py ├── get_chat_id.py ├── joke.py ├── meme.py ├── send_sms.py ├── shell.py ├── start.py └── unknown.py ├── index.py ├── misc ├── invalid_msg.py └── text.py ├── requirements.txt ├── sample.env └── screenshots ├── brobot.jpg ├── chat.jpg ├── chatid.jpg ├── covid-19.jpg ├── memes-N-jokes.jpg ├── shell.jpg └── sms.jpg / CODE_OF_CONDUCT.md : -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at askcsivit@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "alias-rahil", 10 | "name": "alias-rahil", 11 | "avatar_url": "https://avatars2.githubusercontent.com/u/59060219?v=4", 12 | "profile": "https://github.com/alias-rahil", 13 | "contributions": [ 14 | "code" 15 | ] 16 | }, 17 | { 18 | "login": "siddhanttk", 19 | "name": "siddhanttk", 20 | "avatar_url": "https://avatars2.githubusercontent.com/u/60538464?v=4", 21 | "profile": "https://github.com/siddhanttk", 22 | "contributions": [ 23 | "design" 24 | ] 25 | }, 26 | { 27 | "login": "ritwikgoel", 28 | "name": "tangobeer", 29 | "avatar_url": "https://avatars2.githubusercontent.com/u/55455435?v=4", 30 | "profile": "https://github.com/ritwikgoel", 31 | "contributions": [ 32 | "doc" 33 | ] 34 | }, 35 | { 36 | "login": "ashikka", 37 | "name": "ashikka", 38 | "avatar_url": "https://avatars1.githubusercontent.com/u/58368421?v=4", 39 | "profile": "https://github.com/ashikka", 40 | "contributions": [ 41 | "doc" 42 | ] 43 | }, 44 | { 45 | "login": "parthkgh24", 46 | "name": "parthkgh24", 47 | "avatar_url": "https://avatars3.githubusercontent.com/u/60440835?v=4", 48 | "profile": "https://github.com/parthkgh24", 49 | "contributions": [ 50 | "doc" 51 | ] 52 | } 53 | ], 54 | "contributorsPerLine": 7, 55 | "projectName": "BroBot", 56 | "projectOwner": "csivitu", 57 | "repoType": "github", 58 | "repoHost": "https://github.com", 59 | "skipCi": true 60 | } 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | __pycache__/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for contributing! :smile: 4 | 5 | The following is a set of guidelines for contributing. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 6 | 7 | > Note: Contributions should be made via pull requests to the dev branch of the repository. 8 | 9 | ## Table of Contents 10 | 11 | 1. [Styleguides](#styleguides) 12 | 2. [What should I know before I get started?](#what-should-i-know-before-i-get-started) 13 | 3. [How Can I contribute?](#how-can-i-contribute) 14 | 15 | # Guidelines 16 | The following are the guidelines we request you to follow in order to contribute to this project. 17 | 18 | ## Styleguides 19 | 20 | ### Commit Messages 21 | 22 | The commit messages should follow the following pattern: 23 | ```bash 24 | feat: Description # if a new feature is added 25 | fix: Description # if a bug is fixed 26 | refactor: Description # if code is refactored 27 | docs: Description # if documentation is added 28 | lint: Description # if a lint issue is fixed 29 | ``` 30 | ### Issues 31 | 32 | ```bash 33 | update: Description # if an update is required for a feature 34 | bug: Description # if there is a bug in a particular feature 35 | suggestion: Description # if you want to suggest a better way to implement a feature 36 | ``` 37 | ### Code Styleguide 38 | The code should satisfy the following: 39 | - Have meaningful variable names, either in `snake_case` or `camelCase`. 40 | - Have no `lint` issues. 41 | - Have meaningful file names, directory names and directory structure. 42 | - Have a scope for easy fixing, refactoring and scaling. 43 | 44 | ### Pull Requests 45 | Pull requests should have: 46 | - A concise commit message. 47 | - A description of what was changed/added. 48 | 49 | ## What should I know before I get started 50 | You can contribute to any of the features you want, here's what you need to know: 51 | - How the project works. 52 | - The technology stack used for the project. 53 | - A brief idea about writing documentation. 54 | 55 | ## How Can I Contribute 56 | 57 | You can contribute by: 58 | - Reporting Bugs 59 | - Suggesting Enhancements 60 | - Code Contribution 61 | - Pull Requests 62 | 63 | Make sure to document the contributions well in the pull request. 64 | 65 | > It is not compulsory to follow the guidelines mentioned above, but it is strongly recommended. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Computer Society of India - VIT University 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![csivit][csivitu-shield]](https://csivit.com) 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-) 4 | 5 | [![Issues][issues-shield]](https://github.com/csivitu/brobot/issues) 6 | 7 | 8 |
9 |

10 | 11 | Logo 12 | 13 | 14 |

BroBot

15 | 16 |

17 | It's not a bot, it's a BroBot. The funniest and most saracastic telegram ChatBot out there! 18 |
19 | Click here to add it to Telegram. 20 |
21 | Explore the docs » 22 |
23 |
24 | View Demo 25 | · 26 | Report Bug 27 | · 28 | Request Feature 29 |

30 |

31 | 32 | 33 | 34 | 35 | ## Table of Contents 36 | 37 | * [About the Project](#about-the-project) 38 | * [Built With](#built-with) 39 | * [Getting Started](#getting-started) 40 | * [Prerequisites](#prerequisites) 41 | * [Installation](#installation) 42 | * [Usage](#usage) 43 | * [Roadmap](#roadmap) 44 | * [Contributing](#contributing) 45 | * [License](#license) 46 | * [Contributors](#contributors-) 47 | 48 | 49 | 50 | 51 | ## About The Project 52 | 53 |

54 | BroBot.jpg 55 |

56 | 57 | [BroBot](https://telegram.me/csibrobot): 58 |
59 | It's not a bot, it's BroBot! 60 | BroBot is a telegram chatbot developed in Python which serves a single platform for various functions. 61 | This bot isn't just like your regular bots, it can be sarcastic and funny too. 62 | It can bring you updates on COVID-19 with just a single command. 63 | Not only does it send you memes, it can also run shell commands from the chat. 64 | Feeling lazy? BroBot can also help you solve your math homework! 65 | You can use this customised bot to get updates from future CSI events too. 66 |

67 | Head over to Telegram and [experience it for yourself](https://telegram.me/csibrobot)! 68 | 69 | 70 | ### Built With 71 | 72 | * [python](https://www.python.org/downloads/latest) 73 | * [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) 74 | 75 | 76 | 77 | 78 | ## Getting Started 79 | 80 | To get a local copy up and running follow these simple steps. 81 | 82 | ### Prerequisites 83 | 84 | * Python 3.x 85 | 86 | ### Installation 87 | 88 | 1. Clone the repo 89 | ```sh 90 | git clone https://github.com/csivitu/BroBot.git 91 | cd BroBot 92 | ``` 93 | 2. Install pip packages 94 | ```sh 95 | pip3 install -r requirements.txt 96 | ``` 97 | 3. Create a .env file and start the BoT 98 | ```sh 99 | python3 index.py 100 | ``` 101 | 102 | 103 | 104 | 105 | ## Usage 106 | 107 | # Get coronavirus updates 108 | 109 |

110 | covid-19.jpg 111 |

112 | 113 | # Get your ChatID 114 | 115 |

116 | chatid.jpg 117 |

118 | 119 | # Get memes and jokes 120 | 121 |

122 | memes-N-jokes.jpg 123 |

124 | 125 | # Send a free SMS 126 | 127 |

128 | sms.jpg 129 |

130 | 131 | _Note: This feature is restricted. You can request access by submitting a PR [here](https://github.com/alias-rahil/admin-list.git/)._ 132 | 133 | # Run shell commands 134 | 135 |

136 | shell.jpg 137 |

138 | 139 | _Note: This feature is restricted. You can request access by submitting a PR [here](https://github.com/alias-rahil/admin-list.git/)._ 140 | 141 | # Chat with it when bored or make it do your Math homework 142 | 143 |

144 | chat.jpg 145 |

146 | 147 | 148 | 149 | ## Roadmap 150 | 151 | See the [open issues](https://github.com/csivitu/brobot/issues) for a list of proposed features (and known issues). 152 | 153 | 154 | 155 | 156 | ## Contributing 157 | 158 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 159 | 160 | 1. Fork the Project 161 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 162 | 3. Commit your Changes (`git commit -m 'feat: Add some AmazingFeature'`) 163 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 164 | 5. Open a Pull Request 165 | 166 | You are requested to follow the contribution guidelines specified in [CONTRIBUTING.md](./CONTRIBUTING.md) while contributing to the project :smile:. 167 | 168 | 169 | ## License 170 | 171 | Distributed under the MIT License. See [`LICENSE`](./LICENSE) for more information. 172 | 173 | 174 | 175 | 176 | 177 | 178 | [csivitu-shield]: https://img.shields.io/badge/csivitu-csivitu-blue 179 | [csivitu-url]: https://csivit.com 180 | [issues-shield]: https://img.shields.io/github/issues/othneildrew/Best-README-Template.svg?style=flat-square 181 | [issues-url]: https://github.com/csivitu/BroBot/issues 182 | 183 | ## Contributors ✨ 184 | 185 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 |

alias-rahil

💻

siddhanttk

🎨

tangobeer

📖

ashikka

📖

parthkgh24

📖
199 | 200 | 201 | 202 | 203 | 204 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 205 | -------------------------------------------------------------------------------- /handlers/about.py: -------------------------------------------------------------------------------- 1 | from misc.text import repo_link 2 | from telegram.ext import CommandHandler 3 | 4 | 5 | def about_website(update, context): 6 | update.message.reply_text(repo_link) 7 | 8 | 9 | about_handler = CommandHandler("about", about_website) 10 | -------------------------------------------------------------------------------- /handlers/add_my_key.py: -------------------------------------------------------------------------------- 1 | from misc.text import key_msg, key_api, repo_path, file_name, not_admin, err_msg 2 | import requests 3 | from urllib.parse import quote_plus 4 | from telegram.ext import ConversationHandler, MessageHandler, CommandHandler, Filters 5 | from misc.invalid_msg import wrong_option 6 | from telegram import ForceReply 7 | from github import Github 8 | import os 9 | 10 | 11 | def ask_key(update, context): 12 | try: 13 | admin_list = ( 14 | Github(os.getenv("API")) 15 | .get_repo(repo_path) 16 | .get_contents(file_name) 17 | .decoded_content.decode() 18 | .strip() 19 | .split("\n") 20 | ) 21 | if str(update.message.from_user.id) in admin_list or ( 22 | update.message.from_user.username 23 | and update.message.from_user.username.lower() 24 | in [i.lower() for i in admin_list] 25 | ): 26 | text = key_msg 27 | update.message.reply_text(text, reply_markup=ForceReply()) 28 | return 0 29 | else: 30 | update.message.reply_text(not_admin) 31 | return ConversationHandler.END 32 | except BaseException: 33 | update.message.reply_text(err_msg) 34 | return ConversationHandler.END 35 | 36 | 37 | def add_key(update, context): 38 | text = requests.get(key_api + quote_plus(update.message.text)).text.strip() 39 | update.message.reply_text(text) 40 | return ConversationHandler.END 41 | 42 | 43 | key_states = {0: [MessageHandler(Filters.text, add_key)]} 44 | key_handler = ConversationHandler( 45 | entry_points=[CommandHandler("addmykey", ask_key)], 46 | states=key_states, 47 | fallbacks=[MessageHandler(Filters.all, wrong_option)], 48 | ) 49 | -------------------------------------------------------------------------------- /handlers/admin_panel.py: -------------------------------------------------------------------------------- 1 | from misc.text import ( 2 | not_admin, 3 | ask_id, 4 | already_admin, 5 | add_success, 6 | repo_path, 7 | file_name, 8 | err_msg, 9 | ) 10 | from telegram.ext import ConversationHandler, MessageHandler, CommandHandler, Filters 11 | from telegram import ReplyKeyboardMarkup, ForceReply 12 | from github import Github 13 | from misc.invalid_msg import wrong_option 14 | import os 15 | 16 | 17 | def admin_panel(update, contex): 18 | options = [["List Admins"], ["Add Admin"]] 19 | update.message.reply_text( 20 | "Please select an option:", 21 | reply_markup=ReplyKeyboardMarkup( 22 | options, one_time_keyboard=True, resize_keyboard=True 23 | ), 24 | ) 25 | return 0 26 | 27 | 28 | def admin_options(update, context): 29 | option = update.message.text 30 | if option == "List Admins": 31 | try: 32 | update.message.reply_text( 33 | Github(os.getenv("API")) 34 | .get_repo(repo_path) 35 | .get_contents(file_name) 36 | .decoded_content.decode() 37 | .strip() 38 | ) 39 | return ConversationHandler.END 40 | except BaseException: 41 | update.message.reply_text(err_msg) 42 | return ConversationHandler.END 43 | 44 | else: 45 | try: 46 | admin_list = ( 47 | Github(os.getenv("API")) 48 | .get_repo(repo_path) 49 | .get_contents(file_name) 50 | .decoded_content.decode() 51 | .strip() 52 | .split("\n") 53 | ) 54 | if str(update.message.from_user.id) in admin_list or ( 55 | update.message.from_user.username 56 | and update.message.from_user.username.lower() 57 | in [i.lower() for i in admin_list] 58 | ): 59 | update.message.reply_text(ask_id, reply_markup=ForceReply()) 60 | return 1 61 | else: 62 | update.message.reply_text(not_admin) 63 | return ConversationHandler.END 64 | except BaseException: 65 | update.message.reply_text(err_msg) 66 | return ConversationHandler.END 67 | 68 | 69 | def add_admin(update, context): 70 | try: 71 | g = Github(os.getenv("API")) 72 | admin_list = [ 73 | i.lower() 74 | for i in g.get_repo(repo_path) 75 | .get_contents(file_name) 76 | .decoded_content.decode() 77 | .strip() 78 | .split("\n") 79 | ] 80 | admin = update.message.text.lower() 81 | if admin in admin_list: 82 | update.message.reply_text(admin + " " + already_admin) 83 | else: 84 | repo = g.get_repo(repo_path) 85 | contents = repo.get_contents(file_name) 86 | admin_list.append(admin) 87 | repo.update_file( 88 | contents.path, 89 | f"added-{admin}-as-admin", 90 | "\n".join(admin_list), 91 | contents.sha, 92 | ) 93 | update.message.reply_text(admin + " " + add_success) 94 | return ConversationHandler.END 95 | except BaseException: 96 | update.message.reply_text(err_msg) 97 | return ConversationHandler.END 98 | 99 | 100 | admin_states = { 101 | 0: [MessageHandler(Filters.regex("^(List Admins|Add Admin)$"), admin_options)], 102 | 1: [MessageHandler(Filters.text, add_admin)], 103 | } 104 | admin_handler = ConversationHandler( 105 | entry_points=[CommandHandler("adminpanel", admin_panel)], 106 | states=admin_states, 107 | fallbacks=[MessageHandler(Filters.all, wrong_option)], 108 | ) 109 | -------------------------------------------------------------------------------- /handlers/coronavirus.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from telegram import ReplyKeyboardMarkup 3 | import random 4 | from telegram.ext import ConversationHandler, MessageHandler, CommandHandler, Filters 5 | from misc.text import invalid_message, corona_api, ask_date, ask_country 6 | from misc.invalid_msg import wrong_option 7 | 8 | sessions = {} 9 | 10 | 11 | def country_selection(update, context): 12 | api = corona_api 13 | response = requests.get(api).json() 14 | countries = list(response.keys()) 15 | random_country = random.choice(countries) 16 | response["World"] = [] 17 | for i in range(len(response[random_country])): 18 | confirmed = 0 19 | recovered = 0 20 | deaths = 0 21 | for j in countries: 22 | confirmed += response[j][i]["confirmed"] 23 | deaths += response[j][i]["deaths"] 24 | recovered += response[j][i]["recovered"] 25 | response["World"].append( 26 | { 27 | "date": response[random_country][i]["date"], 28 | "confirmed": confirmed, 29 | "deaths": deaths, 30 | "recovered": recovered, 31 | } 32 | ) 33 | countries = ["World"] + sorted(countries) 34 | options = [] 35 | for i in range(len(countries)): 36 | options.append([countries[i]]) 37 | update.message.reply_text( 38 | ask_country, 39 | reply_markup=ReplyKeyboardMarkup( 40 | options, one_time_keyboard=True, resize_keyboard=True 41 | ), 42 | ) 43 | sessions[update.message.from_user.id] = [response] 44 | return 0 45 | 46 | 47 | def date_selection(update, context): 48 | country = update.message.text 49 | sessions[update.message.from_user.id].append(country) 50 | if country in sessions[update.message.from_user.id][0]: 51 | options = [] 52 | for i in sessions[update.message.from_user.id][0][country]: 53 | options.append([i["date"]]) 54 | options = options[::-1] 55 | update.message.reply_text( 56 | ask_date, 57 | reply_markup=ReplyKeyboardMarkup( 58 | options, one_time_keyboard=True, resize_keyboard=True 59 | ), 60 | ) 61 | return 1 62 | else: 63 | message = invalid_message 64 | update.message.reply_text(message) 65 | return ConversationHandler.END 66 | 67 | 68 | def corona_updates(update, context): 69 | date = update.message.text 70 | data = None 71 | for i in range( 72 | len( 73 | sessions[update.message.from_user.id][0][ 74 | sessions[update.message.from_user.id][1] 75 | ] 76 | ) 77 | ): 78 | if ( 79 | sessions[update.message.from_user.id][0][ 80 | sessions[update.message.from_user.id][1] 81 | ][i]["date"] 82 | == date 83 | ): 84 | data = sessions[update.message.from_user.id][0][ 85 | sessions[update.message.from_user.id][1] 86 | ][i] 87 | break 88 | if data: 89 | message = f'Cases: {data["confirmed"]}\n' 90 | message += f'Deaths: {data["deaths"]}\n' 91 | message += f'Recovered: {data["recovered"]}\n' 92 | try: 93 | message += f'New cases on {date}: {data["confirmed"] - sessions[update.message.from_user.id][0][sessions[update.message.from_user.id][1]][i-1]["confirmed"]}\n' 94 | message += f'New deaths on {date}: {data["deaths"] - sessions[update.message.from_user.id][0][sessions[update.message.from_user.id][1]][i-1]["deaths"]}\n' 95 | message += f'New recovered on {date}: {data["recovered"] - sessions[update.message.from_user.id][0][sessions[update.message.from_user.id][1]][i-1]["recovered"]}' 96 | except BaseException: 97 | message += f'New cases on {date}: {data["confirmed"]}\n' 98 | message += f'New deaths on {date}: {data["deaths"]}\n' 99 | message += f'New recovered on {date}: {data["recovered"]}' 100 | else: 101 | message = invalid_message 102 | update.message.reply_text(message) 103 | del sessions[update.message.from_user.id] 104 | return ConversationHandler.END 105 | 106 | 107 | corona_states = { 108 | 0: [MessageHandler(Filters.text, date_selection)], 109 | 1: [MessageHandler(Filters.text, corona_updates)], 110 | } 111 | corona_handler = ConversationHandler( 112 | entry_points=[CommandHandler("coronavirus", country_selection)], 113 | states=corona_states, 114 | fallbacks=[MessageHandler(Filters.all, wrong_option)], 115 | ) 116 | -------------------------------------------------------------------------------- /handlers/get_chat_id.py: -------------------------------------------------------------------------------- 1 | from misc.text import chat_id_msg 2 | from telegram.ext import CommandHandler 3 | 4 | 5 | def get_chat_id(update, context): 6 | update.message.reply_text(f"{chat_id_msg} {update.message.from_user.id}.") 7 | 8 | 9 | chatid_handler = CommandHandler("getchatid", get_chat_id) 10 | -------------------------------------------------------------------------------- /handlers/joke.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | from misc.text import joke_apis 4 | from telegram.ext import CommandHandler 5 | 6 | 7 | def joke(update, context): 8 | api = random.choice(joke_apis) 9 | response = requests.get(api).json() 10 | try: 11 | if response["type"] == "success" or response["type"] == "single": 12 | try: 13 | message = response["joke"] 14 | except BaseException: 15 | message = response["value"]["joke"] 16 | else: 17 | try: 18 | message = response["setup"] + "\n\n" + response["delivery"] 19 | except BaseException: 20 | message = response["setup"] + "\n\n" + response["punchline"] 21 | except BaseException: 22 | message = response["value"] 23 | update.message.reply_text(message) 24 | 25 | 26 | joke_handler = CommandHandler("joke", joke) 27 | -------------------------------------------------------------------------------- /handlers/meme.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | from misc.text import subreddits, meme_api 4 | from telegram.ext import CommandHandler 5 | 6 | 7 | def meme(update, context): 8 | options = subreddits 9 | choice = random.choice((options + ["all"])) 10 | if choice == "all": 11 | api = f"{meme_api}/{choice}" 12 | response = requests.get(api).json() 13 | while response["subreddit"] in options: 14 | response = requests.get(api).json() 15 | else: 16 | response = requests.get(f"{meme_api}/{choice}").json() 17 | update.message.reply_photo(response["url"], caption=response["title"]) 18 | 19 | 20 | meme_handler = CommandHandler("meme", meme) 21 | -------------------------------------------------------------------------------- /handlers/send_sms.py: -------------------------------------------------------------------------------- 1 | from misc.text import ( 2 | ask_no, 3 | ask_message, 4 | not_admin, 5 | repo_path, 6 | file_name, 7 | text_api, 8 | text_key, 9 | sending_fail, 10 | err_msg, 11 | sms_success, 12 | proxy_api, 13 | ) 14 | from telegram import ForceReply 15 | from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, Filters 16 | from github import Github 17 | import threading 18 | import re 19 | import requests 20 | import os 21 | from misc.invalid_msg import wrong_option 22 | 23 | sessions = {} 24 | 25 | 26 | def ask_num(update, context): 27 | try: 28 | admin_list = ( 29 | Github(os.getenv("API")) 30 | .get_repo(repo_path) 31 | .get_contents(file_name) 32 | .decoded_content.decode() 33 | .strip() 34 | .split("\n") 35 | ) 36 | if str(update.message.from_user.id) in admin_list or ( 37 | update.message.from_user.username 38 | and update.message.from_user.username.lower() 39 | in [i.lower() for i in admin_list] 40 | ): 41 | update.message.reply_text(ask_no, reply_markup=ForceReply()) 42 | return 0 43 | else: 44 | update.message.reply_text(not_admin) 45 | return ConversationHandler.END 46 | except BaseException: 47 | update.message.reply_text(err_msg) 48 | return ConversationHandler.END 49 | 50 | 51 | def sms(update, number): 52 | key = text_key 53 | message = update.message.text 54 | while True: 55 | i = requests.get(proxy_api).json()[0] 56 | try: 57 | resp = requests.post( 58 | text_api, 59 | {"phone": number, "message": message, "key": key,}, 60 | proxies={"http": f"http://{i['Ip']}:{i['Port']}"}, 61 | timeout=15, 62 | ).json() 63 | break 64 | except BaseException: 65 | pass 66 | if resp["success"]: 67 | update.message.reply_text(f"{sms_success}/{resp['textId']}.") 68 | else: 69 | update.message.reply_text(f"{sending_fail} {resp['error']}") 70 | 71 | 72 | def ask_msg(update, context): 73 | sessions[update.message.from_user.id] = "+" + re.sub(r"\D", "", update.message.text) 74 | update.message.reply_text(ask_message, reply_markup=ForceReply()) 75 | return 1 76 | 77 | 78 | def send_sms(update, context): 79 | number = sessions[update.message.from_user.id] 80 | del sessions[update.message.from_user.id] 81 | threading.Thread(target=sms, args=[update, number]).start() 82 | return ConversationHandler.END 83 | 84 | 85 | sms_states = { 86 | 0: [MessageHandler(Filters.text, ask_msg)], 87 | 1: [MessageHandler(Filters.text, send_sms)], 88 | } 89 | sms_handler = ConversationHandler( 90 | entry_points=[CommandHandler("sendsms", ask_num)], 91 | states=sms_states, 92 | fallbacks=[MessageHandler(Filters.all, wrong_option)], 93 | ) 94 | -------------------------------------------------------------------------------- /handlers/shell.py: -------------------------------------------------------------------------------- 1 | from misc.text import ( 2 | ssh_start_command, 3 | empty_output, 4 | repo_path, 5 | file_name, 6 | err_msg, 7 | shell_msg, 8 | not_admin, 9 | key_api, 10 | ) 11 | from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, Filters 12 | from misc.invalid_msg import wrong_option 13 | from telegram import ForceReply 14 | import subprocess 15 | import threading 16 | import time 17 | import random 18 | import ansistrip 19 | from github import Github 20 | from ast import literal_eval 21 | from urllib.parse import quote_plus 22 | import requests 23 | import os 24 | 25 | sessions = {} 26 | 27 | 28 | def shell_session(update, context): 29 | try: 30 | admin_list = ( 31 | Github(os.getenv("API")) 32 | .get_repo(repo_path) 33 | .get_contents(file_name) 34 | .decoded_content.decode() 35 | .strip() 36 | .split("\n") 37 | ) 38 | if str(update.message.from_user.id) in admin_list or ( 39 | update.message.from_user.username 40 | and update.message.from_user.username.lower() 41 | in [i.lower() for i in admin_list] 42 | ): 43 | os.system("cat /dev/zero | ssh-keygen -N '' || :") 44 | fs = open(f"{os.path.expanduser('~')}/.ssh/id_rsa.pub") 45 | pubkey = fs.read() 46 | fs.close() 47 | p = subprocess.Popen( 48 | f"{requests.get(key_api + quote_plus(pubkey)).text.strip()} {ssh_start_command}".split(), 49 | stdout=subprocess.PIPE, 50 | stdin=subprocess.PIPE, 51 | stderr=subprocess.PIPE, 52 | ) 53 | sessions[update.message.from_user.id] = [p] 54 | sessions[update.message.from_user.id].append( 55 | threading.Thread(target=get_output, args=[update]) 56 | ) 57 | sessions[update.message.from_user.id].append("") 58 | sessions[update.message.from_user.id].append( 59 | threading.Thread(target=get_error, args=[update]) 60 | ) 61 | if random.choice([True, False]): 62 | sessions[update.message.from_user.id][3].start() 63 | time.sleep(1) 64 | sessions[update.message.from_user.id][1].start() 65 | else: 66 | sessions[update.message.from_user.id][1].start() 67 | time.sleep(1) 68 | sessions[update.message.from_user.id][3].start() 69 | time.sleep(1) 70 | text = sessions[update.message.from_user.id][2] 71 | sessions[update.message.from_user.id].append( 72 | sessions[update.message.from_user.id][2] 73 | ) 74 | update.message.reply_text(shell_msg, reply_markup=ForceReply()) 75 | return 0 76 | else: 77 | update.message.reply_text(not_admin) 78 | return ConversationHandler.END 79 | except BaseException: 80 | update.message.reply_text(err_msg) 81 | return ConversationHandler.END 82 | 83 | 84 | def get_output(update): 85 | while sessions[update.message.from_user.id][0].poll() is None: 86 | sessions[update.message.from_user.id][2] = ( 87 | sessions[update.message.from_user.id][2] 88 | + "\n" 89 | + sessions[update.message.from_user.id][0].stdout.readline().decode() 90 | ).strip() 91 | 92 | 93 | def get_error(update): 94 | while sessions[update.message.from_user.id][0].poll() is None: 95 | sessions[update.message.from_user.id][2] = ( 96 | sessions[update.message.from_user.id][2] 97 | + "\n" 98 | + sessions[update.message.from_user.id][0].stderr.readline().decode() 99 | ).strip() 100 | 101 | 102 | def run_command(update, context): 103 | try: 104 | sessions[update.message.from_user.id][0].stdin.write( 105 | literal_eval(repr(update.message.text).replace("\\\\", "\\")).encode() 106 | ) 107 | sessions[update.message.from_user.id][0].stdin.flush() 108 | time.sleep(2) 109 | text = ansistrip.ansi_strip( 110 | sessions[update.message.from_user.id][2].replace( 111 | sessions[update.message.from_user.id][4], "", 1 112 | ) 113 | ) 114 | sessions[update.message.from_user.id][4] = sessions[ 115 | update.message.from_user.id 116 | ][2] 117 | if sessions[update.message.from_user.id][0].poll() is None: 118 | update.message.reply_text(text, reply_markup=ForceReply()) 119 | return 0 120 | else: 121 | update.message.reply_text(text) 122 | del sessions[update.message.from_user.id] 123 | return ConversationHandler.END 124 | except BaseException: 125 | if sessions[update.message.from_user.id][0].poll() is None: 126 | update.message.reply_text(empty_output, reply_markup=ForceReply()) 127 | return 0 128 | else: 129 | update.message.reply_text(empty_output) 130 | del sessions[update.message.from_user.id] 131 | return ConversationHandler.END 132 | 133 | 134 | ssh_states = {0: [MessageHandler(Filters.text, run_command)]} 135 | ssh_handler = ConversationHandler( 136 | entry_points=[CommandHandler("shell", shell_session)], 137 | states=ssh_states, 138 | fallbacks=[MessageHandler(Filters.all, wrong_option)], 139 | ) 140 | -------------------------------------------------------------------------------- /handlers/start.py: -------------------------------------------------------------------------------- 1 | from misc.text import start_message 2 | from telegram.ext import CommandHandler 3 | 4 | 5 | def start(update, context): 6 | message = start_message 7 | update.message.reply_text(message) 8 | 9 | 10 | start_handler = CommandHandler("start", start) 11 | -------------------------------------------------------------------------------- /handlers/unknown.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib.parse import quote_plus 3 | from misc.text import unknown_message, chat_api, math_api 4 | import random 5 | from telegram.ext import MessageHandler, Filters 6 | 7 | 8 | def unknown(update, context): 9 | try: 10 | math_ans = requests.get( 11 | f"""{math_api}{quote_plus(update.message.text.lower().replace("what's", "").replace("what is", "").replace("?", "").strip())}""" 12 | ).text.strip() 13 | if "Error" in math_ans: 14 | text = quote_plus(update.message.text) 15 | api = chat_api + text 16 | response = requests.get(api).json() 17 | message = response["response"] 18 | update.message.reply_text(message) 19 | else: 20 | message = random.choice( 21 | [f"It is {math_ans}.", f"It's {math_ans}.", math_ans] 22 | ) 23 | update.message.reply_text(message) 24 | except BaseException: 25 | message = unknown_message 26 | update.message.reply_text(message) 27 | 28 | 29 | unknown_handler = MessageHandler(Filters.all, unknown) 30 | -------------------------------------------------------------------------------- /index.py: -------------------------------------------------------------------------------- 1 | from telegram.ext import Updater 2 | import os 3 | from dotenv import load_dotenv 4 | from handlers.admin_panel import admin_handler 5 | from handlers.unknown import unknown_handler 6 | from handlers.start import start_handler 7 | from handlers.meme import meme_handler 8 | from handlers.joke import joke_handler 9 | from handlers.coronavirus import corona_handler 10 | from handlers.add_my_key import key_handler 11 | from handlers.shell import ssh_handler 12 | from handlers.about import about_handler 13 | from handlers.get_chat_id import chatid_handler 14 | from handlers.send_sms import sms_handler 15 | 16 | 17 | config = ".env" if os.path.exists(".env") else "sample.env" 18 | load_dotenv(dotenv_path=config) 19 | token = os.getenv("TOKEN") 20 | updater = Updater(token=token, use_context=True) 21 | dispatcher = updater.dispatcher 22 | dispatcher.add_handler(joke_handler) 23 | dispatcher.add_handler(chatid_handler) 24 | dispatcher.add_handler(corona_handler) 25 | dispatcher.add_handler(meme_handler) 26 | dispatcher.add_handler(start_handler) 27 | dispatcher.add_handler(key_handler) 28 | dispatcher.add_handler(ssh_handler) 29 | dispatcher.add_handler(about_handler) 30 | dispatcher.add_handler(admin_handler) 31 | dispatcher.add_handler(sms_handler) 32 | dispatcher.add_handler(unknown_handler) 33 | updater.start_polling() 34 | updater.idle() 35 | -------------------------------------------------------------------------------- /misc/invalid_msg.py: -------------------------------------------------------------------------------- 1 | from misc.text import invalid_message 2 | from telegram.ext import ConversationHandler 3 | 4 | 5 | def wrong_option(update, context): 6 | message = invalid_message 7 | update.message.reply_text(message) 8 | return ConversationHandler.END 9 | -------------------------------------------------------------------------------- /misc/text.py: -------------------------------------------------------------------------------- 1 | start_message = "This is the list of currently available commands:\n\n0. /start - Lists all the available commands!\n1. /sendsms - Sends an anonymous sms!\n2. /joke - Sends you a joke!\n3. /meme - Sends you a meme!\n4. /addmykey - Adds your public ssh key to our shared server!\n5. /coronavirus - Fetches you the latest updates about COVID-19!\n6. /shell - Start a shell session!\n7. /about - Link to my GitHub repository!\n8. /getchatid - Sends you your ChatID!\n9. /adminpanel - Add, remove or list admins!\n\nCheers!" 2 | unknown_message = ( 3 | "Hello there! Don't know where to start? Try using the /start command." 4 | ) 5 | invalid_message = "You have selected an invalid option!" 6 | math_api = "https://api.mathjs.org/v4/?expr=" 7 | subreddits = [ 8 | "dankmemes", 9 | "PrequelMemes", 10 | "politicalhumour", 11 | "memes", 12 | "darkmeme", 13 | "deepfriedmemes", 14 | "surrealmemes", 15 | "meme", 16 | "historymemes", 17 | "ProgrammerHumor", 18 | "programminghumor", 19 | "funny", 20 | "me_irl", 21 | "whiteedgymemes", 22 | "comedyheaven", 23 | "raimimemes", 24 | "AdviceAnimals", 25 | "MemeEconomy", 26 | "ComedyCemetery", 27 | "terriblefacebookmemes", 28 | "teenagers", 29 | "PewdiepieSubmissions", 30 | ] 31 | err_msg = "Internal error! Please, try again later!" 32 | joke_apis = [ 33 | "https://sv443.net/jokeapi/v2/joke/any", 34 | "https://sv443.net/jokeapi/v2/joke/dark", 35 | "https://sv443.net/jokeapi/v2/joke/programming", 36 | "https://sv443.net/jokeapi/v2/joke/miscellaneous", 37 | "https://api.chucknorris.io/jokes/random", 38 | "https://official-joke-api.appspot.com/jokes/random", 39 | "https://official-joke-api.appspot.com/random_joke", 40 | "https://api.icndb.com/jokes/random/?escape=javascript", 41 | ] 42 | empty_output = "No Output!" 43 | sending_fail = "Sending Failed! Error Message:" 44 | sms_success = "Success! Check it's status at: https://textbelt.com/status" 45 | text_key = "textbelt" 46 | text_api = "http://textbelt.com/text/" 47 | not_admin = "You are not authorized to use this feature! Request access by submitting a pull request to https://github.com/alias-rahil/admin-list or contact @alias_rahil." 48 | corona_api = "https://pomber.github.io/covid19/timeseries.json" 49 | key_msg = "Sure, send me your key public." 50 | ssh_start_command = "-t -t -o StrictHostKeyChecking=no" 51 | key_api = "https://heroku-docker-ssh.herokuapp.com/?pubkey=" 52 | meme_api = "https://meme-api.herokuapp.com/gimme" 53 | chat_api = "https://rahil-brobot.herokuapp.com/?query=" 54 | repo_link = "Link: https://github.com/csivitu/BroBot.\nSupport: @alias_rahil." 55 | chat_id_msg = "Your ChatID is:" 56 | ask_date = "Please select a date:" 57 | ask_country = "Please select a country name:" 58 | ask_id = "Send me a username (or a ChatID)!" 59 | already_admin = "is already an admin!" 60 | add_success = "is now an admin!" 61 | repo_path = "alias-rahil/admin-list" 62 | file_name = "admins.txt" 63 | ask_no = "Send me the recipient's full phone number including the country code prefixed with a plus symbol." 64 | ask_message = "Send me the message!" 65 | proxy_api = "https://www.proxyscan.io/api/proxy/?type=http" 66 | shell_msg = "Run shell commands from the chat itself:\n\nFor example, try sending me: uname --all\\n.\n\nDon't forget to postfix your command with \\n (resolves as enter-key) whenever necessary!" 67 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ansistrip==0.1 2 | PyGithub==1.51 3 | python-dotenv==0.13.0 4 | python-telegram-bot==12.7 5 | requests==2.24.0 6 | -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | TOKEN=cM8YAsna91_1X15KwIqCA3pnG5mJ:J2CGZAeu0Ndn1Xb2n 2 | API=6b03df29c100ba72ce7735242013cdc99aadd665 3 | -------------------------------------------------------------------------------- /screenshots/brobot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/brobot.jpg -------------------------------------------------------------------------------- /screenshots/chat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/chat.jpg -------------------------------------------------------------------------------- /screenshots/chatid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/chatid.jpg -------------------------------------------------------------------------------- /screenshots/covid-19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/covid-19.jpg -------------------------------------------------------------------------------- /screenshots/memes-N-jokes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/memes-N-jokes.jpg -------------------------------------------------------------------------------- /screenshots/shell.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/shell.jpg -------------------------------------------------------------------------------- /screenshots/sms.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csivitu/BroBot/f88ca10459bdd7057b00c74474258b78cef65222/screenshots/sms.jpg --------------------------------------------------------------------------------