├── .github ├── CODEOWNERS ├── README.md ├── dependabot.yml └── workflows │ └── PyLint.yml ├── Dockerfile ├── FallenRobot ├── __init__.py ├── __main__.py ├── config.py ├── events.py ├── modules │ ├── __init__.py │ ├── admin.py │ ├── afk.py │ ├── alive.py │ ├── antiflood.py │ ├── approve.py │ ├── backups.py │ ├── bans.py │ ├── blacklist.py │ ├── blacklist_stickers.py │ ├── blacklistusers.py │ ├── carbon.py │ ├── chatbot.py │ ├── cleaner.py │ ├── connection.py │ ├── country.py │ ├── couples.py │ ├── currency_converter.py │ ├── cust_filters.py │ ├── dbcleanup.py │ ├── debug.py │ ├── dev.py │ ├── disable.py │ ├── disasters.py │ ├── encrypt.py │ ├── english.py │ ├── error_handler.py │ ├── eval.py │ ├── fonts.py │ ├── fun.py │ ├── fun_strings.py │ ├── get_common_chats.py │ ├── gettime.py │ ├── gitinfo.py │ ├── global_bans.py │ ├── google.py │ ├── gps.py │ ├── group.py │ ├── helper_funcs │ │ ├── __init__.py │ │ ├── admin_rights.py │ │ ├── alternate.py │ │ ├── chat_status.py │ │ ├── extraction.py │ │ ├── filters.py │ │ ├── handlers.py │ │ ├── misc.py │ │ ├── msg_types.py │ │ ├── regex_helper.py │ │ ├── string_handling.py │ │ └── telethn │ │ │ ├── __init__.py │ │ │ └── chatstatus.py │ ├── json.py │ ├── locks.py │ ├── log_channel.py │ ├── logo.py │ ├── math.py │ ├── memify.py │ ├── misc.py │ ├── modules.py │ ├── muting.py │ ├── nightmode.py │ ├── notes.py │ ├── paste.py │ ├── ping.py │ ├── purge.py │ ├── reactions.py │ ├── remote_cmds.py │ ├── reporting.py │ ├── rules.py │ ├── sed.py │ ├── shell.py │ ├── source.py │ ├── speed_test.py │ ├── sql │ │ ├── __init__.py │ │ ├── afk_sql.py │ │ ├── antiflood_sql.py │ │ ├── approve_sql.py │ │ ├── blacklist_sql.py │ │ ├── blacklistusers_sql.py │ │ ├── blsticker_sql.py │ │ ├── chatbot_sql.py │ │ ├── cleaner_sql.py │ │ ├── connection_sql.py │ │ ├── cust_filters_sql.py │ │ ├── disable_sql.py │ │ ├── global_bans_sql.py │ │ ├── locks_sql.py │ │ ├── log_channel_sql.py │ │ ├── night_mode_sql.py │ │ ├── notes_sql.py │ │ ├── reporting_sql.py │ │ ├── rss_sql.py │ │ ├── rules_sql.py │ │ ├── userinfo_sql.py │ │ ├── users_sql.py │ │ ├── warns_sql.py │ │ └── welcome_sql.py │ ├── stickers.py │ ├── tagall.py │ ├── telegraph.py │ ├── tiny.py │ ├── translator.py │ ├── truth_and_dare.py │ ├── ud.py │ ├── userinfo.py │ ├── users.py │ ├── wallpaper.py │ ├── warns.py │ ├── weather.py │ ├── webshot.py │ ├── welcome.py │ ├── wiki.py │ ├── writetool.py │ ├── zip.py │ └── zombies.py ├── resources │ ├── blank_background.png │ ├── default.ttf │ ├── fallen.jpg │ ├── fglitch.gif │ └── fonts │ │ ├── AVENGEANCE HEROIC AVENGER AT.otf │ │ ├── AVENGEANCE HEROIC AVENGER AT.ttf │ │ ├── AVENGEANCE HEROIC AVENGER BI.otf │ │ ├── Big Space.otf │ │ ├── CRAWLER-RegularDEMO.ttf │ │ ├── CROWNT.TTF │ │ ├── Chopsic.otf │ │ ├── Crozzoe-Personal-Use.otf │ │ ├── DIGIT.ttf │ │ ├── Damages-Italic.ttf │ │ ├── Damages.ttf │ │ ├── Damages3D-Italic.ttf │ │ ├── Damages3D.ttf │ │ ├── Damages3DFilled-Italic.ttf │ │ ├── Damages3DFilled.ttf │ │ ├── Damar Kurung.otf │ │ ├── Damar Kurung.ttf │ │ ├── Dark Ministry.ttf │ │ ├── Dark Seed.otf │ │ ├── Dark.ttf │ │ ├── Dash-Dermo.ttf │ │ ├── Dead Revolution.otf │ │ ├── DezertDemoDash.ttf │ │ ├── DezertDemoItalic.ttf │ │ ├── DezertDemoItalicDash.ttf │ │ ├── DezertDemoOutline.ttf │ │ ├── DezertDemoOutlineDash.ttf │ │ ├── DezertDemoRegular.ttf │ │ ├── DisposableDroidBB_bld.ttf │ │ ├── DragonForcE.ttf │ │ ├── Dramaga Demo.otf │ │ ├── Dramaga Demo.ttf │ │ ├── Dreamscar.ttf │ │ ├── EVILDEAD.TTF │ │ ├── Europhonic.otf │ │ ├── Exorcista_-Jed_40.ttf │ │ ├── Fire Flight FREE.otf │ │ ├── Fire Flight FREE.ttf │ │ ├── FontRemix.ttf │ │ ├── FontRemix2.ttf │ │ ├── Friend Head.otf │ │ ├── Frostbite Boss Fight.otf │ │ ├── Fucking Hostile.ttf │ │ ├── GRAMES.ttf │ │ ├── Gang Wolfik.ttf │ │ ├── Garda.ttf │ │ ├── Garreng-Personal-Use.otf │ │ ├── Geizer.otf │ │ ├── Georgent.otf │ │ ├── Georgent.ttf │ │ ├── Hallowed Grad.otf │ │ ├── Harker Bold Italic.otf │ │ ├── Harker Italic.otf │ │ ├── Maghrib.ttf │ │ ├── ObelixProB-cyr Alfi Stefa.ttf │ │ ├── RealFast Alfi Stefa.ttf │ │ ├── Roboto-Italic.ttf │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Regular.ttf │ │ ├── TruenoBlkOl.otf │ │ ├── TruenoRg.otf │ │ ├── TruenoRgIt.otf │ │ ├── TruenoSBdIt.otf │ │ ├── Vendetta.otf │ │ ├── __init__.py │ │ ├── digital.ttf │ │ ├── elric.TTF │ │ ├── font.otf │ │ ├── fontx.ttf │ │ ├── hawkmoon.ttf │ │ └── monumentextended-regular.otf └── utils │ ├── admins.py │ ├── errors.py │ ├── fonts.py │ ├── functions.py │ ├── mongo.py │ ├── pastebin.py │ └── post.py ├── Git_Pull.bat ├── Git_Push.bat ├── LICENSE ├── Procfile ├── Setup venv.bat ├── _config.yml ├── app.json ├── heroku.yml ├── requirements.txt ├── restart.bat ├── runtime.txt ├── start.bat └── start_service.bat /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @AnonymousX1025 2 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | [━━━━━━━━━━━━━━━━━━━━ 2 | 3 |

4 | ──「™°‌ 🫧 🇴 🇽 𝐘 𓃭🇨𝐇𝐀𝐓 𝐁𝐎𝐓 ⃟⛦⃕͜༆」── 5 |

6 | 7 |

8 | 9 |

10 | 11 | _**ᴀᴠᴀɪʟᴀʙʟᴇ ᴏɴ ᴛᴇʟᴇɢʀᴀᴍ ᴀs [™°‌ 🫧 🇴 🇽 𝐘 𓃭🇨𝐇𝐀𝐓 𝐁𝐎𝐓 ⃟⛦⃕͜༆](https://t.me/DESISWAGGERHU)**_ 12 | ━━━━━━━━━━━━━━━━━━━━ 13 | 14 |

15 | Stars 16 | 17 | License 18 | Python 19 | 20 | 21 | 22 | 23 |

24 | 25 | ━━━━━━━━━━━━━━━━━━━━ 26 | 27 |

28 | 29 |

30 | 31 |

32 | 𝗗𝗘𝗣𝗟𝗢𝗬𝗠𝗘𝗡𝗧 𝗠𝗘𝗧𝗛𝗢𝗗𝗦 33 |

34 | 35 |

36 | ─「 ᴅᴇᴩʟᴏʏ ᴏɴ ʜᴇʀᴏᴋᴜ 」─ 37 |

38 | 39 |

40 | 41 | 42 |

43 | ─「 ᴅᴇᴩʟᴏʏ ᴏɴ ᴠᴘs/ʟᴏᴄᴀʟ 」─ 44 |

45 | 46 |
47 |

48 | - ᴠᴘs/ʟᴏᴄᴀʟ ᴅᴇᴘʟᴏʏᴍᴇɴᴛ ᴍᴇᴛʜᴏᴅ 49 |

50 | 51 | - Get your [Necessary Variables](https://github.com/AnonymousX1025/FallenRobot/blob/master/FallenRobot/config.py) 52 | - Upgrade and Update by : 53 | `sudo apt-get update && sudo apt-get upgrade -y` 54 | - Install required packages by : 55 | `sudo apt-get install python3-pip -y` 56 | - Install pip by : 57 | `sudo pip3 install -U pip` 58 | - Clone the repository by : 59 | `git clone https://github.com/AnonymousX1025/FallenRobot && cd FallenRobot` 60 | - Install/Upgrade setuptools by : 61 | `pip3 install --upgrade pip setuptools` 62 | - Install requirements by : 63 | `pip3 install -U -r requirements.txt` 64 | - Fill your variables in config by : 65 | `vi FallenRobot/config.py` 66 | 67 | Press `I` on the keyboard for editing config 68 | 69 | Press `Ctrl+C` when you're done with editing config and `:wq` to save the config 70 | - Install tmux to keep running your bot when you close the terminal by : 71 | `sudo apt install tmux && tmux` 72 | - Finally run the bot by : 73 | `python3 -m FallenRobot` 74 | - For getting out from tmux session 75 | 76 | Press `Ctrl+b` and then `d` 77 | 78 |

79 | 80 |

81 | 82 |
83 | ━━━━━━━━━━━━━━━━━━━━ 84 | 85 |

86 | ─「 sᴜᴩᴩᴏʀᴛ 」─ 87 |

88 | 89 |

90 | 91 |

92 |

93 | 94 |

95 | 96 | ━━━━━━━━━━━━━━━━━━━━ 97 | 98 |

99 | ─「 ᴄʀᴇᴅɪᴛs 」─ 100 |

101 | 102 | - [ᴀɴᴏɴʏᴍᴏᴜs](https://github.com/AnonymousX1025) ➻ [sᴏᴍᴇᴛʜɪɴɢ](https://github.com/PRADHAN474/FallenRobot) 103 | - [ᴩᴀᴜʟ ʟᴀʀsᴇɴ](https://github.com/PaulSonOfLars) ➻ [ᴛɢ ʙᴏᴛ](https://github.com/PaulSonOfLars/tgbot) 104 | - [ʜᴀᴍᴋᴇʀ ᴄᴀᴛ](https://github.com/TheHamkerCat) ➻ [ᴡɪʟʟɪᴀᴍ ʙᴜᴛᴄʜᴇʀ](https://github.com/TheHamkerCat/WilliamButcherBot) 105 | 106 | ᴀɴᴅ ᴀʟʟ [ᴛʜᴇ ᴄᴏɴᴛʀɪʙᴜᴛᴏʀs](https://github.com/AnonymousX1025/FallenRobot/graphs/contributors) ᴡʜᴏ ʜᴇʟᴩᴇᴅ ɪɴ ᴍᴀᴋɪɴɢ ғᴀʟʟᴇɴ ✘ ʀᴏʙᴏᴛ ᴜsᴇғᴜʟ & ᴩᴏᴡᴇʀғᴜʟ 🖤 107 | 108 | ━━━━━━━━━━━━━━━━━━━━ 109 | ](https://github.com/AnonymousX1025/FallenRobot.git)https://github.com/AnonymousX1025/FallenRobot.git 110 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "00:00" 8 | timezone: "Asia/Kolkata" 9 | labels: 10 | - "dependencies" 11 | open-pull-requests-limit: 50 12 | ignore: 13 | - dependency-name: "python-telegram-bot" 14 | # Ignoring all ptb updates 15 | - dependency-name: "sqlalchemy" 16 | # Ignoring all sqlalchemy updates 17 | -------------------------------------------------------------------------------- /.github/workflows/PyLint.yml: -------------------------------------------------------------------------------- 1 | name: PyLint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | PEP8: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: Setup Python 12 | uses: actions/setup-python@v1 13 | with: 14 | python-version: 3.10.12 15 | - name: Install Python lint libraries 16 | run: | 17 | pip install autoflake isort black 18 | - name: Remove unused imports and variables 19 | run: | 20 | autoflake --in-place --recursive --remove-all-unused-imports --ignore-init-module-imports . 21 | - name: lint with isort 22 | run: | 23 | isort . 24 | - name: lint with black 25 | run: | 26 | black . 27 | # commit changes 28 | - uses: stefanzweifel/git-auto-commit-action@v4 29 | with: 30 | commit_message: 'Auto Fixes' 31 | commit_options: '--no-verify' 32 | repository: . 33 | commit_user_name: AnonymousX1025 34 | commit_user_email: TheAnonymousX1025@gmail.com 35 | commit_author: AnonymousX1025 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # We're using Debian Slim Buster image 2 | FROM python:3.8.5-slim-buster 3 | 4 | ENV PIP_NO_CACHE_DIR 1 5 | 6 | RUN sed -i.bak 's/us-west-2\.ec2\.//' /etc/apt/sources.list 7 | 8 | # Installing Required Packages 9 | RUN apt update && apt upgrade -y && \ 10 | apt install --no-install-recommends -y \ 11 | debian-keyring \ 12 | debian-archive-keyring \ 13 | bash \ 14 | bzip2 \ 15 | curl \ 16 | figlet \ 17 | git \ 18 | util-linux \ 19 | libffi-dev \ 20 | libjpeg-dev \ 21 | libjpeg62-turbo-dev \ 22 | libwebp-dev \ 23 | linux-headers-amd64 \ 24 | musl-dev \ 25 | musl \ 26 | neofetch \ 27 | php-pgsql \ 28 | python3-lxml \ 29 | postgresql \ 30 | postgresql-client \ 31 | python3-psycopg2 \ 32 | libpq-dev \ 33 | libcurl4-openssl-dev \ 34 | libxml2-dev \ 35 | libxslt1-dev \ 36 | python3-pip \ 37 | python3-requests \ 38 | python3-sqlalchemy \ 39 | python3-tz \ 40 | python3-aiohttp \ 41 | openssl \ 42 | pv \ 43 | jq \ 44 | wget \ 45 | python3 \ 46 | python3-dev \ 47 | libreadline-dev \ 48 | libyaml-dev \ 49 | gcc \ 50 | sqlite3 \ 51 | libsqlite3-dev \ 52 | sudo \ 53 | zlib1g \ 54 | ffmpeg \ 55 | libssl-dev \ 56 | libgconf-2-4 \ 57 | libxi6 \ 58 | xvfb \ 59 | unzip \ 60 | libopus0 \ 61 | libopus-dev \ 62 | && rm -rf /var/lib/apt/lists /var/cache/apt/archives /tmp 63 | 64 | # Pypi package Repo upgrade 65 | RUN pip3 install --upgrade pip setuptools 66 | 67 | # Copy Python Requirements to /root/FallenRobot 68 | RUN git clone https://github.com/AnonymousX1025/FallenRobot /root/FallenRobot 69 | WORKDIR /root/FallenRobot 70 | 71 | #Copy config file to /root/FallenRobot/FallenRobot 72 | COPY ./FallenRobot/config.py ./FallenRobot/config.py* /root/FallenRobot/FallenRobot/ 73 | 74 | ENV PATH="/home/bot/bin:$PATH" 75 | 76 | # Install requirements 77 | RUN pip3 install -U -r requirements.txt 78 | 79 | # Starting Worker 80 | CMD ["python3","-m","FallenRobot"] 81 | -------------------------------------------------------------------------------- /FallenRobot/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | LOGGER = True 3 | 4 | # Get this value from my.telegram.org/apps 5 | API_ID = 6 6 | API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e" 7 | 8 | CASH_API_KEY = "" # Get this value for currency converter from https://www.alphavantage.co/support/#api-key 9 | 10 | DATABASE_URL = "" # A sql database url from elephantsql.com 11 | 12 | EVENT_LOGS = () # Event logs channel to note down important bot level events 13 | 14 | MONGO_DB_URI = "" # Get ths value from cloud.mongodb.com 15 | 16 | # Telegraph link of the image which will be shown at start command. 17 | START_IMG = "https://te.legra.ph/file/40eb1ed850cdea274693e.jpg" 18 | 19 | SUPPORT_CHAT = "BWANDARLOK" # Your Telegram support group chat username where your users will go and bother you 20 | 21 | TOKEN = "" # Get bot token from @BotFather on Telegram 22 | 23 | TIME_API_KEY = "" # Get this value from https://timezonedb.com/api 24 | 25 | OWNER_ID = 5059737154 # User id of your telegram account (Must be integer) 26 | 27 | # Optional fields 28 | BL_CHATS = [] # List of groups that you want blacklisted. 29 | DRAGONS = [] # User id of sudo users 30 | DEV_USERS = [] # User id of dev users 31 | DEMONS = [] # User id of support users 32 | TIGERS = [] # User id of tiger users 33 | WOLVES = [] # User id of whitelist users 34 | 35 | ALLOW_CHATS = True 36 | ALLOW_EXCL = True 37 | DEL_CMDS = True 38 | INFOPIC = True 39 | LOAD = [] 40 | NO_LOAD = [] 41 | STRICT_GBAN = True 42 | TEMP_DOWNLOAD_DIRECTORY = "./" 43 | WORKERS = 8 44 | 45 | 46 | class Production(Config): 47 | LOGGER = True 48 | 49 | 50 | class Development(Config): 51 | LOGGER = True 52 | -------------------------------------------------------------------------------- /FallenRobot/events.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import re 3 | from pathlib import Path 4 | 5 | from pymongo import MongoClient 6 | from telethon import events 7 | 8 | from FallenRobot import MONGO_DB_URI, telethn 9 | 10 | client = MongoClient() 11 | client = MongoClient(MONGO_DB_URI) 12 | db = client["Anonymous"] 13 | gbanned = db.gban 14 | 15 | 16 | def register(**args): 17 | """Registers a new message.""" 18 | pattern = args.get("pattern", None) 19 | 20 | r_pattern = r"^[/!.]" 21 | 22 | if pattern is not None and not pattern.startswith("(?i)"): 23 | args["pattern"] = "(?i)" + pattern 24 | 25 | args["pattern"] = pattern.replace("^/", r_pattern, 1) 26 | 27 | def decorator(func): 28 | telethn.add_event_handler(func, events.NewMessage(**args)) 29 | return func 30 | 31 | return decorator 32 | 33 | 34 | def chataction(**args): 35 | """Registers chat actions.""" 36 | 37 | def decorator(func): 38 | telethn.add_event_handler(func, events.ChatAction(**args)) 39 | return func 40 | 41 | return decorator 42 | 43 | 44 | def userupdate(**args): 45 | """Registers user updates.""" 46 | 47 | def decorator(func): 48 | telethn.add_event_handler(func, events.UserUpdate(**args)) 49 | return func 50 | 51 | return decorator 52 | 53 | 54 | def inlinequery(**args): 55 | """Registers inline query.""" 56 | pattern = args.get("pattern", None) 57 | 58 | if pattern is not None and not pattern.startswith("(?i)"): 59 | args["pattern"] = "(?i)" + pattern 60 | 61 | def decorator(func): 62 | telethn.add_event_handler(func, events.InlineQuery(**args)) 63 | return func 64 | 65 | return decorator 66 | 67 | 68 | def callbackquery(**args): 69 | """Registers inline query.""" 70 | 71 | def decorator(func): 72 | telethn.add_event_handler(func, events.CallbackQuery(**args)) 73 | return func 74 | 75 | return decorator 76 | 77 | 78 | def bot(**args): 79 | pattern = args.get("pattern") 80 | r_pattern = r"^[/]" 81 | 82 | if pattern is not None and not pattern.startswith("(?i)"): 83 | args["pattern"] = "(?i)" + pattern 84 | 85 | args["pattern"] = pattern.replace("^/", r_pattern, 1) 86 | stack = inspect.stack() 87 | previous_stack_frame = stack[1] 88 | file_test = Path(previous_stack_frame.filename) 89 | file_test = file_test.stem.replace(".py", "") 90 | reg = re.compile("(.*)") 91 | 92 | if pattern is not None: 93 | try: 94 | cmd = re.search(reg, pattern) 95 | try: 96 | cmd = cmd.group(1).replace("$", "").replace("\\", "").replace("^", "") 97 | except BaseException: 98 | pass 99 | 100 | try: 101 | FUN_LIST[file_test].append(cmd) 102 | except BaseException: 103 | FUN_LIST.update({file_test: [cmd]}) 104 | except BaseException: 105 | pass 106 | 107 | def decorator(func): 108 | async def wrapper(check): 109 | if check.edit_date: 110 | return 111 | if check.fwd_from: 112 | return 113 | if check.is_group or check.is_private: 114 | pass 115 | else: 116 | print("i don't work in channels") 117 | return 118 | if check.is_group: 119 | if check.chat.megagroup: 120 | pass 121 | else: 122 | print("i don't work in small chats") 123 | return 124 | 125 | users = gbanned.find({}) 126 | for c in users: 127 | if check.sender_id == c["user"]: 128 | return 129 | try: 130 | await func(check) 131 | try: 132 | LOAD_PLUG[file_test].append(func) 133 | except Exception: 134 | LOAD_PLUG.update({file_test: [func]}) 135 | except BaseException: 136 | return 137 | else: 138 | pass 139 | 140 | telethn.add_event_handler(wrapper, events.NewMessage(**args)) 141 | return wrapper 142 | 143 | return decorator 144 | 145 | 146 | def fallenrobot(**args): 147 | pattern = args.get("pattern", None) 148 | args.get("disable_edited", False) 149 | ignore_unsafe = args.get("ignore_unsafe", False) 150 | unsafe_pattern = r"^[^/!#@\$A-Za-z]" 151 | args.get("group_only", False) 152 | args.get("disable_errors", False) 153 | args.get("insecure", False) 154 | if pattern is not None and not pattern.startswith("(?i)"): 155 | args["pattern"] = "(?i)" + pattern 156 | 157 | if "disable_edited" in args: 158 | del args["disable_edited"] 159 | 160 | if "ignore_unsafe" in args: 161 | del args["ignore_unsafe"] 162 | 163 | if "group_only" in args: 164 | del args["group_only"] 165 | 166 | if "disable_errors" in args: 167 | del args["disable_errors"] 168 | 169 | if "insecure" in args: 170 | del args["insecure"] 171 | 172 | if pattern: 173 | if not ignore_unsafe: 174 | args["pattern"] = args["pattern"].replace("^.", unsafe_pattern, 1) 175 | -------------------------------------------------------------------------------- /FallenRobot/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from FallenRobot import LOAD, LOGGER, NO_LOAD 2 | 3 | 4 | def __list_all_modules(): 5 | import glob 6 | from os.path import basename, dirname, isfile 7 | 8 | # This generates a list of modules in this folder for the * in __main__ to work. 9 | mod_paths = glob.glob(dirname(__file__) + "/*.py") 10 | all_modules = [ 11 | basename(f)[:-3] 12 | for f in mod_paths 13 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 14 | ] 15 | 16 | if LOAD or NO_LOAD: 17 | to_load = LOAD 18 | if to_load: 19 | if not all( 20 | any(mod == module_name for module_name in all_modules) 21 | for mod in to_load 22 | ): 23 | LOGGER.error("Invalid loadorder names, Quitting...") 24 | quit(1) 25 | 26 | all_modules = sorted(set(all_modules) - set(to_load)) 27 | to_load = list(all_modules) + to_load 28 | 29 | else: 30 | to_load = all_modules 31 | 32 | if NO_LOAD: 33 | LOGGER.info("Not loading: {}".format(NO_LOAD)) 34 | return [item for item in to_load if item not in NO_LOAD] 35 | 36 | return to_load 37 | 38 | return all_modules 39 | 40 | 41 | ALL_MODULES = __list_all_modules() 42 | LOGGER.info("Modules to load: %s", str(ALL_MODULES)) 43 | __all__ = ALL_MODULES + ["ALL_MODULES"] 44 | -------------------------------------------------------------------------------- /FallenRobot/modules/alive.py: -------------------------------------------------------------------------------- 1 | from pyrogram import __version__ as pyrover 2 | from pyrogram import filters 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message 4 | from telegram import __version__ as telever 5 | from telethon import __version__ as tlhver 6 | 7 | from FallenRobot import BOT_NAME, BOT_USERNAME, OWNER_ID, START_IMG, SUPPORT_CHAT, pbot 8 | 9 | 10 | @pbot.on_message(filters.command("alive")) 11 | async def awake(_, message: Message): 12 | TEXT = f"**ʜᴇʏ {message.from_user.mention},\n\nɪ ᴀᴍ {BOT_NAME}**\n━━━━━━━━━━━━━━━━━━━\n\n" 13 | TEXT += f"» **ᴍʏ ᴅᴇᴠᴇʟᴏᴘᴇʀ :** [™°‌ 🫧 🇴 🇽 𝐘 𝐆 𝐄 𝐍](tg://user?id={OWNER_ID})\n\n" 14 | TEXT += f"» **ʟɪʙʀᴀʀʏ ᴠᴇʀsɪᴏɴ :** `{telever}` \n\n" 15 | TEXT += f"» **ᴛᴇʟᴇᴛʜᴏɴ ᴠᴇʀsɪᴏɴ :** `{tlhver}` \n\n" 16 | TEXT += f"» **ᴘʏʀᴏɢʀᴀᴍ ᴠᴇʀsɪᴏɴ :** `{pyrover}` \n━━━━━━━━━━━━━━━━━\n\n" 17 | BUTTON = [ 18 | [ 19 | InlineKeyboardButton("ʜᴇʟᴘ", url=f"https://t.me/{BOT_USERNAME}?start=help"), 20 | InlineKeyboardButton("sᴜᴘᴘᴏʀᴛ", url=f"https://t.me/{SUPPORT_CHAT}"), 21 | ] 22 | ] 23 | await message.reply_photo( 24 | photo=START_IMG, 25 | caption=TEXT, 26 | reply_markup=InlineKeyboardMarkup(BUTTON), 27 | ) 28 | 29 | 30 | __mod_name__ = "Aʟɪᴠᴇ" 31 | -------------------------------------------------------------------------------- /FallenRobot/modules/blacklistusers.py: -------------------------------------------------------------------------------- 1 | import html 2 | 3 | from telegram import ParseMode, Update 4 | from telegram.error import BadRequest 5 | from telegram.ext import CallbackContext, CommandHandler 6 | from telegram.utils.helpers import mention_html 7 | 8 | import FallenRobot.modules.sql.blacklistusers_sql as sql 9 | from FallenRobot import DEMONS, DEV_USERS, DRAGONS, OWNER_ID, TIGERS, WOLVES, dispatcher 10 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 11 | from FallenRobot.modules.helper_funcs.extraction import ( 12 | extract_user, 13 | extract_user_and_text, 14 | ) 15 | from FallenRobot.modules.log_channel import gloggable 16 | 17 | BLACKLISTWHITELIST = [OWNER_ID] + DEV_USERS + DRAGONS + WOLVES + DEMONS 18 | BLABLEUSERS = [OWNER_ID] + DEV_USERS 19 | 20 | 21 | @dev_plus 22 | @gloggable 23 | def bl_user(update: Update, context: CallbackContext) -> str: 24 | message = update.effective_message 25 | user = update.effective_user 26 | bot, args = context.bot, context.args 27 | user_id, reason = extract_user_and_text(message, args) 28 | 29 | if not user_id: 30 | message.reply_text("I doubt that's a user.") 31 | return "" 32 | 33 | if user_id == bot.id: 34 | message.reply_text("How am I supposed to do my work if I am ignoring myself?") 35 | return "" 36 | 37 | if user_id in BLACKLISTWHITELIST: 38 | message.reply_text("No!\nNoticing Disasters is my job.") 39 | return "" 40 | 41 | try: 42 | target_user = bot.get_chat(user_id) 43 | except BadRequest as excp: 44 | if excp.message == "User not found": 45 | message.reply_text("I can't seem to find this user.") 46 | return "" 47 | else: 48 | raise 49 | 50 | sql.blacklist_user(user_id, reason) 51 | message.reply_text("I shall ignore the existence of this user!") 52 | log_message = ( 53 | f"#BLACKLIST\n" 54 | f"Admin: {mention_html(user.id, html.escape(user.first_name))}\n" 55 | f"User: {mention_html(target_user.id, html.escape(target_user.first_name))}" 56 | ) 57 | if reason: 58 | log_message += f"\nReason: {reason}" 59 | 60 | return log_message 61 | 62 | 63 | @dev_plus 64 | @gloggable 65 | def unbl_user(update: Update, context: CallbackContext) -> str: 66 | message = update.effective_message 67 | user = update.effective_user 68 | bot, args = context.bot, context.args 69 | user_id = extract_user(message, args) 70 | 71 | if not user_id: 72 | message.reply_text("I doubt that's a user.") 73 | return "" 74 | 75 | if user_id == bot.id: 76 | message.reply_text("I always notice myself.") 77 | return "" 78 | 79 | try: 80 | target_user = bot.get_chat(user_id) 81 | except BadRequest as excp: 82 | if excp.message == "User not found": 83 | message.reply_text("I can't seem to find this user.") 84 | return "" 85 | else: 86 | raise 87 | 88 | if sql.is_user_blacklisted(user_id): 89 | sql.unblacklist_user(user_id) 90 | message.reply_text("*notices user*") 91 | log_message = ( 92 | f"#UNBLACKLIST\n" 93 | f"Admin: {mention_html(user.id, html.escape(user.first_name))}\n" 94 | f"User: {mention_html(target_user.id, html.escape(target_user.first_name))}" 95 | ) 96 | 97 | return log_message 98 | 99 | else: 100 | message.reply_text("I am not ignoring them at all though!") 101 | return "" 102 | 103 | 104 | @dev_plus 105 | def bl_users(update: Update, context: CallbackContext): 106 | users = [] 107 | bot = context.bot 108 | for each_user in sql.BLACKLIST_USERS: 109 | user = bot.get_chat(each_user) 110 | reason = sql.get_reason(each_user) 111 | 112 | if reason: 113 | users.append( 114 | f"• {mention_html(user.id, html.escape(user.first_name))} :- {reason}" 115 | ) 116 | else: 117 | users.append(f"• {mention_html(user.id, html.escape(user.first_name))}") 118 | 119 | message = "Blacklisted Users\n" 120 | if not users: 121 | message += "None is being ignored as of yet." 122 | else: 123 | message += "\n".join(users) 124 | 125 | update.effective_message.reply_text(message, parse_mode=ParseMode.HTML) 126 | 127 | 128 | def __user_info__(user_id): 129 | is_blacklisted = sql.is_user_blacklisted(user_id) 130 | 131 | text = "Blacklisted: {}" 132 | if user_id in [777000, 1087968824]: 133 | return "" 134 | if user_id == dispatcher.bot.id: 135 | return "" 136 | if int(user_id) in DRAGONS + TIGERS + WOLVES: 137 | return "" 138 | if is_blacklisted: 139 | text = text.format("Yes") 140 | reason = sql.get_reason(user_id) 141 | if reason: 142 | text += f"\nReason: {reason}" 143 | else: 144 | text = text.format("No") 145 | 146 | return text 147 | 148 | 149 | BL_HANDLER = CommandHandler("ignore", bl_user, run_async=True) 150 | UNBL_HANDLER = CommandHandler("notice", unbl_user, run_async=True) 151 | BLUSERS_HANDLER = CommandHandler("ignoredlist", bl_users, run_async=True) 152 | 153 | dispatcher.add_handler(BL_HANDLER) 154 | dispatcher.add_handler(UNBL_HANDLER) 155 | dispatcher.add_handler(BLUSERS_HANDLER) 156 | 157 | __mod_name__ = "Blacklisting Users" 158 | __handlers__ = [BL_HANDLER, UNBL_HANDLER, BLUSERS_HANDLER] 159 | -------------------------------------------------------------------------------- /FallenRobot/modules/carbon.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters 2 | 3 | from FallenRobot import pbot 4 | from FallenRobot.utils.errors import capture_err 5 | from FallenRobot.utils.functions import make_carbon 6 | 7 | 8 | @pbot.on_message(filters.command("carbon")) 9 | @capture_err 10 | async def carbon_func(_, message): 11 | if message.reply_to_message: 12 | if message.reply_to_message.text: 13 | txt = message.reply_to_message.text 14 | else: 15 | return await message.reply_text("ʀᴇᴘʟʏ ᴛᴏ ᴀ ᴍᴇssᴀɢᴇ ᴏʀ ɢɪᴠᴇ sᴏᴍᴇ ᴛᴇxᴛ.") 16 | else: 17 | try: 18 | txt = message.text.split(None, 1)[1] 19 | except IndexError: 20 | return await message.reply_text("ʀᴇᴘʟʏ ᴛᴏ ᴀ ᴍᴇssᴀɢᴇ ᴏʀ ɢɪᴠᴇ sᴏᴍᴇ ᴛᴇxᴛ.") 21 | m = await message.reply_text("ɢᴇɴᴇʀᴀᴛɪɴɢ ᴄᴀʀʙᴏɴ...") 22 | carbon = await make_carbon(txt) 23 | await m.edit_text("ᴜᴩʟᴏᴀᴅɪɴɢ ɢᴇɴᴇʀᴀᴛᴇᴅ ᴄᴀʀʙᴏɴ...") 24 | await pbot.send_photo( 25 | message.chat.id, 26 | photo=carbon, 27 | caption=f"» ʀᴇᴏ̨ᴜᴇsᴛᴇᴅ ʙʏ : {message.from_user.mention}", 28 | ) 29 | await m.delete() 30 | carbon.close() 31 | 32 | 33 | __mod_name__ = "Cᴀʀʙᴏɴ" 34 | 35 | __help__ = """ 36 | ᴍᴀᴋᴇs ᴀ ᴄᴀʀʙᴏɴ ᴏғ ᴛʜᴇ ɢɪᴠᴇɴ ᴛᴇxᴛ ᴀɴᴅ sᴇɴᴅ ɪᴛ ᴛᴏ ʏᴏᴜ. 37 | 38 | ❍ /carbon *:* ᴍᴀᴋᴇs ᴄᴀʀʙᴏɴ ᴏғ ᴛʜᴇ ɢɪᴠᴇɴ ᴛᴇxᴛ. 39 | """ 40 | -------------------------------------------------------------------------------- /FallenRobot/modules/country.py: -------------------------------------------------------------------------------- 1 | import flag 2 | from countryinfo import CountryInfo 3 | 4 | from FallenRobot import BOT_NAME, telethn 5 | from FallenRobot.events import register 6 | 7 | 8 | @register(pattern="^/country (.*)") 9 | async def msg(event): 10 | if event.fwd_from: 11 | return 12 | input_str = event.pattern_match.group(1) 13 | lol = input_str 14 | country = CountryInfo(lol) 15 | try: 16 | a = country.info() 17 | except: 18 | await event.reply("Country Not Available Currently") 19 | name = a.get("name") 20 | bb = a.get("altSpellings") 21 | hu = "" 22 | for p in bb: 23 | hu += p + ", " 24 | 25 | area = a.get("area") 26 | borders = "" 27 | hell = a.get("borders") 28 | for fk in hell: 29 | borders += fk + ", " 30 | 31 | call = "" 32 | WhAt = a.get("callingCodes") 33 | for what in WhAt: 34 | call += what + " " 35 | 36 | capital = a.get("capital") 37 | currencies = "" 38 | fker = a.get("currencies") 39 | for FKer in fker: 40 | currencies += FKer + ", " 41 | 42 | HmM = a.get("demonym") 43 | geo = a.get("geoJSON") 44 | pablo = geo.get("features") 45 | Pablo = pablo[0] 46 | PAblo = Pablo.get("geometry") 47 | EsCoBaR = PAblo.get("type") 48 | iso = "" 49 | iSo = a.get("ISO") 50 | for hitler in iSo: 51 | po = iSo.get(hitler) 52 | iso += po + ", " 53 | fla = iSo.get("alpha2") 54 | nox = fla.upper() 55 | okie = flag.flag(nox) 56 | 57 | languages = a.get("languages") 58 | lMAO = "" 59 | for lmao in languages: 60 | lMAO += lmao + ", " 61 | 62 | nonive = a.get("nativeName") 63 | waste = a.get("population") 64 | reg = a.get("region") 65 | sub = a.get("subregion") 66 | tik = a.get("timezones") 67 | tom = "" 68 | for jerry in tik: 69 | tom += jerry + ", " 70 | 71 | GOT = a.get("tld") 72 | lanester = "" 73 | for targaryen in GOT: 74 | lanester += targaryen + ", " 75 | 76 | wiki = a.get("wiki") 77 | 78 | caption = f"""Information Gathered Successfully 79 | 80 | Country Name : {name} 81 | Alternative Spellings : {hu} 82 | Country Area : {area} square kilometers 83 | Borders : {borders} 84 | Calling Codes : {call} 85 | Country's Capital : {capital} 86 | Country's currency : {currencies} 87 | Country's Flag : {okie} 88 | Demonym : {HmM} 89 | Country Type : {EsCoBaR} 90 | ISO Names : {iso} 91 | Languages : {lMAO} 92 | Native Name : {nonive} 93 | Population : {waste} 94 | Region : {reg} 95 | Sub Region : {sub} 96 | Time Zones : {tom} 97 | Top Level Domain : {lanester} 98 | Wikipedia : {wiki} 99 | 100 | Information Gathered By {BOT_NAME} 101 | """ 102 | 103 | await telethn.send_message( 104 | event.chat_id, 105 | caption, 106 | parse_mode="HTML", 107 | link_preview=None, 108 | ) 109 | 110 | 111 | __help__ = """ 112 | I will give information about a country 113 | 114 | ❍ /country *:* Gathering info about given country 115 | """ 116 | 117 | __mod_name__ = "Cᴏᴜɴᴛʀʏ" 118 | -------------------------------------------------------------------------------- /FallenRobot/modules/couples.py: -------------------------------------------------------------------------------- 1 | import random 2 | from datetime import datetime 3 | 4 | from pyrogram import filters 5 | from pyrogram.enums import ChatType 6 | 7 | from FallenRobot import pbot 8 | from FallenRobot.utils.mongo import get_couple, save_couple 9 | 10 | 11 | # Date and time 12 | def dt(): 13 | now = datetime.now() 14 | dt_string = now.strftime("%d/%m/%Y %H:%M") 15 | dt_list = dt_string.split(" ") 16 | return dt_list 17 | 18 | 19 | def dt_tom(): 20 | a = ( 21 | str(int(dt()[0].split("/")[0]) + 1) 22 | + "/" 23 | + dt()[0].split("/")[1] 24 | + "/" 25 | + dt()[0].split("/")[2] 26 | ) 27 | return a 28 | 29 | 30 | today = str(dt()[0]) 31 | tomorrow = str(dt_tom()) 32 | 33 | 34 | @pbot.on_message(filters.command(["couple", "couples"])) 35 | async def couple(_, message): 36 | if message.chat.type == ChatType.PRIVATE: 37 | return await message.reply_text("This command only works in groups.") 38 | try: 39 | chat_id = message.chat.id 40 | is_selected = await get_couple(chat_id, today) 41 | if not is_selected: 42 | list_of_users = [] 43 | async for i in pbot.get_chat_members(message.chat.id, limit=50): 44 | if not i.user.is_bot: 45 | list_of_users.append(i.user.id) 46 | if len(list_of_users) < 2: 47 | return await message.reply_text("Not enough users") 48 | c1_id = random.choice(list_of_users) 49 | c2_id = random.choice(list_of_users) 50 | while c1_id == c2_id: 51 | c1_id = random.choice(list_of_users) 52 | c1_mention = (await pbot.get_users(c1_id)).mention 53 | c2_mention = (await pbot.get_users(c2_id)).mention 54 | 55 | couple_selection_message = f"""**Couple of the day :** 56 | 57 | {c1_mention} + {c2_mention} = 😘 58 | __New couple of the day can be chosen at 12AM {tomorrow}__""" 59 | await pbot.send_message(message.chat.id, text=couple_selection_message) 60 | couple = {"c1_id": c1_id, "c2_id": c2_id} 61 | await save_couple(chat_id, today, couple) 62 | 63 | elif is_selected: 64 | c1_id = int(is_selected["c1_id"]) 65 | c2_id = int(is_selected["c2_id"]) 66 | c1_name = (await pbot.get_users(c1_id)).mention 67 | c2_name = (await pbot.get_users(c2_id)).mention 68 | couple_selection_message = f"""Couple of the day : 69 | 70 | {c1_name} + {c2_name} = 😘 71 | __New couple of the day can be chosen at 12AM {tomorrow}__""" 72 | await pbot.send_message(message.chat.id, text=couple_selection_message) 73 | except Exception as e: 74 | print(e) 75 | await message.reply_text(e) 76 | 77 | 78 | __help__ = """ 79 | Choose couples in your chat 80 | 81 | ❍ /couple *:* Choose 2 users and send their name as couples in your chat. 82 | """ 83 | 84 | __mod_name__ = "Cᴏᴜᴘʟᴇ" 85 | -------------------------------------------------------------------------------- /FallenRobot/modules/currency_converter.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from telegram import ParseMode, Update 3 | from telegram.ext import CallbackContext, CommandHandler 4 | 5 | from FallenRobot import CASH_API_KEY, dispatcher 6 | 7 | 8 | def convert(update: Update, context: CallbackContext): 9 | args = update.effective_message.text.split(" ") 10 | 11 | if len(args) == 4: 12 | try: 13 | orig_cur_amount = float(args[1]) 14 | 15 | except ValueError: 16 | update.effective_message.reply_text("Invalid Amount Of Currency") 17 | return 18 | 19 | orig_cur = args[2].upper() 20 | 21 | new_cur = args[3].upper() 22 | 23 | request_url = ( 24 | f"https://www.alphavantage.co/query" 25 | f"?function=CURRENCY_EXCHANGE_RATE" 26 | f"&from_currency={orig_cur}" 27 | f"&to_currency={new_cur}" 28 | f"&apikey={CASH_API_KEY}" 29 | ) 30 | response = requests.get(request_url).json() 31 | try: 32 | current_rate = float( 33 | response["Realtime Currency Exchange Rate"]["5. Exchange Rate"] 34 | ) 35 | except KeyError: 36 | update.effective_message.reply_text("Currency Not Supported.") 37 | return 38 | new_cur_amount = round(orig_cur_amount * current_rate, 5) 39 | update.effective_message.reply_text( 40 | f"{orig_cur_amount} {orig_cur} = {new_cur_amount} {new_cur}" 41 | ) 42 | 43 | elif len(args) == 1: 44 | update.effective_message.reply_text(__help__, parse_mode=ParseMode.MARKDOWN) 45 | 46 | else: 47 | update.effective_message.reply_text( 48 | f"*Invalid Args!!:* Required 3 But Passed {len(args) -1}", 49 | parse_mode=ParseMode.MARKDOWN, 50 | ) 51 | 52 | 53 | __mod_name__ = "Cᴀsʜ" 54 | 55 | __help__ = """ 56 | Converts money from one exchange to another 57 | 58 | Usage: /cash amount from to 59 | Example: /cash 20 USD INR 60 | """ 61 | 62 | CONVERTER_HANDLER = CommandHandler("cash", convert, run_async=True) 63 | dispatcher.add_handler(CONVERTER_HANDLER) 64 | __command_list__ = ["cash"] 65 | 66 | __handlers__ = [CONVERTER_HANDLER] 67 | -------------------------------------------------------------------------------- /FallenRobot/modules/dbcleanup.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update 4 | from telegram.error import BadRequest, Unauthorized 5 | from telegram.ext import CallbackContext, CallbackQueryHandler, CommandHandler 6 | 7 | import FallenRobot.modules.sql.global_bans_sql as gban_sql 8 | import FallenRobot.modules.sql.users_sql as user_sql 9 | from FallenRobot import DEV_USERS, OWNER_ID, dispatcher 10 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 11 | 12 | 13 | def get_invalid_chats(update: Update, context: CallbackContext, remove: bool = False): 14 | bot = context.bot 15 | chat_id = update.effective_chat.id 16 | chats = user_sql.get_all_chats() 17 | kicked_chats, progress = 0, 0 18 | chat_list = [] 19 | progress_message = None 20 | 21 | for chat in chats: 22 | if ((100 * chats.index(chat)) / len(chats)) > progress: 23 | progress_bar = f"{progress}% completed in getting invalid chats." 24 | if progress_message: 25 | try: 26 | bot.editMessageText( 27 | progress_bar, chat_id, progress_message.message_id 28 | ) 29 | except: 30 | pass 31 | else: 32 | progress_message = bot.sendMessage(chat_id, progress_bar) 33 | progress += 5 34 | 35 | cid = chat.chat_id 36 | sleep(0.1) 37 | try: 38 | bot.get_chat(cid, timeout=60) 39 | except (BadRequest, Unauthorized): 40 | kicked_chats += 1 41 | chat_list.append(cid) 42 | except: 43 | pass 44 | 45 | try: 46 | progress_message.delete() 47 | except: 48 | pass 49 | 50 | if not remove: 51 | return kicked_chats 52 | else: 53 | for muted_chat in chat_list: 54 | sleep(0.1) 55 | user_sql.rem_chat(muted_chat) 56 | return kicked_chats 57 | 58 | 59 | def get_invalid_gban(update: Update, context: CallbackContext, remove: bool = False): 60 | bot = context.bot 61 | banned = gban_sql.get_gban_list() 62 | ungbanned_users = 0 63 | ungban_list = [] 64 | 65 | for user in banned: 66 | user_id = user["user_id"] 67 | sleep(0.1) 68 | try: 69 | bot.get_chat(user_id) 70 | except BadRequest: 71 | ungbanned_users += 1 72 | ungban_list.append(user_id) 73 | except: 74 | pass 75 | 76 | if not remove: 77 | return ungbanned_users 78 | else: 79 | for user_id in ungban_list: 80 | sleep(0.1) 81 | gban_sql.ungban_user(user_id) 82 | return ungbanned_users 83 | 84 | 85 | @dev_plus 86 | def dbcleanup(update: Update, context: CallbackContext): 87 | msg = update.effective_message 88 | 89 | msg.reply_text("Getting invalid chat count ...") 90 | invalid_chat_count = get_invalid_chats(update, context) 91 | 92 | msg.reply_text("Getting invalid gbanned count ...") 93 | invalid_gban_count = get_invalid_gban(update, context) 94 | 95 | reply = f"Total invalid chats - {invalid_chat_count}\n" 96 | reply += f"Total invalid gbanned users - {invalid_gban_count}" 97 | 98 | buttons = [[InlineKeyboardButton("Cleanup DB", callback_data="db_cleanup")]] 99 | 100 | update.effective_message.reply_text( 101 | reply, reply_markup=InlineKeyboardMarkup(buttons) 102 | ) 103 | 104 | 105 | def callback_button(update: Update, context: CallbackContext): 106 | bot = context.bot 107 | query = update.callback_query 108 | message = query.message 109 | chat_id = update.effective_chat.id 110 | query_type = query.data 111 | 112 | admin_list = [OWNER_ID] + DEV_USERS 113 | 114 | bot.answer_callback_query(query.id) 115 | 116 | if query_type == "db_leave_chat": 117 | if query.from_user.id in admin_list: 118 | bot.editMessageText("Leaving chats ...", chat_id, message.message_id) 119 | chat_count = get_muted_chats(update, context, True) 120 | bot.sendMessage(chat_id, f"Left {chat_count} chats.") 121 | else: 122 | query.answer("You are not allowed to use this.") 123 | elif query_type == "db_cleanup": 124 | if query.from_user.id in admin_list: 125 | bot.editMessageText("Cleaning up DB ...", chat_id, message.message_id) 126 | invalid_chat_count = get_invalid_chats(update, context, True) 127 | invalid_gban_count = get_invalid_gban(update, context, True) 128 | reply = "Cleaned up {} chats and {} gbanned users from db.".format( 129 | invalid_chat_count, invalid_gban_count 130 | ) 131 | bot.sendMessage(chat_id, reply) 132 | else: 133 | query.answer("You are not allowed to use this.") 134 | 135 | 136 | DB_CLEANUP_HANDLER = CommandHandler("dbcleanup", dbcleanup, run_async=True) 137 | BUTTON_HANDLER = CallbackQueryHandler(callback_button, pattern="db_.*", run_async=True) 138 | 139 | dispatcher.add_handler(DB_CLEANUP_HANDLER) 140 | dispatcher.add_handler(BUTTON_HANDLER) 141 | 142 | __mod_name__ = "DB Cleanup" 143 | __handlers__ = [DB_CLEANUP_HANDLER, BUTTON_HANDLER] 144 | -------------------------------------------------------------------------------- /FallenRobot/modules/debug.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | 4 | from telegram import Update 5 | from telegram.ext import CallbackContext, CommandHandler 6 | from telethon import events 7 | 8 | from FallenRobot import dispatcher, telethn 9 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 10 | 11 | DEBUG_MODE = False 12 | 13 | 14 | @dev_plus 15 | def debug(update: Update, context: CallbackContext): 16 | global DEBUG_MODE 17 | args = update.effective_message.text.split(None, 1) 18 | message = update.effective_message 19 | print(DEBUG_MODE) 20 | if len(args) > 1: 21 | if args[1] in ("yes", "on"): 22 | DEBUG_MODE = True 23 | message.reply_text("Debug mode is now on.") 24 | elif args[1] in ("no", "off"): 25 | DEBUG_MODE = False 26 | message.reply_text("Debug mode is now off.") 27 | else: 28 | if DEBUG_MODE: 29 | message.reply_text("Debug mode is currently on.") 30 | else: 31 | message.reply_text("Debug mode is currently off.") 32 | 33 | 34 | @telethn.on(events.NewMessage(pattern="[/!].*")) 35 | async def i_do_nothing_yes(event): 36 | global DEBUG_MODE 37 | if DEBUG_MODE: 38 | print(f"-{event.from_id} ({event.chat_id}) : {event.text}") 39 | if os.path.exists("updates.txt"): 40 | with open("updates.txt", "r") as f: 41 | text = f.read() 42 | with open("updates.txt", "w+") as f: 43 | f.write(text + f"\n-{event.from_id} ({event.chat_id}) : {event.text}") 44 | else: 45 | with open("updates.txt", "w+") as f: 46 | f.write( 47 | f"- {event.from_id} ({event.chat_id}) : {event.text} | {datetime.datetime.now()}" 48 | ) 49 | 50 | 51 | @dev_plus 52 | def logs(update: Update, context: CallbackContext): 53 | user = update.effective_user 54 | with open("log.txt", "rb") as f: 55 | context.bot.send_document(document=f, filename=f.name, chat_id=user.id) 56 | 57 | 58 | LOG_HANDLER = CommandHandler("logs", logs, run_async=True) 59 | DEBUG_HANDLER = CommandHandler("debug", debug, run_async=True) 60 | 61 | dispatcher.add_handler(LOG_HANDLER) 62 | dispatcher.add_handler(DEBUG_HANDLER) 63 | 64 | __mod_name__ = "Debug" 65 | __command_list__ = ["debug"] 66 | __handlers__ = [DEBUG_HANDLER] 67 | -------------------------------------------------------------------------------- /FallenRobot/modules/dev.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import sys 4 | from contextlib import suppress 5 | from time import sleep 6 | 7 | from telegram import TelegramError, Update 8 | from telegram.error import Unauthorized 9 | from telegram.ext import CallbackContext, CommandHandler 10 | 11 | import FallenRobot 12 | from FallenRobot import dispatcher 13 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 14 | 15 | 16 | @dev_plus 17 | def allow_groups(update: Update, context: CallbackContext): 18 | args = context.args 19 | if not args: 20 | update.effective_message.reply_text(f"Current state: {FallenRobot.ALLOW_CHATS}") 21 | return 22 | if args[0].lower() in ["off", "no"]: 23 | FallenRobot.ALLOW_CHATS = True 24 | elif args[0].lower() in ["yes", "on"]: 25 | FallenRobot.ALLOW_CHATS = False 26 | else: 27 | update.effective_message.reply_text("Format: /lockdown Yes/No or Off/On") 28 | return 29 | update.effective_message.reply_text("Done! Lockdown value toggled.") 30 | 31 | 32 | @dev_plus 33 | def leave(update: Update, context: CallbackContext): 34 | bot = context.bot 35 | args = context.args 36 | if args: 37 | chat_id = str(args[0]) 38 | try: 39 | bot.leave_chat(int(chat_id)) 40 | except TelegramError: 41 | update.effective_message.reply_text( 42 | "Beep boop, I could not leave that group(dunno why tho)." 43 | ) 44 | return 45 | with suppress(Unauthorized): 46 | update.effective_message.reply_text("Beep boop, I left that soup!.") 47 | else: 48 | update.effective_message.reply_text("Send a valid chat ID") 49 | 50 | 51 | @dev_plus 52 | def gitpull(update: Update, context: CallbackContext): 53 | sent_msg = update.effective_message.reply_text( 54 | "Pulling all changes from remote and then attempting to restart." 55 | ) 56 | subprocess.Popen("git pull", stdout=subprocess.PIPE, shell=True) 57 | 58 | sent_msg_text = sent_msg.text + "\n\nChanges pulled...I guess.. Restarting in " 59 | 60 | for i in reversed(range(5)): 61 | sent_msg.edit_text(sent_msg_text + str(i + 1)) 62 | sleep(1) 63 | 64 | sent_msg.edit_text("Restarted.") 65 | 66 | os.system("restart.bat") 67 | os.execv("start.bat", sys.argv) 68 | 69 | 70 | @dev_plus 71 | def restart(update: Update, context: CallbackContext): 72 | update.effective_message.reply_text( 73 | "Starting a new instance and shutting down this one" 74 | ) 75 | 76 | os.system("restart.bat") 77 | os.execv("start.bat", sys.argv) 78 | 79 | 80 | LEAVE_HANDLER = CommandHandler("leave", leave, run_async=True) 81 | GITPULL_HANDLER = CommandHandler("gitpull", gitpull, run_async=True) 82 | RESTART_HANDLER = CommandHandler("reboot", restart, run_async=True) 83 | ALLOWGROUPS_HANDLER = CommandHandler("lockdown", allow_groups, run_async=True) 84 | 85 | 86 | dispatcher.add_handler(ALLOWGROUPS_HANDLER) 87 | dispatcher.add_handler(LEAVE_HANDLER) 88 | dispatcher.add_handler(GITPULL_HANDLER) 89 | dispatcher.add_handler(RESTART_HANDLER) 90 | 91 | __mod_name__ = "Dᴇᴠ" 92 | 93 | __handlers__ = [LEAVE_HANDLER, GITPULL_HANDLER, RESTART_HANDLER, ALLOWGROUPS_HANDLER] 94 | -------------------------------------------------------------------------------- /FallenRobot/modules/encrypt.py: -------------------------------------------------------------------------------- 1 | import secureme 2 | 3 | from FallenRobot.events import register 4 | 5 | 6 | @register(pattern="^/encrypt ?(.*)") 7 | async def hmm(event): 8 | if event.reply_to_msg_id: 9 | lel = await event.get_reply_message() 10 | cmd = lel.text 11 | else: 12 | cmd = event.pattern_match.group(1) 13 | Text = cmd 14 | k = secureme.encrypt(Text) 15 | await event.reply(k) 16 | 17 | 18 | @register(pattern="^/decrypt ?(.*)") 19 | async def hmm(event): 20 | if event.reply_to_msg_id: 21 | lel = await event.get_reply_message() 22 | ok = lel.text 23 | else: 24 | ok = event.pattern_match.group(1) 25 | Text = ok 26 | k = secureme.decrypt(Text) 27 | await event.reply(k) 28 | 29 | 30 | __mod_name__ = "Tᴏᴏʟs" 31 | 32 | __help__ = """ 33 | 34 | *ᴄᴏɴᴠᴇʀᴛs* 35 | ❍ /encrypt*:* ᴇɴᴄʀʏᴘᴛs ᴛʜᴇ ɢɪᴠᴇɴ ᴛᴇxᴛ 36 | ❍ /decrypt*:* ᴅᴇᴄʀʏᴘᴛs ᴘʀᴇᴠɪᴏᴜsʟʏ ᴇᴄʀʏᴘᴛᴇᴅ ᴛᴇxᴛ 37 | """ 38 | -------------------------------------------------------------------------------- /FallenRobot/modules/english.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import requests 4 | from PyDictionary import PyDictionary 5 | from telethon import * 6 | from telethon.tl.types import * 7 | 8 | from FallenRobot.events import register 9 | 10 | API_KEY = "6ae0c3a0-afdc-4532-a810-82ded0054236" 11 | URL = "http://services.gingersoftware.com/Ginger/correct/json/GingerTheText" 12 | 13 | 14 | @register(pattern="^/spell(?: |$)(.*)") 15 | async def _(event): 16 | ctext = await event.get_reply_message() 17 | msg = ctext.text 18 | # print (msg) 19 | params = dict(lang="US", clientVersion="2.0", apiKey=API_KEY, text=msg) 20 | 21 | res = requests.get(URL, params=params) 22 | changes = json.loads(res.text).get("LightGingerTheTextResult") 23 | curr_string = "" 24 | prev_end = 0 25 | 26 | for change in changes: 27 | start = change.get("From") 28 | end = change.get("To") + 1 29 | suggestions = change.get("Suggestions") 30 | if suggestions: 31 | sugg_str = suggestions[0].get("Text") 32 | curr_string += msg[prev_end:start] + sugg_str 33 | prev_end = end 34 | 35 | curr_string += msg[prev_end:] 36 | await event.reply(curr_string) 37 | 38 | 39 | dictionary = PyDictionary() 40 | 41 | 42 | @register(pattern="^/define") 43 | async def _(event): 44 | text = event.text[len("/define ") :] 45 | word = f"{text}" 46 | let = dictionary.meaning(word) 47 | set = str(let) 48 | jet = set.replace("{", "") 49 | net = jet.replace("}", "") 50 | got = net.replace("'", "") 51 | await event.reply(got) 52 | 53 | 54 | @register(pattern="^/synonyms") 55 | async def _(event): 56 | text = event.text[len("/synonyms ") :] 57 | word = f"{text}" 58 | let = dictionary.synonym(word) 59 | set = str(let) 60 | jet = set.replace("{", "") 61 | net = jet.replace("}", "") 62 | got = net.replace("'", "") 63 | await event.reply(got) 64 | 65 | 66 | @register(pattern="^/antonyms") 67 | async def _(event): 68 | text = message.text[len("/antonyms ") :] 69 | word = f"{text}" 70 | let = dictionary.antonym(word) 71 | set = str(let) 72 | jet = set.replace("{", "") 73 | net = jet.replace("}", "") 74 | got = net.replace("'", "") 75 | await event.reply(got) 76 | 77 | 78 | __help__ = """ 79 | ❍ /define *:* Type the word or expression you want to search\nFor example /define kill 80 | ❍ /spell*:* while replying to a message, will reply with a grammar corrected version 81 | ❍ /synonyms *:* Find the synonyms of a word 82 | ❍ /antonyms *:* Find the antonyms of a word 83 | """ 84 | 85 | __mod_name__ = "Eɴɢʟɪsʜ" 86 | -------------------------------------------------------------------------------- /FallenRobot/modules/error_handler.py: -------------------------------------------------------------------------------- 1 | import html 2 | import io 3 | import random 4 | import sys 5 | import traceback 6 | 7 | import pretty_errors 8 | import requests 9 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update 10 | from telegram.ext import CallbackContext, CommandHandler 11 | 12 | from FallenRobot import DEV_USERS, OWNER_ID, dispatcher 13 | 14 | pretty_errors.mono() 15 | 16 | 17 | class ErrorsDict(dict): 18 | "A custom dict to store errors and their count" 19 | 20 | def __init__(self, *args, **kwargs): 21 | self.raw = [] 22 | super().__init__(*args, **kwargs) 23 | 24 | def __contains__(self, error): 25 | self.raw.append(error) 26 | error.identifier = "".join(random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZ", k=5)) 27 | for e in self: 28 | if type(e) is type(error) and e.args == error.args: 29 | self[e] += 1 30 | return True 31 | self[error] = 0 32 | return False 33 | 34 | def __len__(self): 35 | return len(self.raw) 36 | 37 | 38 | errors = ErrorsDict() 39 | 40 | 41 | def error_callback(update: Update, context: CallbackContext): 42 | if not update: 43 | return 44 | if context.error in errors: 45 | return 46 | try: 47 | stringio = io.StringIO() 48 | pretty_errors.output_stderr = stringio 49 | output = pretty_errors.excepthook( 50 | type(context.error), context.error, context.error.__traceback__ 51 | ) 52 | pretty_errors.output_stderr = sys.stderr 53 | pretty_error = stringio.getvalue() 54 | stringio.close() 55 | except: 56 | pretty_error = "Failed to create pretty error." 57 | tb_list = traceback.format_exception( 58 | None, context.error, context.error.__traceback__ 59 | ) 60 | tb = "".join(tb_list) 61 | pretty_message = ( 62 | "{}\n" 63 | "-------------------------------------------------------------------------------\n" 64 | "An exception was raised while handling an update\n" 65 | "User: {}\n" 66 | "Chat: {} {}\n" 67 | "Callback data: {}\n" 68 | "Message: {}\n\n" 69 | "Full Traceback: {}" 70 | ).format( 71 | pretty_error, 72 | update.effective_user.id, 73 | update.effective_chat.title if update.effective_chat else "", 74 | update.effective_chat.id if update.effective_chat else "", 75 | update.callback_query.data if update.callback_query else "None", 76 | update.effective_message.text if update.effective_message else "No message", 77 | tb, 78 | ) 79 | key = requests.post( 80 | "https://nekobin.com/api/documents", json={"content": pretty_message} 81 | ).json() 82 | e = html.escape(f"{context.error}") 83 | if not key.get("result", {}).get("key"): 84 | with open("error.txt", "w+") as f: 85 | f.write(pretty_message) 86 | context.bot.send_document( 87 | OWNER_ID, 88 | open("error.txt", "rb"), 89 | caption=f"#{context.error.identifier}\nAn unknown error occured:\n{e}", 90 | parse_mode="html", 91 | ) 92 | return 93 | key = key.get("result").get("key") 94 | url = f"https://nekobin.com/{key}.py" 95 | context.bot.send_message( 96 | OWNER_ID, 97 | text=f"#{context.error.identifier}\nAn unknown error occured:\n{e}", 98 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("ɴᴇᴋᴏʙɪɴ", url=url)]]), 99 | parse_mode="html", 100 | ) 101 | 102 | 103 | def list_errors(update: Update, context: CallbackContext): 104 | if update.effective_user.id not in DEV_USERS: 105 | return 106 | e = { 107 | k: v for k, v in sorted(errors.items(), key=lambda item: item[1], reverse=True) 108 | } 109 | msg = "Errors List:\n" 110 | for x in e: 111 | msg += f"• {x}: {e[x]} #{x.identifier}\n" 112 | msg += f"{len(errors)} have occurred since startup." 113 | if len(msg) > 4096: 114 | with open("errors_msg.txt", "w+") as f: 115 | f.write(msg) 116 | context.bot.send_document( 117 | update.effective_chat.id, 118 | open("errors_msg.txt", "rb"), 119 | caption=f"Too many errors have occured..", 120 | parse_mode="html", 121 | ) 122 | return 123 | update.effective_message.reply_text(msg, parse_mode="html") 124 | 125 | 126 | dispatcher.add_error_handler(error_callback, run_async=True) 127 | dispatcher.add_handler(CommandHandler("errors", list_errors, run_async=True)) 128 | -------------------------------------------------------------------------------- /FallenRobot/modules/eval.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | 4 | # Common imports for eval 5 | import textwrap 6 | import traceback 7 | from contextlib import redirect_stdout 8 | 9 | from telegram import ParseMode, Update 10 | from telegram.ext import CallbackContext, CommandHandler 11 | 12 | from FallenRobot import LOGGER, dispatcher 13 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 14 | 15 | namespaces = {} 16 | 17 | 18 | def namespace_of(chat, update, bot): 19 | if chat not in namespaces: 20 | namespaces[chat] = { 21 | "__builtins__": globals()["__builtins__"], 22 | "bot": bot, 23 | "effective_message": update.effective_message, 24 | "effective_user": update.effective_user, 25 | "effective_chat": update.effective_chat, 26 | "update": update, 27 | } 28 | 29 | return namespaces[chat] 30 | 31 | 32 | def log_input(update): 33 | user = update.effective_user.id 34 | chat = update.effective_chat.id 35 | LOGGER.info(f"IN: {update.effective_message.text} (user={user}, chat={chat})") 36 | 37 | 38 | def send(msg, bot, update): 39 | if len(str(msg)) > 2000: 40 | with io.BytesIO(str.encode(msg)) as out_file: 41 | out_file.name = "output.txt" 42 | bot.send_document(chat_id=update.effective_chat.id, document=out_file) 43 | else: 44 | LOGGER.info(f"OUT: '{msg}'") 45 | bot.send_message( 46 | chat_id=update.effective_chat.id, 47 | text=f"`{msg}`", 48 | parse_mode=ParseMode.MARKDOWN, 49 | ) 50 | 51 | 52 | @dev_plus 53 | def evaluate(update: Update, context: CallbackContext): 54 | bot = context.bot 55 | send(do(eval, bot, update), bot, update) 56 | 57 | 58 | @dev_plus 59 | def execute(update: Update, context: CallbackContext): 60 | bot = context.bot 61 | send(do(exec, bot, update), bot, update) 62 | 63 | 64 | def cleanup_code(code): 65 | if code.startswith("```") and code.endswith("```"): 66 | return "\n".join(code.split("\n")[1:-1]) 67 | return code.strip("` \n") 68 | 69 | 70 | def do(func, bot, update): 71 | log_input(update) 72 | content = update.message.text.split(" ", 1)[-1] 73 | body = cleanup_code(content) 74 | env = namespace_of(update.message.chat_id, update, bot) 75 | 76 | os.chdir(os.getcwd()) 77 | with open( 78 | os.path.join(os.getcwd(), "FallenRobot/modules/helper_funcs/temp.txt"), "w" 79 | ) as temp: 80 | temp.write(body) 81 | 82 | stdout = io.StringIO() 83 | 84 | to_compile = f'def func():\n{textwrap.indent(body, " ")}' 85 | 86 | try: 87 | exec(to_compile, env) 88 | except Exception as e: 89 | return f"{e.__class__.__name__}: {e}" 90 | 91 | func = env["func"] 92 | 93 | try: 94 | with redirect_stdout(stdout): 95 | func_return = func() 96 | except Exception: 97 | value = stdout.getvalue() 98 | return f"{value}{traceback.format_exc()}" 99 | else: 100 | value = stdout.getvalue() 101 | result = None 102 | if func_return is None: 103 | if value: 104 | result = f"{value}" 105 | else: 106 | try: 107 | result = f"{repr(eval(body, env))}" 108 | except: 109 | pass 110 | else: 111 | result = f"{value}{func_return}" 112 | if result: 113 | return result 114 | 115 | 116 | @dev_plus 117 | def clear(update: Update, context: CallbackContext): 118 | bot = context.bot 119 | log_input(update) 120 | global namespaces 121 | if update.message.chat_id in namespaces: 122 | del namespaces[update.message.chat_id] 123 | send("Cleared locals.", bot, update) 124 | 125 | 126 | EVAL_HANDLER = CommandHandler(("e", "ev", "eva", "eval"), evaluate, run_async=True) 127 | EXEC_HANDLER = CommandHandler(("x", "ex", "exe", "exec", "py"), execute, run_async=True) 128 | CLEAR_HANDLER = CommandHandler("clearlocals", clear, run_async=True) 129 | 130 | dispatcher.add_handler(EVAL_HANDLER) 131 | dispatcher.add_handler(EXEC_HANDLER) 132 | dispatcher.add_handler(CLEAR_HANDLER) 133 | 134 | __mod_name__ = "Eᴠᴀʟ ᴍᴏᴅᴜʟᴇ" 135 | -------------------------------------------------------------------------------- /FallenRobot/modules/get_common_chats.py: -------------------------------------------------------------------------------- 1 | import os 2 | from time import sleep 3 | 4 | from telegram import Update 5 | from telegram.error import BadRequest, RetryAfter, Unauthorized 6 | from telegram.ext import CallbackContext, CommandHandler, Filters 7 | 8 | from FallenRobot import OWNER_ID, dispatcher 9 | from FallenRobot.modules.helper_funcs.extraction import extract_user 10 | from FallenRobot.modules.sql.users_sql import get_user_com_chats 11 | 12 | 13 | def get_user_common_chats(update: Update, context: CallbackContext): 14 | bot, args = context.bot, context.args 15 | msg = update.effective_message 16 | user = extract_user(msg, args) 17 | if not user: 18 | msg.reply_text("I share no common chats with the void.") 19 | return 20 | common_list = get_user_com_chats(user) 21 | if not common_list: 22 | msg.reply_text("No common chats with this user!") 23 | return 24 | name = bot.get_chat(user).first_name 25 | text = f"Common chats with {name}\n" 26 | for chat in common_list: 27 | try: 28 | chat_name = bot.get_chat(chat).title 29 | sleep(0.3) 30 | text += f"• {chat_name}\n" 31 | except BadRequest: 32 | pass 33 | except Unauthorized: 34 | pass 35 | except RetryAfter as e: 36 | sleep(e.retry_after) 37 | 38 | if len(text) < 4096: 39 | msg.reply_text(text, parse_mode="HTML") 40 | else: 41 | with open("common_chats.txt", "w") as f: 42 | f.write(text) 43 | with open("common_chats.txt", "rb") as f: 44 | msg.reply_document(f) 45 | os.remove("common_chats.txt") 46 | 47 | 48 | COMMON_CHATS_HANDLER = CommandHandler( 49 | "getchats", get_user_common_chats, filters=Filters.user(OWNER_ID), run_async=True 50 | ) 51 | 52 | dispatcher.add_handler(COMMON_CHATS_HANDLER) 53 | -------------------------------------------------------------------------------- /FallenRobot/modules/gettime.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import List 3 | 4 | import requests 5 | from telegram import ParseMode, Update 6 | from telegram.ext import CallbackContext 7 | 8 | from FallenRobot import TIME_API_KEY, dispatcher 9 | from FallenRobot.modules.disable import DisableAbleCommandHandler 10 | 11 | 12 | def generate_time(to_find: str, findtype: List[str]) -> str: 13 | data = requests.get( 14 | f"https://api.timezonedb.com/v2.1/list-time-zone" 15 | f"?key={TIME_API_KEY}" 16 | f"&format=json" 17 | f"&fields=countryCode,countryName,zoneName,gmtOffset,timestamp,dst" 18 | ).json() 19 | 20 | for zone in data["zones"]: 21 | for eachtype in findtype: 22 | if to_find in zone[eachtype].lower(): 23 | country_name = zone["countryName"] 24 | country_zone = zone["zoneName"] 25 | country_code = zone["countryCode"] 26 | 27 | if zone["dst"] == 1: 28 | daylight_saving = "Yes" 29 | else: 30 | daylight_saving = "No" 31 | 32 | date_fmt = r"%d-%m-%Y" 33 | time_fmt = r"%H:%M:%S" 34 | day_fmt = r"%A" 35 | gmt_offset = zone["gmtOffset"] 36 | timestamp = datetime.datetime.now( 37 | datetime.timezone.utc 38 | ) + datetime.timedelta(seconds=gmt_offset) 39 | current_date = timestamp.strftime(date_fmt) 40 | current_time = timestamp.strftime(time_fmt) 41 | current_day = timestamp.strftime(day_fmt) 42 | 43 | break 44 | 45 | try: 46 | result = ( 47 | f"Country: {country_name}\n" 48 | f"Zone Name: {country_zone}\n" 49 | f"Country Code: {country_code}\n" 50 | f"Daylight saving: {daylight_saving}\n" 51 | f"Day: {current_day}\n" 52 | f"Current Time: {current_time}\n" 53 | f"Current Date: {current_date}\n" 54 | 'Timezones: List here' 55 | ) 56 | except: 57 | result = None 58 | 59 | return result 60 | 61 | 62 | def gettime(update: Update, context: CallbackContext): 63 | message = update.effective_message 64 | 65 | try: 66 | query = message.text.strip().split(" ", 1)[1] 67 | except: 68 | message.reply_text("Provide a country name/abbreviation/timezone to find.") 69 | return 70 | send_message = message.reply_text( 71 | f"Finding timezone info for {query}", parse_mode=ParseMode.HTML 72 | ) 73 | 74 | query_timezone = query.lower() 75 | if len(query_timezone) == 2: 76 | result = generate_time(query_timezone, ["countryCode"]) 77 | else: 78 | result = generate_time(query_timezone, ["zoneName", "countryName"]) 79 | 80 | if not result: 81 | send_message.edit_text( 82 | f"Timezone info not available for {query}\n" 83 | 'All Timezones: List here', 84 | parse_mode=ParseMode.HTML, 85 | disable_web_page_preview=True, 86 | ) 87 | return 88 | 89 | send_message.edit_text( 90 | result, parse_mode=ParseMode.HTML, disable_web_page_preview=True 91 | ) 92 | 93 | 94 | __help__ = """ 95 | ❍ /time *:* Gives information about a timezone. 96 | *Available queries:* Country Code/Country Name/Timezone Name 97 | 98 | ❍ ⏰ [ᴛɪᴍᴇᴢᴏɴᴇs ʟɪsᴛ](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) 99 | 100 | 💡 Ex:- /time IN *:* It will shows Indian current time and date.. 101 | """ 102 | 103 | TIME_HANDLER = DisableAbleCommandHandler("time", gettime, run_async=True) 104 | 105 | dispatcher.add_handler(TIME_HANDLER) 106 | 107 | __mod_name__ = "Tɪᴍᴇ" 108 | __command_list__ = ["time"] 109 | __handlers__ = [TIME_HANDLER] 110 | -------------------------------------------------------------------------------- /FallenRobot/modules/gitinfo.py: -------------------------------------------------------------------------------- 1 | from aiohttp import ClientSession 2 | from pyrogram import filters 3 | 4 | from FallenRobot import pbot 5 | from FallenRobot.utils.errors import capture_err 6 | 7 | 8 | @pbot.on_message(filters.command("github")) 9 | @capture_err 10 | async def github(_, message): 11 | if len(message.command) != 2: 12 | return await message.reply_text("/git username") 13 | username = message.text.split(None, 1)[1] 14 | URL = f"https://api.github.com/users/{username}" 15 | async with ClientSession() as session: 16 | async with session.get(URL) as request: 17 | if request.status == 404: 18 | return await message.reply_text("404") 19 | result = await request.json() 20 | try: 21 | url = result["html_url"] 22 | name = result["name"] 23 | company = result["company"] 24 | bio = result["bio"] 25 | created_at = result["created_at"] 26 | avatar_url = result["avatar_url"] 27 | blog = result["blog"] 28 | location = result["location"] 29 | repositories = result["public_repos"] 30 | followers = result["followers"] 31 | following = result["following"] 32 | caption = f"""**Info Of {name}** 33 | **Username :** `{username}` 34 | **Bio :** `{bio}` 35 | **Profile Link :** [Here]({url}) 36 | **Company :** `{company}` 37 | **Created On :** `{created_at}` 38 | **Repositories :** `{repositories}` 39 | **Blog :** `{blog}` 40 | **Location :** `{location}` 41 | **Followers :** `{followers}` 42 | **Following :** `{following}`""" 43 | except: 44 | print(str(e)) 45 | await message.reply_photo(photo=avatar_url, caption=caption) 46 | 47 | 48 | __mod_name__ = "Gɪᴛʜᴜʙ" 49 | 50 | __help__ = """ 51 | Provides you information about a github profile 52 | 53 | ❍ /github *:* Get information about a GitHub user. 54 | """ 55 | -------------------------------------------------------------------------------- /FallenRobot/modules/gps.py: -------------------------------------------------------------------------------- 1 | from geopy.geocoders import Nominatim 2 | from telethon import * 3 | from telethon.tl import * 4 | 5 | from FallenRobot import * 6 | from FallenRobot import telethn as tbot 7 | from FallenRobot.events import register 8 | 9 | GMAPS_LOC = "https://maps.googleapis.com/maps/api/geocode/json" 10 | 11 | 12 | @register(pattern="^/gps (.*)") 13 | async def _(event): 14 | args = event.pattern_match.group(1) 15 | 16 | try: 17 | geolocator = Nominatim(user_agent="FallenRobot") 18 | geoloc = geolocator.geocode(args) 19 | gm = f"https://www.google.com/maps/search/{geoloc.latitude},{geoloc.longitude}" 20 | await tbot.send_file( 21 | event.chat_id, 22 | file=types.InputMediaGeoPoint( 23 | types.InputGeoPoint(float(geoloc.latitude), float(geoloc.longitude)) 24 | ), 25 | ) 26 | await event.reply( 27 | f"ᴏᴘᴇɴ ᴡɪᴛʜ : [🌏ɢᴏᴏɢʟᴇ ᴍᴀᴘs]({gm})", 28 | link_preview=False, 29 | ) 30 | except: 31 | await event.reply("I can't find that") 32 | 33 | 34 | __help__ = """ 35 | Sends you the gps location of the given query... 36 | 37 | ❍ /gps *:* Get gps location. 38 | """ 39 | 40 | __mod_name__ = "Gᴘs" 41 | -------------------------------------------------------------------------------- /FallenRobot/modules/group.py: -------------------------------------------------------------------------------- 1 | __help__ = """ 2 | ❍ /setgtitle *:* Sets new chat title in your group. 3 | ❍ /setgpic*:* As a reply to file or photo to set group profile pic! 4 | ❍ /delgpic*:* Same as above but to remove group profile pic. 5 | ❍ /setsticker*:* As a reply to some sticker to set it as group sticker set! 6 | ❍ /setdescription *:* Sets new chat description in group. 7 | """ 8 | 9 | __mod_name__ = "Gʀᴏᴜᴘ" 10 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/__init__.py: -------------------------------------------------------------------------------- 1 | """Helpers, also known as Utilities""" 2 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/admin_rights.py: -------------------------------------------------------------------------------- 1 | from telegram import Chat, User 2 | 3 | 4 | def user_can_promote(chat: Chat, user: User, bot_id: int) -> bool: 5 | return chat.get_member(user.id).can_promote_members 6 | 7 | 8 | def user_can_ban(chat: Chat, user: User, bot_id: int) -> bool: 9 | return chat.get_member(user.id).can_restrict_members 10 | 11 | 12 | def user_can_pin(chat: Chat, user: User, bot_id: int) -> bool: 13 | return chat.get_member(user.id).can_pin_messages 14 | 15 | 16 | def user_can_changeinfo(chat: Chat, user: User, bot_id: int) -> bool: 17 | return chat.get_member(user.id).can_change_info 18 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/alternate.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from telegram import ChatAction 4 | from telegram.error import BadRequest 5 | 6 | 7 | def send_message(message, text, *args, **kwargs): 8 | try: 9 | return message.reply_text(text, *args, **kwargs) 10 | except BadRequest as err: 11 | if str(err) == "Reply message not found": 12 | return message.reply_text(text, quote=False, *args, **kwargs) 13 | 14 | 15 | def typing_action(func): 16 | """Sends typing action while processing func command.""" 17 | 18 | @wraps(func) 19 | def command_func(update, context, *args, **kwargs): 20 | context.bot.send_chat_action( 21 | chat_id=update.effective_chat.id, action=ChatAction.TYPING 22 | ) 23 | return func(update, context, *args, **kwargs) 24 | 25 | return command_func 26 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/filters.py: -------------------------------------------------------------------------------- 1 | from telegram import Message 2 | from telegram.ext import MessageFilter 3 | 4 | from FallenRobot import DEMONS, DEV_USERS, DRAGONS 5 | 6 | 7 | class CustomFilters(object): 8 | class _Supporters(MessageFilter): 9 | def filter(self, message: Message): 10 | return bool(message.from_user and message.from_user.id in DEMONS) 11 | 12 | support_filter = _Supporters() 13 | 14 | class Sudoers(MessageFilter): 15 | def filter(self, message: Message): 16 | return bool(message.from_user and message.from_user.id in DRAGONS) 17 | 18 | sudo_filter = Sudoers() 19 | 20 | class Developers(MessageFilter): 21 | def filter(self, message: Message): 22 | return bool(message.from_user and message.from_user.id in DEV_USERS) 23 | 24 | dev_filter = Developers() 25 | 26 | class _MimeType(MessageFilter): 27 | def __init__(self, mimetype): 28 | self.mime_type = mimetype 29 | self.name = "CustomFilters.mime_type({})".format(self.mime_type) 30 | 31 | def filter(self, message: Message): 32 | return bool( 33 | message.document and message.document.mime_type == self.mime_type, 34 | ) 35 | 36 | mime_type = _MimeType 37 | 38 | class _HasText(MessageFilter): 39 | def filter(self, message: Message): 40 | return bool( 41 | message.text 42 | or message.sticker 43 | or message.photo 44 | or message.document 45 | or message.video, 46 | ) 47 | 48 | has_text = _HasText() 49 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/handlers.py: -------------------------------------------------------------------------------- 1 | from pyrate_limiter import ( 2 | BucketFullException, 3 | Duration, 4 | Limiter, 5 | MemoryListBucket, 6 | RequestRate, 7 | ) 8 | from telegram import Update 9 | from telegram.ext import CommandHandler, Filters, MessageHandler, RegexHandler 10 | 11 | import FallenRobot.modules.sql.blacklistusers_sql as sql 12 | from FallenRobot import ALLOW_EXCL, DEMONS, DEV_USERS, DRAGONS, TIGERS, WOLVES 13 | 14 | if ALLOW_EXCL: 15 | CMD_STARTERS = ("/", "!") 16 | else: 17 | CMD_STARTERS = "/" 18 | 19 | 20 | class AntiSpam: 21 | def __init__(self): 22 | self.whitelist = ( 23 | (DEV_USERS or []) 24 | + (DRAGONS or []) 25 | + (WOLVES or []) 26 | + (DEMONS or []) 27 | + (TIGERS or []) 28 | ) 29 | # Values are HIGHLY experimental, its recommended you pay attention to our commits as we will be adjusting the values over time with what suits best. 30 | Duration.CUSTOM = 15 # Custom duration, 15 seconds 31 | self.sec_limit = RequestRate(6, Duration.CUSTOM) # 6 / Per 15 Seconds 32 | self.min_limit = RequestRate(20, Duration.MINUTE) # 20 / Per minute 33 | self.hour_limit = RequestRate(100, Duration.HOUR) # 100 / Per hour 34 | self.daily_limit = RequestRate(1000, Duration.DAY) # 1000 / Per day 35 | self.limiter = Limiter( 36 | self.sec_limit, 37 | self.min_limit, 38 | self.hour_limit, 39 | self.daily_limit, 40 | bucket_class=MemoryListBucket, 41 | ) 42 | 43 | def check_user(self, user): 44 | """ 45 | Return True if user is to be ignored else False 46 | """ 47 | if user in self.whitelist: 48 | return False 49 | try: 50 | self.limiter.try_acquire(user) 51 | return False 52 | except BucketFullException: 53 | return True 54 | 55 | 56 | SpamChecker = AntiSpam() 57 | MessageHandlerChecker = AntiSpam() 58 | 59 | 60 | class CustomCommandHandler(CommandHandler): 61 | def __init__(self, command, callback, admin_ok=False, allow_edit=False, **kwargs): 62 | super().__init__(command, callback, **kwargs) 63 | 64 | if allow_edit is False: 65 | self.filters &= ~( 66 | Filters.update.edited_message | Filters.update.edited_channel_post 67 | ) 68 | 69 | def check_update(self, update): 70 | if isinstance(update, Update) and update.effective_message: 71 | message = update.effective_message 72 | 73 | try: 74 | user_id = update.effective_user.id 75 | except: 76 | user_id = None 77 | 78 | if user_id: 79 | if sql.is_user_blacklisted(user_id): 80 | return False 81 | 82 | if message.text and len(message.text) > 1: 83 | fst_word = message.text.split(None, 1)[0] 84 | if len(fst_word) > 1 and any( 85 | fst_word.startswith(start) for start in CMD_STARTERS 86 | ): 87 | args = message.text.split()[1:] 88 | command = fst_word[1:].split("@") 89 | command.append(message.bot.username) 90 | if user_id == 1087968824: 91 | user_id = update.effective_chat.id 92 | if not ( 93 | command[0].lower() in self.command 94 | and command[1].lower() == message.bot.username.lower() 95 | ): 96 | return None 97 | if SpamChecker.check_user(user_id): 98 | return None 99 | filter_result = self.filters(update) 100 | if filter_result: 101 | return args, filter_result 102 | else: 103 | return False 104 | 105 | def handle_update(self, update, dispatcher, check_result, context=None): 106 | if context: 107 | self.collect_additional_context(context, update, dispatcher, check_result) 108 | return self.callback(update, context) 109 | else: 110 | optional_args = self.collect_optional_args(dispatcher, update, check_result) 111 | return self.callback(dispatcher.bot, update, **optional_args) 112 | 113 | def collect_additional_context(self, context, update, dispatcher, check_result): 114 | if isinstance(check_result, bool): 115 | context.args = update.effective_message.text.split()[1:] 116 | else: 117 | context.args = check_result[0] 118 | if isinstance(check_result[1], dict): 119 | context.update(check_result[1]) 120 | 121 | 122 | class CustomRegexHandler(RegexHandler): 123 | def __init__(self, pattern, callback, friendly="", **kwargs): 124 | super().__init__(pattern, callback, **kwargs) 125 | 126 | 127 | class CustomMessageHandler(MessageHandler): 128 | def __init__(self, filters, callback, friendly="", allow_edit=False, **kwargs): 129 | super().__init__(filters, callback, **kwargs) 130 | if allow_edit is False: 131 | self.filters &= ~( 132 | Filters.update.edited_message | Filters.update.edited_channel_post 133 | ) 134 | 135 | def check_update(self, update): 136 | if isinstance(update, Update) and update.effective_message: 137 | return self.filters(update) 138 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/regex_helper.py: -------------------------------------------------------------------------------- 1 | import regex 2 | 3 | 4 | def regex_searcher(regex_string, string): 5 | try: 6 | search = regex.search(regex_string, string, timeout=6) 7 | except TimeoutError: 8 | return False 9 | except Exception: 10 | return False 11 | return search 12 | 13 | 14 | def infinite_loop_check(regex_string): 15 | loop_matches = [ 16 | r"\((.{1,}[\+\*]){1,}\)[\+\*].", 17 | r"[\(\[].{1,}\{\d(,)?\}[\)\]]\{\d(,)?\}", 18 | r"\(.{1,}\)\{.{1,}(,)?\}\(.*\)(\+|\* |\{.*\})", 19 | ] 20 | for match in loop_matches: 21 | match_1 = regex.search(match, regex_string) 22 | if match_1: 23 | return True 24 | return False 25 | 26 | 27 | # 28 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/telethn/__init__.py: -------------------------------------------------------------------------------- 1 | from FallenRobot import DEMONS, DEV_USERS, DRAGONS, TIGERS, WOLVES, telethn 2 | 3 | IMMUNE_USERS = DRAGONS + WOLVES + DEMONS + TIGERS + DEV_USERS 4 | 5 | IMMUNE_USERS = ( 6 | list(DRAGONS) + list(WOLVES) + list(DEMONS) + list(TIGERS) + list(DEV_USERS) 7 | ) 8 | -------------------------------------------------------------------------------- /FallenRobot/modules/helper_funcs/telethn/chatstatus.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.types import ChannelParticipantsAdmins 2 | 3 | from FallenRobot import DRAGONS 4 | from FallenRobot.modules.helper_funcs.telethn import IMMUNE_USERS, telethn 5 | 6 | 7 | async def user_is_ban_protected(user_id: int, message): 8 | status = False 9 | if message.is_private or user_id in (IMMUNE_USERS): 10 | return True 11 | 12 | async for user in telethn.iter_participants( 13 | message.chat_id, filter=ChannelParticipantsAdmins 14 | ): 15 | if user_id == user.id: 16 | status = True 17 | break 18 | return status 19 | 20 | 21 | async def user_is_admin(user_id: int, message): 22 | status = False 23 | if message.is_private: 24 | return True 25 | 26 | async for user in telethn.iter_participants( 27 | message.chat_id, filter=ChannelParticipantsAdmins 28 | ): 29 | if user_id == user.id or user_id in DRAGONS: 30 | status = True 31 | break 32 | return status 33 | 34 | 35 | async def is_user_admin(user_id: int, chat_id): 36 | status = False 37 | async for user in telethn.iter_participants( 38 | chat_id, filter=ChannelParticipantsAdmins 39 | ): 40 | if user_id == user.id or user_id in DRAGONS: 41 | status = True 42 | break 43 | return status 44 | 45 | 46 | async def fallen_is_admin(chat_id: int): 47 | status = False 48 | fallen = await telethn.get_me() 49 | async for user in telethn.iter_participants( 50 | chat_id, filter=ChannelParticipantsAdmins 51 | ): 52 | if fallen.id == user.id: 53 | status = True 54 | break 55 | return status 56 | 57 | 58 | async def is_user_in_chat(chat_id: int, user_id: int): 59 | status = False 60 | async for user in telethn.iter_participants(chat_id): 61 | if user_id == user.id: 62 | status = True 63 | break 64 | return status 65 | 66 | 67 | async def can_change_info(message): 68 | status = False 69 | if message.chat.admin_rights: 70 | status = message.chat.admin_rights.change_info 71 | return status 72 | 73 | 74 | async def can_ban_users(message): 75 | status = False 76 | if message.chat.admin_rights: 77 | status = message.chat.admin_rights.ban_users 78 | return status 79 | 80 | 81 | async def can_pin_messages(message): 82 | status = False 83 | if message.chat.admin_rights: 84 | status = message.chat.admin_rights.pin_messages 85 | return status 86 | 87 | 88 | async def can_invite_users(message): 89 | status = False 90 | if message.chat.admin_rights: 91 | status = message.chat.admin_rights.invite_users 92 | return status 93 | 94 | 95 | async def can_add_admins(message): 96 | status = False 97 | if message.chat.admin_rights: 98 | status = message.chat.admin_rights.add_admins 99 | return status 100 | 101 | 102 | async def can_delete_messages(message): 103 | if message.is_private: 104 | return True 105 | elif message.chat.admin_rights: 106 | status = message.chat.admin_rights.delete_messages 107 | return status 108 | else: 109 | return False 110 | -------------------------------------------------------------------------------- /FallenRobot/modules/json.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | from telethon import types 4 | from telethon.tl import functions 5 | 6 | from FallenRobot import telethn as tbot 7 | from FallenRobot.events import register 8 | 9 | 10 | async def is_register_admin(chat, user): 11 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 12 | return isinstance( 13 | ( 14 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 15 | ).participant, 16 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 17 | ) 18 | if isinstance(chat, types.InputPeerUser): 19 | return True 20 | 21 | 22 | @register(pattern="^/json$") 23 | async def _(event): 24 | if event.fwd_from: 25 | return 26 | if event.is_group: 27 | if not (await is_register_admin(event.input_chat, event.message.sender_id)): 28 | await event.reply( 29 | "🥴 ɴᴇᴇᴅ ᴀᴅᴍɪɴ ᴩᴏᴡᴇʀ ᴛᴏ ᴜsᴇ ᴛʜɪs ɪɴ ɢʀᴏᴜᴩs﹐ ʙᴜᴛ ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ɪᴛ ɪɴ ᴍʏ ᴩᴍ." 30 | ) 31 | return 32 | 33 | the_real_message = None 34 | reply_to_id = None 35 | if event.reply_to_msg_id: 36 | previous_message = await event.get_reply_message() 37 | the_real_message = previous_message.stringify() 38 | reply_to_id = event.reply_to_msg_id 39 | else: 40 | the_real_message = event.stringify() 41 | reply_to_id = event.message.id 42 | if len(the_real_message) > 4095: 43 | with io.BytesIO(str.encode(the_real_message)) as out_file: 44 | out_file.name = "json.text" 45 | await tbot.send_file( 46 | event.chat_id, 47 | out_file, 48 | force_document=True, 49 | allow_cache=False, 50 | reply_to=reply_to_id, 51 | ) 52 | await event.delete() 53 | else: 54 | await event.reply("`{}`".format(the_real_message)) 55 | -------------------------------------------------------------------------------- /FallenRobot/modules/memify.py: -------------------------------------------------------------------------------- 1 | import os 2 | import textwrap 3 | 4 | from PIL import Image, ImageDraw, ImageFont 5 | 6 | from FallenRobot import telethn as bot 7 | from FallenRobot.events import register 8 | 9 | 10 | @register(pattern="^/mmf ?(.*)") 11 | async def handler(event): 12 | if event.fwd_from: 13 | return 14 | 15 | if not event.reply_to_msg_id: 16 | await event.reply("Provide Some Text To Draw!") 17 | 18 | return 19 | 20 | reply_message = await event.get_reply_message() 21 | 22 | if not reply_message.media: 23 | await event.reply("```Reply to a image/sticker.```") 24 | 25 | return 26 | 27 | file = await bot.download_media(reply_message) 28 | 29 | msg = await event.reply("```Memifying this image! ✊🏻 ```") 30 | 31 | text = str(event.pattern_match.group(1)).strip() 32 | 33 | if len(text) < 1: 34 | return await msg.reply("You might want to try `/mmf text`") 35 | 36 | meme = await drawText(file, text) 37 | 38 | await bot.send_file(event.chat_id, file=meme, force_document=False) 39 | 40 | await msg.delete() 41 | 42 | os.remove(meme) 43 | 44 | 45 | async def drawText(image_path, text): 46 | img = Image.open(image_path) 47 | 48 | os.remove(image_path) 49 | 50 | i_width, i_height = img.size 51 | 52 | if os.name == "nt": 53 | fnt = "ariel.ttf" 54 | 55 | else: 56 | fnt = "./FallenRobot/resources/default.ttf" 57 | 58 | m_font = ImageFont.truetype(fnt, int((70 / 640) * i_width)) 59 | 60 | if ";" in text: 61 | upper_text, lower_text = text.split(";") 62 | 63 | else: 64 | upper_text = text 65 | 66 | lower_text = "" 67 | 68 | draw = ImageDraw.Draw(img) 69 | 70 | current_h, pad = 10, 5 71 | 72 | if upper_text: 73 | for u_text in textwrap.wrap(upper_text, width=15): 74 | u_width, u_height = draw.textsize(u_text, font=m_font) 75 | 76 | draw.text( 77 | xy=(((i_width - u_width) / 2) - 2, int((current_h / 640) * i_width)), 78 | text=u_text, 79 | font=m_font, 80 | fill=(0, 0, 0), 81 | ) 82 | 83 | draw.text( 84 | xy=(((i_width - u_width) / 2) + 2, int((current_h / 640) * i_width)), 85 | text=u_text, 86 | font=m_font, 87 | fill=(0, 0, 0), 88 | ) 89 | 90 | draw.text( 91 | xy=((i_width - u_width) / 2, int(((current_h / 640) * i_width)) - 2), 92 | text=u_text, 93 | font=m_font, 94 | fill=(0, 0, 0), 95 | ) 96 | 97 | draw.text( 98 | xy=(((i_width - u_width) / 2), int(((current_h / 640) * i_width)) + 2), 99 | text=u_text, 100 | font=m_font, 101 | fill=(0, 0, 0), 102 | ) 103 | 104 | draw.text( 105 | xy=((i_width - u_width) / 2, int((current_h / 640) * i_width)), 106 | text=u_text, 107 | font=m_font, 108 | fill=(255, 255, 255), 109 | ) 110 | 111 | current_h += u_height + pad 112 | 113 | if lower_text: 114 | for l_text in textwrap.wrap(lower_text, width=15): 115 | u_width, u_height = draw.textsize(l_text, font=m_font) 116 | 117 | draw.text( 118 | xy=( 119 | ((i_width - u_width) / 2) - 2, 120 | i_height - u_height - int((20 / 640) * i_width), 121 | ), 122 | text=l_text, 123 | font=m_font, 124 | fill=(0, 0, 0), 125 | ) 126 | 127 | draw.text( 128 | xy=( 129 | ((i_width - u_width) / 2) + 2, 130 | i_height - u_height - int((20 / 640) * i_width), 131 | ), 132 | text=l_text, 133 | font=m_font, 134 | fill=(0, 0, 0), 135 | ) 136 | 137 | draw.text( 138 | xy=( 139 | (i_width - u_width) / 2, 140 | (i_height - u_height - int((20 / 640) * i_width)) - 2, 141 | ), 142 | text=l_text, 143 | font=m_font, 144 | fill=(0, 0, 0), 145 | ) 146 | 147 | draw.text( 148 | xy=( 149 | (i_width - u_width) / 2, 150 | (i_height - u_height - int((20 / 640) * i_width)) + 2, 151 | ), 152 | text=l_text, 153 | font=m_font, 154 | fill=(0, 0, 0), 155 | ) 156 | 157 | draw.text( 158 | xy=( 159 | (i_width - u_width) / 2, 160 | i_height - u_height - int((20 / 640) * i_width), 161 | ), 162 | text=l_text, 163 | font=m_font, 164 | fill=(255, 255, 255), 165 | ) 166 | 167 | current_h += u_height + pad 168 | 169 | image_name = "memify.webp" 170 | 171 | webp_file = os.path.join(image_name) 172 | 173 | img.save(webp_file, "webp") 174 | 175 | return webp_file 176 | 177 | 178 | __mod_name__ = "mmf" 179 | -------------------------------------------------------------------------------- /FallenRobot/modules/misc.py: -------------------------------------------------------------------------------- 1 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ParseMode, Update 2 | from telegram.ext import CallbackContext, CommandHandler, Filters 3 | 4 | from FallenRobot import dispatcher 5 | from FallenRobot.modules.disable import DisableAbleCommandHandler 6 | from FallenRobot.modules.helper_funcs.chat_status import user_admin 7 | 8 | MARKDOWN_HELP = f""" 9 | Markdown is a very powerful formatting tool supported by telegram. {dispatcher.bot.first_name} has some enhancements, to make sure that \ 10 | saved messages are correctly parsed, and to allow you to create buttons. 11 | 12 | • _italic_: wrapping text with '_' will produce italic text 13 | • *bold*: wrapping text with '*' will produce bold text 14 | • `code`: wrapping text with '`' will produce monospaced text, also known as 'code' 15 | • [sometext](someURL): this will create a link - the message will just show sometext, \ 16 | and tapping on it will open the page at someURL. 17 | Example:[test](example.com) 18 | 19 | • [buttontext](buttonurl:someURL): this is a special enhancement to allow users to have telegram \ 20 | buttons in their markdown. buttontext will be what is displayed on the button, and someurl \ 21 | will be the url which is opened. 22 | Example: [This is a button](buttonurl:example.com) 23 | 24 | If you want multiple buttons on the same line, use :same, as such: 25 | [one](buttonurl://example.com) 26 | [two](buttonurl://google.com:same) 27 | This will create two buttons on a single line, instead of one button per line. 28 | 29 | Keep in mind that your message MUST contain some text other than just a button! 30 | """ 31 | 32 | 33 | @user_admin 34 | def echo(update: Update, context: CallbackContext): 35 | args = update.effective_message.text.split(None, 1) 36 | message = update.effective_message 37 | 38 | if message.reply_to_message: 39 | message.reply_to_message.reply_text( 40 | args[1], parse_mode="MARKDOWN", disable_web_page_preview=True 41 | ) 42 | else: 43 | message.reply_text( 44 | args[1], quote=False, parse_mode="MARKDOWN", disable_web_page_preview=True 45 | ) 46 | message.delete() 47 | 48 | 49 | def markdown_help_sender(update: Update): 50 | update.effective_message.reply_text(MARKDOWN_HELP, parse_mode=ParseMode.HTML) 51 | update.effective_message.reply_text( 52 | "Try forwarding the following message to me, and you'll see, and Use #test!" 53 | ) 54 | update.effective_message.reply_text( 55 | "/save test This is a markdown test. _italics_, *bold*, code, " 56 | "[URL](example.com) [button](buttonurl:github.com) " 57 | "[button2](buttonurl://google.com:same)" 58 | ) 59 | 60 | 61 | def markdown_help(update: Update, context: CallbackContext): 62 | if update.effective_chat.type != "private": 63 | update.effective_message.reply_text( 64 | "Contact me in pm", 65 | reply_markup=InlineKeyboardMarkup( 66 | [ 67 | [ 68 | InlineKeyboardButton( 69 | "Markdown help", 70 | url=f"t.me/{context.bot.username}?start=markdownhelp", 71 | ) 72 | ] 73 | ] 74 | ), 75 | ) 76 | return 77 | markdown_help_sender(update) 78 | 79 | 80 | __help__ = """ 81 | *Available commands:* 82 | *Markdown:* 83 | ❍ /markdownhelp*:* quick summary of how markdown works in telegram - can only be called in private chats 84 | *React:* 85 | ❍ /react*:* Reacts with a random reaction 86 | *Urban Dictonary:* 87 | ❍ /ud *:* Type the word or expression you want to search use 88 | *Wikipedia:* 89 | ❍ /wiki *:* wikipedia your query 90 | """ 91 | 92 | ECHO_HANDLER = DisableAbleCommandHandler( 93 | "echo", echo, filters=Filters.chat_type.groups, run_async=True 94 | ) 95 | MD_HELP_HANDLER = CommandHandler("markdownhelp", markdown_help, run_async=True) 96 | 97 | dispatcher.add_handler(ECHO_HANDLER) 98 | dispatcher.add_handler(MD_HELP_HANDLER) 99 | 100 | __mod_name__ = "Exᴛʀᴀs" 101 | __command_list__ = ["id", "echo"] 102 | __handlers__ = [ 103 | ECHO_HANDLER, 104 | MD_HELP_HANDLER, 105 | ] 106 | -------------------------------------------------------------------------------- /FallenRobot/modules/nightmode.py: -------------------------------------------------------------------------------- 1 | from apscheduler.schedulers.asyncio import AsyncIOScheduler 2 | from telethon import functions, types 3 | from telethon.tl.types import ChatBannedRights 4 | 5 | from FallenRobot import BOT_NAME 6 | from FallenRobot import telethn as tbot 7 | from FallenRobot.events import register 8 | from FallenRobot.modules.sql.night_mode_sql import ( 9 | add_nightmode, 10 | get_all_chat_id, 11 | is_nightmode_indb, 12 | rmnightmode, 13 | ) 14 | 15 | 16 | async def is_register_admin(chat, user): 17 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 18 | return isinstance( 19 | ( 20 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 21 | ).participant, 22 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 23 | ) 24 | elif isinstance(chat, types.InputPeerChat): 25 | ui = await tbot.get_peer_id(user) 26 | ps = ( 27 | await tbot(functions.messages.GetFullChatRequest(chat.chat_id)) 28 | ).full_chat.participants.participants 29 | return isinstance( 30 | next((p for p in ps if p.user_id == ui), None), 31 | (types.ChatParticipantAdmin, types.ChatParticipantCreator), 32 | ) 33 | else: 34 | return None 35 | 36 | 37 | hehes = ChatBannedRights( 38 | until_date=None, 39 | send_messages=True, 40 | send_media=True, 41 | send_stickers=True, 42 | send_gifs=True, 43 | send_games=True, 44 | send_inline=True, 45 | send_polls=True, 46 | invite_users=True, 47 | pin_messages=True, 48 | change_info=True, 49 | ) 50 | openhehe = ChatBannedRights( 51 | until_date=None, 52 | send_messages=False, 53 | send_media=False, 54 | send_stickers=False, 55 | send_gifs=False, 56 | send_games=False, 57 | send_inline=False, 58 | send_polls=False, 59 | invite_users=True, 60 | pin_messages=True, 61 | change_info=True, 62 | ) 63 | 64 | 65 | @register(pattern="^/nightmode") 66 | async def close_ws(event): 67 | if event.is_group: 68 | if not (await is_register_admin(event.input_chat, event.message.sender_id)): 69 | await event.reply("🤦🏻‍♂️You are not admin so you can't use this command...") 70 | return 71 | 72 | if not event.is_group: 73 | await event.reply("You Can Only Enable Night Mode in Groups.") 74 | return 75 | if is_nightmode_indb(str(event.chat_id)): 76 | await event.reply("This Chat is Has Already Enabled Night Mode.") 77 | return 78 | add_nightmode(str(event.chat_id)) 79 | await event.reply( 80 | f"Added Chat {event.chat.title} With Id {event.chat_id} To Database. **This Group Will Be Closed On 12Am(IST) And Will Opened On 06Am(IST)**" 81 | ) 82 | 83 | 84 | @register(pattern="^/rmnight") 85 | async def disable_ws(event): 86 | if event.is_group: 87 | if not (await is_register_admin(event.input_chat, event.message.sender_id)): 88 | await event.reply("🤦🏻‍♂️You are not admin so you can't use this command...") 89 | return 90 | 91 | if not event.is_group: 92 | await event.reply("You Can Only Disable Night Mode in Groups.") 93 | return 94 | if not is_nightmode_indb(str(event.chat_id)): 95 | await event.reply("This Chat is Has Not Enabled Night Mode.") 96 | return 97 | rmnightmode(str(event.chat_id)) 98 | await event.reply( 99 | f"Removed Chat {event.chat.title} With Id {event.chat_id} From Database." 100 | ) 101 | 102 | 103 | async def job_close(): 104 | ws_chats = get_all_chat_id() 105 | if len(ws_chats) == 0: 106 | return 107 | for warner in ws_chats: 108 | try: 109 | await tbot.send_message( 110 | int(warner.chat_id), 111 | f"**Night Mode Started**\n\n`Group Is Closing Till 6 Am, Only admins can messages in this chat.`\n\n__Powered By {BOT_NAME}__", 112 | ) 113 | await tbot( 114 | functions.messages.EditChatDefaultBannedRightsRequest( 115 | peer=int(warner.chat_id), banned_rights=hehes 116 | ) 117 | ) 118 | except Exception as e: 119 | logger.info(f"Unable To Close Group {warner} - {e}") 120 | 121 | 122 | # Run everyday at 12am 123 | scheduler = AsyncIOScheduler(timezone="Asia/Kolkata") 124 | scheduler.add_job(job_close, trigger="cron", hour=23, minute=59) 125 | scheduler.start() 126 | 127 | 128 | async def job_open(): 129 | ws_chats = get_all_chat_id() 130 | if len(ws_chats) == 0: 131 | return 132 | for warner in ws_chats: 133 | try: 134 | await tbot.send_message( 135 | int(warner.chat_id), 136 | f"**Night Mode Ended**\n\n`Group is opening again now everyone can send messages in this chat.`\n__Powered By {BOT_NAME}__", 137 | ) 138 | await tbot( 139 | functions.messages.EditChatDefaultBannedRightsRequest( 140 | peer=int(warner.chat_id), banned_rights=openhehe 141 | ) 142 | ) 143 | except Exception as e: 144 | logger.info(f"Unable To Open Group {warner.chat_id} - {e}") 145 | 146 | 147 | # Run everyday at 06 148 | scheduler = AsyncIOScheduler(timezone="Asia/Kolkata") 149 | scheduler.add_job(job_open, trigger="cron", hour=6, minute=1) 150 | scheduler.start() 151 | 152 | __help__ = """ 153 | *Admins Only* 154 | 155 | ❍ /nightmode*:* Adds Group to NightMode Chats 156 | ❍ /rmnight*:* Removes Group From NightMode Chats 157 | 158 | *Note:* Night Mode chats get Automatically closed at 12 am(IST) and Automatically openned at 6 am(IST) to Prevent Night Spams. 159 | """ 160 | 161 | __mod_name__ = "Nɪɢʜᴛ" 162 | -------------------------------------------------------------------------------- /FallenRobot/modules/paste.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import re 4 | 5 | import aiofiles 6 | from aiohttp import ClientSession 7 | from pykeyboard import InlineKeyboard 8 | from pyrogram import filters 9 | from pyrogram.types import InlineKeyboardButton 10 | 11 | from FallenRobot import pbot as app 12 | from FallenRobot.utils.errors import capture_err 13 | from FallenRobot.utils.pastebin import paste 14 | 15 | pattern = re.compile(r"^text/|json$|yaml$|xml$|toml$|x-sh$|x-shellscript$") 16 | 17 | 18 | async def isPreviewUp(preview: str) -> bool: 19 | for _ in range(7): 20 | try: 21 | async with ClientSession().head(preview, timeout=2) as resp: 22 | status = resp.status 23 | size = resp.content_length 24 | except asyncio.exceptions.TimeoutError: 25 | return False 26 | if status == 404 or (status == 200 and size == 0): 27 | await asyncio.sleep(0.4) 28 | else: 29 | return True if status == 200 else False 30 | return False 31 | 32 | 33 | @app.on_message(filters.command("paste")) 34 | @capture_err 35 | async def paste_func(_, message): 36 | if not message.reply_to_message: 37 | return await message.reply_text("Reply To A Message With /paste") 38 | m = await message.reply_text("ᴘᴀsᴛɪɴɢ......") 39 | if message.reply_to_message.text: 40 | content = str(message.reply_to_message.text) 41 | elif message.reply_to_message.document: 42 | document = message.reply_to_message.document 43 | if document.file_size > 1048576: 44 | return await m.edit("You can only paste files smaller than 1MB.") 45 | if not pattern.search(document.mime_type): 46 | return await m.edit("Only text files can be pasted.") 47 | doc = await message.reply_to_message.download() 48 | async with aiofiles.open(doc, mode="r") as f: 49 | content = await f.read() 50 | os.remove(doc) 51 | link = await paste(content) 52 | preview = link + "/preview.png" 53 | button = InlineKeyboard(row_width=1) 54 | button.add(InlineKeyboardButton(text="ᴘᴀsᴛᴇ ʟɪɴᴋ", url=link)) 55 | 56 | if await isPreviewUp(preview): 57 | try: 58 | await message.reply_photo(photo=preview, quote=False, reply_markup=button) 59 | return await m.delete() 60 | except Exception: 61 | pass 62 | return await m.edit(link) 63 | 64 | 65 | __mod_name__ = "Pᴀsᴛᴇ" 66 | __help__ = """ 67 | Pastes the given file and shows you the result 68 | 69 | ❍ /paste *:* Reply to a text file 70 | """ 71 | -------------------------------------------------------------------------------- /FallenRobot/modules/ping.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from telegram import ParseMode, Update 4 | from telegram.ext import CallbackContext 5 | 6 | from FallenRobot import StartTime, dispatcher 7 | from FallenRobot.modules.disable import DisableAbleCommandHandler 8 | 9 | 10 | def get_readable_time(seconds: int) -> str: 11 | count = 0 12 | ping_time = "" 13 | time_list = [] 14 | time_suffix_list = ["s", "ᴍ", "ʜ", "ᴅᴀʏs"] 15 | 16 | while count < 4: 17 | count += 1 18 | if count < 3: 19 | remainder, result = divmod(seconds, 60) 20 | else: 21 | remainder, result = divmod(seconds, 24) 22 | if seconds == 0 and remainder == 0: 23 | break 24 | time_list.append(int(result)) 25 | seconds = int(remainder) 26 | 27 | for x in range(len(time_list)): 28 | time_list[x] = str(time_list[x]) + time_suffix_list[x] 29 | if len(time_list) == 4: 30 | ping_time += time_list.pop() + ", " 31 | 32 | time_list.reverse() 33 | ping_time += ":".join(time_list) 34 | 35 | return ping_time 36 | 37 | 38 | def ping(update: Update, context: CallbackContext): 39 | msg = update.effective_message 40 | 41 | start_time = time.time() 42 | message = msg.reply_text("🏓 ᴘɪɴɢɪɴɢ ʙᴀʙʏ....​") 43 | end_time = time.time() 44 | telegram_ping = str(round((end_time - start_time) * 1000, 3)) + " ms" 45 | uptime = get_readable_time((time.time() - StartTime)) 46 | 47 | message.edit_text( 48 | "ɪ ᴀᴍ ᴀʟɪᴠᴇ ʙᴀʙʏ🥀✨\n" 49 | "ᴛɪᴍᴇ ᴛᴀᴋᴇɴ: {}\n" 50 | "ᴜᴘᴛɪᴍᴇ: {}".format(telegram_ping, uptime), 51 | parse_mode=ParseMode.HTML, 52 | ) 53 | 54 | 55 | PING_HANDLER = DisableAbleCommandHandler("ping", ping, run_async=True) 56 | dispatcher.add_handler(PING_HANDLER) 57 | 58 | __command_list__ = ["ping"] 59 | 60 | __handlers__ = [PING_HANDLER] 61 | -------------------------------------------------------------------------------- /FallenRobot/modules/purge.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from telethon import events 4 | 5 | from FallenRobot import telethn 6 | from FallenRobot.modules.helper_funcs.telethn.chatstatus import ( 7 | can_delete_messages, 8 | user_is_admin, 9 | ) 10 | 11 | 12 | async def purge_messages(event): 13 | start = time.perf_counter() 14 | if event.from_id is None: 15 | return 16 | 17 | if not await user_is_admin( 18 | user_id=event.sender_id, message=event 19 | ) and event.from_id not in [1087968824]: 20 | await event.reply("Only Admins are allowed to use this command") 21 | return 22 | 23 | if not await can_delete_messages(message=event): 24 | await event.reply("Can't seem to purge the message") 25 | return 26 | 27 | reply_msg = await event.get_reply_message() 28 | if not reply_msg: 29 | await event.reply("Reply to a message to select where to start purging from.") 30 | return 31 | messages = [] 32 | message_id = reply_msg.id 33 | delete_to = event.message.id 34 | 35 | messages.append(event.reply_to_msg_id) 36 | for msg_id in range(message_id, delete_to + 1): 37 | messages.append(msg_id) 38 | if len(messages) == 100: 39 | await event.client.delete_messages(event.chat_id, messages) 40 | messages = [] 41 | 42 | try: 43 | await event.client.delete_messages(event.chat_id, messages) 44 | except: 45 | pass 46 | time_ = time.perf_counter() - start 47 | text = f"`Purged Successfully in {time_:0.2f} Seconds.`" 48 | await event.respond(text, parse_mode="markdown") 49 | 50 | 51 | async def delete_messages(event): 52 | if event.from_id is None: 53 | return 54 | 55 | if not await user_is_admin( 56 | user_id=event.sender_id, message=event 57 | ) and event.from_id not in [1087968824]: 58 | await event.reply("Only Admins are allowed to use this command") 59 | return 60 | 61 | if not await can_delete_messages(message=event): 62 | await event.reply("Can't seem to delete this?") 63 | return 64 | 65 | message = await event.get_reply_message() 66 | if not message: 67 | await event.reply("Whadya want to delete?") 68 | return 69 | chat = await event.get_input_chat() 70 | del_message = [message, event.message] 71 | await event.client.delete_messages(chat, del_message) 72 | 73 | 74 | __help__ = """ 75 | ❍ /del*:* deletes the message you replied to 76 | ❍ /purge*:* deletes all messages between this and the replied to message. 77 | """ 78 | 79 | PURGE_HANDLER = purge_messages, events.NewMessage(pattern="^[!/]purge$") 80 | DEL_HANDLER = delete_messages, events.NewMessage(pattern="^[!/]del$") 81 | 82 | telethn.add_event_handler(*PURGE_HANDLER) 83 | telethn.add_event_handler(*DEL_HANDLER) 84 | 85 | __mod_name__ = "Pᴜʀɢᴇ" 86 | __command_list__ = ["del", "purge"] 87 | __handlers__ = [PURGE_HANDLER, DEL_HANDLER] 88 | -------------------------------------------------------------------------------- /FallenRobot/modules/reactions.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from telegram import Update 4 | from telegram.ext import CallbackContext 5 | 6 | from FallenRobot import dispatcher 7 | from FallenRobot.modules.disable import DisableAbleCommandHandler 8 | 9 | reactions = [ 10 | "( ͡° ͜ʖ ͡°)", 11 | "( . •́ _ʖ •̀ .)", 12 | "( ಠ ͜ʖ ಠ)", 13 | "( ͡ ͜ʖ ͡ )", 14 | "(ʘ ͜ʖ ʘ)", 15 | "ヾ(´〇`)ノ♪♪♪", 16 | "ヽ(o´∀`)ノ♪♬", 17 | "♪♬((d⌒ω⌒b))♬♪", 18 | "└(^^)┐", 19 | "( ̄▽ ̄)/♫•*¨*•.¸¸♪", 20 | "ヾ(⌐■_■)ノ♪", 21 | "乁( • ω •乁)", 22 | "♬♫♪◖(● o ●)◗♪♫♬", 23 | "(っ˘ڡ˘ς)", 24 | "( ˘▽˘)っ♨", 25 | "( ・ω・)⊃-[二二]", 26 | "(*´ー`)旦 旦( ̄ω ̄*)", 27 | "(  ̄▽ ̄)[] [](≧▽≦ )", 28 | "(* ̄▽ ̄)旦 且(´∀`*)", 29 | "(ノ ˘_˘)ノ ζ|||ζ ζ|||ζ ζ|||ζ", 30 | "(ノ°∀°)ノ⌒・*:.。. .。.:*・゜゚・*☆", 31 | "(⊃。•́‿•̀。)⊃━✿✿✿✿✿✿", 32 | "(∩` ロ ´)⊃━炎炎炎炎炎", 33 | "( ・∀・)・・・--------☆", 34 | "( -ω-)/占~~~~~", 35 | "○∞∞∞∞ヽ(^ー^ )", 36 | "(*^^)/~~~~~~~~~~◎", 37 | "(((  ̄□)_/", 38 | "(メ ̄▽ ̄)︻┳═一", 39 | "ヽ( ・∀・)ノ_θ彡☆Σ(ノ `Д´)ノ", 40 | "(*`0´)θ☆(メ°皿°)ノ", 41 | "(; -_-)――――――C<―_-)", 42 | "ヽ(>_<ヽ) ―⊂|=0ヘ(^‿^ )", 43 | "(҂` ロ ´)︻デ═一 \(º □ º l|l)/", 44 | "/( .□.)\ ︵╰(°益°)╯︵ /(.□. /)", 45 | "(`⌒*)O-(`⌒´Q)", 46 | "(っ•﹏•)っ ✴==≡눈٩(`皿´҂)ง", 47 | "ヾ(・ω・)メ(・ω・)ノ", 48 | "(*^ω^)八(⌒▽⌒)八(-‿‿- )ヽ", 49 | "ヽ( ⌒ω⌒)人(=^‥^= )ノ", 50 | "。*:☆(・ω・人・ω・)。:゜☆。", 51 | "(°(°ω(°ω°(☆ω☆)°ω°)ω°)°)", 52 | "(っ˘▽˘)(˘▽˘)˘▽˘ς)", 53 | "(*^ω^)人(^ω^*)", 54 | "\(▽ ̄ \ ( ̄▽ ̄) /  ̄▽)/", 55 | "( ̄Θ ̄)", 56 | "\( ˋ Θ ´ )/", 57 | "( ´(00)ˋ )", 58 | "\( ̄(oo) ̄)/", 59 | "/(≧ x ≦)\", 60 | "/(=・ x ・=)\", 61 | "(=^・ω・^=)", 62 | "(= ; ェ ; =)", 63 | "(=⌒‿‿⌒=)", 64 | "(^• ω •^)", 65 | "ଲ(ⓛ ω ⓛ)ଲ", 66 | "ଲ(ⓛ ω ⓛ)ଲ", 67 | "(^◔ᴥ◔^)", 68 | "[(--)]..zzZ", 69 | "( ̄o ̄) zzZZzzZZ", 70 | "(_ _*) Z z z", 71 | "☆ミ(o*・ω・)ノ", 72 | "ε=ε=ε=ε=┌(; ̄▽ ̄)┘", 73 | "ε===(っ≧ω≦)っ", 74 | "__φ(..)", 75 | "ヾ( `ー´)シφ__", 76 | "( ^▽^)ψ__", 77 | "|・ω・)", 78 | "|д・)", 79 | "┬┴┬┴┤・ω・)ノ", 80 | "|・д・)ノ", 81 | "(* ̄ii ̄)", 82 | "(^〃^)", 83 | "m(_ _)m", 84 | "人(_ _*)", 85 | "(シ. .)シ", 86 | "(^_~)", 87 | "(>ω^)", 88 | "(^_<)〜☆", 89 | "(^_<)", 90 | "(づ ̄ ³ ̄)づ", 91 | "(⊃。•́‿•̀。)⊃", 92 | "⊂(´• ω •`⊂)", 93 | "(*・ω・)ノ", 94 | "(^-^*)/", 95 | "ヾ(*'▽'*)", 96 | "(^0^)ノ", 97 | "(*°ー°)ノ", 98 | "( ̄ω ̄)/", 99 | "(≧▽≦)/", 100 | "w(°o°)w", 101 | "(⊙_⊙)", 102 | "(°ロ°) !", 103 | "∑(O_O;)", 104 | "(¬_¬)", 105 | "(¬_¬ )", 106 | "(↼_↼)", 107 | "( ̄ω ̄;)", 108 | "┐('~`;)┌", 109 | "(・_・;)", 110 | "(@_@)", 111 | "(•ิ_•ิ)?", 112 | "ヽ(ー_ー )ノ", 113 | "┐( ̄ヘ ̄)┌", 114 | "┐( ̄~ ̄)┌", 115 | "┐( ´ д ` )┌", 116 | "╮(︶▽︶)╭", 117 | "ᕕ( ᐛ )ᕗ", 118 | "(ノωヽ)", 119 | "(″ロ゛)", 120 | "(/ω\)", 121 | "(((><)))", 122 | "~(>_<~)", 123 | "(×_×)", 124 | "(×﹏×)", 125 | "(ノ_<。)", 126 | "(μ_μ)", 127 | "o(TヘTo)", 128 | "( ゚,_ゝ`)", 129 | "( ╥ω╥ )", 130 | "(/ˍ・、)", 131 | "(つω`。)", 132 | "(T_T)", 133 | "o(〒﹏〒)o", 134 | "(#`Д´)", 135 | "(・`ω´・)", 136 | "( `ε´ )", 137 | "(メ` ロ ´)", 138 | "Σ(▼□▼メ)", 139 | "(҂ `з´ )", 140 | "٩(╬ʘ益ʘ╬)۶", 141 | "↑_(ΦwΦ)Ψ", 142 | "(ノಥ益ಥ)ノ", 143 | "(#><)", 144 | "(; ̄Д ̄)", 145 | "(¬_¬;)", 146 | "(^^#)", 147 | "( ̄︿ ̄)", 148 | "ヾ(  ̄O ̄)ツ", 149 | "(ᗒᗣᗕ)՞", 150 | "(ノ_<。)ヾ(´ ▽ ` )", 151 | "ヽ( ̄ω ̄(。。 )ゝ", 152 | "(ノ_;)ヾ(´ ∀ ` )", 153 | "(´-ω-`( _ _ )", 154 | "(⌒_⌒;)", 155 | "(*/_\)", 156 | "( ◡‿◡ *)", 157 | "(//ω//)", 158 | "( ̄▽ ̄*)ゞ", 159 | "(„ಡωಡ„)", 160 | "(ノ´ з `)ノ", 161 | "(♡-_-♡)", 162 | "(─‿‿─)♡", 163 | "(´ ω `♡)", 164 | "(ღ˘⌣˘ღ)", 165 | "(´• ω •`) ♡", 166 | "╰(*´︶`*)╯♡", 167 | "(≧◡≦) ♡", 168 | "♡ (˘▽˘>ԅ( ˘⌣˘)", 169 | "σ(≧ε≦σ) ♡", 170 | "(˘∀˘)/(μ‿μ) ❤", 171 | "Σ>―(〃°ω°〃)♡→", 172 | "(* ^ ω ^)", 173 | "(o^▽^o)", 174 | "ヽ(・∀・)ノ", 175 | "(o・ω・o)", 176 | "(^人^)", 177 | "( ´ ω ` )", 178 | "(´• ω •`)", 179 | "╰(▔∀▔)╯", 180 | "(✯◡✯)", 181 | "(⌒‿⌒)", 182 | "(*°▽°*)", 183 | "(´。• ᵕ •。`)", 184 | "ヽ(>∀<☆)ノ", 185 | "\( ̄▽ ̄)/", 186 | "(o˘◡˘o)", 187 | "(╯✧▽✧)╯", 188 | "( ‾́ ◡ ‾́ )", 189 | "(๑˘︶˘๑)", 190 | "(´・ᴗ・ ` )", 191 | "( ͡° ʖ̯ ͡°)", 192 | "( ఠ ͟ʖ ఠ)", 193 | "( ಥ ʖ̯ ಥ)", 194 | "(≖ ͜ʖ≖)", 195 | "ヘ( ̄ω ̄ヘ)", 196 | "(ノ≧∀≦)ノ", 197 | "└( ̄- ̄└))", 198 | "┌(^^)┘", 199 | "(^_^♪)", 200 | "(〜 ̄△ ̄)〜", 201 | "(「• ω •)「", 202 | "( ˘ ɜ˘) ♬♪♫", 203 | "( o˘◡˘o) ┌iii┐", 204 | "♨o(>_<)o♨", 205 | "( ・・)つ―{}@{}@{}-", 206 | "(*´з`)口゚。゚口(・∀・ )", 207 | "( *^^)o∀*∀o(^^* )", 208 | "-●●●-c(・・ )", 209 | "(ノ≧∀≦)ノ ‥…━━━★", 210 | "╰( ͡° ͜ʖ ͡° )つ──☆*:・゚", 211 | "(∩ᄑ_ᄑ)⊃━☆゚*・。*・:≡( ε:)", 212 | ] 213 | 214 | 215 | def react(update: Update, context: CallbackContext): 216 | message = update.effective_message 217 | react = random.choice(reactions) 218 | if message.reply_to_message: 219 | message.reply_to_message.reply_text(react) 220 | else: 221 | message.reply_text(react) 222 | 223 | 224 | REACT_HANDLER = DisableAbleCommandHandler("react", react, run_async=True) 225 | 226 | dispatcher.add_handler(REACT_HANDLER) 227 | 228 | __command_list__ = ["react"] 229 | __handlers__ = [REACT_HANDLER] 230 | -------------------------------------------------------------------------------- /FallenRobot/modules/sed.py: -------------------------------------------------------------------------------- 1 | import sre_constants 2 | 3 | import regex 4 | import telegram 5 | from telegram import Update 6 | from telegram.ext import CallbackContext, Filters 7 | 8 | from FallenRobot import LOGGER, dispatcher 9 | from FallenRobot.modules.disable import DisableAbleMessageHandler 10 | from FallenRobot.modules.helper_funcs.regex_helper import infinite_loop_check 11 | 12 | DELIMITERS = ("/", ":", "|", "_") 13 | 14 | 15 | def separate_sed(sed_string): 16 | if ( 17 | len(sed_string) >= 3 18 | and sed_string[1] in DELIMITERS 19 | and sed_string.count(sed_string[1]) >= 2 20 | ): 21 | delim = sed_string[1] 22 | start = counter = 2 23 | while counter < len(sed_string): 24 | if sed_string[counter] == "\\": 25 | counter += 1 26 | 27 | elif sed_string[counter] == delim: 28 | replace = sed_string[start:counter] 29 | counter += 1 30 | start = counter 31 | break 32 | 33 | counter += 1 34 | 35 | else: 36 | return None 37 | 38 | while counter < len(sed_string): 39 | if ( 40 | sed_string[counter] == "\\" 41 | and counter + 1 < len(sed_string) 42 | and sed_string[counter + 1] == delim 43 | ): 44 | sed_string = sed_string[:counter] + sed_string[counter + 1 :] 45 | 46 | elif sed_string[counter] == delim: 47 | replace_with = sed_string[start:counter] 48 | counter += 1 49 | break 50 | 51 | counter += 1 52 | else: 53 | return replace, sed_string[start:], "" 54 | 55 | flags = "" 56 | if counter < len(sed_string): 57 | flags = sed_string[counter:] 58 | return replace, replace_with, flags.lower() 59 | 60 | 61 | def sed(update: Update, context: CallbackContext): 62 | sed_result = separate_sed(update.effective_message.text) 63 | if sed_result and update.effective_message.reply_to_message: 64 | if update.effective_message.reply_to_message.text: 65 | to_fix = update.effective_message.reply_to_message.text 66 | elif update.effective_message.reply_to_message.caption: 67 | to_fix = update.effective_message.reply_to_message.caption 68 | else: 69 | return 70 | 71 | repl, repl_with, flags = sed_result 72 | if not repl: 73 | update.effective_message.reply_to_message.reply_text( 74 | "You're trying to replace... " "nothing with something?" 75 | ) 76 | return 77 | 78 | try: 79 | try: 80 | check = regex.match(repl, to_fix, flags=regex.IGNORECASE, timeout=5) 81 | except TimeoutError: 82 | return 83 | if check and check.group(0).lower() == to_fix.lower(): 84 | update.effective_message.reply_to_message.reply_text( 85 | "Hey everyone, {} is trying to make " 86 | "me say stuff I don't wanna " 87 | "say!".format(update.effective_user.first_name) 88 | ) 89 | return 90 | if infinite_loop_check(repl): 91 | update.effective_message.reply_text( 92 | "I'm afraid I can't run that regex." 93 | ) 94 | return 95 | if "i" in flags and "g" in flags: 96 | text = regex.sub( 97 | repl, repl_with, to_fix, flags=regex.I, timeout=3 98 | ).strip() 99 | elif "i" in flags: 100 | text = regex.sub( 101 | repl, repl_with, to_fix, count=1, flags=regex.I, timeout=3 102 | ).strip() 103 | elif "g" in flags: 104 | text = regex.sub(repl, repl_with, to_fix, timeout=3).strip() 105 | else: 106 | text = regex.sub(repl, repl_with, to_fix, count=1, timeout=3).strip() 107 | except TimeoutError: 108 | update.effective_message.reply_text("Timeout") 109 | return 110 | except sre_constants.error: 111 | LOGGER.warning(update.effective_message.text) 112 | LOGGER.exception("SRE constant error") 113 | update.effective_message.reply_text("Do you even sed? Apparently not.") 114 | return 115 | 116 | # empty string errors -_- 117 | if len(text) >= telegram.MAX_MESSAGE_LENGTH: 118 | update.effective_message.reply_text( 119 | "The result of the sed command was too long for \ 120 | telegram!" 121 | ) 122 | elif text: 123 | update.effective_message.reply_to_message.reply_text(text) 124 | 125 | 126 | __mod_name__ = "Sed/Regex" 127 | 128 | SED_HANDLER = DisableAbleMessageHandler( 129 | Filters.regex(r"s([{}]).*?\1.*".format("".join(DELIMITERS))), 130 | sed, 131 | friendly="sed", 132 | run_async=True, 133 | ) 134 | 135 | dispatcher.add_handler(SED_HANDLER) 136 | -------------------------------------------------------------------------------- /FallenRobot/modules/shell.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | from telegram import ParseMode, Update 4 | from telegram.ext import CallbackContext, CommandHandler 5 | 6 | from FallenRobot import LOGGER, dispatcher 7 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 8 | 9 | 10 | @dev_plus 11 | def shell(update: Update, context: CallbackContext): 12 | message = update.effective_message 13 | cmd = message.text.split(" ", 1) 14 | if len(cmd) == 1: 15 | message.reply_text("No command to execute was given.") 16 | return 17 | cmd = cmd[1] 18 | process = subprocess.Popen( 19 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True 20 | ) 21 | stdout, stderr = process.communicate() 22 | reply = "" 23 | stderr = stderr.decode() 24 | stdout = stdout.decode() 25 | if stdout: 26 | reply += f"*Stdout*\n`{stdout}`\n" 27 | LOGGER.info(f"Shell - {cmd} - {stdout}") 28 | if stderr: 29 | reply += f"*Stderr*\n`{stderr}`\n" 30 | LOGGER.error(f"Shell - {cmd} - {stderr}") 31 | if len(reply) > 3000: 32 | with open("shell_output.txt", "w") as file: 33 | file.write(reply) 34 | with open("shell_output.txt", "rb") as doc: 35 | context.bot.send_document( 36 | document=doc, 37 | filename=doc.name, 38 | reply_to_message_id=message.message_id, 39 | chat_id=message.chat_id, 40 | ) 41 | else: 42 | message.reply_text(reply, parse_mode=ParseMode.MARKDOWN) 43 | 44 | 45 | SHELL_HANDLER = CommandHandler(["sh"], shell, run_async=True) 46 | 47 | dispatcher.add_handler(SHELL_HANDLER) 48 | 49 | __mod_name__ = "Shell" 50 | 51 | __command_list__ = ["sh"] 52 | __handlers__ = [SHELL_HANDLER] 53 | -------------------------------------------------------------------------------- /FallenRobot/modules/source.py: -------------------------------------------------------------------------------- 1 | from platform import python_version as y 2 | 3 | from pyrogram import __version__ as z 4 | from pyrogram import filters 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message 6 | from telegram import __version__ as o 7 | from telethon import __version__ as s 8 | 9 | from FallenRobot import BOT_NAME, BOT_USERNAME, OWNER_ID, START_IMG, pbot 10 | 11 | 12 | @pbot.on_message(filters.command(["repo", "source"])) 13 | async def repo(_, message: Message): 14 | await message.reply_photo( 15 | photo=START_IMG, 16 | caption=f"""**ʜᴇʏ {message.from_user.mention}, 17 | 18 | ɪ ᴀᴍ [{BOT_NAME}](https://t.me/{BOT_USERNAME})** 19 | 20 | **» ᴍʏ ᴅᴇᴠᴇʟᴏᴘᴇʀ :** ™°‌ 🫧 🇴 🇽 𝐘 𝐆 𝐄 𝐍 21 | **» ᴩʏᴛʜᴏɴ ᴠᴇʀsɪᴏɴ :** `{y()}` 22 | **» ʟɪʙʀᴀʀʏ ᴠᴇʀsɪᴏɴ :** `{o}` 23 | **» ᴛᴇʟᴇᴛʜᴏɴ ᴠᴇʀsɪᴏɴ :** `{s}` 24 | **» ᴘʏʀᴏɢʀᴀᴍ ᴠᴇʀsɪᴏɴ :** `{z}` 25 | """, 26 | reply_markup=InlineKeyboardMarkup( 27 | [ 28 | [ 29 | InlineKeyboardButton("🌺 𝙳𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚁 🌺", user_id=OWNER_ID), 30 | InlineKeyboardButton( 31 | "❄️ 𝙱𝚠𝚊𝚗𝚍𝚊𝚛𝙻𝚘𝚔 ❄️", 32 | url="https://t.me/BWANDARLOK", 33 | ), 34 | ] 35 | ] 36 | ), 37 | ) 38 | 39 | 40 | __mod_name__ = "Rᴇᴩᴏ" 41 | -------------------------------------------------------------------------------- /FallenRobot/modules/speed_test.py: -------------------------------------------------------------------------------- 1 | import speedtest 2 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ParseMode, Update 3 | from telegram.ext import CallbackContext, CallbackQueryHandler 4 | 5 | from FallenRobot import DEV_USERS, dispatcher 6 | from FallenRobot.modules.disable import DisableAbleCommandHandler 7 | from FallenRobot.modules.helper_funcs.chat_status import dev_plus 8 | 9 | 10 | def convert(speed): 11 | return round(int(speed) / 1048576, 2) 12 | 13 | 14 | @dev_plus 15 | def speedtestxyz(update: Update, context: CallbackContext): 16 | buttons = [ 17 | [ 18 | InlineKeyboardButton("ɪᴍᴀɢᴇ", callback_data="speedtest_image"), 19 | InlineKeyboardButton("ᴛᴇxᴛ", callback_data="speedtest_text"), 20 | ] 21 | ] 22 | update.effective_message.reply_text( 23 | "sᴩᴇᴇᴅᴛᴇsᴛ ᴍᴏᴅᴇ", reply_markup=InlineKeyboardMarkup(buttons) 24 | ) 25 | 26 | 27 | def speedtestxyz_callback(update: Update, context: CallbackContext): 28 | query = update.callback_query 29 | 30 | if query.from_user.id in DEV_USERS: 31 | msg = update.effective_message.edit_text("ʀᴜɴɴɪɴɢ ᴀ sᴩᴇᴇᴅᴛᴇsᴛ...") 32 | speed = speedtest.Speedtest() 33 | speed.get_best_server() 34 | speed.download() 35 | speed.upload() 36 | replymsg = "sᴩᴇᴇᴅᴛᴇsᴛ ʀᴇsᴜʟᴛ" 37 | 38 | if query.data == "speedtest_image": 39 | speedtest_image = speed.results.share() 40 | update.effective_message.reply_photo( 41 | photo=speedtest_image, caption=replymsg 42 | ) 43 | msg.delete() 44 | 45 | elif query.data == "speedtest_text": 46 | result = speed.results.dict() 47 | replymsg += f"\nDownload: `{convert(result['download'])}Mb/s`\nUpload: `{convert(result['upload'])}Mb/s`\nPing: `{result['ping']}`" 48 | update.effective_message.edit_text(replymsg, parse_mode=ParseMode.MARKDOWN) 49 | else: 50 | return 51 | 52 | 53 | SPEED_TEST_HANDLER = DisableAbleCommandHandler( 54 | "speedtest", speedtestxyz, run_async=True 55 | ) 56 | SPEED_TEST_CALLBACKHANDLER = CallbackQueryHandler( 57 | speedtestxyz_callback, pattern="speedtest_.*", run_async=True 58 | ) 59 | 60 | dispatcher.add_handler(SPEED_TEST_HANDLER) 61 | dispatcher.add_handler(SPEED_TEST_CALLBACKHANDLER) 62 | 63 | __help__ = """ 64 | » /speedtest *:* Runs a speedtest and check the server speed. 65 | """ 66 | 67 | __mod_name__ = "SᴘᴇᴇᴅTᴇsᴛ" 68 | 69 | __command_list__ = ["speedtest"] 70 | __handlers__ = [SPEED_TEST_HANDLER, SPEED_TEST_CALLBACKHANDLER] 71 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import scoped_session, sessionmaker 4 | 5 | from FallenRobot import DB_URI 6 | from FallenRobot import LOGGER as log 7 | 8 | if DB_URI and DB_URI.startswith("postgres://"): 9 | DB_URI = DB_URI.replace("postgres://", "postgresql://", 1) 10 | 11 | 12 | def start() -> scoped_session: 13 | engine = create_engine(DB_URI, client_encoding="utf8") 14 | log.info("[PostgreSQL] Connecting to database......") 15 | BASE.metadata.bind = engine 16 | BASE.metadata.create_all(engine) 17 | return scoped_session(sessionmaker(bind=engine, autoflush=False)) 18 | 19 | 20 | BASE = declarative_base() 21 | try: 22 | SESSION = start() 23 | except Exception as e: 24 | log.exception(f"[PostgreSQL] Failed to connect due to {e}") 25 | exit() 26 | 27 | log.info("[PostgreSQL] Connection successful, session started.") 28 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/afk_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import BigInteger, Boolean, Column, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class AFK(BASE): 9 | __tablename__ = "afk_users" 10 | 11 | user_id = Column(BigInteger, primary_key=True) 12 | is_afk = Column(Boolean) 13 | reason = Column(UnicodeText) 14 | 15 | def __init__(self, user_id, reason="", is_afk=True): 16 | self.user_id = user_id 17 | self.reason = reason 18 | self.is_afk = is_afk 19 | 20 | def __repr__(self): 21 | return "afk_status for {}".format(self.user_id) 22 | 23 | 24 | AFK.__table__.create(checkfirst=True) 25 | INSERTION_LOCK = threading.RLock() 26 | 27 | AFK_USERS = {} 28 | 29 | 30 | def is_afk(user_id): 31 | return user_id in AFK_USERS 32 | 33 | 34 | def check_afk_status(user_id): 35 | try: 36 | return SESSION.query(AFK).get(user_id) 37 | finally: 38 | SESSION.close() 39 | 40 | 41 | def set_afk(user_id, reason=""): 42 | with INSERTION_LOCK: 43 | curr = SESSION.query(AFK).get(user_id) 44 | if not curr: 45 | curr = AFK(user_id, reason, True) 46 | else: 47 | curr.is_afk = True 48 | 49 | AFK_USERS[user_id] = reason 50 | 51 | SESSION.add(curr) 52 | SESSION.commit() 53 | 54 | 55 | def rm_afk(user_id): 56 | with INSERTION_LOCK: 57 | curr = SESSION.query(AFK).get(user_id) 58 | if curr: 59 | if user_id in AFK_USERS: # sanity check 60 | del AFK_USERS[user_id] 61 | 62 | SESSION.delete(curr) 63 | SESSION.commit() 64 | return True 65 | 66 | SESSION.close() 67 | return False 68 | 69 | 70 | def toggle_afk(user_id, reason=""): 71 | with INSERTION_LOCK: 72 | curr = SESSION.query(AFK).get(user_id) 73 | if not curr: 74 | curr = AFK(user_id, reason, True) 75 | elif curr.is_afk: 76 | curr.is_afk = False 77 | elif not curr.is_afk: 78 | curr.is_afk = True 79 | SESSION.add(curr) 80 | SESSION.commit() 81 | 82 | 83 | def __load_afk_users(): 84 | global AFK_USERS 85 | try: 86 | all_afk = SESSION.query(AFK).all() 87 | AFK_USERS = {user.user_id: user.reason for user in all_afk if user.is_afk} 88 | finally: 89 | SESSION.close() 90 | 91 | 92 | __load_afk_users() 93 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/antiflood_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import BigInteger, Column, String, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | DEF_COUNT = 1 8 | DEF_LIMIT = 0 9 | DEF_OBJ = (None, DEF_COUNT, DEF_LIMIT) 10 | 11 | 12 | class FloodControl(BASE): 13 | __tablename__ = "antiflood" 14 | chat_id = Column(String(14), primary_key=True) 15 | user_id = Column(BigInteger) 16 | count = Column(BigInteger, default=DEF_COUNT) 17 | limit = Column(BigInteger, default=DEF_LIMIT) 18 | 19 | def __init__(self, chat_id): 20 | self.chat_id = str(chat_id) # ensure string 21 | 22 | def __repr__(self): 23 | return "" % self.chat_id 24 | 25 | 26 | class FloodSettings(BASE): 27 | __tablename__ = "antiflood_settings" 28 | chat_id = Column(String(14), primary_key=True) 29 | flood_type = Column(BigInteger, default=1) 30 | value = Column(UnicodeText, default="0") 31 | 32 | def __init__(self, chat_id, flood_type=1, value="0"): 33 | self.chat_id = str(chat_id) 34 | self.flood_type = flood_type 35 | self.value = value 36 | 37 | def __repr__(self): 38 | return "<{} will executing {} for flood.>".format(self.chat_id, self.flood_type) 39 | 40 | 41 | FloodControl.__table__.create(checkfirst=True) 42 | FloodSettings.__table__.create(checkfirst=True) 43 | 44 | INSERTION_FLOOD_LOCK = threading.RLock() 45 | INSERTION_FLOOD_SETTINGS_LOCK = threading.RLock() 46 | 47 | CHAT_FLOOD = {} 48 | 49 | 50 | def set_flood(chat_id, amount): 51 | with INSERTION_FLOOD_LOCK: 52 | flood = SESSION.query(FloodControl).get(str(chat_id)) 53 | if not flood: 54 | flood = FloodControl(str(chat_id)) 55 | 56 | flood.user_id = None 57 | flood.limit = amount 58 | 59 | CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, amount) 60 | 61 | SESSION.add(flood) 62 | SESSION.commit() 63 | 64 | 65 | def update_flood(chat_id: str, user_id) -> bool: 66 | if str(chat_id) in CHAT_FLOOD: 67 | curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ) 68 | 69 | if limit == 0: # no antiflood 70 | return False 71 | 72 | if user_id != curr_user_id or user_id is None: # other user 73 | CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT, limit) 74 | return False 75 | 76 | count += 1 77 | if count > limit: # too many msgs, kick 78 | CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit) 79 | return True 80 | 81 | # default -> update 82 | CHAT_FLOOD[str(chat_id)] = (user_id, count, limit) 83 | return False 84 | 85 | 86 | def get_flood_limit(chat_id): 87 | return CHAT_FLOOD.get(str(chat_id), DEF_OBJ)[2] 88 | 89 | 90 | def set_flood_strength(chat_id, flood_type, value): 91 | # for flood_type 92 | # 1 = ban 93 | # 2 = kick 94 | # 3 = mute 95 | # 4 = tban 96 | # 5 = tmute 97 | with INSERTION_FLOOD_SETTINGS_LOCK: 98 | curr_setting = SESSION.query(FloodSettings).get(str(chat_id)) 99 | if not curr_setting: 100 | curr_setting = FloodSettings( 101 | chat_id, flood_type=int(flood_type), value=value 102 | ) 103 | 104 | curr_setting.flood_type = int(flood_type) 105 | curr_setting.value = str(value) 106 | 107 | SESSION.add(curr_setting) 108 | SESSION.commit() 109 | 110 | 111 | def get_flood_setting(chat_id): 112 | try: 113 | setting = SESSION.query(FloodSettings).get(str(chat_id)) 114 | if setting: 115 | return setting.flood_type, setting.value 116 | else: 117 | return 1, "0" 118 | 119 | finally: 120 | SESSION.close() 121 | 122 | 123 | def migrate_chat(old_chat_id, new_chat_id): 124 | with INSERTION_FLOOD_LOCK: 125 | flood = SESSION.query(FloodControl).get(str(old_chat_id)) 126 | if flood: 127 | CHAT_FLOOD[str(new_chat_id)] = CHAT_FLOOD.get(str(old_chat_id), DEF_OBJ) 128 | flood.chat_id = str(new_chat_id) 129 | SESSION.commit() 130 | 131 | SESSION.close() 132 | 133 | 134 | def __load_flood_settings(): 135 | global CHAT_FLOOD 136 | try: 137 | all_chats = SESSION.query(FloodControl).all() 138 | CHAT_FLOOD = {chat.chat_id: (None, DEF_COUNT, chat.limit) for chat in all_chats} 139 | finally: 140 | SESSION.close() 141 | 142 | 143 | __load_flood_settings() 144 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/approve_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String 4 | from sqlalchemy.sql.sqltypes import BigInteger 5 | 6 | from FallenRobot.modules.sql import BASE, SESSION 7 | 8 | 9 | class Approvals(BASE): 10 | __tablename__ = "approval" 11 | chat_id = Column(String(14), primary_key=True) 12 | user_id = Column(BigInteger, primary_key=True) 13 | 14 | def __init__(self, chat_id, user_id): 15 | self.chat_id = str(chat_id) # ensure string 16 | self.user_id = user_id 17 | 18 | def __repr__(self): 19 | return "" % self.user_id 20 | 21 | 22 | Approvals.__table__.create(checkfirst=True) 23 | 24 | APPROVE_INSERTION_LOCK = threading.RLock() 25 | 26 | 27 | def approve(chat_id, user_id): 28 | with APPROVE_INSERTION_LOCK: 29 | approve_user = Approvals(str(chat_id), user_id) 30 | SESSION.add(approve_user) 31 | SESSION.commit() 32 | 33 | 34 | def is_approved(chat_id, user_id): 35 | try: 36 | return SESSION.query(Approvals).get((str(chat_id), user_id)) 37 | finally: 38 | SESSION.close() 39 | 40 | 41 | def disapprove(chat_id, user_id): 42 | with APPROVE_INSERTION_LOCK: 43 | disapprove_user = SESSION.query(Approvals).get((str(chat_id), user_id)) 44 | if disapprove_user: 45 | SESSION.delete(disapprove_user) 46 | SESSION.commit() 47 | return True 48 | else: 49 | SESSION.close() 50 | return False 51 | 52 | 53 | def list_approved(chat_id): 54 | try: 55 | return ( 56 | SESSION.query(Approvals) 57 | .filter(Approvals.chat_id == str(chat_id)) 58 | .order_by(Approvals.user_id.asc()) 59 | .all() 60 | ) 61 | finally: 62 | SESSION.close() 63 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/blacklistusers_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class BlacklistUsers(BASE): 9 | __tablename__ = "blacklistusers" 10 | user_id = Column(String(14), primary_key=True) 11 | reason = Column(UnicodeText) 12 | 13 | def __init__(self, user_id, reason=None): 14 | self.user_id = user_id 15 | self.reason = reason 16 | 17 | 18 | BlacklistUsers.__table__.create(checkfirst=True) 19 | 20 | BLACKLIST_LOCK = threading.RLock() 21 | BLACKLIST_USERS = set() 22 | 23 | 24 | def blacklist_user(user_id, reason=None): 25 | with BLACKLIST_LOCK: 26 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 27 | if not user: 28 | user = BlacklistUsers(str(user_id), reason) 29 | else: 30 | user.reason = reason 31 | 32 | SESSION.add(user) 33 | SESSION.commit() 34 | __load_blacklist_userid_list() 35 | 36 | 37 | def unblacklist_user(user_id): 38 | with BLACKLIST_LOCK: 39 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 40 | if user: 41 | SESSION.delete(user) 42 | 43 | SESSION.commit() 44 | __load_blacklist_userid_list() 45 | 46 | 47 | def get_reason(user_id): 48 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 49 | rep = "" 50 | if user: 51 | rep = user.reason 52 | 53 | SESSION.close() 54 | return rep 55 | 56 | 57 | def is_user_blacklisted(user_id): 58 | return user_id in BLACKLIST_USERS 59 | 60 | 61 | def __load_blacklist_userid_list(): 62 | global BLACKLIST_USERS 63 | try: 64 | BLACKLIST_USERS = {int(x.user_id) for x in SESSION.query(BlacklistUsers).all()} 65 | finally: 66 | SESSION.close() 67 | 68 | 69 | __load_blacklist_userid_list() 70 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/chatbot_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class FallenChats(BASE): 9 | __tablename__ = "fallen_chats" 10 | chat_id = Column(String(14), primary_key=True) 11 | 12 | def __init__(self, chat_id): 13 | self.chat_id = chat_id 14 | 15 | 16 | FallenChats.__table__.create(checkfirst=True) 17 | INSERTION_LOCK = threading.RLock() 18 | 19 | 20 | def is_fallen(chat_id): 21 | try: 22 | chat = SESSION.query(FallenChats).get(str(chat_id)) 23 | return bool(chat) 24 | finally: 25 | SESSION.close() 26 | 27 | 28 | def set_fallen(chat_id): 29 | with INSERTION_LOCK: 30 | fallenchat = SESSION.query(FallenChats).get(str(chat_id)) 31 | if not fallenchat: 32 | fallenchat = FallenChats(str(chat_id)) 33 | SESSION.add(fallenchat) 34 | SESSION.commit() 35 | 36 | 37 | def rem_fallen(chat_id): 38 | with INSERTION_LOCK: 39 | fallenchat = SESSION.query(FallenChats).get(str(chat_id)) 40 | if fallenchat: 41 | SESSION.delete(fallenchat) 42 | SESSION.commit() 43 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/disable_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String, UnicodeText, distinct, func 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class Disable(BASE): 9 | __tablename__ = "disabled_commands" 10 | chat_id = Column(String(14), primary_key=True) 11 | command = Column(UnicodeText, primary_key=True) 12 | 13 | def __init__(self, chat_id, command): 14 | self.chat_id = chat_id 15 | self.command = command 16 | 17 | def __repr__(self): 18 | return "Disabled cmd {} in {}".format(self.command, self.chat_id) 19 | 20 | 21 | Disable.__table__.create(checkfirst=True) 22 | DISABLE_INSERTION_LOCK = threading.RLock() 23 | 24 | DISABLED = {} 25 | 26 | 27 | def disable_command(chat_id, disable): 28 | with DISABLE_INSERTION_LOCK: 29 | disabled = SESSION.query(Disable).get((str(chat_id), disable)) 30 | 31 | if not disabled: 32 | DISABLED.setdefault(str(chat_id), set()).add(disable) 33 | 34 | disabled = Disable(str(chat_id), disable) 35 | SESSION.add(disabled) 36 | SESSION.commit() 37 | return True 38 | 39 | SESSION.close() 40 | return False 41 | 42 | 43 | def enable_command(chat_id, enable): 44 | with DISABLE_INSERTION_LOCK: 45 | disabled = SESSION.query(Disable).get((str(chat_id), enable)) 46 | 47 | if disabled: 48 | if enable in DISABLED.get(str(chat_id)): # sanity check 49 | DISABLED.setdefault(str(chat_id), set()).remove(enable) 50 | 51 | SESSION.delete(disabled) 52 | SESSION.commit() 53 | return True 54 | 55 | SESSION.close() 56 | return False 57 | 58 | 59 | def is_command_disabled(chat_id, cmd): 60 | return str(cmd).lower() in DISABLED.get(str(chat_id), set()) 61 | 62 | 63 | def get_all_disabled(chat_id): 64 | return DISABLED.get(str(chat_id), set()) 65 | 66 | 67 | def num_chats(): 68 | try: 69 | return SESSION.query(func.count(distinct(Disable.chat_id))).scalar() 70 | finally: 71 | SESSION.close() 72 | 73 | 74 | def num_disabled(): 75 | try: 76 | return SESSION.query(Disable).count() 77 | finally: 78 | SESSION.close() 79 | 80 | 81 | def migrate_chat(old_chat_id, new_chat_id): 82 | with DISABLE_INSERTION_LOCK: 83 | chats = SESSION.query(Disable).filter(Disable.chat_id == str(old_chat_id)).all() 84 | for chat in chats: 85 | chat.chat_id = str(new_chat_id) 86 | SESSION.add(chat) 87 | 88 | if str(old_chat_id) in DISABLED: 89 | DISABLED[str(new_chat_id)] = DISABLED.get(str(old_chat_id), set()) 90 | 91 | SESSION.commit() 92 | 93 | 94 | def __load_disabled_commands(): 95 | global DISABLED 96 | try: 97 | all_chats = SESSION.query(Disable).all() 98 | for chat in all_chats: 99 | DISABLED.setdefault(chat.chat_id, set()).add(chat.command) 100 | 101 | finally: 102 | SESSION.close() 103 | 104 | 105 | __load_disabled_commands() 106 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/global_bans_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class GloballyBannedUsers(BASE): 9 | __tablename__ = "gbans" 10 | user_id = Column(BigInteger, primary_key=True) 11 | name = Column(UnicodeText, nullable=False) 12 | reason = Column(UnicodeText) 13 | 14 | def __init__(self, user_id, name, reason=None): 15 | self.user_id = user_id 16 | self.name = name 17 | self.reason = reason 18 | 19 | def __repr__(self): 20 | return "".format(self.name, self.user_id) 21 | 22 | def to_dict(self): 23 | return {"user_id": self.user_id, "name": self.name, "reason": self.reason} 24 | 25 | 26 | class GbanSettings(BASE): 27 | __tablename__ = "gban_settings" 28 | chat_id = Column(String(14), primary_key=True) 29 | setting = Column(Boolean, default=True, nullable=False) 30 | 31 | def __init__(self, chat_id, enabled): 32 | self.chat_id = str(chat_id) 33 | self.setting = enabled 34 | 35 | def __repr__(self): 36 | return "".format(self.chat_id, self.setting) 37 | 38 | 39 | GloballyBannedUsers.__table__.create(checkfirst=True) 40 | GbanSettings.__table__.create(checkfirst=True) 41 | 42 | GBANNED_USERS_LOCK = threading.RLock() 43 | GBAN_SETTING_LOCK = threading.RLock() 44 | GBANNED_LIST = set() 45 | GBANSTAT_LIST = set() 46 | 47 | 48 | def gban_user(user_id, name, reason=None): 49 | with GBANNED_USERS_LOCK: 50 | user = SESSION.query(GloballyBannedUsers).get(user_id) 51 | if not user: 52 | user = GloballyBannedUsers(user_id, name, reason) 53 | else: 54 | user.name = name 55 | user.reason = reason 56 | 57 | SESSION.merge(user) 58 | SESSION.commit() 59 | __load_gbanned_userid_list() 60 | 61 | 62 | def update_gban_reason(user_id, name, reason=None): 63 | with GBANNED_USERS_LOCK: 64 | user = SESSION.query(GloballyBannedUsers).get(user_id) 65 | if not user: 66 | return None 67 | old_reason = user.reason 68 | user.name = name 69 | user.reason = reason 70 | 71 | SESSION.merge(user) 72 | SESSION.commit() 73 | return old_reason 74 | 75 | 76 | def ungban_user(user_id): 77 | with GBANNED_USERS_LOCK: 78 | user = SESSION.query(GloballyBannedUsers).get(user_id) 79 | if user: 80 | SESSION.delete(user) 81 | 82 | SESSION.commit() 83 | __load_gbanned_userid_list() 84 | 85 | 86 | def is_user_gbanned(user_id): 87 | return user_id in GBANNED_LIST 88 | 89 | 90 | def get_gbanned_user(user_id): 91 | try: 92 | return SESSION.query(GloballyBannedUsers).get(user_id) 93 | finally: 94 | SESSION.close() 95 | 96 | 97 | def get_gban_list(): 98 | try: 99 | return [x.to_dict() for x in SESSION.query(GloballyBannedUsers).all()] 100 | finally: 101 | SESSION.close() 102 | 103 | 104 | def enable_gbans(chat_id): 105 | with GBAN_SETTING_LOCK: 106 | chat = SESSION.query(GbanSettings).get(str(chat_id)) 107 | if not chat: 108 | chat = GbanSettings(chat_id, True) 109 | 110 | chat.setting = True 111 | SESSION.add(chat) 112 | SESSION.commit() 113 | if str(chat_id) in GBANSTAT_LIST: 114 | GBANSTAT_LIST.remove(str(chat_id)) 115 | 116 | 117 | def disable_gbans(chat_id): 118 | with GBAN_SETTING_LOCK: 119 | chat = SESSION.query(GbanSettings).get(str(chat_id)) 120 | if not chat: 121 | chat = GbanSettings(chat_id, False) 122 | 123 | chat.setting = False 124 | SESSION.add(chat) 125 | SESSION.commit() 126 | GBANSTAT_LIST.add(str(chat_id)) 127 | 128 | 129 | def does_chat_gban(chat_id): 130 | return str(chat_id) not in GBANSTAT_LIST 131 | 132 | 133 | def num_gbanned_users(): 134 | return len(GBANNED_LIST) 135 | 136 | 137 | def __load_gbanned_userid_list(): 138 | global GBANNED_LIST 139 | try: 140 | GBANNED_LIST = {x.user_id for x in SESSION.query(GloballyBannedUsers).all()} 141 | finally: 142 | SESSION.close() 143 | 144 | 145 | def __load_gban_stat_list(): 146 | global GBANSTAT_LIST 147 | try: 148 | GBANSTAT_LIST = { 149 | x.chat_id for x in SESSION.query(GbanSettings).all() if not x.setting 150 | } 151 | finally: 152 | SESSION.close() 153 | 154 | 155 | def migrate_chat(old_chat_id, new_chat_id): 156 | with GBAN_SETTING_LOCK: 157 | chat = SESSION.query(GbanSettings).get(str(old_chat_id)) 158 | if chat: 159 | chat.chat_id = new_chat_id 160 | SESSION.add(chat) 161 | 162 | SESSION.commit() 163 | 164 | 165 | # Create in memory userid to avoid disk access 166 | __load_gbanned_userid_list() 167 | __load_gban_stat_list() 168 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/log_channel_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String, distinct, func 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class GroupLogs(BASE): 9 | __tablename__ = "log_channels" 10 | chat_id = Column(String(14), primary_key=True) 11 | log_channel = Column(String(14), nullable=False) 12 | 13 | def __init__(self, chat_id, log_channel): 14 | self.chat_id = str(chat_id) 15 | self.log_channel = str(log_channel) 16 | 17 | 18 | GroupLogs.__table__.create(checkfirst=True) 19 | 20 | LOGS_INSERTION_LOCK = threading.RLock() 21 | 22 | CHANNELS = {} 23 | 24 | 25 | def set_chat_log_channel(chat_id, log_channel): 26 | with LOGS_INSERTION_LOCK: 27 | res = SESSION.query(GroupLogs).get(str(chat_id)) 28 | if res: 29 | res.log_channel = log_channel 30 | else: 31 | res = GroupLogs(chat_id, log_channel) 32 | SESSION.add(res) 33 | 34 | CHANNELS[str(chat_id)] = log_channel 35 | SESSION.commit() 36 | 37 | 38 | def get_chat_log_channel(chat_id): 39 | return CHANNELS.get(str(chat_id)) 40 | 41 | 42 | def stop_chat_logging(chat_id): 43 | with LOGS_INSERTION_LOCK: 44 | res = SESSION.query(GroupLogs).get(str(chat_id)) 45 | if res: 46 | if str(chat_id) in CHANNELS: 47 | del CHANNELS[str(chat_id)] 48 | 49 | log_channel = res.log_channel 50 | SESSION.delete(res) 51 | SESSION.commit() 52 | return log_channel 53 | 54 | 55 | def num_logchannels(): 56 | try: 57 | return SESSION.query(func.count(distinct(GroupLogs.chat_id))).scalar() 58 | finally: 59 | SESSION.close() 60 | 61 | 62 | def migrate_chat(old_chat_id, new_chat_id): 63 | with LOGS_INSERTION_LOCK: 64 | chat = SESSION.query(GroupLogs).get(str(old_chat_id)) 65 | if chat: 66 | chat.chat_id = str(new_chat_id) 67 | SESSION.add(chat) 68 | if str(old_chat_id) in CHANNELS: 69 | CHANNELS[str(new_chat_id)] = CHANNELS.get(str(old_chat_id)) 70 | 71 | SESSION.commit() 72 | 73 | 74 | def __load_log_channels(): 75 | global CHANNELS 76 | try: 77 | all_chats = SESSION.query(GroupLogs).all() 78 | CHANNELS = {chat.chat_id: chat.log_channel for chat in all_chats} 79 | finally: 80 | SESSION.close() 81 | 82 | 83 | __load_log_channels() 84 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/night_mode_sql.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, String 2 | 3 | from FallenRobot.modules.sql import BASE, SESSION 4 | 5 | 6 | class Nightmode(BASE): 7 | __tablename__ = "nightmode" 8 | chat_id = Column(String(14), primary_key=True) 9 | 10 | def __init__(self, chat_id): 11 | self.chat_id = chat_id 12 | 13 | 14 | Nightmode.__table__.create(checkfirst=True) 15 | 16 | 17 | def add_nightmode(chat_id: str): 18 | nightmoddy = Nightmode(str(chat_id)) 19 | SESSION.add(nightmoddy) 20 | SESSION.commit() 21 | 22 | 23 | def rmnightmode(chat_id: str): 24 | rmnightmoddy = SESSION.query(Nightmode).get(str(chat_id)) 25 | if rmnightmoddy: 26 | SESSION.delete(rmnightmoddy) 27 | SESSION.commit() 28 | 29 | 30 | def get_all_chat_id(): 31 | stark = SESSION.query(Nightmode).all() 32 | SESSION.close() 33 | return stark 34 | 35 | 36 | def is_nightmode_indb(chat_id: str): 37 | try: 38 | s__ = SESSION.query(Nightmode).get(str(chat_id)) 39 | if s__: 40 | return str(s__.chat_id) 41 | finally: 42 | SESSION.close() 43 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/reporting_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from typing import Union 3 | 4 | from sqlalchemy import BigInteger, Boolean, Column, String 5 | 6 | from FallenRobot.modules.sql import BASE, SESSION 7 | 8 | 9 | class ReportingUserSettings(BASE): 10 | __tablename__ = "user_report_settings" 11 | user_id = Column(BigInteger, primary_key=True) 12 | should_report = Column(Boolean, default=True) 13 | 14 | def __init__(self, user_id): 15 | self.user_id = user_id 16 | 17 | def __repr__(self): 18 | return "".format(self.user_id) 19 | 20 | 21 | class ReportingChatSettings(BASE): 22 | __tablename__ = "chat_report_settings" 23 | chat_id = Column(String(14), primary_key=True) 24 | should_report = Column(Boolean, default=True) 25 | 26 | def __init__(self, chat_id): 27 | self.chat_id = str(chat_id) 28 | 29 | def __repr__(self): 30 | return "".format(self.chat_id) 31 | 32 | 33 | ReportingUserSettings.__table__.create(checkfirst=True) 34 | ReportingChatSettings.__table__.create(checkfirst=True) 35 | 36 | CHAT_LOCK = threading.RLock() 37 | USER_LOCK = threading.RLock() 38 | 39 | 40 | def chat_should_report(chat_id: Union[str, int]) -> bool: 41 | try: 42 | chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id)) 43 | if chat_setting: 44 | return chat_setting.should_report 45 | return False 46 | finally: 47 | SESSION.close() 48 | 49 | 50 | def user_should_report(user_id: int) -> bool: 51 | try: 52 | user_setting = SESSION.query(ReportingUserSettings).get(user_id) 53 | if user_setting: 54 | return user_setting.should_report 55 | return True 56 | finally: 57 | SESSION.close() 58 | 59 | 60 | def set_chat_setting(chat_id: Union[int, str], setting: bool): 61 | with CHAT_LOCK: 62 | chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id)) 63 | if not chat_setting: 64 | chat_setting = ReportingChatSettings(chat_id) 65 | 66 | chat_setting.should_report = setting 67 | SESSION.add(chat_setting) 68 | SESSION.commit() 69 | 70 | 71 | def set_user_setting(user_id: int, setting: bool): 72 | with USER_LOCK: 73 | user_setting = SESSION.query(ReportingUserSettings).get(user_id) 74 | if not user_setting: 75 | user_setting = ReportingUserSettings(user_id) 76 | 77 | user_setting.should_report = setting 78 | SESSION.add(user_setting) 79 | SESSION.commit() 80 | 81 | 82 | def migrate_chat(old_chat_id, new_chat_id): 83 | with CHAT_LOCK: 84 | chat_notes = ( 85 | SESSION.query(ReportingChatSettings) 86 | .filter(ReportingChatSettings.chat_id == str(old_chat_id)) 87 | .all() 88 | ) 89 | for note in chat_notes: 90 | note.chat_id = str(new_chat_id) 91 | SESSION.commit() 92 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/rss_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import BigInteger, Column, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class RSS(BASE): 9 | __tablename__ = "rss_feed" 10 | id = Column(BigInteger, primary_key=True) 11 | chat_id = Column(UnicodeText, nullable=False) 12 | feed_link = Column(UnicodeText) 13 | old_entry_link = Column(UnicodeText) 14 | 15 | def __init__(self, chat_id, feed_link, old_entry_link): 16 | self.chat_id = chat_id 17 | self.feed_link = feed_link 18 | self.old_entry_link = old_entry_link 19 | 20 | def __repr__(self): 21 | return "".format( 22 | self.chat_id, self.feed_link, self.old_entry_link 23 | ) 24 | 25 | 26 | RSS.__table__.create(checkfirst=True) 27 | INSERTION_LOCK = threading.RLock() 28 | 29 | 30 | def check_url_availability(tg_chat_id, tg_feed_link): 31 | try: 32 | return ( 33 | SESSION.query(RSS) 34 | .filter(RSS.feed_link == tg_feed_link, RSS.chat_id == tg_chat_id) 35 | .all() 36 | ) 37 | finally: 38 | SESSION.close() 39 | 40 | 41 | def add_url(tg_chat_id, tg_feed_link, tg_old_entry_link): 42 | with INSERTION_LOCK: 43 | action = RSS(tg_chat_id, tg_feed_link, tg_old_entry_link) 44 | 45 | SESSION.add(action) 46 | SESSION.commit() 47 | 48 | 49 | def remove_url(tg_chat_id, tg_feed_link): 50 | with INSERTION_LOCK: 51 | # this loops to delete any possible duplicates for the same TG User ID, TG Chat ID and link 52 | for row in check_url_availability(tg_chat_id, tg_feed_link): 53 | # add the action to the DB query 54 | SESSION.delete(row) 55 | 56 | SESSION.commit() 57 | 58 | 59 | def get_urls(tg_chat_id): 60 | try: 61 | return SESSION.query(RSS).filter(RSS.chat_id == tg_chat_id).all() 62 | finally: 63 | SESSION.close() 64 | 65 | 66 | def get_all(): 67 | try: 68 | return SESSION.query(RSS).all() 69 | finally: 70 | SESSION.close() 71 | 72 | 73 | def update_url(row_id, new_entry_links): 74 | with INSERTION_LOCK: 75 | row = SESSION.query(RSS).get(row_id) 76 | 77 | # set the new old_entry_link with the latest update from the RSS Feed 78 | row.old_entry_link = new_entry_links[0] 79 | 80 | # commit the changes to the DB 81 | SESSION.commit() 82 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/rules_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String, UnicodeText, distinct, func 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class Rules(BASE): 9 | __tablename__ = "rules" 10 | chat_id = Column(String(14), primary_key=True) 11 | rules = Column(UnicodeText, default="") 12 | 13 | def __init__(self, chat_id): 14 | self.chat_id = chat_id 15 | 16 | def __repr__(self): 17 | return "".format(self.chat_id, self.rules) 18 | 19 | 20 | Rules.__table__.create(checkfirst=True) 21 | 22 | INSERTION_LOCK = threading.RLock() 23 | 24 | 25 | def set_rules(chat_id, rules_text): 26 | with INSERTION_LOCK: 27 | rules = SESSION.query(Rules).get(str(chat_id)) 28 | if not rules: 29 | rules = Rules(str(chat_id)) 30 | rules.rules = rules_text 31 | 32 | SESSION.add(rules) 33 | SESSION.commit() 34 | 35 | 36 | def get_rules(chat_id): 37 | rules = SESSION.query(Rules).get(str(chat_id)) 38 | ret = "" 39 | if rules: 40 | ret = rules.rules 41 | 42 | SESSION.close() 43 | return ret 44 | 45 | 46 | def num_chats(): 47 | try: 48 | return SESSION.query(func.count(distinct(Rules.chat_id))).scalar() 49 | finally: 50 | SESSION.close() 51 | 52 | 53 | def migrate_chat(old_chat_id, new_chat_id): 54 | with INSERTION_LOCK: 55 | chat = SESSION.query(Rules).get(str(old_chat_id)) 56 | if chat: 57 | chat.chat_id = str(new_chat_id) 58 | SESSION.commit() 59 | -------------------------------------------------------------------------------- /FallenRobot/modules/sql/userinfo_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import BigInteger, Column, UnicodeText 4 | 5 | from FallenRobot.modules.sql import BASE, SESSION 6 | 7 | 8 | class UserInfo(BASE): 9 | __tablename__ = "userinfo" 10 | user_id = Column(BigInteger, primary_key=True) 11 | info = Column(UnicodeText) 12 | 13 | def __init__(self, user_id, info): 14 | self.user_id = user_id 15 | self.info = info 16 | 17 | def __repr__(self): 18 | return "" % self.user_id 19 | 20 | 21 | class UserBio(BASE): 22 | __tablename__ = "userbio" 23 | user_id = Column(BigInteger, primary_key=True) 24 | bio = Column(UnicodeText) 25 | 26 | def __init__(self, user_id, bio): 27 | self.user_id = user_id 28 | self.bio = bio 29 | 30 | def __repr__(self): 31 | return "" % self.user_id 32 | 33 | 34 | UserInfo.__table__.create(checkfirst=True) 35 | UserBio.__table__.create(checkfirst=True) 36 | 37 | INSERTION_LOCK = threading.RLock() 38 | 39 | 40 | def get_user_me_info(user_id): 41 | userinfo = SESSION.query(UserInfo).get(user_id) 42 | SESSION.close() 43 | if userinfo: 44 | return userinfo.info 45 | return None 46 | 47 | 48 | def set_user_me_info(user_id, info): 49 | with INSERTION_LOCK: 50 | userinfo = SESSION.query(UserInfo).get(user_id) 51 | if userinfo: 52 | userinfo.info = info 53 | else: 54 | userinfo = UserInfo(user_id, info) 55 | SESSION.add(userinfo) 56 | SESSION.commit() 57 | 58 | 59 | def get_user_bio(user_id): 60 | userbio = SESSION.query(UserBio).get(user_id) 61 | SESSION.close() 62 | if userbio: 63 | return userbio.bio 64 | return None 65 | 66 | 67 | def set_user_bio(user_id, bio): 68 | with INSERTION_LOCK: 69 | userbio = SESSION.query(UserBio).get(user_id) 70 | if userbio: 71 | userbio.bio = bio 72 | else: 73 | userbio = UserBio(user_id, bio) 74 | 75 | SESSION.add(userbio) 76 | SESSION.commit() 77 | -------------------------------------------------------------------------------- /FallenRobot/modules/tagall.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from telethon import events 4 | from telethon.errors import UserNotParticipantError 5 | from telethon.tl.functions.channels import GetParticipantRequest 6 | from telethon.tl.types import ChannelParticipantAdmin, ChannelParticipantCreator 7 | 8 | from FallenRobot import telethn as client 9 | 10 | spam_chats = [] 11 | 12 | 13 | @client.on(events.NewMessage(pattern="^/tagall ?(.*)")) 14 | @client.on(events.NewMessage(pattern="^@all ?(.*)")) 15 | async def mentionall(event): 16 | chat_id = event.chat_id 17 | if event.is_private: 18 | return await event.respond( 19 | "__This command can be use in groups and channels!__" 20 | ) 21 | 22 | is_admin = False 23 | try: 24 | partici_ = await client(GetParticipantRequest(event.chat_id, event.sender_id)) 25 | except UserNotParticipantError: 26 | is_admin = False 27 | else: 28 | if isinstance( 29 | partici_.participant, (ChannelParticipantAdmin, ChannelParticipantCreator) 30 | ): 31 | is_admin = True 32 | if not is_admin: 33 | return await event.respond("__Only admins can mention all!__") 34 | 35 | if event.pattern_match.group(1) and event.is_reply: 36 | return await event.respond("__Give me one argument!__") 37 | elif event.pattern_match.group(1): 38 | mode = "text_on_cmd" 39 | msg = event.pattern_match.group(1) 40 | elif event.is_reply: 41 | mode = "text_on_reply" 42 | msg = await event.get_reply_message() 43 | if msg == None: 44 | return await event.respond( 45 | "__I can't mention members for older messages! (messages which are sent before I'm added to group)__" 46 | ) 47 | else: 48 | return await event.respond( 49 | "__Reply to a message or give me some text to mention others!__" 50 | ) 51 | 52 | spam_chats.append(chat_id) 53 | usrnum = 0 54 | usrtxt = "" 55 | async for usr in client.iter_participants(chat_id): 56 | if not chat_id in spam_chats: 57 | break 58 | usrnum += 1 59 | usrtxt += f"[{usr.first_name}](tg://user?id={usr.id}), " 60 | if usrnum == 5: 61 | if mode == "text_on_cmd": 62 | txt = f"{msg}\n{usrtxt}" 63 | await client.send_message(chat_id, txt) 64 | elif mode == "text_on_reply": 65 | await msg.reply(usrtxt) 66 | await asyncio.sleep(3) 67 | usrnum = 0 68 | usrtxt = "" 69 | try: 70 | spam_chats.remove(chat_id) 71 | except: 72 | pass 73 | 74 | 75 | @client.on(events.NewMessage(pattern="^/cancel$")) 76 | async def cancel_spam(event): 77 | if not event.chat_id in spam_chats: 78 | return await event.respond("__There is no proccess on going...__") 79 | is_admin = False 80 | try: 81 | partici_ = await client(GetParticipantRequest(event.chat_id, event.sender_id)) 82 | except UserNotParticipantError: 83 | is_admin = False 84 | else: 85 | if isinstance( 86 | partici_.participant, (ChannelParticipantAdmin, ChannelParticipantCreator) 87 | ): 88 | is_admin = True 89 | if not is_admin: 90 | return await event.respond("__Only admins can execute this command!__") 91 | 92 | else: 93 | try: 94 | spam_chats.remove(event.chat_id) 95 | except: 96 | pass 97 | return await event.respond("__Stopped mention.__") 98 | 99 | 100 | __mod_name__ = "Tᴀɢ Aʟʟ" 101 | __help__ = """ 102 | *Only for admins* 103 | 104 | ❍ /tagall or @all '(reply to message or add another message) To mention all members in your group, without exception.' 105 | """ 106 | -------------------------------------------------------------------------------- /FallenRobot/modules/telegraph.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import datetime 3 | 4 | from PIL import Image 5 | from telegraph import Telegraph, exceptions, upload_file 6 | 7 | from FallenRobot import telethn as tbot 8 | from FallenRobot.events import register 9 | 10 | Anonymous = "Fallen" 11 | 12 | TMP_DOWNLOAD_DIRECTORY = "./" 13 | telegraph = Telegraph() 14 | r = telegraph.create_account(short_name=Anonymous) 15 | auth_url = r["auth_url"] 16 | 17 | 18 | @register(pattern="^/tg(m|t) ?(.*)") 19 | async def _(event): 20 | if event.fwd_from: 21 | return 22 | optional_title = event.pattern_match.group(2) 23 | if event.reply_to_msg_id: 24 | start = datetime.now() 25 | r_message = await event.get_reply_message() 26 | input_str = event.pattern_match.group(1) 27 | if input_str == "m": 28 | downloaded_file_name = await tbot.download_media( 29 | r_message, TMP_DOWNLOAD_DIRECTORY 30 | ) 31 | end = datetime.now() 32 | ms = (end - start).seconds 33 | h = await event.reply( 34 | "Downloaded to {} in {} seconds.".format(downloaded_file_name, ms) 35 | ) 36 | if downloaded_file_name.endswith((".webp")): 37 | resize_image(downloaded_file_name) 38 | try: 39 | start = datetime.now() 40 | media_urls = upload_file(downloaded_file_name) 41 | except exceptions.TelegraphException as exc: 42 | await h.edit("ERROR: " + str(exc)) 43 | os.remove(downloaded_file_name) 44 | else: 45 | end = datetime.now() 46 | (end - start).seconds 47 | os.remove(downloaded_file_name) 48 | await h.edit( 49 | "Uploaded to https://te.legra.ph{})".format(media_urls[0]), 50 | link_preview=True, 51 | ) 52 | elif input_str == "t": 53 | user_object = await tbot.get_entity(r_message.sender_id) 54 | title_of_page = user_object.first_name # + " " + user_object.last_name 55 | # apparently, all Users do not have last_name field 56 | if optional_title: 57 | title_of_page = optional_title 58 | page_content = r_message.message 59 | if r_message.media: 60 | if page_content != "": 61 | title_of_page = page_content 62 | downloaded_file_name = await tbot.download_media( 63 | r_message, TMP_DOWNLOAD_DIRECTORY 64 | ) 65 | m_list = None 66 | with open(downloaded_file_name, "rb") as fd: 67 | m_list = fd.readlines() 68 | for m in m_list: 69 | page_content += m.decode("UTF-8") + "\n" 70 | os.remove(downloaded_file_name) 71 | page_content = page_content.replace("\n", "
") 72 | response = telegraph.create_page(title_of_page, html_content=page_content) 73 | end = datetime.now() 74 | ms = (end - start).seconds 75 | await event.reply( 76 | "Pasted to https://telegra.ph/{} in {} seconds.".format( 77 | response["path"], ms 78 | ), 79 | link_preview=True, 80 | ) 81 | else: 82 | await event.reply("Reply to a message to get a permanent telegra.ph link.") 83 | 84 | 85 | def resize_image(image): 86 | im = Image.open(image) 87 | im.save(image, "PNG") 88 | 89 | 90 | __help__ = """ 91 | ❍ /tgm :Get Telegraph Link Of Replied Media 92 | ❍ /tgt :Get Telegraph Link of Replied Text 93 | ❍ /tgt [custom name]: Get telegraph link of replied text with custom name. 94 | """ 95 | 96 | __mod_name__ = "T-Gʀᴀᴘʜ" 97 | -------------------------------------------------------------------------------- /FallenRobot/modules/tiny.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import cv2 4 | from PIL import Image 5 | 6 | from FallenRobot import telethn as tbot 7 | from FallenRobot.events import register 8 | 9 | 10 | @register(pattern="^/tiny ?(.*)") 11 | async def _(event): 12 | reply = await event.get_reply_message() 13 | if not (reply and (reply.media)): 14 | await event.reply("`Please reply to a sticker`") 15 | return 16 | kontol = await event.reply("`Processing tiny...`") 17 | ik = await tbot.download_media(reply) 18 | im1 = Image.open("FallenRobot/resources/blank_background.png") 19 | if ik.endswith(".tgs"): 20 | await tbot.download_media(reply, "blank_background.tgs") 21 | os.system("lottie_convert.py blank_background.tgs json.json") 22 | json = open("json.json", "r") 23 | jsn = json.read() 24 | jsn = jsn.replace("512", "2000") 25 | ("json.json", "w").write(jsn) 26 | os.system("lottie_convert.py json.json blank_background.tgs") 27 | file = "blank_background.tgs" 28 | os.remove("json.json") 29 | elif ik.endswith((".gif", ".mp4")): 30 | iik = cv2.VideoCapture(ik) 31 | busy = iik.read() 32 | cv2.imwrite("i.png", busy) 33 | fil = "i.png" 34 | im = Image.open(fil) 35 | z, d = im.size 36 | if z == d: 37 | xxx, yyy = 200, 200 38 | else: 39 | t = z + d 40 | a = z / t 41 | b = d / t 42 | aa = (a * 100) - 50 43 | bb = (b * 100) - 50 44 | xxx = 200 + 5 * aa 45 | yyy = 200 + 5 * bb 46 | k = im.resize((int(xxx), int(yyy))) 47 | k.save("k.png", format="PNG", optimize=True) 48 | im2 = Image.open("k.png") 49 | back_im = im1.copy() 50 | back_im.paste(im2, (150, 0)) 51 | back_im.save("o.webp", "WEBP", quality=95) 52 | file = "o.webp" 53 | os.remove(fil) 54 | os.remove("k.png") 55 | else: 56 | im = Image.open(ik) 57 | z, d = im.size 58 | if z == d: 59 | xxx, yyy = 200, 200 60 | else: 61 | t = z + d 62 | a = z / t 63 | b = d / t 64 | aa = (a * 100) - 50 65 | bb = (b * 100) - 50 66 | xxx = 200 + 5 * aa 67 | yyy = 200 + 5 * bb 68 | k = im.resize((int(xxx), int(yyy))) 69 | k.save("k.png", format="PNG", optimize=True) 70 | im2 = Image.open("k.png") 71 | back_im = im1.copy() 72 | back_im.paste(im2, (150, 0)) 73 | back_im.save("o.webp", "WEBP", quality=95) 74 | file = "o.webp" 75 | os.remove("k.png") 76 | await tbot.send_file(event.chat_id, file, reply_to=event.reply_to_msg_id) 77 | await kontol.delete() 78 | os.remove(file) 79 | os.remove(ik) 80 | 81 | 82 | __mod_name__ = "Tɪɴʏ" 83 | __help__ = """ 84 | ❍ /tiny*:* reply a sticker and see magic 85 | """ 86 | -------------------------------------------------------------------------------- /FallenRobot/modules/translator.py: -------------------------------------------------------------------------------- 1 | from gpytranslate import SyncTranslator 2 | from telegram import ParseMode, Update 3 | from telegram.ext import CallbackContext 4 | 5 | from FallenRobot import dispatcher 6 | from FallenRobot.modules.disable import DisableAbleCommandHandler 7 | 8 | trans = SyncTranslator() 9 | 10 | 11 | def totranslate(update: Update, context: CallbackContext) -> None: 12 | message = update.effective_message 13 | reply_msg = message.reply_to_message 14 | if not reply_msg: 15 | message.reply_text( 16 | "Reply to messages or write messages from other languages for translating into the intended language\n\n" 17 | "Example: `/tr en-hi` to translate from English to Hindi\n" 18 | "Or use: `/tr en` for automatic detection and translating it into english.\n" 19 | "Click here to see [List of available Language Codes](https://te.legra.ph/LANGUAGE-CODES-05-23-2).", 20 | parse_mode="markdown", 21 | disable_web_page_preview=True, 22 | ) 23 | return 24 | if reply_msg.caption: 25 | to_translate = reply_msg.caption 26 | elif reply_msg.text: 27 | to_translate = reply_msg.text 28 | try: 29 | args = message.text.split()[1].lower() 30 | if "//" in args: 31 | source = args.split("//")[0] 32 | dest = args.split("//")[1] 33 | else: 34 | source = trans.detect(to_translate) 35 | dest = args 36 | except IndexError: 37 | source = trans.detect(to_translate) 38 | dest = "en" 39 | translation = trans(to_translate, sourcelang=source, targetlang=dest) 40 | reply = ( 41 | f"ᴛʀᴀɴsʟᴀᴛᴇᴅ ғʀᴏᴍ {source} ᴛᴏ {dest} :\n" 42 | f"{translation.text}" 43 | ) 44 | 45 | message.reply_text(reply, parse_mode=ParseMode.HTML) 46 | 47 | 48 | __help__ = """ 49 | ❍ /tr or /tl (language code) as reply to a long message 50 | *Example:* 51 | ❍ /tr en*:* translates something to english 52 | ❍ /tr hi-en*:* translates hindi to english 53 | 54 | [ʟᴀɴɢᴜᴀɢᴇ ᴄᴏᴅᴇs](https://te.legra.ph/LANGUAGE-CODES-05-23-2) 55 | """ 56 | __mod_name__ = "Tʀᴀɴsʟᴀᴛᴏʀ" 57 | 58 | TRANSLATE_HANDLER = DisableAbleCommandHandler(["tr", "tl"], totranslate, run_async=True) 59 | 60 | dispatcher.add_handler(TRANSLATE_HANDLER) 61 | 62 | __command_list__ = ["tr", "tl"] 63 | __handlers__ = [TRANSLATE_HANDLER] 64 | -------------------------------------------------------------------------------- /FallenRobot/modules/truth_and_dare.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from telegram import Update 3 | from telegram.ext import CallbackContext 4 | 5 | from FallenRobot import dispatcher 6 | from FallenRobot.modules.disable import DisableAbleCommandHandler 7 | 8 | 9 | def truth(update: Update, context: CallbackContext): 10 | truth = requests.get(f"https://api.truthordarebot.xyz/v1/truth").json()["question"] 11 | update.effective_message.reply_text(truth) 12 | 13 | 14 | def dare(update: Update, context: CallbackContext): 15 | dare = requests.get(f"https://api.truthordarebot.xyz/v1/dare").json()["question"] 16 | update.effective_message.reply_text(dare) 17 | 18 | 19 | TRUTH_HANDLER = DisableAbleCommandHandler("truth", truth, run_async=True) 20 | DARE_HANDLER = DisableAbleCommandHandler("dare", dare, run_async=True) 21 | 22 | dispatcher.add_handler(TRUTH_HANDLER) 23 | dispatcher.add_handler(DARE_HANDLER) 24 | 25 | 26 | __help__ = """ 27 | *Truth & Dare* 28 | 29 | ❍ /truth *:* Sends a random truth string. 30 | ❍ /dare *:* Sends a random dare string. 31 | """ 32 | 33 | __mod_name__ = "Tʀᴜᴛʜ-Dᴀʀᴇ" 34 | -------------------------------------------------------------------------------- /FallenRobot/modules/ud.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from telegram import ParseMode, Update 3 | from telegram.ext import CallbackContext 4 | 5 | from FallenRobot import dispatcher 6 | from FallenRobot.modules.disable import DisableAbleCommandHandler 7 | 8 | 9 | def ud(update: Update, context: CallbackContext): 10 | message = update.effective_message 11 | text = message.text[len("/ud ") :] 12 | results = requests.get( 13 | f"https://api.urbandictionary.com/v0/define?term={text}" 14 | ).json() 15 | try: 16 | reply_text = f'*{text}*\n\n{results["list"][0]["definition"]}\n\n_{results["list"][0]["example"]}_' 17 | except: 18 | reply_text = "No results found." 19 | message.reply_text(reply_text, parse_mode=ParseMode.MARKDOWN) 20 | 21 | 22 | UD_HANDLER = DisableAbleCommandHandler(["ud"], ud, run_async=True) 23 | 24 | dispatcher.add_handler(UD_HANDLER) 25 | 26 | __help__ = """ 27 | » /ud (text) *:* Searchs the given text on Urban Dictionary and sends you the information. 28 | """ 29 | __mod_name__ = "Uʀʙᴀɴ D" 30 | 31 | __command_list__ = ["ud"] 32 | __handlers__ = [UD_HANDLER] 33 | -------------------------------------------------------------------------------- /FallenRobot/modules/wallpaper.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import requests 4 | from pyrogram import filters 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message 6 | 7 | from FallenRobot import pbot 8 | 9 | ##TO-DO 10 | 11 | 12 | @pbot.on_message(filters.command(["wall", "wallpaper"])) 13 | async def wall(_, message: Message): 14 | try: 15 | text = message.text.split(None, 1)[1] 16 | except IndexError: 17 | text = None 18 | if not text: 19 | return await message.reply_text("`Please give some query to search.`") 20 | m = await message.reply_text("`Searching for wallpapers...`") 21 | try: 22 | url = requests.get(f"https://api.safone.me/wall?query={text}").json()["results"] 23 | ran = random.randint(0, 3) 24 | await message.reply_photo( 25 | photo=url[ran]["imageUrl"], 26 | caption=f"🥀 **ʀᴇǫᴜᴇsᴛᴇᴅ ʙʏ :** {message.from_user.mention}", 27 | reply_markup=InlineKeyboardMarkup( 28 | [ 29 | [InlineKeyboardButton("ʟɪɴᴋ", url=url[ran]["imageUrl"])], 30 | ] 31 | ), 32 | ) 33 | await m.delete() 34 | except Exception as e: 35 | await m.edit_text( 36 | f"`ᴡᴀʟʟᴘᴀᴘᴇʀ ɴᴏᴛ ғᴏᴜɴᴅ ғᴏʀ : `{text}`", 37 | ) 38 | -------------------------------------------------------------------------------- /FallenRobot/modules/weather.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import aiohttp 4 | from telethon.tl import functions, types 5 | 6 | from FallenRobot import telethn as tbot 7 | from FallenRobot.events import register 8 | 9 | 10 | async def is_register_admin(chat, user): 11 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 12 | return isinstance( 13 | ( 14 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 15 | ).participant, 16 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 17 | ) 18 | if isinstance(chat, types.InputPeerUser): 19 | return True 20 | 21 | 22 | @register(pattern="^/weather (.*)") 23 | async def _(event): 24 | if event.fwd_from: 25 | return 26 | 27 | sample_url = "https://wttr.in/{}.png" 28 | input_str = event.pattern_match.group(1) 29 | async with aiohttp.ClientSession() as session: 30 | response_api_zero = await session.get(sample_url.format(input_str)) 31 | response_api = await response_api_zero.read() 32 | with io.BytesIO(response_api) as out_file: 33 | await event.reply(file=out_file) 34 | 35 | 36 | __help__ = """ 37 | I can find weather of all cities 38 | 39 | ❍ /weather *:* Advanced weather module, usage same as /weather 40 | ❍ /weather moon*:* Get the current status of moon 41 | """ 42 | 43 | __mod_name__ = "Wᴇᴀᴛʜᴇʀ" 44 | -------------------------------------------------------------------------------- /FallenRobot/modules/webshot.py: -------------------------------------------------------------------------------- 1 | from base64 import b64decode 2 | from inspect import getfullargspec 3 | from io import BytesIO 4 | 5 | from pyrogram import filters 6 | from pyrogram.types import Message 7 | 8 | from FallenRobot import pbot as app 9 | from FallenRobot.utils.post import post 10 | 11 | 12 | async def take_screenshot(url: str, full: bool = False): 13 | url = "https://" + url if not url.startswith("http") else url 14 | payload = { 15 | "url": url, 16 | "width": 1920, 17 | "height": 1080, 18 | "scale": 1, 19 | "format": "jpeg", 20 | } 21 | if full: 22 | payload["full"] = True 23 | data = await post( 24 | "https://webscreenshot.vercel.app/api", 25 | data=payload, 26 | ) 27 | if "image" not in data: 28 | return None 29 | b = data["image"].replace("data:image/jpeg;base64,", "") 30 | file = BytesIO(b64decode(b)) 31 | file.name = "webss.jpg" 32 | return file 33 | 34 | 35 | async def eor(msg: Message, **kwargs): 36 | func = ( 37 | (msg.edit_text if msg.from_user.is_self else msg.reply) 38 | if msg.from_user 39 | else msg.reply 40 | ) 41 | spec = getfullargspec(func.__wrapped__).args 42 | return await func(**{k: v for k, v in kwargs.items() if k in spec}) 43 | 44 | 45 | @app.on_message(filters.command(["webss", "ss", "webshot"])) 46 | async def take_ss(_, message: Message): 47 | if len(message.command) < 2: 48 | return await eor(message, text="ɢɪᴠᴇ ᴀ ᴜʀʟ ᴛᴏ ғᴇᴛᴄʜ sᴄʀᴇᴇɴsʜᴏᴛ.") 49 | 50 | if len(message.command) == 2: 51 | url = message.text.split(None, 1)[1] 52 | full = False 53 | elif len(message.command) == 3: 54 | url = message.text.split(None, 2)[1] 55 | full = message.text.split(None, 2)[2].lower().strip() in [ 56 | "yes", 57 | "y", 58 | "1", 59 | "true", 60 | ] 61 | else: 62 | return await eor(message, text="ɪɴᴠᴀʟɪᴅ ᴄᴏᴍᴍᴀɴᴅ.") 63 | 64 | m = await eor(message, text="ᴄᴀᴘᴛᴜʀɪɴɢ sᴄʀᴇᴇɴsʜᴏᴛ...") 65 | 66 | try: 67 | photo = await take_screenshot(url, full) 68 | if not photo: 69 | return await m.edit("ғᴀɪʟᴇᴅ ᴛᴏ ᴛᴀᴋᴇ sᴄʀᴇᴇɴsʜᴏᴛ.") 70 | 71 | m = await m.edit("ᴜᴘʟᴏᴀᴅɪɴɢ...") 72 | 73 | if not full: 74 | await message.reply_document(photo) 75 | else: 76 | await message.reply_document(photo) 77 | await m.delete() 78 | except Exception as e: 79 | await m.edit(str(e)) 80 | 81 | 82 | __help__ = """ 83 | » /webss *:* Sends the screenshot of the given url. 84 | """ 85 | __mod_name__ = "Wᴇʙsʜᴏᴛ" 86 | -------------------------------------------------------------------------------- /FallenRobot/modules/wiki.py: -------------------------------------------------------------------------------- 1 | import wikipedia 2 | from telegram import ParseMode, Update 3 | from telegram.ext import CallbackContext 4 | from wikipedia.exceptions import DisambiguationError, PageError 5 | 6 | from FallenRobot import dispatcher 7 | from FallenRobot.modules.disable import DisableAbleCommandHandler 8 | 9 | 10 | def wiki(update: Update, context: CallbackContext): 11 | msg = ( 12 | update.effective_message.reply_to_message 13 | if update.effective_message.reply_to_message 14 | else update.effective_message 15 | ) 16 | res = "" 17 | if msg == update.effective_message: 18 | search = msg.text.split(" ", maxsplit=1)[1] 19 | else: 20 | search = msg.text 21 | try: 22 | res = wikipedia.summary(search) 23 | except DisambiguationError as e: 24 | update.message.reply_text( 25 | "Disambiguated pages found! Adjust your query accordingly.\n{}".format( 26 | e 27 | ), 28 | parse_mode=ParseMode.HTML, 29 | ) 30 | except PageError as e: 31 | update.message.reply_text( 32 | "{}".format(e), parse_mode=ParseMode.HTML 33 | ) 34 | if res: 35 | result = f"{search}\n\n" 36 | result += f"{res}\n" 37 | result += f"""Read more...""" 38 | if len(result) > 4000: 39 | with open("result.txt", "w") as f: 40 | f.write(f"{result}\n\nUwU OwO OmO UmU") 41 | with open("result.txt", "rb") as f: 42 | context.bot.send_document( 43 | document=f, 44 | filename=f.name, 45 | reply_to_message_id=update.message.message_id, 46 | chat_id=update.effective_chat.id, 47 | parse_mode=ParseMode.HTML, 48 | ) 49 | else: 50 | update.message.reply_text( 51 | result, parse_mode=ParseMode.HTML, disable_web_page_preview=True 52 | ) 53 | 54 | 55 | WIKI_HANDLER = DisableAbleCommandHandler("wiki", wiki, run_async=True) 56 | 57 | dispatcher.add_handler(WIKI_HANDLER) 58 | 59 | __help__ = """ 60 | » /wiki (text) *:* Searchs about the given text on wikipedia. 61 | """ 62 | __mod_name__ = "Wɪᴋɪ" 63 | -------------------------------------------------------------------------------- /FallenRobot/modules/writetool.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ParseMode, Update 3 | from telegram.ext import CallbackContext 4 | 5 | from FallenRobot import BOT_NAME, BOT_USERNAME, dispatcher 6 | from FallenRobot.modules.disable import DisableAbleCommandHandler 7 | 8 | 9 | def handwrite(update: Update, context: CallbackContext): 10 | message = update.effective_message 11 | if message.reply_to_message: 12 | text = message.reply_to_message.text 13 | else: 14 | text = update.effective_message.text.split(None, 1)[1] 15 | m = message.reply_text("Writing the text...") 16 | req = requests.get(f"https://api.sdbots.tk/write?text={text}").url 17 | message.reply_photo( 18 | photo=req, 19 | caption=f""" 20 | Successfully Written Text 💘 21 | 22 | ✨ **Written By :** [{BOT_NAME}](https://t.me/{BOT_USERNAME}) 23 | 🥀 **Requested by :** {update.effective_user.first_name} 24 | ❄ **Link :** `{req}`""", 25 | parse_mode=ParseMode.MARKDOWN, 26 | reply_markup=InlineKeyboardMarkup( 27 | [ 28 | [ 29 | InlineKeyboardButton("• ᴛᴇʟᴇɢʀᴀᴩʜ •", url=req), 30 | ], 31 | ] 32 | ), 33 | ) 34 | m.delete() 35 | 36 | 37 | __help__ = """ 38 | Writes the given text on white page with a pen 🖊 39 | 40 | ❍ /write *:*Writes the given text. 41 | """ 42 | 43 | WRITE_HANDLER = DisableAbleCommandHandler("write", handwrite, run_async=True) 44 | dispatcher.add_handler(WRITE_HANDLER) 45 | 46 | __mod_name__ = "WʀɪᴛᴇTᴏᴏʟ" 47 | 48 | __command_list__ = ["write"] 49 | __handlers__ = [WRITE_HANDLER] 50 | -------------------------------------------------------------------------------- /FallenRobot/modules/zombies.py: -------------------------------------------------------------------------------- 1 | from asyncio import sleep 2 | 3 | from pyrogram import filters 4 | from pyrogram.types import Message 5 | 6 | from FallenRobot import pbot 7 | from FallenRobot.utils.admins import can_restrict 8 | 9 | 10 | @pbot.on_message(filters.command(["zombies", "ghosts"])) 11 | @can_restrict 12 | async def ban_zombies(_, message: Message): 13 | del_zom = 0 14 | no_z = "`0 deleted accounts found in this chat.`" 15 | try: 16 | clean = message.text.split(None, 1)[1] 17 | except: 18 | clean = None 19 | if clean != "clean": 20 | check = await message.reply_text("`Searching for deleted accounts...`") 21 | async for user in pbot.get_chat_members(message.chat.id): 22 | if user.user.is_deleted: 23 | del_zom += 1 24 | await sleep(1) 25 | if del_zom > 0: 26 | return await check.edit_text( 27 | f"`{del_zom}` found in this chat.\nClean them by /zombies clean" 28 | ) 29 | else: 30 | return await check.edit_text(no_z) 31 | cleaner = await message.reply_text("`Cleaning deleted accounts from this chat...`") 32 | deleted_u = [] 33 | banned = 0 34 | failed = 0 35 | async for user in pbot.get_chat_members(message.chat.id): 36 | if user.user.is_deleted: 37 | deleted_u.append(int(user.user.id)) 38 | if len(deleted_u) > 0: 39 | for deleted in deleted_u: 40 | try: 41 | await message.chat.ban_member(deleted) 42 | banned += 1 43 | except: 44 | continue 45 | failed += 1 46 | return await cleaner.edit_text( 47 | f"Cleaned `{banned}` zombies from this chat.\nFailed to remove `{failed}` admin zombies." 48 | ) 49 | else: 50 | return await check.edit_text(no_z) 51 | 52 | 53 | __help__ = """ 54 | *Remove Deleted Accounts* 55 | 56 | ❍ /zombies *:* Starts searching for deleted accounts in the group. 57 | ❍ /zombies clean *:* Removes the deleted accounts from the group. 58 | """ 59 | 60 | __mod_name__ = "Zᴏᴍʙɪᴇ" 61 | -------------------------------------------------------------------------------- /FallenRobot/resources/blank_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/blank_background.png -------------------------------------------------------------------------------- /FallenRobot/resources/default.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/default.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fallen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fallen.jpg -------------------------------------------------------------------------------- /FallenRobot/resources/fglitch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fglitch.gif -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER AT.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER AT.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER AT.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER AT.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER BI.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/AVENGEANCE HEROIC AVENGER BI.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Big Space.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Big Space.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/CRAWLER-RegularDEMO.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/CRAWLER-RegularDEMO.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/CROWNT.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/CROWNT.TTF -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Chopsic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Chopsic.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Crozzoe-Personal-Use.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Crozzoe-Personal-Use.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DIGIT.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DIGIT.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages-Italic.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages3D-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages3D-Italic.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages3D.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages3D.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages3DFilled-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages3DFilled-Italic.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damages3DFilled.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damages3DFilled.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damar Kurung.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damar Kurung.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Damar Kurung.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Damar Kurung.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dark Ministry.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dark Ministry.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dark Seed.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dark Seed.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dark.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dark.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dash-Dermo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dash-Dermo.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dead Revolution.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dead Revolution.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoDash.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoDash.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoItalic.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoItalicDash.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoItalicDash.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoOutline.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoOutline.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoOutlineDash.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoOutlineDash.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DezertDemoRegular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DezertDemoRegular.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DisposableDroidBB_bld.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DisposableDroidBB_bld.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/DragonForcE.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/DragonForcE.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dramaga Demo.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dramaga Demo.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dramaga Demo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dramaga Demo.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Dreamscar.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Dreamscar.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/EVILDEAD.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/EVILDEAD.TTF -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Europhonic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Europhonic.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Exorcista_-Jed_40.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Exorcista_-Jed_40.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Fire Flight FREE.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Fire Flight FREE.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Fire Flight FREE.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Fire Flight FREE.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/FontRemix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/FontRemix.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/FontRemix2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/FontRemix2.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Friend Head.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Friend Head.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Frostbite Boss Fight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Frostbite Boss Fight.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Fucking Hostile.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Fucking Hostile.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/GRAMES.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/GRAMES.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Gang Wolfik.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Gang Wolfik.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Garda.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Garda.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Garreng-Personal-Use.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Garreng-Personal-Use.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Geizer.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Geizer.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Georgent.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Georgent.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Georgent.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Georgent.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Hallowed Grad.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Hallowed Grad.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Harker Bold Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Harker Bold Italic.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Harker Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Harker Italic.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Maghrib.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Maghrib.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/ObelixProB-cyr Alfi Stefa.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/ObelixProB-cyr Alfi Stefa.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/RealFast Alfi Stefa.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/RealFast Alfi Stefa.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/TruenoBlkOl.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/TruenoBlkOl.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/TruenoRg.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/TruenoRg.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/TruenoRgIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/TruenoRgIt.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/TruenoSBdIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/TruenoSBdIt.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/Vendetta.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/Vendetta.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/digital.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/digital.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/elric.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/elric.TTF -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/font.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/font.otf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/fontx.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/fontx.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/hawkmoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/hawkmoon.ttf -------------------------------------------------------------------------------- /FallenRobot/resources/fonts/monumentextended-regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRADHAN474/managerbot/ed974ff6a42a8a18d8255a39f0a92b5c46aa2c4c/FallenRobot/resources/fonts/monumentextended-regular.otf -------------------------------------------------------------------------------- /FallenRobot/utils/admins.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | from pyrogram.enums import ChatMemberStatus 4 | from pyrogram.types import Message 5 | 6 | from FallenRobot import DEV_USERS, pbot 7 | 8 | 9 | def can_restrict(func: Callable) -> Callable: 10 | async def non_admin(_, message: Message): 11 | if message.from_user.id in DEV_USERS: 12 | return await func(_, message) 13 | 14 | check = await pbot.get_chat_member(message.chat.id, message.from_user.id) 15 | if check.status not in [ChatMemberStatus.OWNER, ChatMemberStatus.ADMINISTRATOR]: 16 | return await message.reply_text( 17 | "» ʏᴏᴜ'ʀᴇ ɴᴏᴛ ᴀɴ ᴀᴅᴍɪɴ ʙᴀʙʏ, ᴘʟᴇᴀsᴇ sᴛᴀʏ ɪɴ ʏᴏᴜʀ ʟɪᴍɪᴛs." 18 | ) 19 | 20 | admin = ( 21 | await pbot.get_chat_member(message.chat.id, message.from_user.id) 22 | ).privileges 23 | if admin.can_restrict_members: 24 | return await func(_, message) 25 | else: 26 | return await message.reply_text( 27 | "`You don't have permissions to restrict users in this chat." 28 | ) 29 | 30 | return non_admin 31 | -------------------------------------------------------------------------------- /FallenRobot/utils/errors.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import traceback 3 | from functools import wraps 4 | 5 | from pyrogram.errors.exceptions.forbidden_403 import ChatWriteForbidden 6 | 7 | from FallenRobot import OWNER_ID, pbot 8 | 9 | 10 | def split_limits(text): 11 | if len(text) < 2048: 12 | return [text] 13 | 14 | lines = text.splitlines(True) 15 | small_msg = "" 16 | result = [] 17 | for line in lines: 18 | if len(small_msg) + len(line) < 2048: 19 | small_msg += line 20 | else: 21 | result.append(small_msg) 22 | small_msg = line 23 | 24 | result.append(small_msg) 25 | 26 | return result 27 | 28 | 29 | def capture_err(func): 30 | @wraps(func) 31 | async def capture(client, message, *args, **kwargs): 32 | try: 33 | return await func(client, message, *args, **kwargs) 34 | except ChatWriteForbidden: 35 | return 36 | except Exception as err: 37 | exc_type, exc_obj, exc_tb = sys.exc_info() 38 | errors = traceback.format_exception( 39 | exc_type, 40 | value=exc_obj, 41 | tb=exc_tb, 42 | ) 43 | error_feedback = split_limits( 44 | "**ERROR** | `{}` | `{}`\n\n```{}```\n\n```{}```\n".format( 45 | 0 if not message.from_user else message.from_user.id, 46 | 0 if not message.chat else message.chat.id, 47 | message.text or message.caption, 48 | "".join(errors), 49 | ), 50 | ) 51 | for x in error_feedback: 52 | await pbot.send_message(OWNER_ID, x) 53 | raise err 54 | 55 | return capture 56 | -------------------------------------------------------------------------------- /FallenRobot/utils/functions.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | 3 | from aiohttp import ClientSession 4 | 5 | 6 | async def make_carbon(code): 7 | url = "https://carbonara.solopov.dev/api/cook" 8 | async with ClientSession().post(url, json={"code": code}) as resp: 9 | image = BytesIO(await resp.read()) 10 | image.name = "carbon.png" 11 | return image 12 | -------------------------------------------------------------------------------- /FallenRobot/utils/mongo.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient as MongoCli 2 | 3 | from FallenRobot import MONGO_DB_URI 4 | 5 | mongo = MongoCli(MONGO_DB_URI) 6 | db = mongo.FallenRobot 7 | 8 | coupledb = db.couple 9 | 10 | 11 | async def _get_lovers(chat_id: int): 12 | lovers = await coupledb.find_one({"chat_id": chat_id}) 13 | if lovers: 14 | lovers = lovers["couple"] 15 | else: 16 | lovers = {} 17 | return lovers 18 | 19 | 20 | async def get_couple(chat_id: int, date: str): 21 | lovers = await _get_lovers(chat_id) 22 | if date in lovers: 23 | return lovers[date] 24 | else: 25 | return False 26 | 27 | 28 | async def save_couple(chat_id: int, date: str, couple: dict): 29 | lovers = await _get_lovers(chat_id) 30 | lovers[date] = couple 31 | await coupledb.update_one( 32 | {"chat_id": chat_id}, 33 | {"$set": {"couple": lovers}}, 34 | upsert=True, 35 | ) 36 | -------------------------------------------------------------------------------- /FallenRobot/utils/pastebin.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from asyncio import get_running_loop 3 | from functools import partial 4 | 5 | 6 | def _netcat(host, port, content): 7 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | s.connect((host, port)) 9 | s.sendall(content.encode()) 10 | s.shutdown(socket.SHUT_WR) 11 | while True: 12 | data = s.recv(4096).decode("utf-8").strip("\n\x00") 13 | if not data: 14 | break 15 | return data 16 | s.close() 17 | 18 | 19 | async def paste(content): 20 | loop = get_running_loop() 21 | link = await loop.run_in_executor(None, partial(_netcat, "ezup.dev", 9999, content)) 22 | return link 23 | -------------------------------------------------------------------------------- /FallenRobot/utils/post.py: -------------------------------------------------------------------------------- 1 | from aiohttp import ClientSession 2 | 3 | 4 | async def post(url: str, *args, **kwargs): 5 | async with ClientSession().post(url, *args, **kwargs) as resp: 6 | try: 7 | data = await resp.json() 8 | except Exception: 9 | data = await resp.text() 10 | return data 11 | -------------------------------------------------------------------------------- /Git_Pull.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | TITLE Github Quick-Pull 3 | 4 | :: Print the branch cause ..oooooo fancy! 5 | echo Pulling from branch: 6 | git branch 7 | echo. 8 | git pull 9 | -------------------------------------------------------------------------------- /Git_Push.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | TITLE Github Quick-pushing 3 | 4 | :: Print the branch cause people like me push to wrong branches and cry about it later. 5 | echo Pushing to branch: 6 | git branch 7 | echo. 8 | :: Take input for comment and thats about it 9 | set /p commit_title="Enter Commit title (pushes with you as author): " 10 | 11 | :: If you are reading comments to understand this part then you can go back stab yourself. 12 | echo. 13 | git pull 14 | git add * 15 | git commit -m "%commit_title%" 16 | git push 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 AnonymousX1025 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 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 -m FallenRobot 2 | -------------------------------------------------------------------------------- /Setup venv.bat: -------------------------------------------------------------------------------- 1 | TITLE Setting up virtual env 2 | :: Running it once is fine, this just sets up virtual env >> install all modules there 3 | py -m venv env && env\scripts\activate.bat && pip install -r requirements.txt 4 | 5 | :: Note to rerun the requirements.txt in case you ever add a module. 6 | :: Running this multiple time will not make a mess of your setup, dont worry about that bit. 7 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "™°‌ 🫧 🇴 🇽 𝐘 𓃭 🇷 𝐎𝐁𝐎𝐓 ⃟⛦⃕͜༆", 3 | "description": "Telegram Group Management Bot.", 4 | "logo": "https://graph.org/file/79b2347e9834e02510895.jpg", 5 | "keywords": [ 6 | "telegram", 7 | "modular", 8 | "group", 9 | "manager", 10 | "Fallen" 11 | ], 12 | "repository": "https://github.com/PRADHAN474/managerbot", 13 | "stack": "heroku-22", 14 | "addons": [ 15 | { 16 | "options": { 17 | "version": "12" 18 | }, 19 | "plan": "heroku-postgresql" 20 | } 21 | ], 22 | "env": { 23 | "API_ID": { 24 | "description": "Get this value from my.telegram.org/apps.", 25 | "required": true, 26 | "value": "28365981" 27 | }, 28 | "API_HASH": { 29 | "description": "Get this value from my.telegram.org/apps.", 30 | "required": true, 31 | "value": "3c382f8e3f46ffd6cd9526d2aebc4c3a" 32 | }, 33 | "ALLOW_EXCL": { 34 | "description": "Set this to True if you want ! to be a command prefix along with /. Recommended is True", 35 | "value": "True" 36 | }, 37 | "CASH_API_KEY": { 38 | "description": "Required for currency converter. Get yours from https://www.alphavantage.co/support/#api-key", 39 | "required": true, 40 | "value": "KZOKAC9RSH0YORF9" 41 | }, 42 | "DEL_CMDS": { 43 | "description": "Set this to True if you want to delete command messages from users who don't have the perms to run that command.", 44 | "value": "True" 45 | }, 46 | "ENV": { 47 | "description": "Setting this to ANYTHING will enable environment variables. Leave it as it is", 48 | "required": true, 49 | "value": "True" 50 | }, 51 | "EVENT_LOGS": { 52 | "description": "Event logs channel to note down important bot level events, recommend to make this public. ex: '-123456'", 53 | "required": true, 54 | "value": "" 55 | }, 56 | "MONGO_DB_URI": { 57 | "description": "Required for database connections.", 58 | "required": true, 59 | "value": "" 60 | }, 61 | "OWNER_ID": { 62 | "description": "Your user ID as an integer.", 63 | "required": false, 64 | "value": "5059737154" 65 | }, 66 | "START_IMG": { 67 | "description": "Telegraph link of the image which will be shown at start command.", 68 | "required": true, 69 | "value": "https://graph.org/file/79b2347e9834e02510895.jpg" 70 | }, 71 | "SUPPORT_CHAT": { 72 | "description": "Your Telegram support group chat username where your users will go and bother you with shit But be like: MyGroupChatUsernameBlah. If this ever points to Fallen Support than consider you made an enemy.", 73 | "required": false, 74 | "value": "BWANDARLOK" 75 | }, 76 | "TIME_API_KEY": { 77 | "description": "Required for timezone information. Get yours from https://timezonedb.com/api", 78 | "required": true, 79 | "value": "B9Y6LCIU7C29" 80 | }, 81 | "TOKEN": { 82 | "description": "Get bot token from @BotFather on TG", 83 | "required": true, 84 | "value": "" 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | run: 5 | worker: python3 -m FallenRobot 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==23.1.0 2 | aiohttp==3.8.5 3 | apscheduler==3.6.3 4 | asyncio==3.4.3 5 | beautifulsoup4==4.12.2 6 | bing_image_downloader==1.1.2 7 | bleach==6.0.0 8 | bs4==0.0.1 9 | cachetools==4.2.2 10 | countryinfo==0.1.2 11 | currencyconverter==0.17.9 12 | dateparser==1.1.8 13 | emoji==2.6.0 14 | emoji-country-flag==1.3.2 15 | feedparser==6.0.10 16 | future==0.18.3 17 | geopy==2.3.0 18 | gpytranslate==1.5.1 19 | hachoir==3.2.0 20 | html2text==2020.1.16 21 | jikanpy==4.3.2 22 | lxml==4.9.3 23 | markdown2==2.4.9 24 | motor==3.2.0 25 | opencv-python-headless==4.8.0.74 26 | pillow==10.0.0 27 | pretty_errors==1.2.25 28 | psutil==5.9.5 29 | psycopg2-binary==2.9.6 30 | pydictionary==2.0.1 31 | pykeyboard==0.1.5 32 | pynewtonmath==1.0.1 33 | pyrate-limiter==2.10.0 34 | pyrogram==2.0.106 35 | python-telegram-bot==13.15 36 | regex==2023.6.3 37 | requests==2.31.0 38 | secureme==0.0.4 39 | search_engine_parser==0.6.8 40 | speedtest-cli==2.1.3 41 | sqlalchemy==1.4.46 42 | telegraph==2.2.0 43 | telethon==1.29.1 44 | tgcrypto==1.2.5 45 | wikipedia==1.4.0 46 | -------------------------------------------------------------------------------- /restart.bat: -------------------------------------------------------------------------------- 1 | :: starts a cmd to silently start the bat file, just another dirty way of getting things done for my env on windows 2 | start cmd.exe /c start_service.bat -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.12 2 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | TITLE Fallen Robot 3 | :: Enables virtual env mode and then starts Fallen 4 | env\scripts\activate.bat && py -m FallenRobot 5 | -------------------------------------------------------------------------------- /start_service.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: This runs the batch file as an admin - required UAC to be off 3 | :: This is just an asty hack in to get job done cause we host it on windows dedi. 4 | :: BatchGotAdmin 5 | :------------------------------------- 6 | REM --> Check for permissions 7 | >nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" 8 | 9 | REM --> If error flag set, we do not have admin. 10 | if '%errorlevel%' NEQ '0' ( 11 | echo Requesting administrative privileges... 12 | goto UACPrompt 13 | ) else ( goto gotAdmin ) 14 | 15 | :UACPrompt 16 | echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs" 17 | set params = %*:"="" 18 | echo UAC.ShellExecute "cmd.exe", "/c %~s0 %params%", "", "runas", 1 >> "%temp%\getadmin.vbs" 19 | 20 | "%temp%\getadmin.vbs" 21 | del "%temp%\getadmin.vbs" 22 | exit /B 23 | 24 | :gotAdmin 25 | pushd "%CD%" 26 | CD /D "%~dp0" 27 | :-------------------------------------- 28 | :: your commands begin from this point. 29 | :: stops the service and then starts it 30 | net stop FallenRobot 31 | net start FallenRobot 32 | --------------------------------------------------------------------------------