├── runtime.txt ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── python-app.yml │ └── main.yml ├── Procfile ├── SiestaRobot ├── modules │ ├── helper_funcs │ │ ├── __init__.py │ │ ├── telethn │ │ │ ├── __init__.py │ │ │ └── chatstatus.py │ │ ├── admin_rights.py │ │ ├── regex_helper.py │ │ ├── readable_time.py │ │ ├── alternate.py │ │ ├── filters.py │ │ └── channel_mode.py │ ├── tools.py │ ├── musichelp.py │ ├── sql │ │ ├── __init__.py │ │ ├── afk_redis │ │ ├── night_mode_sql.py │ │ ├── forceSubscribe_sql.py │ │ ├── nsfw_sql.py │ │ ├── rules_sql.py │ │ ├── language_sql.py │ │ ├── nsfw_watch_sql.py │ │ ├── approve_sql.py │ │ ├── blacklistusers_sql.py │ │ ├── antichannel_sql.py │ │ ├── userinfo_sql.py │ │ ├── afk_sql.py │ │ ├── log_channel_sql.py │ │ ├── reporting_sql.py │ │ └── disable_sql.py │ ├── encrypt.py │ ├── apakah.py │ ├── truth_and_dare.py │ ├── urbandictionary.py │ ├── alive.py │ ├── core.py │ ├── tagall.py │ ├── __init__.py │ ├── pokedex.py │ ├── shell.py │ ├── cash.py │ ├── texttospeech.py │ ├── pyrogithub.py │ ├── json.py │ ├── carbon.py │ ├── currency_converter.py │ ├── wallpaper.py │ ├── antichannel.py │ ├── webshot.py │ ├── wiki.py │ ├── reddit.py │ ├── random_api.py │ ├── debug.py │ ├── gtranslator.py │ ├── speed_test.py │ ├── language.py │ ├── paste.py │ ├── tiny.py │ ├── kamuii.py │ ├── mentionsall.py │ ├── purge.py │ ├── shippering.py │ ├── country.py │ ├── weather.py │ ├── dev.py │ ├── urluploader.py │ ├── quotes.py │ ├── zombies.py │ ├── truth_and_dare_string.py │ ├── speachtotext.py │ ├── whatanime.py │ ├── ping.py │ ├── img_pdf.py │ ├── eval.py │ ├── gettime.py │ ├── info.py │ ├── sangmata.py │ ├── rembg.py │ ├── imdb.py │ └── bug.py ├── resources │ ├── Siesta.jpg │ ├── Siesta.png │ ├── Siesta3.jpg │ ├── default.ttf │ ├── fonts │ │ ├── 0.ttf │ │ ├── 1.ttf │ │ ├── 2.ttf │ │ ├── 3.ttf │ │ ├── 4.ttf │ │ ├── 5.ttf │ │ ├── 6.ttf │ │ ├── 7.ttf │ │ ├── 9.ttf │ │ ├── 11.otf │ │ ├── 12.otf │ │ └── default.ttf │ └── siesta_stickers.png ├── services │ ├── types │ │ └── __init__.py │ ├── dark.py │ ├── sections.py │ ├── keyboard.py │ └── tasks.py ├── language │ ├── __init__.py │ └── langs.py ├── elevated_users.json ├── utils │ ├── filter_groups.py │ ├── paste.py │ ├── arqapi.py │ ├── adminperms.py │ ├── pastebin.py │ ├── errors.py │ ├── uputils.py │ ├── http.py │ └── permissions.py ├── ex_plugins │ ├── chatbot.py │ └── errors.py ├── mongo.py ├── confing.py └── config.py ├── .deepsource.toml ├── Dockerfile ├── requirements.txt ├── .gitignore └── README.md /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.1 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @shiinobu 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 -m SiestaRobot 2 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/__init__.py: -------------------------------------------------------------------------------- 1 | """Helpers, also known as Utilities.""" 2 | -------------------------------------------------------------------------------- /SiestaRobot/resources/Siesta.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/Siesta.jpg -------------------------------------------------------------------------------- /SiestaRobot/resources/Siesta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/Siesta.png -------------------------------------------------------------------------------- /SiestaRobot/resources/Siesta3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/Siesta3.jpg -------------------------------------------------------------------------------- /SiestaRobot/resources/default.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/default.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/0.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/0.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/1.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/2.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/3.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/3.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/4.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/4.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/5.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/5.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/6.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/6.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/7.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/7.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/9.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/9.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/11.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/11.otf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/12.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/12.otf -------------------------------------------------------------------------------- /SiestaRobot/resources/fonts/default.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/fonts/default.ttf -------------------------------------------------------------------------------- /SiestaRobot/resources/siesta_stickers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shiinobu/SiestaRobot/HEAD/SiestaRobot/resources/siesta_stickers.png -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "python" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | runtime_version = "3.x.x" 9 | -------------------------------------------------------------------------------- /SiestaRobot/modules/tools.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot.modules.language import gs 2 | 3 | 4 | def helps(chat): 5 | return gs(chat, "tools_help") 6 | 7 | 8 | __mod_name__ = "Tools" 9 | -------------------------------------------------------------------------------- /SiestaRobot/modules/musichelp.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot.modules.language import gs 2 | 3 | 4 | def helps(chat): 5 | return gs(chat, "musicplayer_help") 6 | 7 | 8 | __mod_name__ = "Musicplayer" -------------------------------------------------------------------------------- /SiestaRobot/services/types/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | from .InlineQueryResult import (InlineQueryResultAudio, 4 | InlineQueryResultCachedDocument) 5 | -------------------------------------------------------------------------------- /SiestaRobot/language/__init__.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot.language.langs import langs 2 | 3 | get_string = langs.get_string 4 | reload_strings = langs.reload_strings 5 | get_languages = langs.get_languages 6 | get_language = langs.get_language -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "06:00" 8 | timezone: "Asia/Jakarta" 9 | labels: 10 | - "dependencies" 11 | open-pull-requests-limit: 20 12 | -------------------------------------------------------------------------------- /SiestaRobot/elevated_users.json: -------------------------------------------------------------------------------- 1 | { 2 | "devs": [], 3 | "supports": [], 4 | "whitelists": [], 5 | "spammers": [], 6 | "dragons": [], 7 | "demons": [], 8 | "wolfes": [], 9 | "heroes": [], 10 | "tigers": [], 11 | "sudos": [] 12 | } 13 | -------------------------------------------------------------------------------- /SiestaRobot/services/dark.py: -------------------------------------------------------------------------------- 1 | def get_arg(message): 2 | msg = message.text 3 | msg = msg.replace(" ", "", 1) if msg[1] == " " else msg 4 | split = msg[1:].replace("\n", " \n").split(" ") 5 | if " ".join(split[1:]).strip() == "": 6 | return "" 7 | return " ".join(split[1:]) 8 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/telethn/__init__.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import DEV_USERS, DRAGONS, DEMONS, 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 | -------------------------------------------------------------------------------- /SiestaRobot/utils/filter_groups.py: -------------------------------------------------------------------------------- 1 | chat_filters_group = 1 2 | chatbot_group = 2 3 | karma_positive_group = 3 4 | karma_negative_group = 4 5 | regex_group = 5 6 | welcome_captcha_group = 6 7 | antiflood_group = 7 8 | nsfw_detect_group = 8 9 | blacklist_filters_group = 9 10 | pipes_group = 10 11 | taglog_group = 11 12 | chat_watcher_group = 12 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:11 2 | FROM python:3.10.1-slim-buster 3 | 4 | WORKDIR /SiestaRobot/ 5 | 6 | RUN apt-get update && apt-get upgrade -y 7 | RUN apt-get -y install git 8 | RUN python3.9 -m pip install -U pip 9 | RUN apt-get install -y wget python3-pip curl bash neofetch ffmpeg software-properties-common 10 | 11 | COPY requirements.txt . 12 | 13 | RUN pip3 install wheel 14 | RUN pip3 install --no-cache-dir -U -r requirements.txt 15 | 16 | COPY . . 17 | CMD ["python3.9", "-m", "SiestaRobot"] 18 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/__init__.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import DB_URL 2 | from sqlalchemy import create_engine 3 | from sqlalchemy.ext.declarative import declarative_base 4 | from sqlalchemy.orm import scoped_session, sessionmaker 5 | 6 | 7 | def start() -> scoped_session: 8 | engine = create_engine(DB_URL, client_encoding="utf8") 9 | BASE.metadata.bind = engine 10 | BASE.metadata.create_all(engine) 11 | return scoped_session(sessionmaker(bind=engine, autoflush=True)) 12 | 13 | 14 | BASE = declarative_base() 15 | SESSION = start() 16 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/afk_redis: -------------------------------------------------------------------------------- 1 | from NaoRobot import REDIS 2 | 3 | # AFK 4 | def is_user_afk(userid): 5 | rget = REDIS.get(f"is_afk_{userid}") 6 | if rget: 7 | return True 8 | else: 9 | return False 10 | 11 | 12 | def start_afk(userid, reason): 13 | REDIS.set(f"is_afk_{userid}", reason) 14 | 15 | 16 | def afk_reason(userid): 17 | return strb(REDIS.get(f"is_afk_{userid}")) 18 | 19 | 20 | def end_afk(userid): 21 | REDIS.delete(f"is_afk_{userid}") 22 | return True 23 | 24 | 25 | # Helpers 26 | def strb(redis_string): 27 | return str(redis_string) 28 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/admin_rights.py: -------------------------------------------------------------------------------- 1 | from telegram import User, Chat 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 | -------------------------------------------------------------------------------- /SiestaRobot/services/sections.py: -------------------------------------------------------------------------------- 1 | n = "\n" 2 | w = " " 3 | 4 | 5 | bold = lambda x: f"**{x}:** " 6 | bold_ul = lambda x: f"**--{x}:**-- " 7 | 8 | mono = lambda x: f"`{x}`{n}" 9 | 10 | 11 | def section( 12 | title: str, 13 | body: dict, 14 | indent: int = 2, 15 | underline: bool = False, 16 | ) -> str: 17 | 18 | text = (bold_ul(title) + n) if underline else bold(title) + n 19 | 20 | for key, value in body.items(): 21 | text += ( 22 | indent * w 23 | + bold(key) 24 | + ((value[0] + n) if isinstance(value, list) else mono(value)) 25 | ) 26 | return text 27 | -------------------------------------------------------------------------------- /SiestaRobot/utils/paste.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 | -------------------------------------------------------------------------------- /SiestaRobot/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 | -------------------------------------------------------------------------------- /SiestaRobot/ex_plugins/chatbot.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot.mongo import client as db_x 2 | 3 | lydia = db_x["CHATBOT"] 4 | 5 | 6 | def add_chat(chat_id): 7 | stark = lydia.find_one({"chat_id": chat_id}) 8 | if stark: 9 | return False 10 | lydia.insert_one({"chat_id": chat_id}) 11 | return True 12 | 13 | 14 | def remove_chat(chat_id): 15 | stark = lydia.find_one({"chat_id": chat_id}) 16 | if not stark: 17 | return False 18 | lydia.delete_one({"chat_id": chat_id}) 19 | return True 20 | 21 | 22 | def get_all_chats(): 23 | r = list(lydia.find()) 24 | if r: 25 | return r 26 | return False 27 | 28 | 29 | def get_session(chat_id): 30 | stark = lydia.find_one({"chat_id": chat_id}) 31 | if not stark: 32 | return False 33 | return stark 34 | -------------------------------------------------------------------------------- /SiestaRobot/modules/encrypt.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import telethn as tbot 2 | import os 3 | from SiestaRobot.events import register 4 | import secureme 5 | 6 | 7 | @register(pattern="^/encrypt ?(.*)") 8 | async def hmm(event): 9 | if event.reply_to_msg_id: 10 | lel = await event.get_reply_message() 11 | cmd = lel.text 12 | else: 13 | cmd = event.pattern_match.group(1) 14 | Text = cmd 15 | k = secureme.encrypt(Text) 16 | await event.reply(k) 17 | 18 | 19 | @register(pattern="^/decrypt ?(.*)") 20 | async def hmm(event): 21 | if event.reply_to_msg_id: 22 | lel = await event.get_reply_message() 23 | ok = lel.text 24 | else: 25 | ok = event.pattern_match.group(1) 26 | Text = ok 27 | k = secureme.decrypt(Text) 28 | await event.reply(k) 29 | -------------------------------------------------------------------------------- /SiestaRobot/mongo.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | from motor import motor_asyncio 4 | from pymongo import MongoClient 5 | from pymongo.errors import ServerSelectionTimeoutError 6 | from SiestaRobot import MONGO_DB_URI 7 | from SiestaRobot.confing import get_int_key, get_str_key 8 | 9 | 10 | MONGO_PORT = get_int_key("27017") 11 | MONGO_DB_URI = get_str_key("MONGO_DB_URI") 12 | MONGO_DB = "SiestaRobot" 13 | 14 | 15 | client = MongoClient() 16 | client = MongoClient(MONGO_DB_URI, MONGO_PORT)[MONGO_DB] 17 | motor = motor_asyncio.AsyncIOMotorClient(MONGO_DB_URI, MONGO_PORT) 18 | db = motor[MONGO_DB] 19 | db = client["VainBot"] 20 | try: 21 | asyncio.get_event_loop().run_until_complete(motor.server_info()) 22 | except ServerSelectionTimeoutError: 23 | sys.exit(log.critical("Can't connect to mongodb! Exiting...")) 24 | -------------------------------------------------------------------------------- /SiestaRobot/modules/apakah.py: -------------------------------------------------------------------------------- 1 | import random 2 | from SiestaRobot.events import register 3 | from SiestaRobot import telethn 4 | 5 | APAKAH_STRING = ["Iya", 6 | "Tidak", 7 | "Mungkin", 8 | "Mungkin Tidak", 9 | "Bisa jadi", 10 | "Mungkin Tidak", 11 | "Tidak Mungkin", 12 | "YNTKTS", 13 | "Pala bapak kau pecah", 14 | "Apa iya?", 15 | "Tanya aja sama mamak kau tu pler" 16 | ] 17 | 18 | 19 | @register(pattern="^/apakah ?(.*)") 20 | async def apakah(event): 21 | quew = event.pattern_match.group(1) 22 | if not quew: 23 | await event.reply('Berikan saya pertanyaan 😐') 24 | return 25 | await event.reply(random.choice(APAKAH_STRING)) 26 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/readable_time.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def get_readable_time(seconds: int) -> str: 5 | count = 0 6 | readable_time = "" 7 | time_list = [] 8 | time_suffix_list = ["s", "m", "h", "days"] 9 | 10 | while count < 4: 11 | count += 1 12 | if count < 3: 13 | remainder, result = divmod(seconds, 60) 14 | else: 15 | remainder, result = divmod(seconds, 24) 16 | if seconds == 0 and remainder == 0: 17 | break 18 | time_list.append(int(result)) 19 | seconds = int(remainder) 20 | 21 | for x in range(len(time_list)): 22 | time_list[x] = str(time_list[x]) + time_suffix_list[x] 23 | if len(time_list) == 4: 24 | readable_time += time_list.pop() + ", " 25 | 26 | time_list.reverse() 27 | readable_time += ":".join(time_list) 28 | 29 | return readable_time 30 | -------------------------------------------------------------------------------- /SiestaRobot/utils/arqapi.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | from random import randint 4 | from time import time 5 | 6 | import aiohttp 7 | from SiestaRobot import aiohttpsession 8 | from aiohttp import ClientSession 9 | 10 | from google_trans_new import google_translator 11 | from Python_ARQ import ARQ 12 | from search_engine_parser import GoogleSearch 13 | 14 | from SiestaRobot import BOT_ID, OWNER_ID, ARQ_API_URL, ARQ_API_KEY 15 | from SiestaRobot import pbot 16 | 17 | ARQ_API = "WZQUBA-PFAZQJ-OMIINH-MIVHYM-ARQ" 18 | ARQ_API_KEY = "WZQUBA-PFAZQJ-OMIINH-MIVHYM-ARQ" 19 | SUDOERS = OWNER_ID 20 | ARQ_API_URL = "https://thearq.tech" 21 | 22 | # Aiohttp Client 23 | print("[INFO]: INITIALZING AIOHTTP SESSION") 24 | aiohttpsession = ClientSession() 25 | # ARQ Client 26 | print("[INFO]: INITIALIZING ARQ CLIENT") 27 | arq = ARQ(ARQ_API_URL, ARQ_API_KEY, aiohttpsession) 28 | 29 | app = pbot 30 | import socket 31 | -------------------------------------------------------------------------------- /SiestaRobot/modules/truth_and_dare.py: -------------------------------------------------------------------------------- 1 | import html 2 | import random 3 | import SiestaRobot.modules.truth_and_dare_string as truth_and_dare_string 4 | from SiestaRobot import dispatcher 5 | from telegram import ParseMode, Update, Bot 6 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 7 | from telegram.ext import CallbackContext, run_async 8 | 9 | 10 | def truth(update: Update, context: CallbackContext): 11 | args = context.args 12 | update.effective_message.reply_text(random.choice(truth_and_dare_string.TRUTH)) 13 | 14 | 15 | def dare(update: Update, context: CallbackContext): 16 | args = context.args 17 | update.effective_message.reply_text(random.choice(truth_and_dare_string.DARE)) 18 | 19 | 20 | TRUTH_HANDLER = DisableAbleCommandHandler("truth", truth, run_async=True) 21 | DARE_HANDLER = DisableAbleCommandHandler("dare", dare, run_async=True) 22 | 23 | dispatcher.add_handler(TRUTH_HANDLER) 24 | dispatcher.add_handler(DARE_HANDLER) 25 | -------------------------------------------------------------------------------- /SiestaRobot/modules/urbandictionary.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from SiestaRobot import dispatcher 3 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 4 | from telegram import ParseMode, Update 5 | from telegram.ext import CallbackContext, run_async 6 | 7 | 8 | def ud(update: Update, context: CallbackContext): 9 | message = update.effective_message 10 | text = message.text[len("/ud ") :] 11 | results = requests.get( 12 | f"https://api.urbandictionary.com/v0/define?term={text}" 13 | ).json() 14 | try: 15 | reply_text = f'*{text}*\n\n{results["list"][0]["definition"]}\n\n_{results["list"][0]["example"]}_' 16 | except: 17 | reply_text = "No results found." 18 | message.reply_text(reply_text, parse_mode=ParseMode.MARKDOWN) 19 | 20 | 21 | UD_HANDLER = DisableAbleCommandHandler(["ud"], ud, run_async=True) 22 | 23 | dispatcher.add_handler(UD_HANDLER) 24 | 25 | __command_list__ = ["ud"] 26 | __handlers__ = [UD_HANDLER] 27 | -------------------------------------------------------------------------------- /SiestaRobot/confing.py: -------------------------------------------------------------------------------- 1 | from envparse import env 2 | from SiestaRobot import LOGGER 3 | 4 | DEFAULTS = { 5 | "LOAD_MODULES": True, 6 | } 7 | 8 | 9 | def get_str_key(name, required=False): 10 | if name in DEFAULTS: 11 | default = DEFAULTS[name] 12 | else: 13 | default = None 14 | if not (data := env.str(name, default=default)) and not required: 15 | LOGGER.warn("No str key: " + name) 16 | return None 17 | elif not data: 18 | LOGGER.critical("No str key: " + name) 19 | sys.exit(2) 20 | else: 21 | return data 22 | 23 | 24 | def get_int_key(name, required=False): 25 | if name in DEFAULTS: 26 | default = DEFAULTS[name] 27 | else: 28 | default = None 29 | if not (data := env.int(name, default=default)) and not required: 30 | LOGGER.warn("No int key: " + name) 31 | return None 32 | elif not data: 33 | LOGGER.critical("No int key: " + name) 34 | sys.exit(2) 35 | else: 36 | return data 37 | -------------------------------------------------------------------------------- /.github/workflows/python-app.yml: -------------------------------------------------------------------------------- 1 | name: FailCheck 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | max-parallel: 5 11 | matrix: 12 | python-version: [3.9] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | sudo apt-get install libpq-dev 23 | python -m pip install --upgrade pip 24 | pip install -r requirements.txt 25 | pip install flake8 flake8-print flake8-quotes 26 | - name: Check for showstoppers 27 | run: | 28 | flake8 . --count --select=E999 --show-source --statistics 29 | shellcheck: 30 | 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - uses: actions/checkout@v1 35 | - name: Check for install script errors 36 | uses: ludeeus/action-shellcheck@0.1.0 37 | -------------------------------------------------------------------------------- /SiestaRobot/utils/adminperms.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import filters 3 | from pyrogram.types import ChatPermissions, Message 4 | from SiestaRobot import pbot as app 5 | 6 | 7 | async def member_permissions(chat_id: int, user_id: int): 8 | perms = [] 9 | member = await app.get_chat_member(chat_id, user_id) 10 | if member.can_post_messages: 11 | perms.append("can_post_messages") 12 | if member.can_edit_messages: 13 | perms.append("can_edit_messages") 14 | if member.can_delete_messages: 15 | perms.append("can_delete_messages") 16 | if member.can_restrict_members: 17 | perms.append("can_restrict_members") 18 | if member.can_promote_members: 19 | perms.append("can_promote_members") 20 | if member.can_change_info: 21 | perms.append("can_change_info") 22 | if member.can_invite_users: 23 | perms.append("can_invite_users") 24 | if member.can_pin_messages: 25 | perms.append("can_pin_messages") 26 | if member.can_manage_voice_chats: 27 | perms.append("can_manage_voice_chats") 28 | return perms 29 | -------------------------------------------------------------------------------- /SiestaRobot/services/keyboard.py: -------------------------------------------------------------------------------- 1 | from pykeyboard import InlineKeyboard 2 | from pyrogram.types import InlineKeyboardButton as Ikb 3 | 4 | from SiestaRobot.utils.functions import get_urls_from_text as is_url 5 | 6 | 7 | def keyboard(buttons_list, row_width: int = 2): 8 | """ 9 | Buttons builder, pass buttons in a list and it will 10 | return pyrogram.types.IKB object 11 | Ex: keyboard([["click here", "https://google.com"]]) 12 | if theres, a url, it will make url button, else callback button 13 | """ 14 | buttons = InlineKeyboard(row_width=row_width) 15 | data = [ 16 | ( 17 | Ikb(text=str(i[0]), callback_data=str(i[1])) 18 | if not is_url(i[1]) 19 | else Ikb(text=str(i[0]), url=str(i[1])) 20 | ) 21 | for i in buttons_list 22 | ] 23 | buttons.add(*data) 24 | return buttons 25 | 26 | 27 | def ikb(data: dict, row_width: int = 2): 28 | """ 29 | Converts a dict to pyrogram buttons 30 | Ex: dict_to_keyboard({"click here": "this is callback data"}) 31 | """ 32 | return keyboard(data.items(), row_width=row_width) 33 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/night_mode_sql.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Boolean, Column, String, UnicodeText 2 | from SiestaRobot.modules.sql import BASE, SESSION 3 | 4 | 5 | class Nightmode(BASE): 6 | __tablename__ = "nightmode" 7 | chat_id = Column(String(14), primary_key=True) 8 | 9 | def __init__(self, chat_id): 10 | self.chat_id = chat_id 11 | 12 | 13 | Nightmode.__table__.create(checkfirst=True) 14 | 15 | 16 | def add_nightmode(chat_id: str): 17 | nightmoddy = Nightmode(str(chat_id)) 18 | SESSION.add(nightmoddy) 19 | SESSION.commit() 20 | 21 | 22 | def rmnightmode(chat_id: str): 23 | rmnightmoddy = SESSION.query(Nightmode).get(str(chat_id)) 24 | if rmnightmoddy: 25 | SESSION.delete(rmnightmoddy) 26 | SESSION.commit() 27 | 28 | 29 | def get_all_chat_id(): 30 | stark = SESSION.query(Nightmode).all() 31 | SESSION.close() 32 | return stark 33 | 34 | 35 | def is_nightmode_indb(chat_id: str): 36 | try: 37 | s__ = SESSION.query(Nightmode).get(str(chat_id)) 38 | if s__: 39 | return str(s__.chat_id) 40 | finally: 41 | SESSION.close() 42 | -------------------------------------------------------------------------------- /SiestaRobot/modules/alive.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from platform import python_version as kontol 4 | from telethon import events, Button 5 | from telegram import __version__ as telever 6 | from telethon import __version__ as tlhver 7 | from pyrogram import __version__ as pyrover 8 | from SiestaRobot.events import register 9 | from SiestaRobot import telethn as tbot 10 | 11 | 12 | PHOTO = "https://telegra.ph/file/ff2fa22dfa6ae838cc6cd.jpg" 13 | 14 | @register(pattern=("/alive")) 15 | async def awake(event): 16 | TEXT = f"**Hi [{event.sender.first_name}](tg://user?id={event.sender.id}), I'm Siesta Robot.** \n\n" 17 | TEXT += "💠 **I'm Working Properly** \n\n" 18 | TEXT += f"💠 **My Master : [Vain](https://t.me/saint_foire)** \n\n" 19 | TEXT += f"💠 **Library Version :** `{telever}` \n\n" 20 | TEXT += f"💠 **Telethon Version :** `{tlhver}` \n\n" 21 | TEXT += f"💠 **Pyrogram Version :** `{pyrover}` \n\n" 22 | TEXT += "**Thanks For Adding Me Here ❤️**" 23 | BUTTON = [[Button.url("Help", "https://t.me/Siestaxbot?start=help"), Button.url("Support", "https://t.me/machinaxsupport")]] 24 | await tbot.send_file(event.chat_id, PHOTO, caption=TEXT, buttons=BUTTON) 25 | -------------------------------------------------------------------------------- /SiestaRobot/modules/core.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import telethn as tbot 2 | from SiestaRobot.events import register 3 | import os 4 | import asyncio 5 | import os 6 | import time 7 | from datetime import datetime 8 | from SiestaRobot import OWNER_ID, DEV_USERS 9 | from SiestaRobot import TEMP_DOWNLOAD_DIRECTORY as path 10 | from SiestaRobot import TEMP_DOWNLOAD_DIRECTORY 11 | from datetime import datetime 12 | water = './SiestaRobot/resources/Siesta.jpg' 13 | client = tbot 14 | 15 | @register(pattern=r"^/send ?(.*)") 16 | async def Prof(event): 17 | if event.sender_id == OWNER_ID: 18 | pass 19 | else: 20 | return 21 | thumb = water 22 | message_id = event.message.id 23 | input_str = event.pattern_match.group(1) 24 | the_plugin_file = "./SiestaRobot/modules/{}.py".format(input_str) 25 | if os.path.exists(the_plugin_file): 26 | message_id = event.message.id 27 | await event.client.send_file( 28 | event.chat_id, 29 | the_plugin_file, 30 | force_document=True, 31 | allow_cache=False, 32 | thumb=thumb, 33 | reply_to=message_id, 34 | ) 35 | else: 36 | await event.reply("No File Found!") 37 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/forceSubscribe_sql.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, String, Numeric, Boolean 2 | from SiestaRobot.modules.sql import BASE, SESSION 3 | 4 | 5 | class forceSubscribe(BASE): 6 | __tablename__ = "forceSubscribe" 7 | chat_id = Column(Numeric, primary_key=True) 8 | channel = Column(String) 9 | 10 | def __init__(self, chat_id, channel): 11 | self.chat_id = chat_id 12 | self.channel = channel 13 | 14 | 15 | forceSubscribe.__table__.create(checkfirst=True) 16 | 17 | 18 | def fs_settings(chat_id): 19 | try: 20 | return ( 21 | SESSION.query(forceSubscribe) 22 | .filter(forceSubscribe.chat_id == chat_id) 23 | .one() 24 | ) 25 | except: 26 | return None 27 | finally: 28 | SESSION.close() 29 | 30 | 31 | def add_channel(chat_id, channel): 32 | adder = SESSION.query(forceSubscribe).get(chat_id) 33 | if adder: 34 | adder.channel = channel 35 | else: 36 | adder = forceSubscribe(chat_id, channel) 37 | SESSION.add(adder) 38 | SESSION.commit() 39 | 40 | 41 | def disapprove(chat_id): 42 | rem = SESSION.query(forceSubscribe).get(chat_id) 43 | if rem: 44 | SESSION.delete(rem) 45 | SESSION.commit() 46 | -------------------------------------------------------------------------------- /SiestaRobot/modules/tagall.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from telethon import events 3 | from telethon.tl.types import ChannelParticipantsAdmins 4 | from SiestaRobot import telethn 5 | from SiestaRobot.events import register as tomori 6 | 7 | 8 | @tomori(pattern="^/tagall ?(.*)") 9 | async def _(event): 10 | if event.fwd_from: 11 | return 12 | mentions = "Hi Friends I'm Siesta I Call To All Of You" 13 | chat = await event.get_input_chat() 14 | async for x in telethn.iter_participants(chat, 100): 15 | mentions += f" \n [{x.first_name}](tg://user?id={x.id})" 16 | await event.reply(mentions) 17 | await event.delete() 18 | 19 | 20 | @tomori(pattern="^/users ?(.*)") 21 | async def _(event): 22 | if event.fwd_from: 23 | return 24 | mentions = "Users : " 25 | chat = await event.get_input_chat() 26 | async for x in telethn.iter_participants(chat, filter=ChannelParticipantsAdmins): 27 | mentions += f" \n [{x.first_name}](tg://user?id={x.id})" 28 | reply_message = None 29 | if event.reply_to_msg_id: 30 | reply_message = await event.get_reply_message() 31 | await reply_message.reply(mentions) 32 | else: 33 | await event.reply(mentions) 34 | await event.delete() 35 | 36 | 37 | __mod_name__ = "Tagger" 38 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the Geez-Userbot branch 8 | push: 9 | branches: [ main] 10 | pull_request: 11 | branches: [ main] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | build: 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | # Steps represent a sequence of tasks that will be executed as part of the job 24 | steps: 25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 26 | - uses: actions/checkout@v2 27 | 28 | # Runs a single command using the runners shell 29 | - name: Run a one-line script 30 | run: echo Hello, world! 31 | 32 | # Runs a set of commands using the runners shell 33 | - name: Run a multi-line script 34 | run: | 35 | echo Add other actions to build, 36 | echo test, and deploy your project. 37 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/alternate.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from telegram import error, ChatAction 3 | 4 | 5 | def send_message(message, text, *args, **kwargs): 6 | try: 7 | return message.reply_text(text, *args, **kwargs) 8 | except error.BadRequest as err: 9 | if str(err) == "Reply message not found": 10 | return message.reply_text(text, quote=False, *args, **kwargs) 11 | 12 | 13 | def typing_action(func): 14 | """Sends typing action while processing func command.""" 15 | 16 | @wraps(func) 17 | def command_func(update, context, *args, **kwargs): 18 | context.bot.send_chat_action( 19 | chat_id=update.effective_chat.id, action=ChatAction.TYPING 20 | ) 21 | return func(update, context, *args, **kwargs) 22 | 23 | return command_func 24 | 25 | 26 | def send_action(action): 27 | """Sends `action` while processing func command.""" 28 | 29 | def decorator(func): 30 | @wraps(func) 31 | def command_func(update, context, *args, **kwargs): 32 | context.bot.send_chat_action( 33 | chat_id=update.effective_chat.id, action=action 34 | ) 35 | return func(update, context, *args, **kwargs) 36 | 37 | return command_func 38 | 39 | return decorator 40 | -------------------------------------------------------------------------------- /SiestaRobot/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import LOAD, NO_LOAD, LOGGER 2 | import sys 3 | 4 | 5 | def __list_all_modules(): 6 | from os.path import dirname, basename, isfile 7 | import glob 8 | 9 | # This generates a list of modules in this folder for the * in __main__ to work. 10 | mod_paths = glob.glob(dirname(__file__) + "/*.py") 11 | all_modules = [ 12 | basename(f)[:-3] 13 | for f in mod_paths 14 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 15 | ] 16 | 17 | if LOAD or NO_LOAD: 18 | to_load = LOAD 19 | if to_load: 20 | if not all( 21 | any(mod == module_name for module_name in all_modules) 22 | for mod in to_load 23 | ): 24 | LOGGER.error("[Charlotte] Invalid loadorder names. Quitting.") 25 | sys.exit(1) 26 | 27 | all_modules = sorted(set(all_modules) - set(to_load)) 28 | to_load = list(all_modules) + to_load 29 | 30 | else: 31 | to_load = all_modules 32 | 33 | if NO_LOAD: 34 | LOGGER.info("[Charlotte] Not loading: {}".format(NO_LOAD)) 35 | return [item for item in to_load if item not in NO_LOAD] 36 | 37 | return to_load 38 | 39 | return all_modules 40 | 41 | 42 | ALL_MODULES = __list_all_modules() 43 | LOGGER.info("[Charlotte] Modules to load: %s", str(ALL_MODULES)) 44 | __all__ = ALL_MODULES + ["ALL_MODULES"] 45 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/nsfw_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from sqlalchemy import Column, String 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | # |----------------------------------| 5 | # | Test Module by @EverythingSuckz | 6 | # | Kang with Credits | 7 | # |----------------------------------| 8 | class NSFWChats(BASE): 9 | __tablename__ = "nsfw_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 | NSFWChats.__table__.create(checkfirst=True) 16 | INSERTION_LOCK = threading.RLock() 17 | 18 | 19 | def is_nsfw(chat_id): 20 | try: 21 | chat = SESSION.query(NSFWChats).get(str(chat_id)) 22 | if chat: 23 | return True 24 | else: 25 | return False 26 | finally: 27 | SESSION.close() 28 | 29 | def set_nsfw(chat_id): 30 | with INSERTION_LOCK: 31 | nsfwchat = SESSION.query(NSFWChats).get(str(chat_id)) 32 | if not nsfwchat: 33 | nsfwchat = NSFWChats(str(chat_id)) 34 | SESSION.add(nsfwchat) 35 | SESSION.commit() 36 | 37 | def rem_nsfw(chat_id): 38 | with INSERTION_LOCK: 39 | nsfwchat = SESSION.query(NSFWChats).get(str(chat_id)) 40 | if nsfwchat: 41 | SESSION.delete(nsfwchat) 42 | SESSION.commit() 43 | 44 | 45 | def get_all_nsfw_chats(): 46 | try: 47 | return SESSION.query(NSFWChats.chat_id).all() 48 | finally: 49 | SESSION.close() 50 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/rules_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | from sqlalchemy import Column, String, UnicodeText, distinct, func 5 | 6 | 7 | class Rules(BASE): 8 | __tablename__ = "rules" 9 | chat_id = Column(String(14), primary_key=True) 10 | rules = Column(UnicodeText, default="") 11 | 12 | def __init__(self, chat_id): 13 | self.chat_id = chat_id 14 | 15 | def __repr__(self): 16 | return "".format(self.chat_id, self.rules) 17 | 18 | 19 | Rules.__table__.create(checkfirst=True) 20 | 21 | INSERTION_LOCK = threading.RLock() 22 | 23 | 24 | def set_rules(chat_id, rules_text): 25 | with INSERTION_LOCK: 26 | rules = SESSION.query(Rules).get(str(chat_id)) 27 | if not rules: 28 | rules = Rules(str(chat_id)) 29 | rules.rules = rules_text 30 | 31 | SESSION.add(rules) 32 | SESSION.commit() 33 | 34 | 35 | def get_rules(chat_id): 36 | rules = SESSION.query(Rules).get(str(chat_id)) 37 | ret = "" 38 | if rules: 39 | ret = rules.rules 40 | 41 | SESSION.close() 42 | return ret 43 | 44 | 45 | def num_chats(): 46 | try: 47 | return SESSION.query(func.count(distinct(Rules.chat_id))).scalar() 48 | finally: 49 | SESSION.close() 50 | 51 | 52 | def migrate_chat(old_chat_id, new_chat_id): 53 | with INSERTION_LOCK: 54 | chat = SESSION.query(Rules).get(str(old_chat_id)) 55 | if chat: 56 | chat.chat_id = str(new_chat_id) 57 | SESSION.commit() 58 | -------------------------------------------------------------------------------- /SiestaRobot/language/langs.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import os 3 | from typing import Dict 4 | 5 | 6 | class Language: 7 | def __init__(self) -> None: 8 | self.languages: Dict = {} 9 | self.reload_strings() 10 | 11 | def get_string(self, lang: str, string: str) -> str: 12 | try: 13 | return self.languages[lang][string] 14 | except KeyError: 15 | # a keyerror happened, the english file must have it 16 | en_string = self.languages["en"].get(string) 17 | if en_string is None: 18 | raise StringNotFound(f"String: ({string}) not found.") 19 | return en_string 20 | 21 | def reload_strings(self) -> None: 22 | for filename in os.listdir(r"./SiestaRobot/language"): 23 | if filename.endswith(".yaml"): 24 | language_name = filename[:-5] 25 | self.languages[language_name] = yaml.safe_load( 26 | open(r"./SiestaRobot/language/" + filename, encoding="utf8") 27 | ) 28 | 29 | def get_languages(self) -> Dict: 30 | to_return: Dict = {} 31 | for language in self.languages: 32 | to_return[language] = self.languages[language]["language"] 33 | return to_return 34 | 35 | def get_language(self, language: str) -> str: 36 | return self.languages[language]["language"] 37 | 38 | 39 | class StringNotFound(Exception): 40 | """ 41 | Raised when language string not found for the 42 | given key inside english locale. 43 | """ 44 | 45 | 46 | langs = Language() -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/language_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Column, String, UnicodeText 4 | from SiestaRobot.modules.sql import SESSION, BASE 5 | 6 | 7 | class ChatLangs(BASE): 8 | __tablename__ = "chatlangs" 9 | chat_id = Column(String(14), primary_key=True) 10 | language = Column(UnicodeText) 11 | 12 | def __init__(self, chat_id, language): 13 | self.chat_id = str(chat_id) # ensure string 14 | self.language = language 15 | 16 | def __repr__(self): 17 | return "Language {} chat {}".format(self.language, self.chat_id) 18 | 19 | 20 | CHAT_LANG = {} 21 | LANG_LOCK = threading.RLock() 22 | ChatLangs.__table__.create(checkfirst=True) 23 | 24 | 25 | def set_lang(chat_id: str, lang: str) -> None: 26 | with LANG_LOCK: 27 | curr = SESSION.query(ChatLangs).get(str(chat_id)) 28 | if not curr: 29 | curr = ChatLangs(str(chat_id), lang) 30 | SESSION.add(curr) 31 | SESSION.flush() 32 | else: 33 | curr.language = lang 34 | 35 | CHAT_LANG[str(chat_id)] = lang 36 | SESSION.commit() 37 | 38 | 39 | def get_chat_lang(chat_id: str) -> str: 40 | lang = CHAT_LANG.get(str(chat_id)) 41 | if lang is None: 42 | lang = "en" 43 | return lang 44 | 45 | 46 | def __load_chat_language() -> None: 47 | global CHAT_LANG 48 | try: 49 | allchats = SESSION.query(ChatLangs).all() 50 | CHAT_LANG = {x.chat_id: x.language for x in allchats} 51 | finally: 52 | SESSION.close() 53 | 54 | 55 | __load_chat_language() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | emoji 3 | lxml 4 | wget 5 | gtts 6 | beautifulsoup4 7 | requests 8 | python-telegram-bot==13.10.0 9 | SQLAlchemy==1.4.29 10 | psycopg2-binary 11 | feedparser 12 | faker 13 | hachoir 14 | pykeyboard 15 | pynewtonmath 16 | aiofiles 17 | ffmpeg-python 18 | spongemock 19 | zalgo-text 20 | geopy 21 | nltk 22 | psutil 23 | aiohttp 24 | Pillow 25 | CurrencyConverter 26 | google_images_download 27 | google-api-python-client 28 | googletrans==4.0.0-rc1 29 | google-trans-new==1.1.9 30 | jikanpy 31 | speedtest-cli 32 | coffeehouse 33 | regex 34 | bleach 35 | wikipedia 36 | markdown2 37 | telethon 38 | telegraph 39 | heroku3 40 | spamwatch 41 | alphabet_detector 42 | pyrate-limiter 43 | cachetools 44 | ujson 45 | pretty_errors 46 | pygithub 47 | TgCrypto 48 | pyrogram==1.3.5 49 | PyDictionary 50 | git+https://github.com/Sorrybabe/downloader 51 | youtube_search_python==1.4.9 52 | youtube_search 53 | lyrics_extractor 54 | asyncio 55 | cloudscraper 56 | dateparser 57 | pymongo 58 | dnspython 59 | secureme 60 | apscheduler 61 | emoji-country-flag 62 | countryinfo 63 | html2text 64 | bs4 65 | redis 66 | pySmartDL 67 | bing_image_downloader 68 | search_engine_parser 69 | pytz 70 | jikanpy 71 | tswift 72 | python-arq 73 | envparse 74 | #profanity (Credits to Julia) 75 | better_profanity 76 | textblob 77 | nudepy 78 | nekos.py 79 | motor 80 | gpytranslate 81 | fontTools 82 | opencv-python-headless 83 | odmantic 84 | tzlocal 85 | pendulum 86 | fuzzysearch 87 | img2pdf 88 | multicolorcaptcha 89 | git+https://github.com/python-telegram-bot/ptbcontrib.git 90 | git+https://github.com/TotallyNotChase/glitch-this.git 91 | pyYAML>=5.1.2 92 | 93 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/filters.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import DEV_USERS, DRAGONS, DEMONS 2 | from telegram import Message 3 | from telegram.ext import MessageFilter 4 | 5 | 6 | class CustomFilters(object): 7 | class _Supporters(MessageFilter): 8 | def filter(self, message: Message): 9 | return bool(message.from_user and message.from_user.id in DEMONS) 10 | 11 | support_filter = _Supporters() 12 | 13 | class _Sudoers(MessageFilter): 14 | def filter(self, message: Message): 15 | return bool(message.from_user and message.from_user.id in DRAGONS) 16 | 17 | sudo_filter = _Sudoers() 18 | 19 | class _Developers(MessageFilter): 20 | def filter(self, message: Message): 21 | return bool(message.from_user and message.from_user.id in DEV_USERS) 22 | 23 | dev_filter = _Developers() 24 | 25 | class _MimeType(MessageFilter): 26 | def __init__(self, mimetype): 27 | self.mime_type = mimetype 28 | self.name = "CustomFilters.mime_type({})".format(self.mime_type) 29 | 30 | def filter(self, message: Message): 31 | return bool( 32 | message.document and message.document.mime_type == self.mime_type, 33 | ) 34 | 35 | mime_type = _MimeType 36 | 37 | class _HasText(MessageFilter): 38 | def filter(self, message: Message): 39 | return bool( 40 | message.text 41 | or message.sticker 42 | or message.photo 43 | or message.document 44 | or message.video, 45 | ) 46 | 47 | has_text = _HasText() 48 | -------------------------------------------------------------------------------- /SiestaRobot/modules/pokedex.py: -------------------------------------------------------------------------------- 1 | # Pokedex Module Credits Pranav Ajay 🐰Github = Red-Aura 🐹 Telegram= @madepranav 2 | 3 | import aiohttp 4 | from pyrogram import filters 5 | from SiestaRobot import pbot as tomori 6 | 7 | 8 | @tomori.on_message(filters.command("pokedex")) 9 | async def PokeDex(_, message): 10 | if len(message.command) != 2: 11 | await message.reply_text("/pokedex Pokemon Name") 12 | return 13 | pokemon = message.text.split(None, 1)[1] 14 | pokedex = f"https://some-random-api.ml/pokedex?pokemon={pokemon}" 15 | async with aiohttp.ClientSession() as session: 16 | async with session.get(pokedex) as request: 17 | if request.status == 404: 18 | return await message.reply_text("Wrong Pokemon Name") 19 | 20 | result = await request.json() 21 | try: 22 | pokemon = result["name"] 23 | pokedex = result["id"] 24 | type = result["type"] 25 | poke_img = f"https://img.pokemondb.net/artwork/large/{pokemon}.jpg" 26 | abilities = result["abilities"] 27 | height = result["height"] 28 | weight = result["weight"] 29 | gender = result["gender"] 30 | stats = result["stats"] 31 | description = result["description"] 32 | caption = f""" 33 | **Pokemon:** `{pokemon}` 34 | **Pokedex:** `{pokedex}` 35 | **Type:** `{type}` 36 | **Abilities:** `{abilities}` 37 | **Height:** `{height}` 38 | **Weight:** `{weight}` 39 | **Gender:** `{gender}` 40 | **Stats:** `{stats}` 41 | **Description:** `{description}`""" 42 | except Exception as e: 43 | print(str(e)) 44 | pass 45 | await message.reply_photo(photo=poke_img, caption=caption) 46 | -------------------------------------------------------------------------------- /SiestaRobot/modules/shell.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | from SiestaRobot import LOGGER, dispatcher 4 | from SiestaRobot.modules.helper_funcs.chat_status import dev_plus 5 | from telegram import ParseMode, Update 6 | from telegram.ext import CallbackContext, CommandHandler 7 | from telegram.ext.dispatcher import run_async 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 | dispatcher.add_handler(SHELL_HANDLER) 47 | __mod_name__ = "Shell" 48 | __command_list__ = ["sh"] 49 | __handlers__ = [SHELL_HANDLER] 50 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/nsfw_watch_sql.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) Midhun KM 2020-2021 2 | # This program is free software: you can redistribute it and/or modify 3 | # it under the terms of the GNU Affero General Public License as published by 4 | # the Free Software Foundation, either version 3 of the License, or 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU Affero General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Affero General Public License 12 | # along with this program. If not, see . 13 | 14 | from sqlalchemy import Column, String 15 | 16 | from SiestaRobot.modules.sql import BASE, SESSION 17 | 18 | 19 | class Nsfwatch(BASE): 20 | __tablename__ = "nsfwatch" 21 | chat_id = Column(String(14), primary_key=True) 22 | 23 | def __init__(self, chat_id): 24 | self.chat_id = chat_id 25 | 26 | 27 | Nsfwatch.__table__.create(checkfirst=True) 28 | 29 | 30 | def add_nsfwatch(chat_id: str): 31 | nsfws = Nsfwatch(str(chat_id)) 32 | SESSION.add(nsfws) 33 | SESSION.commit() 34 | 35 | 36 | def rmnsfwatch(chat_id: str): 37 | nsfwm = SESSION.query(Nsfwatch).get(str(chat_id)) 38 | if nsfwm: 39 | SESSION.delete(nsfwm) 40 | SESSION.commit() 41 | 42 | 43 | def get_all_nsfw_enabled_chat(): 44 | stark = SESSION.query(Nsfwatch).all() 45 | SESSION.close() 46 | return stark 47 | 48 | 49 | def is_nsfwatch_indb(chat_id: str): 50 | try: 51 | s__ = SESSION.query(Nsfwatch).get(str(chat_id)) 52 | if s__: 53 | return str(s__.chat_id) 54 | finally: 55 | SESSION.close() 56 | -------------------------------------------------------------------------------- /SiestaRobot/ex_plugins/errors.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import traceback 3 | from functools import wraps 4 | from pyrogram.errors.exceptions.forbidden_403 import ChatWriteForbidden 5 | from SiestaRobot import EVENT_LOGS, pbot as app 6 | 7 | 8 | def split_limits(text): 9 | if len(text) < 2048: 10 | return [text] 11 | 12 | lines = text.splitlines(True) 13 | small_msg = "" 14 | result = [] 15 | for line in lines: 16 | if len(small_msg) + len(line) < 2048: 17 | small_msg += line 18 | else: 19 | result.append(small_msg) 20 | small_msg = line 21 | else: 22 | result.append(small_msg) 23 | 24 | return result 25 | 26 | 27 | def capture_err(func): 28 | @wraps(func) 29 | async def capture(client, message, *args, **kwargs): 30 | try: 31 | return await func(client, message, *args, **kwargs) 32 | except ChatWriteForbidden: 33 | await app.leave_chat(message.chat.id) 34 | return 35 | except Exception as err: 36 | exc_type, exc_obj, exc_tb = sys.exc_info() 37 | errors = traceback.format_exception( 38 | etype=exc_type, 39 | value=exc_obj, 40 | tb=exc_tb, 41 | ) 42 | error_feedback = split_limits( 43 | "**ERROR** | `{}` | `{}`\n\n```{}```\n\n```{}```\n".format( 44 | 0 if not message.from_user else message.from_user.id, 45 | 0 if not message.chat else message.chat.id, 46 | message.text or message.caption, 47 | "".join(errors), 48 | ), 49 | ) 50 | for x in error_feedback: 51 | await app.send_message(EVENT_LOGS, x) 52 | raise err 53 | 54 | return capture 55 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/approve_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from sqlalchemy import Column, String, UnicodeText, func, distinct 3 | from sqlalchemy.sql.sqltypes import BigInteger 4 | 5 | from SiestaRobot.modules.sql import BASE, SESSION 6 | 7 | class Approvals(BASE): 8 | __tablename__ = "approval" 9 | chat_id = Column(String(14), primary_key=True) 10 | user_id = Column(BigInteger, primary_key=True) 11 | 12 | def __init__(self, chat_id, user_id): 13 | self.chat_id = str(chat_id) # ensure string 14 | self.user_id = user_id 15 | 16 | def __repr__(self): 17 | return "" % self.user_id 18 | 19 | 20 | Approvals.__table__.create(checkfirst=True) 21 | 22 | APPROVE_INSERTION_LOCK = threading.RLock() 23 | 24 | 25 | def approve(chat_id, user_id): 26 | with APPROVE_INSERTION_LOCK: 27 | approve_user = Approvals(str(chat_id), user_id) 28 | SESSION.add(approve_user) 29 | SESSION.commit() 30 | 31 | 32 | def is_approved(chat_id, user_id): 33 | try: 34 | return SESSION.query(Approvals).get((str(chat_id), user_id)) 35 | finally: 36 | SESSION.close() 37 | 38 | 39 | def disapprove(chat_id, user_id): 40 | with APPROVE_INSERTION_LOCK: 41 | disapprove_user = SESSION.query(Approvals).get((str(chat_id), user_id)) 42 | if disapprove_user: 43 | SESSION.delete(disapprove_user) 44 | SESSION.commit() 45 | return True 46 | else: 47 | SESSION.close() 48 | return False 49 | 50 | 51 | def list_approved(chat_id): 52 | try: 53 | return ( 54 | SESSION.query(Approvals) 55 | .filter(Approvals.chat_id == str(chat_id)) 56 | .order_by(Approvals.user_id.asc()) 57 | .all() 58 | ) 59 | finally: 60 | SESSION.close() 61 | -------------------------------------------------------------------------------- /SiestaRobot/utils/pastebin.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | Copyright (c) 2021 TheHamkerCat 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | """ 20 | import socket 21 | from asyncio import get_running_loop 22 | from functools import partial 23 | 24 | 25 | def _netcat(host, port, content): 26 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 27 | s.connect((host, port)) 28 | s.sendall(content.encode()) 29 | s.shutdown(socket.SHUT_WR) 30 | while True: 31 | data = s.recv(4096).decode("utf-8").strip("\n\x00") 32 | if not data: 33 | break 34 | return data 35 | s.close() 36 | 37 | 38 | async def paste(content): 39 | loop = get_running_loop() 40 | link = await loop.run_in_executor( 41 | None, partial(_netcat, "ezup.dev", 9999, content) 42 | ) 43 | return link 44 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/blacklistusers_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | from sqlalchemy import Column, String, UnicodeText 5 | 6 | 7 | class BlacklistUsers(BASE): 8 | __tablename__ = "blacklistusers" 9 | user_id = Column(String(14), primary_key=True) 10 | reason = Column(UnicodeText) 11 | 12 | def __init__(self, user_id, reason=None): 13 | self.user_id = user_id 14 | self.reason = reason 15 | 16 | 17 | BlacklistUsers.__table__.create(checkfirst=True) 18 | 19 | BLACKLIST_LOCK = threading.RLock() 20 | BLACKLIST_USERS = set() 21 | 22 | 23 | def blacklist_user(user_id, reason=None): 24 | with BLACKLIST_LOCK: 25 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 26 | if not user: 27 | user = BlacklistUsers(str(user_id), reason) 28 | else: 29 | user.reason = reason 30 | 31 | SESSION.add(user) 32 | SESSION.commit() 33 | __load_blacklist_userid_list() 34 | 35 | 36 | def unblacklist_user(user_id): 37 | with BLACKLIST_LOCK: 38 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 39 | if user: 40 | SESSION.delete(user) 41 | 42 | SESSION.commit() 43 | __load_blacklist_userid_list() 44 | 45 | 46 | def get_reason(user_id): 47 | user = SESSION.query(BlacklistUsers).get(str(user_id)) 48 | rep = "" 49 | if user: 50 | rep = user.reason 51 | 52 | SESSION.close() 53 | return rep 54 | 55 | 56 | def is_user_blacklisted(user_id): 57 | return user_id in BLACKLIST_USERS 58 | 59 | 60 | def __load_blacklist_userid_list(): 61 | global BLACKLIST_USERS 62 | try: 63 | BLACKLIST_USERS = {int(x.user_id) for x in SESSION.query(BlacklistUsers).all()} 64 | finally: 65 | SESSION.close() 66 | 67 | 68 | __load_blacklist_userid_list() 69 | -------------------------------------------------------------------------------- /SiestaRobot/modules/cash.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | from telegram import Bot, Update 4 | from telegram.ext import CommandHandler, run_async 5 | 6 | from SiestaRobot import dispatcher, CASH_API_KEY 7 | 8 | 9 | def convert(bot: Bot, update: Update): 10 | 11 | args = update.effective_message.text.split(" ", 3) 12 | if len(args) > 1: 13 | 14 | orig_cur_amount = float(args[1]) 15 | 16 | try: 17 | orig_cur = args[2].upper() 18 | except IndexError: 19 | update.effective_message.reply_text( 20 | "You forgot to mention the currency code." 21 | ) 22 | return 23 | 24 | try: 25 | new_cur = args[3].upper() 26 | except IndexError: 27 | update.effective_message.reply_text( 28 | "You forgot to mention the currency code to convert into." 29 | ) 30 | return 31 | 32 | request_url = f"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency={orig_cur}&to_currency={new_cur}&apikey={CASH_API_KEY}" 33 | response = requests.get(request_url).json() 34 | try: 35 | current_rate = float( 36 | response["Realtime Currency Exchange Rate"]["5. Exchange Rate"] 37 | ) 38 | except KeyError: 39 | update.effective_message.reply_text(f"Currency Not Supported.") 40 | return 41 | new_cur_amount = round(orig_cur_amount * current_rate, 5) 42 | update.effective_message.reply_text( 43 | f"{orig_cur_amount} {orig_cur} = {new_cur_amount} {new_cur}" 44 | ) 45 | else: 46 | update.effective_message.reply_text(__help__) 47 | 48 | 49 | CONVERTER_HANDLER = CommandHandler("cash", convert, run_async=True) 50 | 51 | dispatcher.add_handler(CONVERTER_HANDLER) 52 | 53 | __command_list__ = ["cash"] 54 | __handlers__ = [CONVERTER_HANDLER] 55 | -------------------------------------------------------------------------------- /SiestaRobot/modules/texttospeech.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from gtts import gTTS 4 | from gtts import gTTSError 5 | from telethon import * 6 | from telethon.tl import functions 7 | from telethon.tl import types 8 | from telethon.tl.types import * 9 | 10 | from SiestaRobot import * 11 | 12 | from SiestaRobot import telethn as tbot 13 | from SiestaRobot.events import register 14 | 15 | 16 | @register(pattern="^/tts (.*)") 17 | async def _(event): 18 | if event.fwd_from: 19 | return 20 | input_str = event.pattern_match.group(1) 21 | reply_to_id = event.message.id 22 | if event.reply_to_msg_id: 23 | previous_message = await event.get_reply_message() 24 | text = previous_message.message 25 | lan = input_str 26 | elif "|" in input_str: 27 | lan, text = input_str.split("|") 28 | else: 29 | await event.reply( 30 | "Invalid Syntax\nFormat `/tts lang | text`\nFor eg: `/tts en | hello`" 31 | ) 32 | return 33 | text = text.strip() 34 | lan = lan.strip() 35 | try: 36 | tts = gTTS(text, tld="com", lang=lan) 37 | tts.save("k.mp3") 38 | except AssertionError: 39 | await event.reply( 40 | "The text is empty.\n" 41 | "Nothing left to speak after pre-precessing, " 42 | "tokenizing and cleaning." 43 | ) 44 | return 45 | except ValueError: 46 | await event.reply("Language is not supported.") 47 | return 48 | except RuntimeError: 49 | await event.reply("Error loading the languages dictionary.") 50 | return 51 | except gTTSError: 52 | await event.reply("Error in Google Text-to-Speech API request !") 53 | return 54 | with open("k.mp3", "r"): 55 | await tbot.send_file( 56 | event.chat_id, "k.mp3", voice_note=True, reply_to=reply_to_id 57 | ) 58 | os.remove("k.mp3") 59 | -------------------------------------------------------------------------------- /SiestaRobot/modules/pyrogithub.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | from pyrogram import filters 3 | from SiestaRobot import pbot, BOT_USERNAME 4 | from SiestaRobot.utils.errors import capture_err 5 | 6 | 7 | __mod_name__ = "Github" 8 | 9 | 10 | @pbot.on_message(filters.command(["github", "git", f"git@{BOT_USERNAME}"])) 11 | @capture_err 12 | async def github(_, message): 13 | if len(message.command) != 2: 14 | await message.reply_text("/git Username") 15 | return 16 | username = message.text.split(None, 1)[1] 17 | URL = f"https://api.github.com/users/{username}" 18 | async with aiohttp.ClientSession() as session: 19 | async with session.get(URL) as request: 20 | if request.status == 404: 21 | return await message.reply_text("404") 22 | 23 | result = await request.json() 24 | try: 25 | url = result["html_url"] 26 | name = result["name"] 27 | company = result["company"] 28 | bio = result["bio"] 29 | created_at = result["created_at"] 30 | avatar_url = result["avatar_url"] 31 | blog = result["blog"] 32 | location = result["location"] 33 | repositories = result["public_repos"] 34 | followers = result["followers"] 35 | following = result["following"] 36 | caption = f"""**Info Of {name}** 37 | **Username:** `{username}` 38 | **Bio:** `{bio}` 39 | **Profile Link:** [Here]({url}) 40 | **Company:** `{company}` 41 | **Created On:** `{created_at}` 42 | **Repositories:** `{repositories}` 43 | **Blog:** `{blog}` 44 | **Location:** `{location}` 45 | **Followers:** `{followers}` 46 | **Following:** `{following}`""" 47 | except Exception as e: 48 | print(str(e)) 49 | pass 50 | await message.reply_photo(photo=avatar_url, caption=caption) 51 | -------------------------------------------------------------------------------- /SiestaRobot/utils/errors.py: -------------------------------------------------------------------------------- 1 | """ WRITTEN BY @pokurt, https://github.com/pokurt""" 2 | # credits goes to William, https://github.com/WilliamButcherBot 3 | 4 | import sys 5 | import traceback 6 | from functools import wraps 7 | 8 | from pyrogram.errors.exceptions.forbidden_403 import ChatWriteForbidden 9 | 10 | from SiestaRobot import LOGGER, pbot as app 11 | 12 | 13 | def split_limits(text): 14 | if len(text) < 2048: 15 | return [text] 16 | 17 | lines = text.splitlines(True) 18 | small_msg = "" 19 | result = [] 20 | for line in lines: 21 | if len(small_msg) + len(line) < 2048: 22 | small_msg += line 23 | else: 24 | result.append(small_msg) 25 | small_msg = line 26 | 27 | result.append(small_msg) 28 | 29 | return result 30 | 31 | 32 | def capture_err(func): 33 | @wraps(func) 34 | async def capture(client, message, *args, **kwargs): 35 | try: 36 | return await func(client, message, *args, **kwargs) 37 | except ChatWriteForbidden: 38 | await app.leave_chat(message.chat.id) 39 | return 40 | except Exception as err: 41 | exc_type, exc_obj, exc_tb = sys.exc_info() 42 | errors = traceback.format_exception( 43 | etype=exc_type, 44 | value=exc_obj, 45 | tb=exc_tb, 46 | ) 47 | error_feedback = split_limits( 48 | "**ERROR** | `{}` | `{}`\n\n```{}```\n\n```{}```\n".format( 49 | 0 if not message.from_user else message.from_user.id, 50 | 0 if not message.chat else message.chat.id, 51 | message.text or message.caption, 52 | "".join(errors), 53 | ), 54 | ) 55 | for x in error_feedback: 56 | await app.send_message(LOGGER, x) 57 | raise err 58 | 59 | return capture 60 | -------------------------------------------------------------------------------- /SiestaRobot/modules/json.py: -------------------------------------------------------------------------------- 1 | import io 2 | from SiestaRobot.events import register 3 | from SiestaRobot import telethn as tbot 4 | from telethon import types 5 | from telethon import events 6 | from telethon.tl import functions 7 | from telethon.tl.types import * 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 | "🚨 Need Admin Pewer.. You can't use this command.. But you can use in my pm" 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 | -------------------------------------------------------------------------------- /SiestaRobot/modules/carbon.py: -------------------------------------------------------------------------------- 1 | from platform import python_version as y 2 | from telegram import __version__ as o 3 | from pyrogram import __version__ as z 4 | from telethon import __version__ as s 5 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton 6 | from pyrogram import filters 7 | from SiestaRobot import pbot 8 | from SiestaRobot.utils.errors import capture_err 9 | from SiestaRobot.utils.functions import make_carbon 10 | 11 | 12 | @pbot.on_message(filters.command("carbon")) 13 | @capture_err 14 | async def carbon_func(_, message): 15 | if not message.reply_to_message: 16 | return await message.reply_text("`Reply to a text message to make carbon.`") 17 | if not message.reply_to_message.text: 18 | return await message.reply_text("`Reply to a text message to make carbon.`") 19 | m = await message.reply_text("`Preparing Carbon`") 20 | carbon = await make_carbon(message.reply_to_message.text) 21 | await m.edit("`Uploading`") 22 | await pbot.send_photo(message.chat.id, carbon) 23 | await m.delete() 24 | carbon.close() 25 | 26 | 27 | MEMEK = "https://telegra.ph/file/31c56fb53884915fec558.jpg" 28 | 29 | @pbot.on_message(filters.command("repo")) 30 | async def repo(_, message): 31 | await message.reply_photo( 32 | photo=MEMEK, 33 | caption=f"""✨ **Hey I'm Siesta Robot** ✨ 34 | 35 | **Owner repo : [Vain](https://t.me/saint_foire)** 36 | **Python Version :** `{y()}` 37 | **Library Version :** `{o}` 38 | **Telethon Version :** `{s}` 39 | **Pyrogram Version :** `{z}` 40 | 41 | **Create your own with click button bellow.** 42 | """, 43 | reply_markup=InlineKeyboardMarkup( 44 | [ 45 | [ 46 | InlineKeyboardButton( 47 | "Repo", url="https://github.com/shiinobu/SiestaRobot"), 48 | InlineKeyboardButton( 49 | "Support", url="https://t.me/machinaxsupport") 50 | ] 51 | ] 52 | ) 53 | ) 54 | -------------------------------------------------------------------------------- /SiestaRobot/modules/currency_converter.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | from SiestaRobot import CASH_API_KEY, dispatcher 4 | from telegram import Update, ParseMode 5 | from telegram.ext import CallbackContext, CommandHandler, run_async 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 | CONVERTER_HANDLER = CommandHandler("cash", convert, run_async=True) 54 | 55 | dispatcher.add_handler(CONVERTER_HANDLER) 56 | 57 | __command_list__ = ["cash"] 58 | __handlers__ = [CONVERTER_HANDLER] 59 | -------------------------------------------------------------------------------- /SiestaRobot/modules/wallpaper.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | import requests as r 4 | from SiestaRobot import SUPPORT_CHAT, WALL_API, dispatcher 5 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 6 | from telegram import Update 7 | from telegram.ext import CallbackContext 8 | 9 | # Wallpapers module by @TheRealPhoenix using wall.alphacoders.com 10 | 11 | 12 | def wall(update: Update, context: CallbackContext): 13 | chat_id = update.effective_chat.id 14 | msg = update.effective_message 15 | args = context.args 16 | msg_id = update.effective_message.message_id 17 | bot = context.bot 18 | query = " ".join(args) 19 | if not query: 20 | msg.reply_text("Please enter a query!") 21 | return 22 | caption = query 23 | term = query.replace(" ", "%20") 24 | json_rep = r.get( 25 | f"https://wall.alphacoders.com/api2.0/get.php?auth={WALL_API}&method=search&term={term}", 26 | ).json() 27 | if not json_rep.get("success"): 28 | msg.reply_text(f"An error occurred! Report this @{SUPPORT_CHAT}") 29 | else: 30 | wallpapers = json_rep.get("wallpapers") 31 | if not wallpapers: 32 | msg.reply_text("No results found! Refine your search.") 33 | return 34 | index = randint(0, len(wallpapers) - 1) # Choose random index 35 | wallpaper = wallpapers[index] 36 | wallpaper = wallpaper.get("url_image") 37 | wallpaper = wallpaper.replace("\\", "") 38 | bot.send_photo( 39 | chat_id, 40 | photo=wallpaper, 41 | caption="Preview", 42 | reply_to_message_id=msg_id, 43 | timeout=60, 44 | ) 45 | bot.send_document( 46 | chat_id, 47 | document=wallpaper, 48 | filename="wallpaper", 49 | caption=caption, 50 | reply_to_message_id=msg_id, 51 | timeout=60, 52 | ) 53 | 54 | 55 | WALLPAPER_HANDLER = DisableAbleCommandHandler("wall", wall, run_async=True) 56 | dispatcher.add_handler(WALLPAPER_HANDLER) 57 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/antichannel_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from sqlalchemy import Boolean 4 | from sqlalchemy.sql.sqltypes import String 5 | from sqlalchemy import Column 6 | 7 | from SiestaRobot.modules.sql import BASE, SESSION 8 | 9 | 10 | class AntiChannelSettings(BASE): 11 | __tablename__ = "anti_channel_settings" 12 | 13 | chat_id = Column(String(14), primary_key=True) 14 | setting = Column(Boolean, default=False, nullable=False) 15 | 16 | def __init__(self, chat_id: int, disabled: bool): 17 | self.chat_id = str(chat_id) 18 | self.setting = disabled 19 | 20 | def __repr__(self): 21 | return "".format(self.chat_id, self.setting) 22 | 23 | 24 | AntiChannelSettings.__table__.create(checkfirst=True) 25 | ANTICHANNEL_SETTING_LOCK = threading.RLock() 26 | 27 | def enable_antichannel(chat_id: int): 28 | with ANTICHANNEL_SETTING_LOCK: 29 | chat = SESSION.query(AntiChannelSettings).get(str(chat_id)) 30 | if not chat: 31 | chat = AntiChannelSettings(str(chat_id), True) 32 | 33 | chat.setting = True 34 | SESSION.add(chat) 35 | SESSION.commit() 36 | 37 | 38 | def disable_antichannel(chat_id: int): 39 | with ANTICHANNEL_SETTING_LOCK: 40 | chat = SESSION.query(AntiChannelSettings).get(str(chat_id)) 41 | if not chat: 42 | chat = AntiChannelSettings(str(chat_id), False) 43 | 44 | chat.setting = False 45 | SESSION.add(chat) 46 | SESSION.commit() 47 | 48 | 49 | def antichannel_status(chat_id: int) -> bool: 50 | with ANTICHANNEL_SETTING_LOCK: 51 | d = SESSION.query(AntiChannelSettings).get(str(chat_id)) 52 | if not d: 53 | return False 54 | return d.setting 55 | 56 | 57 | 58 | 59 | def migrate_chat(old_chat_id, new_chat_id): 60 | with ANTICHANNEL_SETTING_LOCK: 61 | chat = SESSION.query(AntiChannelSettings).get(str(old_chat_id)) 62 | if chat: 63 | chat.chat_id = new_chat_id 64 | SESSION.add(chat) 65 | 66 | SESSION.commit() 67 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/userinfo_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from SiestaRobot.modules.sql import BASE, SESSION 3 | from sqlalchemy import Column, UnicodeText 4 | from sqlalchemy.sql.sqltypes import BigInteger 5 | 6 | 7 | class UserInfo(BASE): 8 | __tablename__ = "userinfo" 9 | user_id = Column(BigInteger, primary_key=True) 10 | info = Column(UnicodeText) 11 | 12 | def __init__(self, user_id, info): 13 | self.user_id = user_id 14 | self.info = info 15 | 16 | def __repr__(self): 17 | return "" % self.user_id 18 | 19 | 20 | class UserBio(BASE): 21 | __tablename__ = "userbio" 22 | user_id = Column(BigInteger, primary_key=True) 23 | bio = Column(UnicodeText) 24 | 25 | def __init__(self, user_id, bio): 26 | self.user_id = user_id 27 | self.bio = bio 28 | 29 | def __repr__(self): 30 | return "" % self.user_id 31 | 32 | 33 | UserInfo.__table__.create(checkfirst=True) 34 | UserBio.__table__.create(checkfirst=True) 35 | 36 | INSERTION_LOCK = threading.RLock() 37 | 38 | 39 | def get_user_me_info(user_id): 40 | userinfo = SESSION.query(UserInfo).get(user_id) 41 | SESSION.close() 42 | if userinfo: 43 | return userinfo.info 44 | return None 45 | 46 | 47 | def set_user_me_info(user_id, info): 48 | with INSERTION_LOCK: 49 | userinfo = SESSION.query(UserInfo).get(user_id) 50 | if userinfo: 51 | userinfo.info = info 52 | else: 53 | userinfo = UserInfo(user_id, info) 54 | SESSION.add(userinfo) 55 | SESSION.commit() 56 | 57 | 58 | def get_user_bio(user_id): 59 | userbio = SESSION.query(UserBio).get(user_id) 60 | SESSION.close() 61 | if userbio: 62 | return userbio.bio 63 | return None 64 | 65 | 66 | def set_user_bio(user_id, bio): 67 | with INSERTION_LOCK: 68 | userbio = SESSION.query(UserBio).get(user_id) 69 | if userbio: 70 | userbio.bio = bio 71 | else: 72 | userbio = UserBio(user_id, bio) 73 | 74 | SESSION.add(userbio) 75 | SESSION.commit() 76 | -------------------------------------------------------------------------------- /SiestaRobot/modules/antichannel.py: -------------------------------------------------------------------------------- 1 | import html 2 | 3 | from telegram.ext.filters import Filters 4 | from telegram import Update, message, ParseMode 5 | from telegram.ext import CallbackContext 6 | 7 | from SiestaRobot.modules.helper_funcs.decorators import siestacmd, siestamsg 8 | from SiestaRobot.modules.helper_funcs.channel_mode import user_admin, AdminPerms 9 | from SiestaRobot.modules.sql.antichannel_sql import antichannel_status, disable_antichannel, enable_antichannel 10 | from SiestaRobot.modules.language import gs 11 | 12 | @siestacmd(command="antichannelmode", group=100) 13 | @user_admin(AdminPerms.CAN_RESTRICT_MEMBERS) 14 | def set_antichannel(update: Update, context: CallbackContext): 15 | message = update.effective_message 16 | chat = update.effective_chat 17 | args = context.args 18 | if len(args) > 0: 19 | s = args[0].lower() 20 | if s in ["yes", "on"]: 21 | enable_antichannel(chat.id) 22 | message.reply_html(text=gs(chat.id, "active_antichannel").format(html.escape(chat.title))) 23 | elif s in ["off", "no"]: 24 | disable_antichannel(chat.id) 25 | message.reply_html(text=gs(chat.id, "disable_antichannel").format(html.escape(chat.title))) 26 | else: 27 | message.reply_text(text=gs(chat.id, "invalid_antichannel").format(s)) 28 | return 29 | message.reply_html( 30 | text=gs(chat.id, "status_antichannel").format(antichannel_status(chat.id), html.escape(chat.title))) 31 | 32 | @siestamsg(Filters.chat_type.groups, group=110) 33 | def eliminate_channel(update: Update, context: CallbackContext): 34 | message = update.effective_message 35 | chat = update.effective_chat 36 | bot = context.bot 37 | if not antichannel_status(chat.id): 38 | return 39 | if message.sender_chat and message.sender_chat.type == "channel" and not message.is_automatic_forward: 40 | message.delete() 41 | sender_chat = message.sender_chat 42 | bot.ban_chat_sender_chat(sender_chat_id=sender_chat.id, chat_id=chat.id) 43 | 44 | def helps(chat): 45 | return gs(chat, "antichannel_help") 46 | 47 | __mod_name__ = "Anti-Channel" 48 | -------------------------------------------------------------------------------- /SiestaRobot/modules/webshot.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | Copyright (c) 2021 TheHamkerCat 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | """ 20 | from pyrogram import filters 21 | from pyrogram.types import Message 22 | 23 | from SiestaRobot import pbot as app 24 | from SiestaRobot.utils.errors import capture_err 25 | 26 | __mod_name__ = "Webshot​" 27 | 28 | 29 | @app.on_message(filters.command("webss")) 30 | @capture_err 31 | async def take_ss(_, message: Message): 32 | try: 33 | if len(message.command) != 2: 34 | return await message.reply_text( 35 | "Give A Url To Fetch Screenshot." 36 | ) 37 | url = message.text.split(None, 1)[1] 38 | m = await message.reply_text("**Taking Screenshot**") 39 | await m.edit("**Uploading**") 40 | try: 41 | await message.reply_photo( 42 | photo=f"https://webshot.amanoteam.com/print?q={url}", 43 | quote=False, 44 | ) 45 | except TypeError: 46 | return await m.edit("No Such Website.") 47 | await m.delete() 48 | except Exception as e: 49 | await message.reply_text(str(e)) 50 | -------------------------------------------------------------------------------- /SiestaRobot/services/tasks.py: -------------------------------------------------------------------------------- 1 | from asyncio import Lock, create_task 2 | from time import time 3 | from pyrogram import filters 4 | from pyrogram.types import Message 5 | from SiestaRobot import BOT_ID, BOT_USERNAME, DEV_USERS 6 | from SiestaRobot.services.sections import bold, section, w 7 | tasks = {} 8 | TASKS_LOCK = Lock() 9 | arrow = lambda x: (x.text if x else "") + "\n`→`" 10 | 11 | 12 | def all_tasks(): 13 | return tasks 14 | 15 | 16 | async def add_task( 17 | taskFunc, 18 | task_name, 19 | *args, 20 | **kwargs, 21 | ): 22 | 23 | async with TASKS_LOCK: 24 | global tasks 25 | 26 | task_id = (list(tasks.keys())[-1] + 1) if tasks else 0 27 | 28 | task = create_task( 29 | taskFunc(*args, **kwargs), 30 | name=task_name, 31 | ) 32 | tasks[task_id] = task, int(time()) 33 | return task, task_id 34 | 35 | 36 | async def rm_task(task_id=None): 37 | global tasks 38 | 39 | async with TASKS_LOCK: 40 | for key, value in list(tasks.items()): 41 | if value[0].done() or value[0].cancelled(): 42 | del tasks[key] 43 | 44 | if (task_id is not None) and (task_id in tasks): 45 | task = tasks[task_id][0] 46 | 47 | if not task.done(): 48 | task.cancel() 49 | 50 | del tasks[task_id] 51 | 52 | 53 | async def _get_tasks_text(): 54 | await rm_task() # Clean completed tasks 55 | if not tasks: 56 | return f"{arrow('')} No pending task" 57 | 58 | text = bold("Tasks") + "\n" 59 | 60 | for i, task in enumerate(list(tasks.items())): 61 | indent = w * 4 62 | 63 | t, started = task[1] 64 | elapsed = round(time() - started) 65 | info = t._repr_info() 66 | 67 | id = task[0] 68 | text += section( 69 | f"{indent}Task {i}", 70 | body={ 71 | "Name": t.get_name(), 72 | "Task ID": id, 73 | "Status": info[0].capitalize(), 74 | "Origin": info[2].split("/")[-1].replace(">", ""), 75 | "Running since": f"{elapsed}s", 76 | }, 77 | indent=8, 78 | ) 79 | return text 80 | -------------------------------------------------------------------------------- /SiestaRobot/modules/wiki.py: -------------------------------------------------------------------------------- 1 | import wikipedia 2 | from SiestaRobot import dispatcher 3 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 4 | from telegram import ParseMode, Update 5 | from telegram.ext import CallbackContext, run_async 6 | from wikipedia.exceptions import DisambiguationError, PageError 7 | 8 | 9 | def wiki(update: Update, context: CallbackContext): 10 | msg = ( 11 | update.effective_message.reply_to_message 12 | if update.effective_message.reply_to_message 13 | else update.effective_message 14 | ) 15 | res = "" 16 | if msg == update.effective_message: 17 | search = msg.text.split(" ", maxsplit=1)[1] 18 | else: 19 | search = msg.text 20 | try: 21 | res = wikipedia.summary(search) 22 | except DisambiguationError as e: 23 | update.message.reply_text( 24 | "Disambiguated pages found! Adjust your query accordingly.\n{}".format( 25 | e 26 | ), 27 | parse_mode=ParseMode.HTML, 28 | ) 29 | except PageError as e: 30 | update.message.reply_text( 31 | "{}".format(e), parse_mode=ParseMode.HTML 32 | ) 33 | if res: 34 | result = f"{search}\n\n" 35 | result += f"{res}\n" 36 | result += f"""Read more...""" 37 | if len(result) > 4000: 38 | with open("result.txt", "w") as f: 39 | f.write(f"{result}\n\nUwU OwO OmO UmU") 40 | with open("result.txt", "rb") as f: 41 | context.bot.send_document( 42 | document=f, 43 | filename=f.name, 44 | reply_to_message_id=update.message.message_id, 45 | chat_id=update.effective_chat.id, 46 | parse_mode=ParseMode.HTML, 47 | ) 48 | else: 49 | update.message.reply_text( 50 | result, parse_mode=ParseMode.HTML, disable_web_page_preview=True 51 | ) 52 | 53 | 54 | WIKI_HANDLER = DisableAbleCommandHandler("wiki", wiki, run_async=True) 55 | dispatcher.add_handler(WIKI_HANDLER) 56 | -------------------------------------------------------------------------------- /SiestaRobot/modules/reddit.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | Copyright (c) 2021 TheHamkerCat 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | """ 20 | from pyrogram import filters 21 | 22 | from SiestaRobot import pbot as app, arq 23 | from SiestaRobot.utils.errors import capture_err 24 | 25 | __mod_name__ = "Reddit" 26 | 27 | 28 | @app.on_message(filters.command("reddit") & ~filters.edited) 29 | @capture_err 30 | async def reddit(_, message): 31 | if len(message.command) != 2: 32 | return await message.reply_text("/reddit needs an argument") 33 | subreddit = message.text.split(None, 1)[1] 34 | m = await message.reply_text("Searching") 35 | reddit = await arq.reddit(subreddit) 36 | if not reddit.ok: 37 | return await m.edit(reddit.result) 38 | reddit = reddit.result 39 | nsfw = reddit.nsfw 40 | sreddit = reddit.subreddit 41 | title = reddit.title 42 | image = reddit.url 43 | link = reddit.postLink 44 | if nsfw: 45 | return await m.edit("NSFW RESULTS COULD NOT BE SHOWN.") 46 | caption = f""" 47 | **Title:** `{title}` 48 | **Subreddit:** {sreddit} 49 | **PostLink:** {link}""" 50 | try: 51 | await message.reply_photo(photo=image, caption=caption) 52 | await m.delete() 53 | except Exception as e: 54 | await m.edit(e.MESSAGE) 55 | -------------------------------------------------------------------------------- /SiestaRobot/modules/random_api.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from SiestaRobot.events import register 3 | from SiestaRobot import telethn as tbot 4 | 5 | 6 | @register(pattern="^/ptl ?(.*)") 7 | async def asupan(event): 8 | try: 9 | resp = requests.get("https://api-tede.herokuapp.com/api/asupan/ptl").json() 10 | asupannya = f"{resp['url']}" 11 | return await tbot.send_file(event.chat_id, asupannya) 12 | except Exception: 13 | await event.reply("`Error 404 not found...`") 14 | 15 | 16 | @register(pattern="^/chika ?(.*)") 17 | async def chika(event): 18 | try: 19 | resp = requests.get("https://api-tede.herokuapp.com/api/chika").json() 20 | chikanya = f"{resp['url']}" 21 | return await tbot.send_file(event.chat_id, chikanya) 22 | except Exception: 23 | await event.reply("`Error 404 not found...`") 24 | 25 | 26 | @register(pattern="^/hilih ?(.*)") 27 | async def _(hilih): 28 | kuntul = hilih.pattern_match.group(1) 29 | if not kuntul: 30 | await hilih.reply("Usage: /hilih ") 31 | return 32 | try: 33 | resp = requests.get(f"https://tede-api.herokuapp.com/api/hilih?kata={kuntul}").json() 34 | hilihnya = f"{resp['result']}" 35 | return await hilih.reply(hilihnya) 36 | except Exception: 37 | await hilih.reply("Something went wrong LOL...") 38 | 39 | 40 | # Copyright 2021 © 41 | # Modul Create by https://t.me/xflicks | Github = https://github.com/FeriEXP 42 | # Yang remove cacat 43 | 44 | import requests 45 | import urllib 46 | import asyncio 47 | import os 48 | from pyrogram import filters 49 | from SiestaRobot import TEMP_DOWNLOAD_DIRECTORY, pbot 50 | 51 | 52 | @pbot.on_message(filters.command("boobs")) 53 | async def boobs(client, message): 54 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 55 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 56 | pic_loc = os.path.join(TEMP_DOWNLOAD_DIRECTORY, "bobs.jpg") 57 | a = await message.reply_text("**Mencari Gambar Bugil**") 58 | await asyncio.sleep(0.5) 59 | await a.edit("`Mengirim foto bugil...`") 60 | nsfw = requests.get("http://api.oboobs.ru/noise/1").json()[0]["preview"] 61 | urllib.request.urlretrieve("http://media.oboobs.ru/{}".format(nsfw), pic_loc) 62 | await client.send_photo(message.chat.id, pic_loc, caption="**Sange boleh, Goblok jangan**") 63 | os.remove(pic_loc) 64 | await a.delete() 65 | -------------------------------------------------------------------------------- /SiestaRobot/modules/debug.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | 4 | from telethon import events 5 | from telegram import Update 6 | from telegram.ext import CallbackContext, CommandHandler 7 | 8 | from SiestaRobot import telethn, dispatcher 9 | from SiestaRobot.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 | support_chat = os.getenv("SUPPORT_CHAT") 52 | 53 | 54 | @dev_plus 55 | def logs(update: Update, context: CallbackContext): 56 | user = update.effective_user 57 | with open("log.txt", "rb") as f: 58 | context.bot.send_document(document=f, filename=f.name, chat_id=user.id) 59 | 60 | 61 | LOG_HANDLER = CommandHandler("logs", logs, run_async=True) 62 | dispatcher.add_handler(LOG_HANDLER) 63 | 64 | DEBUG_HANDLER = CommandHandler("debug", debug, run_async=True) 65 | dispatcher.add_handler(DEBUG_HANDLER) 66 | 67 | __mod_name__ = "Debug" 68 | __command_list__ = ["debug"] 69 | __handlers__ = [DEBUG_HANDLER] 70 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/afk_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | from sqlalchemy import Boolean, Column, BigInteger, UnicodeText 5 | 6 | class AFK(BASE): 7 | __tablename__ = "afk_users" 8 | 9 | user_id = Column(BigInteger, primary_key=True) 10 | is_afk = Column(Boolean) 11 | reason = Column(UnicodeText) 12 | 13 | def __init__(self, user_id, reason="", is_afk=True): 14 | self.user_id = user_id 15 | self.reason = reason 16 | self.is_afk = is_afk 17 | 18 | def __repr__(self): 19 | return "afk_status for {}".format(self.user_id) 20 | 21 | 22 | AFK.__table__.create(checkfirst=True) 23 | INSERTION_LOCK = threading.RLock() 24 | 25 | AFK_USERS = {} 26 | 27 | 28 | def is_afk(user_id): 29 | return user_id in AFK_USERS 30 | 31 | 32 | def check_afk_status(user_id): 33 | try: 34 | return SESSION.query(AFK).get(user_id) 35 | finally: 36 | SESSION.close() 37 | 38 | 39 | def set_afk(user_id, reason=""): 40 | with INSERTION_LOCK: 41 | curr = SESSION.query(AFK).get(user_id) 42 | if not curr: 43 | curr = AFK(user_id, reason, True) 44 | else: 45 | curr.is_afk = True 46 | 47 | AFK_USERS[user_id] = reason 48 | 49 | SESSION.add(curr) 50 | SESSION.commit() 51 | 52 | 53 | def rm_afk(user_id): 54 | with INSERTION_LOCK: 55 | curr = SESSION.query(AFK).get(user_id) 56 | if curr: 57 | if user_id in AFK_USERS: # sanity check 58 | del AFK_USERS[user_id] 59 | 60 | SESSION.delete(curr) 61 | SESSION.commit() 62 | return True 63 | 64 | SESSION.close() 65 | return False 66 | 67 | 68 | def toggle_afk(user_id, reason=""): 69 | with INSERTION_LOCK: 70 | curr = SESSION.query(AFK).get(user_id) 71 | if not curr: 72 | curr = AFK(user_id, reason, True) 73 | elif curr.is_afk: 74 | curr.is_afk = False 75 | elif not curr.is_afk: 76 | curr.is_afk = True 77 | SESSION.add(curr) 78 | SESSION.commit() 79 | 80 | 81 | def __load_afk_users(): 82 | global AFK_USERS 83 | try: 84 | all_afk = SESSION.query(AFK).all() 85 | AFK_USERS = {user.user_id: user.reason for user in all_afk if user.is_afk} 86 | finally: 87 | SESSION.close() 88 | 89 | 90 | __load_afk_users() 91 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/log_channel_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | from sqlalchemy import Column, String, distinct, func 5 | 6 | 7 | class GroupLogs(BASE): 8 | __tablename__ = "log_channels" 9 | chat_id = Column(String(14), primary_key=True) 10 | log_channel = Column(String(14), nullable=False) 11 | 12 | def __init__(self, chat_id, log_channel): 13 | self.chat_id = str(chat_id) 14 | self.log_channel = str(log_channel) 15 | 16 | 17 | GroupLogs.__table__.create(checkfirst=True) 18 | 19 | LOGS_INSERTION_LOCK = threading.RLock() 20 | 21 | CHANNELS = {} 22 | 23 | 24 | def set_chat_log_channel(chat_id, log_channel): 25 | with LOGS_INSERTION_LOCK: 26 | res = SESSION.query(GroupLogs).get(str(chat_id)) 27 | if res: 28 | res.log_channel = log_channel 29 | else: 30 | res = GroupLogs(chat_id, log_channel) 31 | SESSION.add(res) 32 | 33 | CHANNELS[str(chat_id)] = log_channel 34 | SESSION.commit() 35 | 36 | 37 | def get_chat_log_channel(chat_id): 38 | return CHANNELS.get(str(chat_id)) 39 | 40 | 41 | def stop_chat_logging(chat_id): 42 | with LOGS_INSERTION_LOCK: 43 | res = SESSION.query(GroupLogs).get(str(chat_id)) 44 | if res: 45 | if str(chat_id) in CHANNELS: 46 | del CHANNELS[str(chat_id)] 47 | 48 | log_channel = res.log_channel 49 | SESSION.delete(res) 50 | SESSION.commit() 51 | return log_channel 52 | 53 | 54 | def num_logchannels(): 55 | try: 56 | return SESSION.query(func.count(distinct(GroupLogs.chat_id))).scalar() 57 | finally: 58 | SESSION.close() 59 | 60 | 61 | def migrate_chat(old_chat_id, new_chat_id): 62 | with LOGS_INSERTION_LOCK: 63 | chat = SESSION.query(GroupLogs).get(str(old_chat_id)) 64 | if chat: 65 | chat.chat_id = str(new_chat_id) 66 | SESSION.add(chat) 67 | if str(old_chat_id) in CHANNELS: 68 | CHANNELS[str(new_chat_id)] = CHANNELS.get(str(old_chat_id)) 69 | 70 | SESSION.commit() 71 | 72 | 73 | def __load_log_channels(): 74 | global CHANNELS 75 | try: 76 | all_chats = SESSION.query(GroupLogs).all() 77 | CHANNELS = {chat.chat_id: chat.log_channel for chat in all_chats} 78 | finally: 79 | SESSION.close() 80 | 81 | 82 | __load_log_channels() 83 | -------------------------------------------------------------------------------- /SiestaRobot/modules/gtranslator.py: -------------------------------------------------------------------------------- 1 | from gpytranslate import Translator 2 | from telegram.ext import CommandHandler, CallbackContext 3 | from telegram import ( 4 | Message, 5 | Chat, 6 | User, 7 | ParseMode, 8 | Update, 9 | InlineKeyboardMarkup, 10 | InlineKeyboardButton, 11 | ) 12 | from SiestaRobot import dispatcher, pbot 13 | from pyrogram import filters 14 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 15 | from SiestaRobot.modules.language import gs 16 | 17 | 18 | def helps(chat): 19 | return gs(chat, "translator_help") 20 | 21 | __mod_name__ = "Translator" 22 | 23 | 24 | trans = Translator() 25 | 26 | 27 | @pbot.on_message(filters.command(["tl", "tr"])) 28 | async def translate(_, message: Message) -> None: 29 | reply_msg = message.reply_to_message 30 | if not reply_msg: 31 | await message.reply_text("Reply to a message to translate it!") 32 | return 33 | if reply_msg.caption: 34 | to_translate = reply_msg.caption 35 | elif reply_msg.text: 36 | to_translate = reply_msg.text 37 | try: 38 | args = message.text.split()[1].lower() 39 | if "//" in args: 40 | source = args.split("//")[0] 41 | dest = args.split("//")[1] 42 | else: 43 | source = await trans.detect(to_translate) 44 | dest = args 45 | except IndexError: 46 | source = await trans.detect(to_translate) 47 | dest = "en" 48 | translation = await trans(to_translate, sourcelang=source, targetlang=dest) 49 | reply = ( 50 | f"Translated from {source} to {dest}:\n" 51 | f"{translation.text}" 52 | ) 53 | 54 | await message.reply_text(reply, parse_mode="html") 55 | 56 | 57 | def languages(update: Update, context: CallbackContext) -> None: 58 | update.effective_message.reply_text( 59 | "Click on the button below to see the list of supported language codes.", 60 | reply_markup=InlineKeyboardMarkup( 61 | [ 62 | [ 63 | InlineKeyboardButton( 64 | text="Language codes", 65 | url="https://telegra.ph/Lang-Codes-03-19-3", 66 | ), 67 | ], 68 | ], 69 | disable_web_page_preview=True, 70 | ), 71 | ) 72 | 73 | 74 | LANG_HANDLER = DisableAbleCommandHandler("langs", languages, run_async=True) 75 | 76 | dispatcher.add_handler(LANG_HANDLER) 77 | -------------------------------------------------------------------------------- /SiestaRobot/utils/uputils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import time 3 | 4 | 5 | async def progress(current, total, event, start, type_of_ps): 6 | """Generic progress_callback for both 7 | upload.py and download.py""" 8 | now = time.time() 9 | diff = now - start 10 | if round(diff % 10.00) == 0 or current == total: 11 | percentage = current * 100 / total 12 | speed = current / diff 13 | elapsed_time = round(diff) * 1000 14 | time_to_completion = round((total - current) / speed) * 1000 15 | estimated_total_time = elapsed_time + time_to_completion 16 | progress_str = "[{0}{1}]\nPercent: {2}%\n".format( 17 | "".join(["█" for i in range(math.floor(percentage / 5))]), 18 | "".join(["░" for i in range(20 - math.floor(percentage / 5))]), 19 | round(percentage, 2), 20 | ) 21 | tmp = progress_str + "{0} of {1}\nETA: {2}".format( 22 | humanbytes(current), humanbytes(total), time_formatter(estimated_total_time) 23 | ) 24 | await event.edit("{}\n {}".format(type_of_ps, tmp)) 25 | 26 | 27 | def convert_from_bytes(size): 28 | power = 2 ** 10 29 | n = 0 30 | units = {0: "", 1: "kilobytes", 2: "megabytes", 3: "gigabytes", 4: "terabytes"} 31 | while size > power: 32 | size /= power 33 | n += 1 34 | return f"{round(size, 2)} {units[n]}" 35 | 36 | 37 | def humanbytes(size): 38 | """Input size in bytes, 39 | outputs in a human readable format""" 40 | # https://stackoverflow.com/a/49361727/4723940 41 | if not size: 42 | return "" 43 | # 2 ** 10 = 1024 44 | power = 2 ** 10 45 | raised_to_pow = 0 46 | dict_power_n = {0: "", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"} 47 | while size > power: 48 | size /= power 49 | raised_to_pow += 1 50 | return str(round(size, 2)) + " " + dict_power_n[raised_to_pow] + "B" 51 | 52 | 53 | def time_formatter(milliseconds: int) -> str: 54 | """Inputs time in milliseconds, to get beautified time, 55 | as string""" 56 | seconds, milliseconds = divmod(int(milliseconds), 1000) 57 | minutes, seconds = divmod(seconds, 60) 58 | hours, minutes = divmod(minutes, 60) 59 | days, hours = divmod(hours, 24) 60 | tmp = ( 61 | ((str(days) + "d, ") if days else "") 62 | + ((str(hours) + "h, ") if hours else "") 63 | + ((str(minutes) + "m, ") if minutes else "") 64 | + ((str(seconds) + "s, ") if seconds else "") 65 | + ((str(milliseconds) + "ms, ") if milliseconds else "") 66 | ) 67 | return tmp[:-2] 68 | -------------------------------------------------------------------------------- /SiestaRobot/modules/speed_test.py: -------------------------------------------------------------------------------- 1 | import speedtest 2 | from SiestaRobot import DEV_USERS, dispatcher 3 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 4 | from SiestaRobot.modules.helper_funcs.chat_status import dev_plus 5 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ParseMode, Update 6 | from telegram.ext import CallbackContext, CallbackQueryHandler 7 | 8 | 9 | def convert(speed): 10 | return round(int(speed) / 1048576, 2) 11 | 12 | 13 | @dev_plus 14 | def speedtestxyz(update: Update, context: CallbackContext): 15 | buttons = [ 16 | [ 17 | InlineKeyboardButton("Image", callback_data="speedtest_image"), 18 | InlineKeyboardButton("Text", callback_data="speedtest_text"), 19 | ], 20 | ] 21 | update.effective_message.reply_text( 22 | "Select SpeedTest Mode", 23 | 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("Running a speedtest....") 32 | speed = speedtest.Speedtest() 33 | speed.get_best_server() 34 | speed.download() 35 | speed.upload() 36 | replymsg = "SpeedTest Results:" 37 | 38 | if query.data == "speedtest_image": 39 | speedtest_image = speed.results.share() 40 | update.effective_message.reply_photo( 41 | photo=speedtest_image, 42 | caption=replymsg, 43 | ) 44 | msg.delete() 45 | 46 | elif query.data == "speedtest_text": 47 | result = speed.results.dict() 48 | replymsg += f"\nDownload: `{convert(result['download'])}Mb/s`\nUpload: `{convert(result['upload'])}Mb/s`\nPing: `{result['ping']}`" 49 | update.effective_message.edit_text(replymsg, parse_mode=ParseMode.MARKDOWN) 50 | else: 51 | query.answer("You are required to join Heroes Association to use this command.") 52 | 53 | 54 | SPEED_TEST_HANDLER = DisableAbleCommandHandler( 55 | "speedtest", speedtestxyz, run_async=True 56 | ) 57 | SPEED_TEST_CALLBACKHANDLER = CallbackQueryHandler( 58 | speedtestxyz_callback, pattern="speedtest_.*", run_async=True 59 | ) 60 | 61 | dispatcher.add_handler(SPEED_TEST_HANDLER) 62 | dispatcher.add_handler(SPEED_TEST_CALLBACKHANDLER) 63 | 64 | __mod_name__ = "SpeedTest" 65 | __command_list__ = ["speedtest"] 66 | __handlers__ = [SPEED_TEST_HANDLER, SPEED_TEST_CALLBACKHANDLER] 67 | -------------------------------------------------------------------------------- /SiestaRobot/modules/language.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import SiestaRobot.modules.sql.language_sql as sql 3 | 4 | from typing import Union, List, Dict, Callable, Generator, Any 5 | 6 | from collections.abc import Iterable 7 | from telegram.ext import CommandHandler, CallbackQueryHandler 8 | from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton 9 | 10 | from SiestaRobot import dispatcher 11 | from SiestaRobot.modules.helper_funcs.chat_status import user_admin, user_admin_no_reply 12 | from SiestaRobot.language import get_string, get_languages, get_language 13 | 14 | 15 | 16 | def paginate( 17 | iterable: Iterable, page_size: int 18 | ) -> Generator[List, None, None]: 19 | while True: 20 | i1, i2 = itertools.tee(iterable) 21 | iterable, page = ( 22 | itertools.islice(i1, page_size, None), 23 | list(itertools.islice(i2, page_size)), 24 | ) 25 | if not page: 26 | break 27 | yield page 28 | 29 | 30 | def gs(chat_id: Union[int, str], string: str) -> str: 31 | lang = sql.get_chat_lang(chat_id) 32 | return get_string(lang, string) 33 | 34 | 35 | @user_admin 36 | def set_lang(update: Update, _) -> None: 37 | chat = update.effective_chat 38 | msg = update.effective_message 39 | 40 | msg_text = gs(chat.id, "curr_chat_lang").format( 41 | get_language(sql.get_chat_lang(chat.id))[:-3] 42 | ) 43 | 44 | keyb = [InlineKeyboardButton( 45 | text=name, 46 | callback_data=f"setLang_{code}", 47 | ) for code, name in get_languages().items()] 48 | keyb = list(paginate(keyb, 2)) 49 | keyb.append( 50 | [ 51 | InlineKeyboardButton( 52 | text="Help us in translations", 53 | url="https://poeditor.com/join/project?hash=gXVtzsSQ88", 54 | ) 55 | ] 56 | ) 57 | msg.reply_text(msg_text, reply_markup=InlineKeyboardMarkup(keyb)) 58 | 59 | 60 | @user_admin_no_reply 61 | def lang_button(update: Update, _) -> None: 62 | query = update.callback_query 63 | chat = update.effective_chat 64 | 65 | query.answer() 66 | lang = query.data.split("_")[1] 67 | sql.set_lang(chat.id, lang) 68 | 69 | query.message.edit_text( 70 | gs(chat.id, "set_chat_lang").format(get_language(lang)[:-3]) 71 | ) 72 | 73 | 74 | SETLANG_HANDLER = CommandHandler("setlang", set_lang) 75 | SETLANG_BUTTON_HANDLER = CallbackQueryHandler(lang_button, pattern=r"setLang_") 76 | 77 | dispatcher.add_handler(SETLANG_HANDLER) 78 | dispatcher.add_handler(SETLANG_BUTTON_HANDLER) -------------------------------------------------------------------------------- /SiestaRobot/modules/paste.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import re 4 | 5 | import aiofiles 6 | from pykeyboard import InlineKeyboard 7 | from pyrogram import filters 8 | from pyrogram.types import InlineKeyboardButton 9 | 10 | from SiestaRobot import aiohttpsession as session 11 | from SiestaRobot import pbot as app 12 | from SiestaRobot.utils.errors import capture_err 13 | from SiestaRobot.utils.pastebin import paste 14 | 15 | __mod_name__ = "Paste​" 16 | 17 | pattern = re.compile( 18 | r"^text/|json$|yaml$|xml$|toml$|x-sh$|x-shellscript$" 19 | ) 20 | 21 | 22 | async def isPreviewUp(preview: str) -> bool: 23 | for _ in range(7): 24 | try: 25 | async with session.head(preview, timeout=2) as resp: 26 | status = resp.status 27 | size = resp.content_length 28 | except asyncio.exceptions.TimeoutError: 29 | return False 30 | if status == 404 or (status == 200 and size == 0): 31 | await asyncio.sleep(0.4) 32 | else: 33 | return True if status == 200 else False 34 | return False 35 | 36 | 37 | @app.on_message(filters.command("paste") & ~filters.edited) 38 | @capture_err 39 | async def paste_func(_, message): 40 | if not message.reply_to_message: 41 | return await message.reply_text( 42 | "Reply To A Message With /paste" 43 | ) 44 | m = await message.reply_text("Pasting...") 45 | if message.reply_to_message.text: 46 | content = str(message.reply_to_message.text) 47 | elif message.reply_to_message.document: 48 | document = message.reply_to_message.document 49 | if document.file_size > 1048576: 50 | return await m.edit( 51 | "You can only paste files smaller than 1MB." 52 | ) 53 | if not pattern.search(document.mime_type): 54 | return await m.edit("Only text files can be pasted.") 55 | doc = await message.reply_to_message.download() 56 | async with aiofiles.open(doc, mode="r") as f: 57 | content = await f.read() 58 | os.remove(doc) 59 | link = await paste(content) 60 | preview = link + "/preview.png" 61 | button = InlineKeyboard(row_width=1) 62 | button.add(InlineKeyboardButton(text="Paste Link", url=link)) 63 | 64 | if await isPreviewUp(preview): 65 | try: 66 | await message.reply_photo( 67 | photo=preview, quote=False, reply_markup=button 68 | ) 69 | return await m.delete() 70 | except Exception: 71 | pass 72 | return await m.edit(link) 73 | -------------------------------------------------------------------------------- /SiestaRobot/utils/http.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | Copyright (c) 2021 TheHamkerCat 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | """ 20 | from asyncio import gather 21 | 22 | from SiestaRobot import aiohttpsession as session 23 | 24 | 25 | async def get(url: str, *args, **kwargs): 26 | async with session.get(url, *args, **kwargs) as resp: 27 | try: 28 | data = await resp.json() 29 | except Exception: 30 | data = await resp.text() 31 | return data 32 | 33 | 34 | async def head(url: str, *args, **kwargs): 35 | async with session.head(url, *args, **kwargs) as resp: 36 | try: 37 | data = await resp.json() 38 | except Exception: 39 | data = await resp.text() 40 | return data 41 | 42 | 43 | async def post(url: str, *args, **kwargs): 44 | async with session.post(url, *args, **kwargs) as resp: 45 | try: 46 | data = await resp.json() 47 | except Exception: 48 | data = await resp.text() 49 | return data 50 | 51 | 52 | async def multiget(url: str, times: int, *args, **kwargs): 53 | return await gather(*[get(url, *args, **kwargs) for _ in range(times)]) 54 | 55 | 56 | async def multihead(url: str, times: int, *args, **kwargs): 57 | return await gather(*[head(url, *args, **kwargs) for _ in range(times)]) 58 | 59 | 60 | async def multipost(url: str, times: int, *args, **kwargs): 61 | return await gather(*[post(url, *args, **kwargs) for _ in range(times)]) 62 | 63 | 64 | async def resp_get(url: str, *args, **kwargs): 65 | return await session.get(url, *args, **kwargs) 66 | 67 | 68 | async def resp_post(url: str, *args, **kwargs): 69 | return await session.post(url, *args, **kwargs) 70 | -------------------------------------------------------------------------------- /SiestaRobot/modules/tiny.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | from PIL import Image 4 | from SiestaRobot.events import register 5 | from SiestaRobot import telethn as tbot 6 | 7 | 8 | @register(pattern="^/tiny ?(.*)") 9 | async def _(event): 10 | reply = await event.get_reply_message() 11 | if not (reply and(reply.media)): 12 | await event.reply("`Please reply to a sticker`") 13 | return 14 | kontol = await event.reply("`Processing tiny...`") 15 | ik = await tbot.download_media(reply) 16 | im1 = Image.open("SiestaRobot/resources/siesta_stickers.png") 17 | if ik.endswith(".tgs"): 18 | await tbot.download_media(reply, "ken.tgs") 19 | os.system("lottie_convert.py ken.tgs json.json") 20 | json = open("json.json", "r") 21 | jsn = json.read() 22 | jsn = jsn.replace("512", "2000") 23 | open = ("json.json", "w").write(jsn) 24 | os.system("lottie_convert.py json.json ken.tgs") 25 | file = "ken.tgs" 26 | os.remove("json.json") 27 | elif ik.endswith((".gif", ".mp4")): 28 | iik = cv2.VideoCapture(ik) 29 | busy = iik.read() 30 | cv2.imwrite("i.png", busy) 31 | fil = "i.png" 32 | im = Image.open(fil) 33 | z, d = im.size 34 | if z == d: 35 | xxx, yyy = 200, 200 36 | else: 37 | t = z + d 38 | a = z / t 39 | b = d / t 40 | aa = (a * 100) - 50 41 | bb = (b * 100) - 50 42 | xxx = 200 + 5 * aa 43 | yyy = 200 + 5 * bb 44 | k = im.resize((int(xxx), int(yyy))) 45 | k.save("k.png", format="PNG", optimize=True) 46 | im2 = Image.open("k.png") 47 | back_im = im1.copy() 48 | back_im.paste(im2, (150, 0)) 49 | back_im.save("o.webp", "WEBP", quality=95) 50 | file = "o.webp" 51 | os.remove(fil) 52 | os.remove("k.png") 53 | else: 54 | im = Image.open(ik) 55 | z, d = im.size 56 | if z == d: 57 | xxx, yyy = 200, 200 58 | else: 59 | t = z + d 60 | a = z / t 61 | b = d / t 62 | aa = (a * 100) - 50 63 | bb = (b * 100) - 50 64 | xxx = 200 + 5 * aa 65 | yyy = 200 + 5 * bb 66 | k = im.resize((int(xxx), int(yyy))) 67 | k.save("k.png", format="PNG", optimize=True) 68 | im2 = Image.open("k.png") 69 | back_im = im1.copy() 70 | back_im.paste(im2, (150, 0)) 71 | back_im.save("o.webp", "WEBP", quality=95) 72 | file = "o.webp" 73 | os.remove("k.png") 74 | await tbot.send_file(event.chat_id, file, reply_to=event.reply_to_msg_id) 75 | await kontol.delete() 76 | os.remove(file) 77 | os.remove(ik) 78 | -------------------------------------------------------------------------------- /SiestaRobot/modules/kamuii.py: -------------------------------------------------------------------------------- 1 | import os 2 | from telethon.errors.rpcerrorlist import YouBlockedUserError 3 | 4 | from SiestaRobot import ubot2 5 | from SiestaRobot.events import register 6 | from SiestaRobot import telethn as tbot, TEMP_DOWNLOAD_DIRECTORY, SUPPORT_CHAT 7 | 8 | 9 | @register(pattern="^/kamuii ?(.*)") 10 | async def _(fry): 11 | level = fry.pattern_match.group(1) 12 | kntl = await fry.reply("`Deepfrying this image...`") 13 | if fry.fwd_from: 14 | return 15 | if not fry.reply_to_msg_id: 16 | await kntl.edit("`Reply to a stickers`") 17 | return 18 | reply_message = await fry.get_reply_message() 19 | if not reply_message.media: 20 | await fry.edit("`this file not supported`") 21 | return 22 | if reply_message.sender.bot: 23 | await fry.edit("`Reply to a asticker to destroy`") 24 | return 25 | chat = "@image_deepfrybot" 26 | message_id_to_reply = fry.message.reply_to_msg_id 27 | async with ubot2.conversation(chat) as conv: 28 | try: 29 | msg = await conv.send_message(reply_message) 30 | if level: 31 | m = f"/deepfry {level}" 32 | msg_level = await conv.send_message( 33 | m, 34 | reply_to=msg.id) 35 | r = await conv.get_response() 36 | response = await conv.get_response() 37 | else: 38 | response = await conv.get_response() 39 | """ - don't spam notif - """ 40 | await ubot2.send_read_acknowledge(conv.chat_id) 41 | except YouBlockedUserError: 42 | await fry.reply(f"`Error, tell the problem on @{SUPPORT_CHAT}`") 43 | return 44 | if response.text.startswith("Forward"): 45 | await fry.edit(f"`Error, tell the problem on @{SUPPORT_CHAT}`") 46 | else: 47 | downloaded_file_name = await ubot2.download_media( 48 | response.media, 49 | TEMP_DOWNLOAD_DIRECTORY 50 | ) 51 | await tbot.send_file( 52 | fry.chat_id, 53 | downloaded_file_name, 54 | force_document=False, 55 | reply_to=message_id_to_reply 56 | ) 57 | """ - cleanup chat after completed - """ 58 | try: 59 | msg_level 60 | except NameError: 61 | await ubot2.delete_messages(conv.chat_id, 62 | [msg.id, response.id]) 63 | else: 64 | await ubot2.delete_messages( 65 | conv.chat_id, 66 | [msg.id, response.id, r.id, msg_level.id]) 67 | await kntl.delete() 68 | return os.remove(downloaded_file_name) 69 | -------------------------------------------------------------------------------- /SiestaRobot/utils/permissions.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from pyrogram.errors.exceptions.forbidden_403 import ChatWriteForbidden 3 | from pyrogram.types import Message 4 | from SiestaRobot import pbot as app 5 | from SiestaRobot import DRAGONS, DEV_USERS, WOLVES, DEMONS, TIGERS 6 | from SiestaRobot.utils.adminperms import member_permissions 7 | 8 | SUDO = DRAGONS, DEV_USERS, WOLVES, DEMONS, TIGERS 9 | 10 | 11 | async def authorised(func, subFunc2, client, message, *args, **kwargs): 12 | chatID = message.chat.id 13 | try: 14 | await func(client, message, *args, **kwargs) 15 | except ChatWriteForbidden: 16 | await app.leave_chat(chatID) 17 | except Exception as e: 18 | try: 19 | await message.reply_text(str(e)) 20 | except ChatWriteForbidden: 21 | await app.leave_chat(chatID) 22 | return subFunc2 23 | 24 | 25 | async def unauthorised(message: Message, permission, subFunc2): 26 | chatID = message.chat.id 27 | text = ( 28 | "You don't have the required permission to perform this action." 29 | + f"\n**Permission:** __{permission}__" 30 | ) 31 | try: 32 | await message.reply_text(text) 33 | except ChatWriteForbidden: 34 | await app.leave_chat(chatID) 35 | return subFunc2 36 | 37 | 38 | def adminsOnly(permission): 39 | def subFunc(func): 40 | @wraps(func) 41 | async def subFunc2(client, message: Message, *args, **kwargs): 42 | chatID = message.chat.id 43 | if not message.from_user: 44 | # For anonymous admins 45 | if message.sender_chat: 46 | return await authorised( 47 | func, subFunc2, client, message, *args, **kwargs 48 | ) 49 | return await unauthorised(message, permission, subFunc2) 50 | # For admins and sudo users 51 | userID = message.from_user.id 52 | permissions = await member_permissions(chatID, userID) 53 | if userID not in SUDO and permission not in permissions: 54 | return await unauthorised(message, permission, subFunc2) 55 | return await authorised(func, subFunc2, client, message, *args, **kwargs) 56 | 57 | return subFunc2 58 | 59 | return subFunc 60 | 61 | 62 | async def edit_or_reply(message, text, parse_mode="md"): 63 | if message.from_user.id: 64 | if message.reply_to_message: 65 | kk = message.reply_to_message.message_id 66 | return await message.reply_text( 67 | text, reply_to_message_id=kk, parse_mode=parse_mode 68 | ) 69 | return await message.reply_text(text, parse_mode=parse_mode) 70 | return await message.edit(text, parse_mode=parse_mode) 71 | -------------------------------------------------------------------------------- /SiestaRobot/modules/mentionsall.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import asyncio 4 | 5 | from telethon import Button, TelegramClient, events 6 | from telethon.tl.types import ChannelParticipantAdmin, ChannelParticipantCreator 7 | from telethon.tl.functions.channels import GetParticipantRequest 8 | from telethon.errors import UserNotParticipantError 9 | 10 | from SiestaRobot import telethn as Client 11 | 12 | spam_chats = [] 13 | 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("This command can be use in groups and channels!") 19 | 20 | is_admin = False 21 | try: 22 | partici_ = await Client(GetParticipantRequest( 23 | event.chat_id, 24 | event.sender_id 25 | )) 26 | except UserNotParticipantError: 27 | is_admin = False 28 | else: 29 | if ( 30 | isinstance( 31 | partici_.participant, 32 | ( 33 | ChannelParticipantAdmin, 34 | ChannelParticipantCreator 35 | ) 36 | ) 37 | ): 38 | is_admin = True 39 | if not is_admin: 40 | return await event.respond("Only admins can mention all!") 41 | 42 | if event.pattern_match.group(1) and event.is_reply: 43 | return await event.respond("Give me one argument!") 44 | elif event.pattern_match.group(1): 45 | mode = "text_on_cmd" 46 | msg = event.pattern_match.group(1) 47 | elif event.is_reply: 48 | mode = "text_on_reply" 49 | msg = await event.get_reply_message() 50 | if msg == None: 51 | return await event.respond("I can't mention members for older messages! (messages which are sent before I'm added to group)") 52 | else: 53 | return await event.respond("Reply to a message or give me some text to mention others!") 54 | 55 | Spam = spam_chats.append(chat_id) 56 | usrnum = 0 57 | usrtxt = '' 58 | async for usr in Client.iter_participants(chat_id): 59 | if not chat_id in spam_chats: 60 | break 61 | usrnum += 1 62 | usrtxt += f"[{usr.first_name}](tg://user?id={usr.id}) " 63 | if usrnum == 10: 64 | if mode == "text_on_cmd": 65 | txt = f"{usrtxt}\n\n{msg}" 66 | await Client.send_message(chat_id, txt) 67 | elif mode == "text_on_reply": 68 | await msg.reply(usrtxt) 69 | await asyncio.sleep(2) 70 | usrnum = 0 71 | usrtxt = '' 72 | try: 73 | spam_chats.remove(chat_id) 74 | except: 75 | pass 76 | 77 | @Client.on(events.NewMessage(pattern="^/cancel$")) 78 | async def cancel_spam(event): 79 | if not event.chat_id in spam_chats: 80 | return await event.respond('There is no proccess on going...') 81 | else: 82 | try: 83 | spam_chats.remove(event.chat_id) 84 | except: 85 | pass 86 | return await event.respond('Stopped.') 87 | 88 | __mod_name__ = "Mentions" 89 | -------------------------------------------------------------------------------- /SiestaRobot/modules/purge.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | from telethon import events 4 | 5 | from SiestaRobot import telethn 6 | from SiestaRobot.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 ( 18 | not await user_is_admin( 19 | user_id=event.sender_id, 20 | message=event, 21 | ) 22 | and event.from_id not in [1087968824] 23 | ): 24 | await event.reply("Only Admins are allowed to use this command") 25 | return 26 | 27 | if not await can_delete_messages(message=event): 28 | await event.reply("Can't seem to purge the message") 29 | return 30 | 31 | reply_msg = await event.get_reply_message() 32 | if not reply_msg: 33 | await event.reply("Reply to a message to select where to start purging from.") 34 | return 35 | messages = [] 36 | message_id = reply_msg.id 37 | delete_to = event.message.id 38 | 39 | messages.append(event.reply_to_msg_id) 40 | for msg_id in range(message_id, delete_to + 1): 41 | messages.append(msg_id) 42 | if len(messages) == 100: 43 | await event.client.delete_messages(event.chat_id, messages) 44 | messages = [] 45 | 46 | try: 47 | await event.client.delete_messages(event.chat_id, messages) 48 | except: 49 | pass 50 | time_ = time.perf_counter() - start 51 | text = f"Purged Successfully in {time_:0.2f} Second(s)" 52 | await event.respond(text, parse_mode="markdown") 53 | 54 | async def delete_messages(event): 55 | if event.from_id is None: 56 | return 57 | 58 | if ( 59 | not await user_is_admin( 60 | user_id=event.sender_id, 61 | message=event, 62 | ) 63 | and event.from_id not in [1087968824] 64 | ): 65 | await event.reply("Only Admins are allowed to use this command") 66 | return 67 | 68 | if not await can_delete_messages(message=event): 69 | await event.reply("Can't seem to delete this?") 70 | return 71 | 72 | message = await event.get_reply_message() 73 | if not message: 74 | await event.reply("Whadya want to delete?") 75 | return 76 | chat = await event.get_input_chat() 77 | del_message = [message, event.message] 78 | await event.client.delete_messages(chat, del_message) 79 | 80 | PURGE_HANDLER = purge_messages, events.NewMessage(pattern="^[!/]purge$") 81 | DEL_HANDLER = delete_messages, events.NewMessage(pattern="^[!/]del$") 82 | 83 | telethn.add_event_handler(*PURGE_HANDLER) 84 | telethn.add_event_handler(*DEL_HANDLER) 85 | 86 | __mod_name__ = "Purges" 87 | __command_list__ = ["del", "purge"] 88 | __handlers__ = [PURGE_HANDLER, DEL_HANDLER] 89 | -------------------------------------------------------------------------------- /SiestaRobot/modules/shippering.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import pbot as app 2 | from SiestaRobot.utils.errors import capture_err 3 | from SiestaRobot.ex_plugins.dbfunctions import get_couple, save_couple 4 | from pyrogram import filters 5 | import random 6 | from datetime import datetime 7 | 8 | 9 | # Date and time 10 | def dt(): 11 | now = datetime.now() 12 | dt_string = now.strftime("%d/%m/%Y %H:%M") 13 | dt_list = dt_string.split(" ") 14 | return dt_list 15 | 16 | 17 | def dt_tom(): 18 | a = ( 19 | str(int(dt()[0].split("/")[0]) + 1) 20 | + "/" 21 | + dt()[0].split("/")[1] 22 | + "/" 23 | + dt()[0].split("/")[2] 24 | ) 25 | return a 26 | 27 | 28 | today = str(dt()[0]) 29 | tomorrow = str(dt_tom()) 30 | 31 | 32 | @app.on_message(filters.command("couples") & ~filters.edited) 33 | @capture_err 34 | async def couple(_, message): 35 | if message.chat.type == "private": 36 | await message.reply_text("This command only works in groups.") 37 | return 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 app.iter_chat_members(message.chat.id): 44 | if not i.user.is_bot: 45 | list_of_users.append(i.user.id) 46 | if len(list_of_users) < 2: 47 | await message.reply_text("Not enough users") 48 | return 49 | c1_id = random.choice(list_of_users) 50 | c2_id = random.choice(list_of_users) 51 | while c1_id == c2_id: 52 | c1_id = random.choice(list_of_users) 53 | c1_mention = (await app.get_users(c1_id)).mention 54 | c2_mention = (await app.get_users(c2_id)).mention 55 | 56 | couple_selection_message = f"""**Couple of the day:** 57 | {c1_mention} + {c2_mention} = ❤️ 58 | __New couple of the day may be chosen at 12AM {tomorrow}__""" 59 | await app.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 app.get_users(c1_id)).first_name 67 | c2_name = (await app.get_users(c2_id)).first_name 68 | couple_selection_message = f"""Couple of the day: 69 | [{c1_name}](tg://openmessage?user_id={c1_id}) + [{c2_name}](tg://openmessage?user_id={c2_id}) = ❤️ 70 | __New couple of the day may be chosen at 12AM {tomorrow}__""" 71 | await app.send_message(message.chat.id, text=couple_selection_message) 72 | except Exception as e: 73 | print(e) 74 | await message.reply_text(e) 75 | 76 | 77 | __mod_name__ = "Couples" 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Config files, logs and stuff 2 | NaoRobot/modules/helper_funcs/temp.txt 3 | NaoRobot/elevated_users.json 4 | NaoRobot/config.py 5 | NaoRobot/config.ini 6 | log.txt 7 | kangsticker.png 8 | updates.txt 9 | start_service.bat 10 | 11 | # Session files 12 | NaoRobot/*.session 13 | NaoRobot/*.session-journal 14 | Nao.session-journal 15 | *.session 16 | 17 | # Byte-compiled / optimized / DLL files 18 | __pycache__/ 19 | *.py[cod] 20 | *$py.class 21 | 22 | # C extensions 23 | *.so 24 | 25 | # Distribution / packaging 26 | .Python 27 | build/ 28 | develop-eggs/ 29 | dist/ 30 | downloads/ 31 | eggs/ 32 | .eggs/ 33 | lib/ 34 | lib64/ 35 | parts/ 36 | sdist/ 37 | var/ 38 | wheels/ 39 | pip-wheel-metadata/ 40 | share/python-wheels/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | MANIFEST 45 | 46 | # PyInstaller 47 | # Usually these files are written by a python script from a template 48 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 49 | *.manifest 50 | *.spec 51 | 52 | # Installer logs 53 | pip-log.txt 54 | pip-delete-this-directory.txt 55 | 56 | # Unit test / coverage reports 57 | htmlcov/ 58 | .tox/ 59 | .nox/ 60 | .coverage 61 | .coverage.* 62 | .cache 63 | nosetests.xml 64 | coverage.xml 65 | *.cover 66 | *.py,cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | 70 | # Translations 71 | *.mo 72 | *.pot 73 | 74 | # Django stuff: 75 | *.log 76 | local_settings.py 77 | db.sqlite3 78 | db.sqlite3-journal 79 | 80 | # Flask stuff: 81 | instance/ 82 | .webassets-cache 83 | 84 | # Scrapy stuff: 85 | .scrapy 86 | 87 | # Sphinx documentation 88 | docs/_build/ 89 | 90 | # PyBuilder 91 | target/ 92 | 93 | # Jupyter Notebook 94 | .ipynb_checkpoints 95 | 96 | # IPython 97 | profile_default/ 98 | ipython_config.py 99 | 100 | # pyenv 101 | .python-version 102 | 103 | # pipenv 104 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 105 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 106 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 107 | # install all needed dependencies. 108 | #Pipfile.lock 109 | 110 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 111 | __pypackages__/ 112 | 113 | # Celery stuff 114 | celerybeat-schedule 115 | celerybeat.pid 116 | 117 | # SageMath parsed files 118 | *.sage.py 119 | 120 | # Environments 121 | .env 122 | .venv 123 | env/ 124 | venv/ 125 | ENV/ 126 | env.bak/ 127 | venv.bak/ 128 | 129 | # Spyder project settings 130 | .spyderproject 131 | .spyproject 132 | 133 | # Rope project settings 134 | .ropeproject 135 | 136 | # mkdocs documentation 137 | /site 138 | 139 | # mypy 140 | .mypy_cache/ 141 | .dmypy.json 142 | dmypy.json 143 | 144 | # Pyre type checker 145 | .pyre/ 146 | 147 | # VS code and shit 148 | *.pyc 149 | .idea/ 150 | .project 151 | .pydevproject 152 | .directory 153 | .vscode 154 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/reporting_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from typing import Union 3 | 4 | from SiestaRobot.modules.sql import BASE, SESSION 5 | from sqlalchemy import Boolean, Column, String 6 | from sqlalchemy.sql.sqltypes import BigInteger 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 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sql/disable_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from SiestaRobot.modules.sql import BASE, SESSION 4 | from sqlalchemy import Column, String, UnicodeText, distinct, func 5 | 6 | 7 | class Disable(BASE): 8 | __tablename__ = "disabled_commands" 9 | chat_id = Column(String(14), primary_key=True) 10 | command = Column(UnicodeText, primary_key=True) 11 | 12 | def __init__(self, chat_id, command): 13 | self.chat_id = chat_id 14 | self.command = command 15 | 16 | def __repr__(self): 17 | return "Disabled cmd {} in {}".format(self.command, self.chat_id) 18 | 19 | 20 | Disable.__table__.create(checkfirst=True) 21 | DISABLE_INSERTION_LOCK = threading.RLock() 22 | 23 | DISABLED = {} 24 | 25 | 26 | def disable_command(chat_id, disable): 27 | with DISABLE_INSERTION_LOCK: 28 | disabled = SESSION.query(Disable).get((str(chat_id), disable)) 29 | 30 | if not disabled: 31 | DISABLED.setdefault(str(chat_id), set()).add(disable) 32 | 33 | disabled = Disable(str(chat_id), disable) 34 | SESSION.add(disabled) 35 | SESSION.commit() 36 | return True 37 | 38 | SESSION.close() 39 | return False 40 | 41 | 42 | def enable_command(chat_id, enable): 43 | with DISABLE_INSERTION_LOCK: 44 | disabled = SESSION.query(Disable).get((str(chat_id), enable)) 45 | 46 | if disabled: 47 | if enable in DISABLED.get(str(chat_id)): # sanity check 48 | DISABLED.setdefault(str(chat_id), set()).remove(enable) 49 | 50 | SESSION.delete(disabled) 51 | SESSION.commit() 52 | return True 53 | 54 | SESSION.close() 55 | return False 56 | 57 | 58 | def is_command_disabled(chat_id, cmd): 59 | return str(cmd).lower() in DISABLED.get(str(chat_id), set()) 60 | 61 | 62 | def get_all_disabled(chat_id): 63 | return DISABLED.get(str(chat_id), set()) 64 | 65 | 66 | def num_chats(): 67 | try: 68 | return SESSION.query(func.count(distinct(Disable.chat_id))).scalar() 69 | finally: 70 | SESSION.close() 71 | 72 | 73 | def num_disabled(): 74 | try: 75 | return SESSION.query(Disable).count() 76 | finally: 77 | SESSION.close() 78 | 79 | 80 | def migrate_chat(old_chat_id, new_chat_id): 81 | with DISABLE_INSERTION_LOCK: 82 | chats = SESSION.query(Disable).filter(Disable.chat_id == str(old_chat_id)).all() 83 | for chat in chats: 84 | chat.chat_id = str(new_chat_id) 85 | SESSION.add(chat) 86 | 87 | if str(old_chat_id) in DISABLED: 88 | DISABLED[str(new_chat_id)] = DISABLED.get(str(old_chat_id), set()) 89 | 90 | SESSION.commit() 91 | 92 | 93 | def __load_disabled_commands(): 94 | global DISABLED 95 | try: 96 | all_chats = SESSION.query(Disable).all() 97 | for chat in all_chats: 98 | DISABLED.setdefault(chat.chat_id, set()).add(chat.command) 99 | 100 | finally: 101 | SESSION.close() 102 | 103 | 104 | __load_disabled_commands() 105 | -------------------------------------------------------------------------------- /SiestaRobot/modules/country.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.functions.photos import GetUserPhotosRequest 2 | from telethon.tl.functions.users import GetFullUserRequest 3 | from telethon.tl.types import MessageEntityMentionName 4 | from telethon.utils import get_input_location 5 | import flag 6 | import html, os 7 | from countryinfo import CountryInfo 8 | from SiestaRobot import telethn as borg 9 | from SiestaRobot.events import register 10 | 11 | 12 | @register(pattern="^/country (.*)") 13 | async def msg(event): 14 | if event.fwd_from: 15 | return 16 | input_str = event.pattern_match.group(1) 17 | lol = input_str 18 | country = CountryInfo(lol) 19 | try: 20 | a = country.info() 21 | except: 22 | await event.reply("Country Not Avaiable Currently") 23 | name = a.get("name") 24 | bb = a.get("altSpellings") 25 | hu = "" 26 | for p in bb: 27 | hu += p + ", " 28 | 29 | area = a.get("area") 30 | borders = "" 31 | hell = a.get("borders") 32 | for fk in hell: 33 | borders += fk + ", " 34 | 35 | call = "" 36 | WhAt = a.get("callingCodes") 37 | for what in WhAt: 38 | call += what + " " 39 | 40 | capital = a.get("capital") 41 | currencies = "" 42 | fker = a.get("currencies") 43 | for FKer in fker: 44 | currencies += FKer + ", " 45 | 46 | HmM = a.get("demonym") 47 | geo = a.get("geoJSON") 48 | pablo = geo.get("features") 49 | Pablo = pablo[0] 50 | PAblo = Pablo.get("geometry") 51 | EsCoBaR = PAblo.get("type") 52 | iso = "" 53 | iSo = a.get("ISO") 54 | for hitler in iSo: 55 | po = iSo.get(hitler) 56 | iso += po + ", " 57 | fla = iSo.get("alpha2") 58 | nox = fla.upper() 59 | okie = flag.flag(nox) 60 | 61 | languages = a.get("languages") 62 | lMAO = "" 63 | for lmao in languages: 64 | lMAO += lmao + ", " 65 | 66 | nonive = a.get("nativeName") 67 | waste = a.get("population") 68 | reg = a.get("region") 69 | sub = a.get("subregion") 70 | tik = a.get("timezones") 71 | tom = "" 72 | for jerry in tik: 73 | tom += jerry + ", " 74 | 75 | GOT = a.get("tld") 76 | lanester = "" 77 | for targaryen in GOT: 78 | lanester += targaryen + ", " 79 | 80 | wiki = a.get("wiki") 81 | 82 | caption = f"""Information Gathered Successfully 83 | 84 | Country Name:- {name} 85 | Alternative Spellings:- {hu} 86 | Country Area:- {area} square kilometers 87 | Borders:- {borders} 88 | Calling Codes:- {call} 89 | Country's Capital:- {capital} 90 | Country's currency:- {currencies} 91 | Country's Flag:- {okie} 92 | Demonym:- {HmM} 93 | Country Type:- {EsCoBaR} 94 | ISO Names:- {iso} 95 | Languages:- {lMAO} 96 | Native Name:- {nonive} 97 | population:- {waste} 98 | Region:- {reg} 99 | Sub Region:- {sub} 100 | Time Zones:- {tom} 101 | Top Level Domain:- {lanester} 102 | wikipedia:- {wiki} 103 | 104 | Gathered By Siesta Robot ✨. 105 | """ 106 | 107 | await borg.send_message( 108 | event.chat_id, 109 | caption, 110 | parse_mode="HTML", 111 | ) 112 | 113 | await event.delete() 114 | -------------------------------------------------------------------------------- /SiestaRobot/modules/weather.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | import time 4 | 5 | import aiohttp 6 | from telethon import * 7 | from telethon.tl import functions 8 | from telethon.tl import types 9 | from telethon.tl.types import * 10 | 11 | from SiestaRobot import * 12 | 13 | from SiestaRobot import telethn as tbot 14 | from SiestaRobot.events import register 15 | 16 | 17 | async def is_register_admin(chat, user): 18 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 19 | return isinstance( 20 | ( 21 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 22 | ).participant, 23 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 24 | ) 25 | if isinstance(chat, types.InputPeerUser): 26 | return True 27 | 28 | 29 | @register(pattern="^/weather (.*)") 30 | async def _(event): 31 | if event.fwd_from: 32 | return 33 | 34 | sample_url = ( 35 | "https://api.openweathermap.org/data/2.5/weather?q={}&APPID={}&units=metric" 36 | ) 37 | input_str = event.pattern_match.group(1) 38 | async with aiohttp.ClientSession() as session: 39 | response_api_zero = await session.get( 40 | sample_url.format(input_str, OPENWEATHERMAP_ID) 41 | ) 42 | response_api = await response_api_zero.json() 43 | if response_api["cod"] == 200: 44 | country_code = response_api["sys"]["country"] 45 | country_time_zone = int(response_api["timezone"]) 46 | sun_rise_time = int(response_api["sys"]["sunrise"]) + country_time_zone 47 | sun_set_time = int(response_api["sys"]["sunset"]) + country_time_zone 48 | await event.reply( 49 | """**Location**: {} 50 | **Temperature**: {}°С 51 | __minimium__: {}°С 52 | __maximum__ : {}°С 53 | **Humidity**: {}% 54 | **Wind**: {}m/s 55 | **Clouds**: {}hpa 56 | **Sunrise**: {} {} 57 | **Sunset**: {} {}""".format( 58 | input_str, 59 | response_api["main"]["temp"], 60 | response_api["main"]["temp_min"], 61 | response_api["main"]["temp_max"], 62 | response_api["main"]["humidity"], 63 | response_api["wind"]["speed"], 64 | response_api["clouds"]["all"], 65 | # response_api["main"]["pressure"], 66 | time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(sun_rise_time)), 67 | country_code, 68 | time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(sun_set_time)), 69 | country_code, 70 | ) 71 | ) 72 | else: 73 | await event.reply(response_api["message"]) 74 | 75 | 76 | @register(pattern="^/wttr (.*)") 77 | async def _(event): 78 | if event.fwd_from: 79 | return 80 | 81 | sample_url = "https://wttr.in/{}.png" 82 | # logger.info(sample_url) 83 | input_str = event.pattern_match.group(1) 84 | async with aiohttp.ClientSession() as session: 85 | response_api_zero = await session.get(sample_url.format(input_str)) 86 | # logger.info(response_api_zero) 87 | response_api = await response_api_zero.read() 88 | with io.BytesIO(response_api) as out_file: 89 | await event.reply(file=out_file) 90 | -------------------------------------------------------------------------------- /SiestaRobot/modules/dev.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import sys 4 | 5 | from contextlib import suppress 6 | from time import sleep 7 | 8 | import SiestaRobot 9 | 10 | from SiestaRobot import dispatcher 11 | from SiestaRobot.modules.helper_funcs.chat_status import dev_plus 12 | from telegram import TelegramError, Update 13 | from telegram.error import Unauthorized 14 | from telegram.ext import CallbackContext, CommandHandler 15 | 16 | 17 | @dev_plus 18 | def allow_groups(update: Update, context: CallbackContext): 19 | args = context.args 20 | if not args: 21 | state = "Lockdown is " + "on" if not SiestaRobot.ALLOW_CHATS else "off" 22 | update.effective_message.reply_text(f"Current state: {state}") 23 | return 24 | if args[0].lower() in ["off", "no"]: 25 | SiestaRobot.ALLOW_CHATS = True 26 | elif args[0].lower() in ["yes", "on"]: 27 | SiestaRobot.ALLOW_CHATS = False 28 | else: 29 | update.effective_message.reply_text("Format: /lockdown Yes/No or Off/On") 30 | return 31 | update.effective_message.reply_text("Done! Lockdown value toggled.") 32 | 33 | 34 | @dev_plus 35 | def leave(update: Update, context: CallbackContext): 36 | bot = context.bot 37 | args = context.args 38 | if args: 39 | chat_id = str(args[0]) 40 | try: 41 | bot.leave_chat(int(chat_id)) 42 | except TelegramError: 43 | update.effective_message.reply_text( 44 | "Beep boop, I could not leave that group(dunno why tho).", 45 | ) 46 | return 47 | with suppress(Unauthorized): 48 | update.effective_message.reply_text("Beep boop, I left that soup!.") 49 | else: 50 | update.effective_message.reply_text("Send a valid chat ID") 51 | 52 | 53 | @dev_plus 54 | def gitpull(update: Update, context: CallbackContext): 55 | sent_msg = update.effective_message.reply_text( 56 | "Pulling all changes from remote and then attempting to restart.", 57 | ) 58 | subprocess.Popen("git pull", stdout=subprocess.PIPE, shell=True) 59 | 60 | sent_msg_text = sent_msg.text + "\n\nChanges pulled...I guess.. Restarting in " 61 | 62 | for i in reversed(range(5)): 63 | sent_msg.edit_text(sent_msg_text + str(i + 1)) 64 | sleep(1) 65 | 66 | sent_msg.edit_text("Restarted.") 67 | 68 | os.system("restart.bat") 69 | os.execv("start.bat", sys.argv) 70 | 71 | 72 | @dev_plus 73 | def restart(update: Update, context: CallbackContext): 74 | update.effective_message.reply_text( 75 | "Starting a new instance and shutting down this one", 76 | ) 77 | 78 | os.system("restart.bat") 79 | os.execv("start.bat", sys.argv) 80 | 81 | 82 | LEAVE_HANDLER = CommandHandler("leave", leave, run_async=True) 83 | GITPULL_HANDLER = CommandHandler("gitpull", gitpull, run_async=True) 84 | RESTART_HANDLER = CommandHandler("reboot", restart, run_async=True) 85 | ALLOWGROUPS_HANDLER = CommandHandler("lockdown", allow_groups, run_async=True) 86 | 87 | dispatcher.add_handler(ALLOWGROUPS_HANDLER) 88 | dispatcher.add_handler(LEAVE_HANDLER) 89 | dispatcher.add_handler(GITPULL_HANDLER) 90 | dispatcher.add_handler(RESTART_HANDLER) 91 | 92 | __mod_name__ = "Dev" 93 | __handlers__ = [LEAVE_HANDLER, GITPULL_HANDLER, RESTART_HANDLER, ALLOWGROUPS_HANDLER] 94 | -------------------------------------------------------------------------------- /SiestaRobot/modules/urluploader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | import aiohttp 5 | 6 | from SiestaRobot.utils.uputils import humanbytes, time_formatter 7 | 8 | 9 | async def download_file(url, file_name, message, start_time, bot): 10 | async with aiohttp.ClientSession() as session: 11 | time.time() 12 | await download_coroutine(session, url, file_name, message, start_time, bot) 13 | return file_name 14 | 15 | 16 | async def download_coroutine(session, url, file_name, event, start, bot): 17 | 18 | CHUNK_SIZE = 1024 * 6 # 2341 19 | downloaded = 0 20 | display_message = "" 21 | async with session.get(url) as response: 22 | total_length = int(response.headers["Content-Length"]) 23 | content_type = response.headers["Content-Type"] 24 | if "text" in content_type and total_length < 500: 25 | return await response.release() 26 | await event.edit( 27 | """**Initiating Download** 28 | **URL:** {} 29 | **File Name:** {} 30 | **File Size:** {} 31 | **© @Misszero_bot**""".format( 32 | url, 33 | os.path.basename(file_name).replace("%20", " "), 34 | humanbytes(total_length), 35 | ), 36 | parse_mode="md", 37 | ) 38 | with open(file_name, "wb") as f_handle: 39 | while True: 40 | chunk = await response.content.read(CHUNK_SIZE) 41 | if not chunk: 42 | break 43 | f_handle.write(chunk) 44 | downloaded += CHUNK_SIZE 45 | now = time.time() 46 | diff = now - start 47 | if round(diff % 10.00) == 0: # downloaded == total_length: 48 | percentage = downloaded * 100 / total_length 49 | speed = downloaded / diff 50 | elapsed_time = round(diff) * 1000 51 | time_to_completion = ( 52 | round((total_length - downloaded) / speed) * 1000 53 | ) 54 | estimated_total_time = elapsed_time + time_to_completion 55 | try: 56 | if total_length < downloaded: 57 | total_length = downloaded 58 | current_message = """Downloading : {}% 59 | URL: {} 60 | File Name: {} 61 | File Size: {} 62 | Downloaded: {} 63 | ETA: {}""".format( 64 | "%.2f" % (percentage), 65 | url, 66 | file_name.split("/")[-1], 67 | humanbytes(total_length), 68 | humanbytes(downloaded), 69 | time_formatter(estimated_total_time), 70 | ) 71 | if ( 72 | current_message != display_message 73 | and current_message != "empty" 74 | ): 75 | print(current_message) 76 | await event.edit(current_message, parse_mode="html") 77 | 78 | display_message = current_message 79 | except Exception as e: 80 | print("Error", e) 81 | # logger.info(str(e)) 82 | return await response.release() 83 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/telethn/chatstatus.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot.modules.helper_funcs.telethn import IMMUNE_USERS, telethn 2 | from SiestaRobot import DRAGONS 3 | from telethon.tl.types import ChannelParticipantsAdmins 4 | 5 | 6 | async def user_is_ban_protected(user_id: int, message): 7 | status = False 8 | if message.is_private or user_id in (IMMUNE_USERS): 9 | return True 10 | 11 | async for user in telethn.iter_participants( 12 | message.chat_id, 13 | 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, 28 | filter=ChannelParticipantsAdmins, 29 | ): 30 | if user_id == user.id or user_id in DRAGONS: 31 | status = True 32 | break 33 | return status 34 | 35 | 36 | async def is_user_admin(user_id: int, chat_id): 37 | status = False 38 | async for user in telethn.iter_participants( 39 | chat_id, 40 | filter=ChannelParticipantsAdmins, 41 | ): 42 | if user_id == user.id or user_id in DRAGONS: 43 | status = True 44 | break 45 | return status 46 | 47 | 48 | async def saitama_is_admin(chat_id: int): 49 | status = False 50 | saitama = await telethn.get_me() 51 | async for user in telethn.iter_participants( 52 | chat_id, 53 | filter=ChannelParticipantsAdmins, 54 | ): 55 | if saitama.id == user.id: 56 | status = True 57 | break 58 | return status 59 | 60 | 61 | async def is_user_in_chat(chat_id: int, user_id: int): 62 | status = False 63 | async for user in telethn.iter_participants(chat_id): 64 | if user_id == user.id: 65 | status = True 66 | break 67 | return status 68 | 69 | 70 | async def can_change_info(message): 71 | status = False 72 | if message.chat.admin_rights: 73 | status = message.chat.admin_rights.change_info 74 | return status 75 | 76 | 77 | async def can_ban_users(message): 78 | status = False 79 | if message.chat.admin_rights: 80 | status = message.chat.admin_rights.ban_users 81 | return status 82 | 83 | 84 | async def can_pin_messages(message): 85 | status = False 86 | if message.chat.admin_rights: 87 | status = message.chat.admin_rights.pin_messages 88 | return status 89 | 90 | 91 | async def can_invite_users(message): 92 | status = False 93 | if message.chat.admin_rights: 94 | status = message.chat.admin_rights.invite_users 95 | return status 96 | 97 | 98 | async def can_add_admins(message): 99 | status = False 100 | if message.chat.admin_rights: 101 | status = message.chat.admin_rights.add_admins 102 | return status 103 | 104 | 105 | async def can_delete_messages(message): 106 | 107 | if message.is_private: 108 | return True 109 | if message.chat.admin_rights: 110 | status = message.chat.admin_rights.delete_messages 111 | return status 112 | return False 113 | -------------------------------------------------------------------------------- /SiestaRobot/modules/quotes.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | from traceback import format_exc 3 | 4 | from pyrogram import filters 5 | from pyrogram.types import Message 6 | 7 | from SiestaRobot import arq 8 | from SiestaRobot.utils.errors import capture_err 9 | from SiestaRobot import pbot as app 10 | 11 | 12 | async def quotify(messages: list): 13 | response = await arq.quotly(messages) 14 | if not response.ok: 15 | return [False, response.result] 16 | sticker = response.result 17 | sticker = BytesIO(sticker) 18 | sticker.name = "sticker.webp" 19 | return [True, sticker] 20 | 21 | 22 | def getArg(message: Message) -> str: 23 | arg = message.text.strip().split(None, 1)[1].strip() 24 | return arg 25 | 26 | 27 | def isArgInt(message: Message) -> bool: 28 | count = getArg(message) 29 | try: 30 | count = int(count) 31 | return [True, count] 32 | except ValueError: 33 | return [False, 0] 34 | 35 | 36 | @app.on_message(filters.command("q") & ~filters.forwarded & ~filters.bot & ~filters.edited) 37 | @capture_err 38 | async def quotly_func(client, message: Message): 39 | if not message.reply_to_message: 40 | return await message.reply_text("Reply to a message to quote it.") 41 | if not message.reply_to_message.text: 42 | return await message.reply_text("Replied message has no text, can't quote it.") 43 | m = await message.reply_text("Quoting Messages Please wait....") 44 | if len(message.command) < 2: 45 | messages = [message.reply_to_message] 46 | 47 | elif len(message.command) == 2: 48 | arg = isArgInt(message) 49 | if arg[0]: 50 | if arg[1] < 2 or arg[1] > 10: 51 | return await m.edit("Argument must be between 2-10.") 52 | count = arg[1] 53 | messages = await client.get_messages( 54 | message.chat.id, 55 | [ 56 | i 57 | for i in range( 58 | message.reply_to_message.message_id, 59 | message.reply_to_message.message_id + count, 60 | ) 61 | ], 62 | replies=0, 63 | ) 64 | else: 65 | if getArg(message) != "r": 66 | return await m.edit( 67 | "Incorrect Argument, Pass **'r'** or **'INT'**, **EX:** __/q 2__" 68 | ) 69 | reply_message = await client.get_messages( 70 | message.chat.id, 71 | message.reply_to_message.message_id, 72 | replies=1, 73 | ) 74 | messages = [reply_message] 75 | else: 76 | await m.edit("Incorrect argument, check quotly module in help section.") 77 | return 78 | try: 79 | sticker = await quotify(messages) 80 | if not sticker[0]: 81 | await message.reply_text(sticker[1]) 82 | return await m.delete() 83 | sticker = sticker[1] 84 | await message.reply_sticker(sticker) 85 | await m.delete() 86 | sticker.close() 87 | except Exception as e: 88 | await m.edit( 89 | "Something wrong happened while quoting messages," 90 | + " This error usually happens when there's a " 91 | + " message containing something other than text." 92 | ) 93 | e = format_exc() 94 | print(e) 95 | 96 | 97 | __mod_name__ = "Quotly" 98 | -------------------------------------------------------------------------------- /SiestaRobot/modules/zombies.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from asyncio import sleep 4 | from telethon import events 5 | from telethon.errors import ChatAdminRequiredError, UserAdminInvalidError 6 | from telethon.tl.functions.channels import EditBannedRequest 7 | from telethon.tl.types import ChatBannedRights, ChannelParticipantsAdmins 8 | 9 | from SiestaRobot import telethn, OWNER_ID, DEV_USERS, DRAGONS, DEMONS 10 | 11 | # =================== CONSTANT =================== 12 | 13 | BANNED_RIGHTS = ChatBannedRights( 14 | until_date=None, 15 | view_messages=True, 16 | send_messages=True, 17 | send_media=True, 18 | send_stickers=True, 19 | send_gifs=True, 20 | send_games=True, 21 | send_inline=True, 22 | embed_links=True, 23 | ) 24 | 25 | 26 | UNBAN_RIGHTS = ChatBannedRights( 27 | until_date=None, 28 | send_messages=None, 29 | send_media=None, 30 | send_stickers=None, 31 | send_gifs=None, 32 | send_games=None, 33 | send_inline=None, 34 | embed_links=None, 35 | ) 36 | 37 | OFFICERS = [OWNER_ID] + DEV_USERS + DRAGONS + DEMONS 38 | 39 | # Check if user has admin rights 40 | 41 | async def is_administrator(user_id: int, message): 42 | admin = False 43 | async for user in telethn.iter_participants( 44 | message.chat_id, filter=ChannelParticipantsAdmins 45 | ): 46 | if user_id == user.id or user_id in OFFICERS: 47 | admin = True 48 | break 49 | return admin 50 | 51 | 52 | @telethn.on(events.NewMessage(pattern="^[!/]zombies ?(.*)")) 53 | async def rm_deletedacc(show): 54 | con = show.pattern_match.group(1).lower() 55 | del_u = 0 56 | del_status = "**Group clean, not found the deleted account.**" 57 | if con != "clean": 58 | kontol = await show.reply("`Searching deleted account...`") 59 | async for user in show.client.iter_participants(show.chat_id): 60 | if user.deleted: 61 | del_u += 1 62 | await sleep(1) 63 | if del_u > 0: 64 | del_status = ( 65 | f"**Founding** `{del_u}` **Deleted account/Zombie On this group," 66 | "\nClean it with command** `/zombies clean`" 67 | ) 68 | return await kontol.edit(del_status) 69 | chat = await show.get_chat() 70 | admin = chat.admin_rights 71 | creator = chat.creator 72 | if not admin and not creator: 73 | return await show.reply("**Sorry you're not admin!**") 74 | memek = await show.reply("`Deleting deleted account...`") 75 | del_u = 0 76 | del_a = 0 77 | async for user in telethn.iter_participants(show.chat_id): 78 | if user.deleted: 79 | try: 80 | await show.client( 81 | EditBannedRequest(show.chat_id, user.id, BANNED_RIGHTS) 82 | ) 83 | except ChatAdminRequiredError: 84 | return await show.edit("`Not have a banned rights on this group`") 85 | except UserAdminInvalidError: 86 | del_u -= 1 87 | del_a += 1 88 | await telethn(EditBannedRequest(show.chat_id, user.id, UNBAN_RIGHTS)) 89 | del_u += 1 90 | if del_u > 0: 91 | del_status = f"**Cleaned** `{del_u}` **Zombies**" 92 | if del_a > 0: 93 | del_status = ( 94 | f"**Cleaned** `{del_u}` **Zombies** " 95 | f"\n`{del_a}` **Admin zombies not deleted.**" 96 | ) 97 | await memek.edit(del_status) 98 | 99 | __mod_name__ = "Zombies" 100 | -------------------------------------------------------------------------------- /SiestaRobot/modules/truth_and_dare_string.py: -------------------------------------------------------------------------------- 1 | TRUTH = ( 2 | "Have you ghosted someone?" "Have you ever walked in on your parents doing 'it'?", 3 | "Who was the last person you liked the most? Why?", 4 | "Have you ever been suspended from school?", 5 | "If you had to choose between going naked or having your thoughts appear in thought bubbles above your head for everyone to read, which would you choose?", 6 | "What’s the one thing you’re afraid to lose?", 7 | "Do you like someone as of the moment?", 8 | "One thing about your best friend you are jealous of?", 9 | "Would you cheat on your boyfriend for a rich guy?", 10 | "What is your biggest turn on?", 11 | "When’s the last time you lied to your parents and why?", 12 | "Describe your ideal partner.", 13 | "What’s the scariest thing you’ve ever done?", 14 | "Have you ever picked your nose and eaten it?", 15 | "When’s the last time you lied to your parents and why?", 16 | "Have you ever lied about your age to participate in a contest?", 17 | "Have you ever been caught checking someone out?", 18 | ) 19 | 20 | DARE = ( 21 | "Show the most embarrassing photo on your phone" 22 | "Show the last five people you texted and what the messages said", 23 | "Let the rest of the group DM someone from your Instagram account", 24 | "Eat a raw piece of garlic", 25 | "Do 100 squats", 26 | "Keep three ice cubes in your mouth until they melt", 27 | "Say something dirty to the person on your leftYou've got company!", 28 | "Give a foot massage to the person on your right", 29 | "Put 10 different available liquids into a cup and drink it", 30 | "*Yell out the first word that comes to your mind", 31 | "Give a lap dance to someone of your choice", 32 | "Remove four items of clothing", 33 | "Like the first 15 posts on your Facebook newsfeed", 34 | "Eat a spoonful of mustard", 35 | "Keep your eyes closed until it's your go again", 36 | "Send a sext to the last person in your phonebook", 37 | "Show off your orgasm face", 38 | "Seductively eat a banana", 39 | "Empty out your wallet/purse and show everyone what's inside", 40 | "Do your best sexy crawl", 41 | "Pretend to be the person to your right for 10 minutes", 42 | "Eat a snack without using your hands", 43 | "Say two honest things about everyone else in the group", 44 | "Twerk for a minute", 45 | "Try and make the group laugh as quickly as possible", 46 | "Try to put your whole fist in your mouth", 47 | "Tell everyone an embarrassing story about yourself", 48 | "Try to lick your elbow", 49 | "Post the oldest selfie on your phone on Instagram Stories", 50 | "Tell the saddest story you know", 51 | "Howl like a wolf for two minutes", 52 | "Dance without music for two minutes", 53 | "Pole dance with an imaginary pole", 54 | "Let someone else tickle you and try not to laugh", 55 | "Put as many snacks into your mouth at once as you can", 56 | "Send your most recent selfie.", 57 | "Send your ugliest selfie.", 58 | "Send a screenshot of your facebook search history", 59 | "Send a screenshot of your gallery.", 60 | "Send a screenshot of your messenger inbox", 61 | "Tell something very intimate.", 62 | "Send a screenshot of your twitter inbox", 63 | "Send a screenshot of your homescreen.", 64 | "Send a cover of your favorite song. 🎤", 65 | "Do a lyric prank on someone and send proof.", 66 | "Confess to your current crush. ❤️", 67 | "Declare who is your true love.", 68 | "Send a screenshot of your gallery.", 69 | "Set your crush’s picture as your dp.", 70 | "Suggest me more dares.", 71 | ) 72 | -------------------------------------------------------------------------------- /SiestaRobot/modules/speachtotext.py: -------------------------------------------------------------------------------- 1 | import os 2 | import urllib.request 3 | from datetime import datetime 4 | from typing import List 5 | from typing import Optional 6 | import requests 7 | from telethon import * 8 | from telethon import events 9 | from telethon.tl import functions 10 | from telethon.tl import types 11 | from telethon.tl.types import * 12 | 13 | from SiestaRobot import * 14 | from SiestaRobot.events import register 15 | from SiestaRobot import telethn as tbot 16 | 17 | 18 | async def is_register_admin(chat, user): 19 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 20 | return isinstance( 21 | ( 22 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 23 | ).participant, 24 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 25 | ) 26 | if isinstance(chat, types.InputPeerUser): 27 | return True 28 | 29 | 30 | @register(pattern="^/stt$") 31 | async def _(event): 32 | if event.fwd_from: 33 | return 34 | start = datetime.now() 35 | if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY): 36 | os.makedirs(TEMP_DOWNLOAD_DIRECTORY) 37 | 38 | if event.reply_to_msg_id: 39 | previous_message = await event.get_reply_message() 40 | required_file_name = await event.client.download_media( 41 | previous_message, TEMP_DOWNLOAD_DIRECTORY 42 | ) 43 | if IBM_WATSON_CRED_URL is None or IBM_WATSON_CRED_PASSWORD is None: 44 | await event.reply( 45 | "You need to set the required ENV variables for this module. \nModule stopping" 46 | ) 47 | else: 48 | # await event.reply("Starting analysis") 49 | headers = { 50 | "Content-Type": previous_message.media.document.mime_type, 51 | } 52 | data = open(required_file_name, "rb").read() 53 | response = requests.post( 54 | IBM_WATSON_CRED_URL + "/v1/recognize", 55 | headers=headers, 56 | data=data, 57 | auth=("apikey", IBM_WATSON_CRED_PASSWORD), 58 | ) 59 | r = response.json() 60 | if "results" in r: 61 | # process the json to appropriate string format 62 | results = r["results"] 63 | transcript_response = "" 64 | transcript_confidence = "" 65 | for alternative in results: 66 | alternatives = alternative["alternatives"][0] 67 | transcript_response += " " + str(alternatives["transcript"]) 68 | transcript_confidence += ( 69 | " " + str(alternatives["confidence"]) + " + " 70 | ) 71 | end = datetime.now() 72 | ms = (end - start).seconds 73 | if transcript_response != "": 74 | string_to_show = "TRANSCRIPT: `{}`\nTime Taken: {} seconds\nConfidence: `{}`".format( 75 | transcript_response, ms, transcript_confidence 76 | ) 77 | else: 78 | string_to_show = "TRANSCRIPT: `Nil`\nTime Taken: {} seconds\n\n**No Results Found**".format( 79 | ms 80 | ) 81 | await event.reply(string_to_show) 82 | else: 83 | await event.reply(r["error"]) 84 | # now, remove the temporary file 85 | os.remove(required_file_name) 86 | else: 87 | await event.reply("Reply to a voice message, to get the text out of it.") 88 | 89 | __mod_name__ = "TTS/STT" 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | ──「 SIESTA ROBOT IS A MODULAR BOT WITH ANIME THEME 」── 3 |

