├── 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 | [](#contributors-)
4 |
5 | [![Issues][issues-shield]](https://github.com/csivitu/brobot/issues)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |
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 |
111 |
112 |
113 | # Get your ChatID
114 |
115 |
116 |
117 |
118 |
119 | # Get memes and jokes
120 |
121 |
122 |
123 |
124 |
125 | # Send a free SMS
126 |
127 |
128 |
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 |
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 |
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 |
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
--------------------------------------------------------------------------------