4 | 5 |

6 | 7 |

8 | 9 |

10 | Siesta on Telegram
11 | License 12 | PRs
13 | Python 14 | Maintenance 15 | SQL Alchemy
16 | Python Telegram Bot 17 | Telethon 18 | Python Version 19 |

20 | 21 |

22 | 23 |

24 | 25 |

26 | ──「 DEPLOY ON HEROKU 」── 27 |

28 | 29 |

30 | 31 | 32 |

33 | ──「 SUPPORT 」── 34 |

35 | 36 |

37 | Vain on Telegram 38 | Support Chat 39 | Update Channel 40 |

41 | 42 |

43 | ──「 CREDIT 」── 44 |

45 | 46 |

47 | Vain Github 48 | Sena Github 49 | Arya Github 50 | Kyy Github 51 |

52 | 53 | ``` 54 | This Bot is Created by ShinobuProject, If your kanging this without fork at least give a credit to get a smile of my hard work. 55 | - SiestaRobot 56 | - EmikoRobot 57 | - YoneRobot 58 | - SaitamaRobot 59 | - TheRealPhoenixBot 60 | - DaisyX 61 | - WilliamButcherBot 62 | ``` 63 | -------------------------------------------------------------------------------- /SiestaRobot/modules/whatanime.py: -------------------------------------------------------------------------------- 1 | import html 2 | import json 3 | import re 4 | import textwrap 5 | from io import BytesIO, StringIO 6 | 7 | import aiohttp 8 | import bs4 9 | import pendulum 10 | import requests 11 | from telethon.errors.rpcerrorlist import FilePartsInvalidError 12 | from telethon.tl.types import ( 13 | DocumentAttributeAnimated, 14 | DocumentAttributeFilename, 15 | MessageMediaDocument, 16 | ) 17 | from telethon.utils import is_image, is_video 18 | 19 | from SiestaRobot.events import register as tomori 20 | 21 | 22 | 23 | @tomori(pattern="^/whatanime(.*)") 24 | async def whatanime(e): 25 | media = e.media 26 | if not media: 27 | r = await e.get_reply_message() 28 | media = getattr(r, "media", None) 29 | if not media: 30 | await e.reply("`Media required`") 31 | return 32 | ig = is_gif(media) or is_video(media) 33 | if not is_image(media) and not ig: 34 | await e.reply("`Media must be an image or gif or video`") 35 | return 36 | filename = "file.jpg" 37 | if not ig and isinstance(media, MessageMediaDocument): 38 | attribs = media.document.attributes 39 | for i in attribs: 40 | if isinstance(i, DocumentAttributeFilename): 41 | filename = i.file_name 42 | break 43 | cut = await e.reply("`Downloading image..`") 44 | content = await e.client.download_media(media, bytes, thumb=-1 if ig else None) 45 | await cut.edit("`Searching for result..`") 46 | file = memory_file(filename, content) 47 | async with aiohttp.ClientSession() as session: 48 | url = "https://api.trace.moe/search?anilistInfo" 49 | async with session.post(url, data={"image": file}) as raw_resp0: 50 | resp0 = await raw_resp0.json() 51 | js0 = resp0.get("result") 52 | if not js0: 53 | await cut.edit("`No results found.`") 54 | return 55 | js0 = js0[0] 56 | text = f'{html.escape(js0["anilist"]["title"]["romaji"])}' 57 | if js0["anilist"]["title"]["native"]: 58 | text += f' ({html.escape(js0["anilist"]["title"]["native"])})' 59 | text += "\n" 60 | if js0["episode"]: 61 | text += f'Episode: {html.escape(str(js0["episode"]))}\n' 62 | percent = round(js0["similarity"] * 100, 2) 63 | text += f"Similarity: {percent}%\n" 64 | at = re.findall(r"t=(.+)&", js0["video"])[0] 65 | dt = pendulum.from_timestamp(float(at)) 66 | text += f"At: {html.escape(dt.to_time_string())}" 67 | await cut.edit(text, parse_mode="html") 68 | dt0 = pendulum.from_timestamp(js0["from"]) 69 | dt1 = pendulum.from_timestamp(js0["to"]) 70 | ctext = ( 71 | f"{html.escape(dt0.to_time_string())} - {html.escape(dt1.to_time_string())}" 72 | ) 73 | async with session.get(js0["video"]) as raw_resp1: 74 | file = memory_file("preview.mp4", await raw_resp1.read()) 75 | try: 76 | await e.reply(ctext, file=file, parse_mode="html") 77 | except FilePartsInvalidError: 78 | await e.reply("`Cannot send preview.`") 79 | 80 | 81 | def memory_file(name=None, contents=None, *, _bytes=True): 82 | if isinstance(contents, str) and _bytes: 83 | contents = contents.encode() 84 | file = BytesIO() if _bytes else StringIO() 85 | if name: 86 | file.name = name 87 | if contents: 88 | file.write(contents) 89 | file.seek(0) 90 | return file 91 | 92 | 93 | def is_gif(file): 94 | # ngl this should be fixed, telethon.utils.is_gif but working 95 | # lazy to go to github and make an issue kek 96 | if not is_video(file): 97 | return False 98 | return DocumentAttributeAnimated() in getattr(file, "document", file).attributes 99 | -------------------------------------------------------------------------------- /SiestaRobot/config.py: -------------------------------------------------------------------------------- 1 | # Create a new config.py or rename this to config.py file in same dir and import, then extend this class. 2 | import json 3 | import os 4 | 5 | 6 | def get_user_list(config, key): 7 | with open("{}/SiestaRobot/{}".format(os.getcwd(), config), "r") as json_file: 8 | return json.load(json_file)[key] 9 | 10 | 11 | # Create a new config.py or rename this to config.py file in same dir and import, then extend this class. 12 | class Config(object): 13 | LOGGER = True 14 | # REQUIRED 15 | # Login to https://my.telegram.org and fill in these slots with the details given by it 16 | 17 | API_ID = 123456 # integer value, dont use "" 18 | API_HASH = "awoo" 19 | TOKEN = "BOT_TOKEN" # This var used to be API_KEY but it is now TOKEN, adjust accordingly. 20 | OWNER_ID = 945137470 # If you dont know, run the bot and do /id in your private chat with it, also an integer 21 | OWNER_USERNAME = "saint_foire" 22 | SUPPORT_CHAT = "machinaxsupport" # Your own group for support, do not add the @ 23 | JOIN_LOGGER = ( 24 | -1001180007354 25 | ) # Prints any new group the bot is added to, prints just the name and ID. 26 | EVENT_LOGS = ( 27 | -1001237968047 28 | ) # Prints information like gbans, sudo promotes, AI enabled disable states that may help in debugging and shit 29 | ERROR_LOGS = ( 30 | -1001732618654 31 | ) # Prints information Error 32 | 33 | # RECOMMENDED 34 | SQLALCHEMY_DATABASE_URI = "something://somewhat:user@hosturl:port/databasename" # needed for any database modules 35 | LOAD = [] 36 | NO_LOAD = ["rss", "cleaner", "connection", "math"] 37 | WEBHOOK = False 38 | INFOPIC = True 39 | URL = None 40 | SPAMWATCH_API = "" # go to support.spamwat.ch to get key 41 | SPAMWATCH_SUPPORT_CHAT = "@SpamWatchSupport" 42 | 43 | # OPTIONAL 44 | ##List of id's - (not usernames) for users which have sudo access to the bot. 45 | DRAGONS = get_user_list("elevated_users.json", "sudos") 46 | ##List of id's - (not usernames) for developers who will have the same perms as the owner 47 | DEV_USERS = get_user_list("elevated_users.json", "devs") 48 | ##List of id's (not usernames) for users which are allowed to gban, but can also be banned. 49 | DEMONS = get_user_list("elevated_users.json", "supports") 50 | # List of id's (not usernames) for users which WONT be banned/kicked by the bot. 51 | TIGERS = get_user_list("elevated_users.json", "tigers") 52 | WOLVES = get_user_list("elevated_users.json", "whitelists") 53 | DONATION_LINK = None # EG, paypal 54 | CERT_PATH = None 55 | PORT = 5000 56 | DEL_CMDS = True # Delete commands that users dont have access to, like delete /ban if a non admin uses it. 57 | STRICT_GBAN = True 58 | WORKERS = ( 59 | 8 # Number of subthreads to use. Set as number of threads your processor uses 60 | ) 61 | BAN_STICKER = "" # banhammer marie sticker id, the bot will send this sticker before banning or kicking a user in chat. 62 | ALLOW_EXCL = True # Allow ! commands as well as / (Leave this to true so that blacklist can work) 63 | CASH_API_KEY = ( 64 | "awoo" # Get your API key from https://www.alphavantage.co/support/#api-key 65 | ) 66 | TIME_API_KEY = "awoo" # Get your API key from https://timezonedb.com/api 67 | WALL_API = ( 68 | "awoo" # For wallpapers, get one from https://wall.alphacoders.com/api.php 69 | ) 70 | AI_API_KEY = "awoo" # For chatbot, get one from https://coffeehouse.intellivoid.net/dashboard 71 | BL_CHATS = [] # List of groups that you want blacklisted. 72 | SPAMMERS = None 73 | REM_BG_API_KEY = "xYCR1ZyK3ZsofjH7Y6hPcyzC" 74 | OPENWEATHERMAP_ID = "887da2c60d9f13fe78b0f9d0c5cbaade" 75 | 76 | 77 | class Production(Config): 78 | LOGGER = True 79 | 80 | 81 | class Development(Config): 82 | LOGGER = True 83 | -------------------------------------------------------------------------------- /SiestaRobot/modules/ping.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import List 3 | 4 | import requests 5 | from telegram import ParseMode, Update 6 | from telegram.ext import CallbackContext, run_async 7 | 8 | from SiestaRobot import StartTime, dispatcher 9 | from SiestaRobot.modules.helper_funcs.chat_status import sudo_plus 10 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 11 | 12 | sites_list = { 13 | "Telegram": "https://api.telegram.org", 14 | "Kaizoku": "https://animekaizoku.com", 15 | "Kayo": "https://animekayo.com", 16 | "Jikan": "https://api.jikan.moe/v3", 17 | } 18 | 19 | 20 | def get_readable_time(seconds: int) -> str: 21 | count = 0 22 | ping_time = "" 23 | time_list = [] 24 | time_suffix_list = ["s", "m", "h", "days"] 25 | 26 | while count < 4: 27 | count += 1 28 | if count < 3: 29 | remainder, result = divmod(seconds, 60) 30 | else: 31 | remainder, result = divmod(seconds, 24) 32 | if seconds == 0 and remainder == 0: 33 | break 34 | time_list.append(int(result)) 35 | seconds = int(remainder) 36 | 37 | for x in range(len(time_list)): 38 | time_list[x] = str(time_list[x]) + time_suffix_list[x] 39 | if len(time_list) == 4: 40 | ping_time += time_list.pop() + ", " 41 | 42 | time_list.reverse() 43 | ping_time += ":".join(time_list) 44 | 45 | return ping_time 46 | 47 | 48 | def ping_func(to_ping: List[str]) -> List[str]: 49 | ping_result = [] 50 | 51 | for each_ping in to_ping: 52 | 53 | start_time = time.time() 54 | site_to_ping = sites_list[each_ping] 55 | r = requests.get(site_to_ping) 56 | end_time = time.time() 57 | ping_time = str(round((end_time - start_time), 2)) + "s" 58 | 59 | pinged_site = f"{each_ping}" 60 | 61 | if each_ping == "Kaizoku" or each_ping == "Kayo": 62 | pinged_site = f'{each_ping}' 63 | ping_time = f"{ping_time} (Status: {r.status_code})" 64 | 65 | ping_text = f"{pinged_site}: {ping_time}" 66 | ping_result.append(ping_text) 67 | 68 | return ping_result 69 | 70 | 71 | @sudo_plus 72 | def ping(update: Update, context: CallbackContext): 73 | msg = update.effective_message 74 | 75 | start_time = time.time() 76 | message = msg.reply_text("Pinging...") 77 | end_time = time.time() 78 | telegram_ping = str(round((end_time - start_time) * 1000, 3)) + " ms" 79 | uptime = get_readable_time((time.time() - StartTime)) 80 | 81 | message.edit_text( 82 | "PONG ✨\n" 83 | "Time Taken: {}\n" 84 | "Service Uptime: {}".format(telegram_ping, uptime), 85 | parse_mode=ParseMode.HTML, 86 | ) 87 | 88 | 89 | @sudo_plus 90 | def pingall(update: Update, context: CallbackContext): 91 | to_ping = ["Kaizoku", "Kayo", "Telegram", "Jikan"] 92 | pinged_list = ping_func(to_ping) 93 | pinged_list.insert(2, "") 94 | uptime = get_readable_time((time.time() - StartTime)) 95 | 96 | reply_msg = "⏱Ping results are:\n" 97 | reply_msg += "\n".join(pinged_list) 98 | reply_msg += "\nService uptime: {}".format(uptime) 99 | 100 | update.effective_message.reply_text( 101 | reply_msg, parse_mode=ParseMode.HTML, disable_web_page_preview=True 102 | ) 103 | 104 | 105 | PING_HANDLER = DisableAbleCommandHandler("ping", ping, run_async=True) 106 | PINGALL_HANDLER = DisableAbleCommandHandler("pingall", pingall, run_async=True) 107 | 108 | dispatcher.add_handler(PING_HANDLER) 109 | dispatcher.add_handler(PINGALL_HANDLER) 110 | 111 | __command_list__ = ["ping", "pingall"] 112 | __handlers__ = [PING_HANDLER, PINGALL_HANDLER] 113 | -------------------------------------------------------------------------------- /SiestaRobot/modules/img_pdf.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | Copyright (c) 2021 TheHamkerCat 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including witout limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | """ 20 | from io import BytesIO 21 | from os import path, remove 22 | from time import time 23 | 24 | import img2pdf 25 | from PIL import Image 26 | from pyrogram import filters 27 | from pyrogram.types import Message 28 | 29 | from SiestaRobot import pbot as app 30 | from SiestaRobot.utils.errors import capture_err 31 | from SiestaRobot.services.sections import section 32 | 33 | 34 | async def convert( 35 | main_message: Message, 36 | reply_messages, 37 | status_message: Message, 38 | start_time: float, 39 | ): 40 | m = status_message 41 | 42 | documents = [] 43 | 44 | for message in reply_messages: 45 | if not message.document: 46 | return await m.edit("Not document, ABORTED!") 47 | 48 | if message.document.mime_type.split("/")[0] != "image": 49 | return await m.edit("Invalid mime type!") 50 | 51 | if message.document.file_size > 5000000: 52 | return await m.edit("Size too large, ABORTED!") 53 | documents.append(await message.download()) 54 | 55 | for img_path in documents: 56 | img = Image.open(img_path).convert("RGB") 57 | img.save(img_path, "JPEG", quality=100) 58 | 59 | pdf = BytesIO(img2pdf.convert(documents)) 60 | pdf.name = "NaoRobot.pdf" 61 | 62 | if len(main_message.command) >= 2: 63 | pdf.name = main_message.text.split(None, 1)[1] 64 | 65 | elapsed = round(time() - start_time, 2) 66 | 67 | await main_message.reply_document( 68 | document=pdf, 69 | caption=section( 70 | "IMG2PDF", 71 | body={ 72 | "Title": pdf.name, 73 | "Size": f"{pdf.__sizeof__() / (10**6)}MB", 74 | "Pages": len(documents), 75 | "Took": f"{elapsed}s", 76 | }, 77 | ), 78 | ) 79 | 80 | await m.delete() 81 | pdf.close() 82 | for file in documents: 83 | if path.exists(file): 84 | remove(file) 85 | 86 | 87 | @app.on_message(filters.command("pdf")) 88 | @capture_err 89 | async def img_to_pdf(_, message: Message): 90 | reply = message.reply_to_message 91 | if not reply: 92 | return await message.reply( 93 | "Reply to an image (as document) or group of images." 94 | ) 95 | 96 | m = await message.reply_text("Converting..") 97 | start_time = time() 98 | 99 | if reply.media_group_id: 100 | messages = await app.get_media_group( 101 | message.chat.id, 102 | reply.message_id, 103 | ) 104 | return await convert(message, messages, m, start_time) 105 | 106 | return await convert(message, [reply], m, start_time) 107 | -------------------------------------------------------------------------------- /SiestaRobot/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 SiestaRobot import LOGGER, dispatcher 10 | from SiestaRobot.modules.helper_funcs.chat_status import dev_plus 11 | from telegram import ParseMode, Update 12 | from telegram.ext import CallbackContext, CommandHandler, run_async 13 | 14 | namespaces = {} 15 | 16 | 17 | def namespace_of(chat, update, bot): 18 | if chat not in namespaces: 19 | namespaces[chat] = { 20 | "__builtins__": globals()["__builtins__"], 21 | "bot": bot, 22 | "effective_message": update.effective_message, 23 | "effective_user": update.effective_user, 24 | "effective_chat": update.effective_chat, 25 | "update": update, 26 | } 27 | 28 | return namespaces[chat] 29 | 30 | 31 | def log_input(update): 32 | user = update.effective_user.id 33 | chat = update.effective_chat.id 34 | LOGGER.info(f"IN: {update.effective_message.text} (user={user}, chat={chat})") 35 | 36 | 37 | def send(msg, bot, update): 38 | if len(str(msg)) > 2000: 39 | with io.BytesIO(str.encode(msg)) as out_file: 40 | out_file.name = "output.txt" 41 | bot.send_document(chat_id=update.effective_chat.id, document=out_file) 42 | else: 43 | LOGGER.info(f"OUT: '{msg}'") 44 | bot.send_message( 45 | chat_id=update.effective_chat.id, 46 | text=f"`{msg}`", 47 | parse_mode=ParseMode.MARKDOWN, 48 | ) 49 | 50 | 51 | @dev_plus 52 | def execute(update: Update, context: CallbackContext): 53 | bot = context.bot 54 | send(do(exec, bot, update), bot, update) 55 | 56 | 57 | def cleanup_code(code): 58 | if code.startswith("```") and code.endswith("```"): 59 | return "\n".join(code.split("\n")[1:-1]) 60 | return code.strip("` \n") 61 | 62 | 63 | def do(func, bot, update): 64 | log_input(update) 65 | content = update.message.text.split(" ", 1)[-1] 66 | body = cleanup_code(content) 67 | env = namespace_of(update.message.chat_id, update, bot) 68 | 69 | os.chdir(os.getcwd()) 70 | with open( 71 | os.path.join(os.getcwd(), "output.txt"), "w" 72 | ) as temp: 73 | temp.write(body) 74 | 75 | stdout = io.StringIO() 76 | 77 | to_compile = f'def func():\n{textwrap.indent(body, " ")}' 78 | 79 | try: 80 | exec(to_compile, env) 81 | except Exception as e: 82 | return f"{e.__class__.__name__}: {e}" 83 | 84 | func = env["func"] 85 | 86 | try: 87 | with redirect_stdout(stdout): 88 | func_return = func() 89 | except Exception as e: 90 | value = stdout.getvalue() 91 | return f"{value}{traceback.format_exc()}" 92 | else: 93 | value = stdout.getvalue() 94 | result = None 95 | if func_return is None: 96 | if value: 97 | result = f"{value}" 98 | else: 99 | try: 100 | result = f"{repr(eval(body, env))}" 101 | except: 102 | pass 103 | else: 104 | result = f"{value}{func_return}" 105 | if result: 106 | return result 107 | 108 | 109 | @dev_plus 110 | def clear(update: Update, context: CallbackContext): 111 | bot = context.bot 112 | log_input(update) 113 | global namespaces 114 | if update.message.chat_id in namespaces: 115 | del namespaces[update.message.chat_id] 116 | send("Cleared locals.", bot, update) 117 | 118 | 119 | EXEC_HANDLER = CommandHandler(("x", "ex", "exe", "exec", "py"), execute, run_async=True) 120 | CLEAR_HANDLER = CommandHandler("clearlocals", clear, run_async=True) 121 | 122 | dispatcher.add_handler(EXEC_HANDLER) 123 | dispatcher.add_handler(CLEAR_HANDLER) 124 | 125 | __mod_name__ = "Eval Module" 126 | -------------------------------------------------------------------------------- /SiestaRobot/modules/gettime.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import List 3 | 4 | import requests 5 | from SiestaRobot import TIME_API_KEY, dispatcher 6 | from SiestaRobot.modules.disable import DisableAbleCommandHandler 7 | from telegram import ParseMode, Update 8 | from telegram.ext import CallbackContext 9 | 10 | 11 | def generate_time(to_find: str, findtype: List[str]) -> str: 12 | data = requests.get( 13 | f"https://api.timezonedb.com/v2.1/list-time-zone" 14 | f"?key={TIME_API_KEY}" 15 | f"&format=json" 16 | f"&fields=countryCode,countryName,zoneName,gmtOffset,timestamp,dst", 17 | ).json() 18 | 19 | for zone in data["zones"]: 20 | for eachtype in findtype: 21 | if to_find in zone[eachtype].lower(): 22 | country_name = zone["countryName"] 23 | country_zone = zone["zoneName"] 24 | country_code = zone["countryCode"] 25 | 26 | if zone["dst"] == 1: 27 | daylight_saving = "Yes" 28 | else: 29 | daylight_saving = "No" 30 | 31 | date_fmt = r"%d-%m-%Y" 32 | time_fmt = r"%H:%M:%S" 33 | day_fmt = r"%A" 34 | gmt_offset = zone["gmtOffset"] 35 | timestamp = ( 36 | datetime.datetime.now( 37 | datetime.timezone.utc, 38 | ) 39 | + datetime.timedelta(seconds=gmt_offset) 40 | ) 41 | current_date = timestamp.strftime(date_fmt) 42 | current_time = timestamp.strftime(time_fmt) 43 | current_day = timestamp.strftime(day_fmt) 44 | 45 | break 46 | 47 | try: 48 | result = ( 49 | f"Country: {country_name}\n" 50 | f"Zone Name: {country_zone}\n" 51 | f"Country Code: {country_code}\n" 52 | f"Daylight saving: {daylight_saving}\n" 53 | f"Day: {current_day}\n" 54 | f"Current Time: {current_time}\n" 55 | f"Current Date: {current_date}\n" 56 | 'Timezones: List here' 57 | ) 58 | except: 59 | result = None 60 | 61 | return result 62 | 63 | 64 | def gettime(update: Update, context: CallbackContext): 65 | message = update.effective_message 66 | 67 | try: 68 | query = message.text.strip().split(" ", 1)[1] 69 | except: 70 | message.reply_text("Provide a country name/abbreviation/timezone to find.") 71 | return 72 | send_message = message.reply_text( 73 | f"Finding timezone info for {query}", 74 | parse_mode=ParseMode.HTML, 75 | ) 76 | 77 | query_timezone = query.lower() 78 | if len(query_timezone) == 2: 79 | result = generate_time(query_timezone, ["countryCode"]) 80 | else: 81 | result = generate_time(query_timezone, ["zoneName", "countryName"]) 82 | 83 | if not result: 84 | send_message.edit_text( 85 | f"Timezone info not available for {query}\n" 86 | 'All Timezones: List here', 87 | parse_mode=ParseMode.HTML, 88 | disable_web_page_preview=True, 89 | ) 90 | return 91 | 92 | send_message.edit_text( 93 | result, 94 | parse_mode=ParseMode.HTML, 95 | disable_web_page_preview=True, 96 | ) 97 | 98 | 99 | TIME_HANDLER = DisableAbleCommandHandler("time", gettime, run_async=True) 100 | 101 | dispatcher.add_handler(TIME_HANDLER) 102 | 103 | __mod_name__ = "Time" 104 | __command_list__ = ["time"] 105 | __handlers__ = [TIME_HANDLER] 106 | -------------------------------------------------------------------------------- /SiestaRobot/modules/helper_funcs/channel_mode.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | import functools 3 | 4 | from telegram import Update, ParseMode 5 | from telegram.ext import CallbackContext 6 | from telegram.inline.inlinekeyboardbutton import InlineKeyboardButton 7 | from telegram.inline.inlinekeyboardmarkup import InlineKeyboardMarkup 8 | 9 | from SiestaRobot import DRAGONS, DEV_USERS, dispatcher 10 | from SiestaRobot.modules.helper_funcs.decorators import siestacallback 11 | 12 | 13 | class AdminPerms(Enum): 14 | CAN_RESTRICT_MEMBERS = 'can_restrict_members' 15 | CAN_PROMOTE_MEMBERS = 'can_promote_members' 16 | CAN_INVITE_USERS = 'can_invite_users' 17 | CAN_DELETE_MESSAGES = 'can_delete_messages' 18 | CAN_CHANGE_INFO = 'can_change_info' 19 | CAN_PIN_MESSAGES = 'can_pin_messages' 20 | 21 | 22 | class ChatStatus(Enum): 23 | CREATOR = "creator" 24 | ADMIN = "administrator" 25 | 26 | 27 | anon_callbacks = {} 28 | anon_callback_messages = {} 29 | 30 | 31 | def user_admin(permission: AdminPerms): 32 | def wrapper(func): 33 | @functools.wraps(func) 34 | def awrapper(update: Update, context: CallbackContext, *args, **kwargs): 35 | nonlocal permission 36 | if update.effective_chat.type == 'private': 37 | return func(update, context, *args, **kwargs) 38 | message = update.effective_message 39 | is_anon = bool(update.effective_message.sender_chat) 40 | 41 | if is_anon: 42 | callback_id = f'anoncb/{message.chat.id}/{message.message_id}/{permission.value}' 43 | anon_callbacks[(message.chat.id, message.message_id)] = ((update, context), func) 44 | anon_callback_messages[(message.chat.id, message.message_id)] = ( 45 | message.reply_text("Seems like you're anonymous, click the button below to prove your identity", 46 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text='Prove identity', 47 | callback_data=callback_id)]]))).message_id 48 | # send message with callback f'anoncb{callback_id}' 49 | else: 50 | user_id = message.from_user.id 51 | chat_id = message.chat.id 52 | mem = context.bot.get_chat_member(chat_id=chat_id, user_id=user_id) 53 | if getattr(mem, permission.value) is True or mem.status == "creator" or user_id in DEV_USERS: 54 | return func(update, context, *args, **kwargs) 55 | else: 56 | return message.reply_text(f"You lack the permission: `{permission.name}`", 57 | parse_mode=ParseMode.MARKDOWN) 58 | 59 | return awrapper 60 | 61 | return wrapper 62 | 63 | 64 | @siestacallback(pattern="anoncb") 65 | def anon_callback_handler1(upd: Update, _: CallbackContext): 66 | callback = upd.callback_query 67 | perm = callback.data.split('/')[3] 68 | chat_id = int(callback.data.split('/')[1]) 69 | message_id = int(callback.data.split('/')[2]) 70 | try: 71 | mem = upd.effective_chat.get_member(user_id=callback.from_user.id) 72 | except BaseException as e: 73 | callback.answer(f"Error: {e}", show_alert=True) 74 | return 75 | if mem.status not in [ChatStatus.ADMIN.value, ChatStatus.CREATOR.value]: 76 | callback.answer("You're aren't admin.") 77 | dispatcher.bot.delete_message(chat_id, anon_callback_messages.pop((chat_id, message_id), None)) 78 | dispatcher.bot.send_message(chat_id, "You lack the permissions required for this command") 79 | elif getattr(mem, perm) is True or mem.status == "creator" or mem.user.id in DRAGONS: 80 | cb = anon_callbacks.pop((chat_id, message_id), None) 81 | if cb: 82 | message_id = anon_callback_messages.pop((chat_id, message_id), None) 83 | if message_id is not None: 84 | dispatcher.bot.delete_message(chat_id, message_id) 85 | return cb[1](cb[0][0], cb[0][1]) 86 | else: 87 | callback.answer("This isn't for ya") 88 | -------------------------------------------------------------------------------- /SiestaRobot/modules/info.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pyrogram import filters 4 | from pyrogram.types import Message 5 | 6 | from SiestaRobot import DEV_USERS 7 | from SiestaRobot import pbot as app 8 | from SiestaRobot.services.sections import section 9 | 10 | 11 | async def get_user_info(user, already=False): 12 | if not already: 13 | user = await app.get_users(user) 14 | if not user.first_name: 15 | return ["Deleted account", None] 16 | user_id = user.id 17 | username = user.username 18 | first_name = user.first_name 19 | mention = user.mention("Link") 20 | dc_id = user.dc_id 21 | photo_id = user.photo.big_file_id if user.photo else None 22 | is_sudo = user_id in DEV_USERS 23 | body = { 24 | "ID": user_id, 25 | "DC": dc_id, 26 | "Name": [first_name], 27 | "Username": [("@" + username) if username else None], 28 | "Mention": [mention], 29 | "Sudo": is_sudo, 30 | } 31 | caption = section("User info", body) 32 | return [caption, photo_id] 33 | 34 | 35 | async def get_chat_info(chat, already=False): 36 | if not already: 37 | chat = await app.get_chat(chat) 38 | chat_id = chat.id 39 | username = chat.username 40 | title = chat.title 41 | type_ = chat.type 42 | is_scam = chat.is_scam 43 | description = chat.description 44 | members = chat.members_count 45 | is_restricted = chat.is_restricted 46 | link = f"[Link](t.me/{username})" if username else None 47 | dc_id = chat.dc_id 48 | photo_id = chat.photo.big_file_id if chat.photo else None 49 | body = { 50 | "ID": chat_id, 51 | "DC": dc_id, 52 | "Type": type_, 53 | "Name": [title], 54 | "Username": [("@" + username) if username else None], 55 | "Mention": [link], 56 | "Members": members, 57 | "Scam": is_scam, 58 | "Restricted": is_restricted, 59 | "Description": [description], 60 | } 61 | caption = section("Chat info", body) 62 | return [caption, photo_id] 63 | 64 | 65 | @app.on_message(filters.command("uinfo")) 66 | async def info_func(_, message: Message): 67 | if message.reply_to_message: 68 | user = message.reply_to_message.from_user.id 69 | elif not message.reply_to_message and len(message.command) == 1: 70 | user = message.from_user.id 71 | elif not message.reply_to_message and len(message.command) != 1: 72 | user = message.text.split(None, 1)[1] 73 | 74 | m = await message.reply_text("Processing...") 75 | 76 | try: 77 | info_caption, photo_id = await get_user_info(user) 78 | except Exception as e: 79 | return await m.edit(str(e)) 80 | 81 | if not photo_id: 82 | return await m.edit( 83 | info_caption, disable_web_page_preview=True 84 | ) 85 | photo = await app.download_media(photo_id) 86 | 87 | await message.reply_photo( 88 | photo, caption=info_caption, quote=False 89 | ) 90 | await m.delete() 91 | os.remove(photo) 92 | 93 | 94 | @app.on_message(filters.command("cinfo")) 95 | async def chat_info_func(_, message: Message): 96 | try: 97 | if len(message.command) > 2: 98 | return await message.reply_text( 99 | "**Usage:**cinfo " 100 | ) 101 | 102 | if len(message.command) == 1: 103 | chat = message.chat.id 104 | elif len(message.command) == 2: 105 | chat = message.text.split(None, 1)[1] 106 | 107 | m = await message.reply_text("Processing...") 108 | 109 | info_caption, photo_id = await get_chat_info(chat) 110 | if not photo_id: 111 | return await m.edit( 112 | info_caption, disable_web_page_preview=True 113 | ) 114 | 115 | photo = await app.download_media(photo_id) 116 | await message.reply_photo( 117 | photo, caption=info_caption, quote=False 118 | ) 119 | 120 | await m.delete() 121 | os.remove(photo) 122 | except Exception as e: 123 | await m.edit(e) 124 | 125 | 126 | __mod_name__ = "nothing" 127 | -------------------------------------------------------------------------------- /SiestaRobot/modules/sangmata.py: -------------------------------------------------------------------------------- 1 | from telethon.errors.rpcerrorlist import YouBlockedUserError 2 | from SiestaRobot import telethn as tbot 3 | from SiestaRobot.events import register 4 | from SiestaRobot import ubot2 as ubot 5 | from asyncio.exceptions import TimeoutError 6 | 7 | 8 | @register(pattern="^/sg ?(.*)") 9 | async def lastname(steal): 10 | steal.pattern_match.group(1) 11 | puki = await steal.reply("```Retrieving Such User Information..```") 12 | if steal.fwd_from: 13 | return 14 | if not steal.reply_to_msg_id: 15 | await puki.edit("```Please Reply To User Message.```") 16 | return 17 | message = await steal.get_reply_message() 18 | chat = "@SangMataInfo_bot" 19 | user_id = message.sender.id 20 | id = f"/search_id {user_id}" 21 | if message.sender.bot: 22 | await puki.edit("```Reply To Real User's Message.```") 23 | return 24 | await puki.edit("```Please wait...```") 25 | try: 26 | async with ubot.conversation(chat) as conv: 27 | try: 28 | msg = await conv.send_message(id) 29 | r = await conv.get_response() 30 | response = await conv.get_response() 31 | except YouBlockedUserError: 32 | await steal.reply( 33 | "```Error, report to @kenbotsupport```" 34 | ) 35 | return 36 | if r.text.startswith("Name"): 37 | respond = await conv.get_response() 38 | await puki.edit(f"`{r.message}`") 39 | await ubot.delete_messages( 40 | conv.chat_id, [msg.id, r.id, response.id, respond.id] 41 | ) 42 | return 43 | if response.text.startswith("No records") or r.text.startswith( 44 | "No records" 45 | ): 46 | await puki.edit("```I Can't Find This User's Information, This User Has Never Changed His Name Before.```") 47 | await ubot.delete_messages( 48 | conv.chat_id, [msg.id, r.id, response.id] 49 | ) 50 | return 51 | else: 52 | respond = await conv.get_response() 53 | await puki.edit(f"```{response.message}```") 54 | await ubot.delete_messages( 55 | conv.chat_id, [msg.id, r.id, response.id, respond.id] 56 | ) 57 | except TimeoutError: 58 | return await puki.edit("`I'm Sick Sorry...`") 59 | 60 | 61 | 62 | @register(pattern="^/quotly ?(.*)") 63 | async def quotess(qotli): 64 | if qotli.fwd_from: 65 | return 66 | if not qotli.reply_to_msg_id: 67 | return await qotli.reply("```Mohon Balas Ke Pesan```") 68 | reply_message = await qotli.get_reply_message() 69 | if not reply_message.text: 70 | return await qotli.reply("```Mohon Balas Ke Pesan```") 71 | chat = "@QuotLyBot" 72 | if reply_message.sender.bot: 73 | return await qotli.reply("```Mohon Balas Ke Pesan```") 74 | await qotli.reply("```Sedang Memproses Sticker, Mohon Menunggu```") 75 | try: 76 | async with ubot.conversation(chat) as conv: 77 | try: 78 | response = await conv.get_response() 79 | msg = await ubot.forward_messages(chat, reply_message) 80 | response = await response 81 | """ - don't spam notif - """ 82 | await ubot.send_read_acknowledge(conv.chat_id) 83 | except YouBlockedUserError: 84 | return await qotli.edit("```Harap Jangan Blockir @QuotLyBot Buka Blokir Lalu Coba Lagi```") 85 | if response.text.startswith("Hi!"): 86 | await qotli.edit("```Mohon Menonaktifkan Pengaturan Privasi Forward Anda```") 87 | else: 88 | await qotli.delete() 89 | await tbot.send_message(qotli.chat_id, response.message) 90 | await tbot.send_read_acknowledge(qotli.chat_id) 91 | """ - cleanup chat after completed - """ 92 | await ubot.delete_messages(conv.chat_id, 93 | [msg.id, response.id]) 94 | except TimeoutError: 95 | await qotli.edit() 96 | -------------------------------------------------------------------------------- /SiestaRobot/modules/rembg.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 TeamDaisyX 2 | 3 | 4 | # This file is part of Daisy (Telegram Bot) 5 | 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or (at your option) any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | 19 | 20 | import io 21 | import os 22 | from datetime import datetime 23 | 24 | import requests 25 | from telethon import types 26 | from telethon.tl import functions 27 | 28 | from SiestaRobot import REM_BG_API_KEY 29 | from SiestaRobot.events import register 30 | from SiestaRobot import telethn as tbot 31 | 32 | REM_BG_API_KEY = "REM_BG_API_KEY" 33 | TEMP_DOWNLOAD_DIRECTORY = "./" 34 | 35 | 36 | async def is_register_admin(chat, user): 37 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 38 | return isinstance( 39 | ( 40 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 41 | ).participant, 42 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 43 | ) 44 | if isinstance(chat, types.InputPeerUser): 45 | return True 46 | 47 | 48 | @register(pattern="^/rmbg") 49 | async def _(event): 50 | HELP_STR = "use `/rmbg` as reply to a media" 51 | if event.fwd_from: 52 | return 53 | if event.is_group: 54 | if await is_register_admin(event.input_chat, event.message.sender_id): 55 | pass 56 | else: 57 | return 58 | if REM_BG_API_KEY is None: 59 | await event.reply("`You need API token from remove.bg to use this plugin.`") 60 | return False 61 | start = datetime.now() 62 | message_id = event.message.id 63 | if event.reply_to_msg_id: 64 | message_id = event.reply_to_msg_id 65 | reply_message = await event.get_reply_message() 66 | await event.reply("`Processing...`") 67 | try: 68 | downloaded_file_name = await tbot.download_media( 69 | reply_message, TEMP_DOWNLOAD_DIRECTORY 70 | ) 71 | except Exception as e: 72 | await event.reply(str(e)) 73 | return 74 | else: 75 | output_file_name = ReTrieveFile(downloaded_file_name) 76 | os.remove(downloaded_file_name) 77 | else: 78 | await event.reply(HELP_STR) 79 | return 80 | contentType = output_file_name.headers.get("content-type") 81 | if "image" in contentType: 82 | with io.BytesIO(output_file_name.content) as remove_bg_image: 83 | remove_bg_image.name = "rmbg.png" 84 | await tbot.send_file( 85 | event.chat_id, 86 | remove_bg_image, 87 | force_document=True, 88 | supports_streaming=False, 89 | allow_cache=False, 90 | reply_to=message_id, 91 | ) 92 | end = datetime.now() 93 | ms = (end - start).seconds 94 | await event.reply("Background Removed in {} seconds".format(ms)) 95 | else: 96 | await event.reply( 97 | "remove.bg API returned Errors. Please report to @kenbotsupport\n`{}".format( 98 | output_file_name.content.decode("UTF-8") 99 | ) 100 | ) 101 | 102 | 103 | def ReTrieveFile(input_file_name): 104 | headers = { 105 | "X-API-Key": REM_BG_API_KEY, 106 | } 107 | files = { 108 | "image_file": (input_file_name, open(input_file_name, "rb")), 109 | } 110 | r = requests.post( 111 | "https://api.remove.bg/v1.0/removebg", 112 | headers=headers, 113 | files=files, 114 | allow_redirects=True, 115 | stream=True, 116 | ) 117 | return r 118 | -------------------------------------------------------------------------------- /SiestaRobot/modules/imdb.py: -------------------------------------------------------------------------------- 1 | from SiestaRobot import telethn as tbot 2 | import os 3 | import re 4 | import bs4 5 | import requests 6 | from telethon import types 7 | from telethon.tl import functions 8 | from SiestaRobot.events import register 9 | 10 | langi = "en" 11 | 12 | 13 | @register(pattern="^/imdb (.*)") 14 | async def imdb(e): 15 | if e.fwd_from: 16 | return 17 | try: 18 | movie_name = e.pattern_match.group(1) 19 | remove_space = movie_name.split(" ") 20 | final_name = "+".join(remove_space) 21 | page = requests.get( 22 | "https://www.imdb.com/find?ref_=nv_sr_fn&q=" + final_name + "&s=all" 23 | ) 24 | str(page.status_code) 25 | soup = bs4.BeautifulSoup(page.content, "html.parser") 26 | odds = soup.findAll("tr", "odd") 27 | mov_title = odds[0].findNext("td").findNext("td").text 28 | mov_link = ( 29 | "http://www.imdb.com/" + odds[0].findNext("td").findNext("td").a["href"] 30 | ) 31 | page1 = requests.get(mov_link) 32 | soup = bs4.BeautifulSoup(page1.content, "lxml") 33 | if soup.find("div", "poster"): 34 | poster = soup.find("div", "poster").img["src"] 35 | else: 36 | poster = "" 37 | if soup.find("div", "title_wrapper"): 38 | pg = soup.find("div", "title_wrapper").findNext("div").text 39 | mov_details = re.sub(r"\s+", " ", pg) 40 | else: 41 | mov_details = "" 42 | credits = soup.findAll("div", "credit_summary_item") 43 | if len(credits) == 1: 44 | director = credits[0].a.text 45 | writer = "Not available" 46 | stars = "Not available" 47 | elif len(credits) > 2: 48 | director = credits[0].a.text 49 | writer = credits[1].a.text 50 | actors = [] 51 | for x in credits[2].findAll("a"): 52 | actors.append(x.text) 53 | actors.pop() 54 | stars = actors[0] + "," + actors[1] + "," + actors[2] 55 | else: 56 | director = credits[0].a.text 57 | writer = "Not available" 58 | actors = [] 59 | for x in credits[1].findAll("a"): 60 | actors.append(x.text) 61 | actors.pop() 62 | stars = actors[0] + "," + actors[1] + "," + actors[2] 63 | if soup.find("div", "inline canwrap"): 64 | story_line = soup.find("div", "inline canwrap").findAll("p")[0].text 65 | else: 66 | story_line = "Not available" 67 | info = soup.findAll("div", "txt-block") 68 | if info: 69 | mov_country = [] 70 | mov_language = [] 71 | for node in info: 72 | a = node.findAll("a") 73 | for i in a: 74 | if "country_of_origin" in i["href"]: 75 | mov_country.append(i.text) 76 | elif "primary_language" in i["href"]: 77 | mov_language.append(i.text) 78 | if soup.findAll("div", "ratingValue"): 79 | for r in soup.findAll("div", "ratingValue"): 80 | mov_rating = r.strong["title"] 81 | else: 82 | mov_rating = "Not available" 83 | await e.reply( 84 | "" 85 | "Title : " 86 | + mov_title 87 | + "\n" 88 | + mov_details 89 | + "\nRating : " 90 | + mov_rating 91 | + "\nCountry : " 92 | + mov_country[0] 93 | + "\nLanguage : " 94 | + mov_language[0] 95 | + "\nDirector : " 96 | + director 97 | + "\nWriter : " 98 | + writer 99 | + "\nStars : " 100 | + stars 101 | + "\nIMDB Url : " 102 | + mov_link 103 | + "\nStory Line : " 104 | + story_line, 105 | link_preview=True, 106 | parse_mode="HTML", 107 | ) 108 | except IndexError: 109 | await e.reply("Plox enter **Valid movie name** kthx") 110 | -------------------------------------------------------------------------------- /SiestaRobot/modules/bug.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Shiinobu Project 2 | 3 | from datetime import datetime 4 | 5 | from pyrogram import filters 6 | from pyrogram.types import ( 7 | InlineKeyboardButton, 8 | InlineKeyboardMarkup, 9 | CallbackQuery, 10 | Message, 11 | ) 12 | 13 | from SiestaRobot import pbot as Client 14 | from SiestaRobot import ( 15 | OWNER_ID as owner_id, 16 | OWNER_USERNAME as owner_usn, 17 | SUPPORT_CHAT as log, 18 | ) 19 | from SiestaRobot.utils.errors import capture_err 20 | 21 | 22 | def content(msg: Message) -> [None, str]: 23 | text_to_return = msg.text 24 | 25 | if msg.text is None: 26 | return None 27 | if " " in text_to_return: 28 | try: 29 | return msg.text.split(None, 1)[1] 30 | except IndexError: 31 | return None 32 | else: 33 | return None 34 | 35 | 36 | @Client.on_message(filters.command("bug")) 37 | @capture_err 38 | async def bug(_, msg: Message): 39 | if msg.chat.username: 40 | chat_username = (f"@{msg.chat.username} / `{msg.chat.id}`") 41 | else: 42 | chat_username = (f"Private Group / `{msg.chat.id}`") 43 | 44 | bugs = content(msg) 45 | user_id = msg.from_user.id 46 | mention = "["+msg.from_user.first_name+"](tg://user?id="+str(msg.from_user.id)+")" 47 | datetimes_fmt = "%d-%m-%Y" 48 | datetimes = datetime.utcnow().strftime(datetimes_fmt) 49 | 50 | thumb = "https://telegra.ph/file/bd218d4af1c69c586ebb0.jpg" 51 | 52 | bug_report = f""" 53 | **#BUG : ** **@{owner_usn}** 54 | 55 | **From User : ** **{mention}** 56 | **User ID : ** **{user_id}** 57 | **Group : ** **{chat_username}** 58 | 59 | **Bug Report : ** **{bugs}** 60 | 61 | **Event Stamp : ** **{datetimes}**""" 62 | 63 | 64 | if msg.chat.type == "private": 65 | await msg.reply_text("❎ This command only works in groups.") 66 | return 67 | 68 | if user_id == owner_id: 69 | if bugs: 70 | await msg.reply_text( 71 | "❎ How can be owner bot reporting bug??", 72 | ) 73 | return 74 | else: 75 | await msg.reply_text( 76 | "Owner noob!" 77 | ) 78 | elif user_id != owner_id: 79 | if bugs: 80 | await msg.reply_text( 81 | f"Bug Report : {bugs}\n\n" 82 | "✅ The bug was successfully reported to the support group!", 83 | reply_markup=InlineKeyboardMarkup( 84 | [ 85 | [ 86 | InlineKeyboardButton( 87 | "Close", callback_data=f"close_reply") 88 | ] 89 | ] 90 | ) 91 | ) 92 | await Client.send_photo( 93 | log, 94 | photo=thumb, 95 | caption=f"{bug_report}", 96 | reply_markup=InlineKeyboardMarkup( 97 | [ 98 | [ 99 | InlineKeyboardButton( 100 | "➡ View Bug", url=f"{msg.link}") 101 | ], 102 | [ 103 | InlineKeyboardButton( 104 | "❌ Close", callback_data="close_send_photo") 105 | ] 106 | ] 107 | ) 108 | ) 109 | else: 110 | await msg.reply_text( 111 | f"❎ No bug to Report!", 112 | ) 113 | 114 | 115 | @Client.on_callback_query(filters.regex("close_reply")) 116 | async def close_reply(msg, CallbackQuery): 117 | await CallbackQuery.message.delete() 118 | 119 | @Client.on_callback_query(filters.regex("close_send_photo")) 120 | async def close_send_photo(_, CallbackQuery): 121 | is_Admin = await Client.get_chat_member( 122 | CallbackQuery.message.chat.id, CallbackQuery.from_user.id 123 | ) 124 | if not is_Admin.can_delete_messages: 125 | return await CallbackQuery.answer( 126 | "You're not allowed to close this.", show_alert=True 127 | ) 128 | else: 129 | await CallbackQuery.message.delete() 130 | 131 | 132 | __mod_name__ = "Bug" 133 | --------------------------------------------------------------------------------