├── runtime.txt ├── Procfile ├── heroku.yml ├── DaisyX ├── stuff │ ├── daisy.jpg │ └── fonts │ │ ├── VT323-Regular.ttf │ │ ├── CaveatBrush-Regular.ttf │ │ ├── MaShanZheng-Regular.ttf │ │ ├── RobotoMono-Medium.ttf │ │ ├── __init__.py │ │ └── OFL.txt ├── modules │ ├── utils │ │ ├── fetch.py │ │ ├── httpx.py │ │ ├── covert.py │ │ ├── term.py │ │ ├── disable.py │ │ ├── restrictions.py │ │ ├── android.py │ │ ├── message.py │ │ ├── buttonhelper.py │ │ ├── text.py │ │ └── anime.py │ ├── MusicPlayer.py │ ├── Autofilters.py │ ├── __init__.py │ ├── books.py │ ├── gps.py │ ├── json.py │ ├── shazam.py │ ├── Cricket_Score.py │ ├── pins.py │ ├── core.py │ ├── fakeit.py │ ├── Mod_APPS.py │ ├── purges.py │ ├── userinfo.py │ ├── direct_link.py │ ├── reports.py │ ├── fbdl.py │ ├── logomaker.py │ ├── afk.py │ ├── spwinfo.py │ ├── bassboost.py │ ├── text_filters.py │ ├── telegraph.py │ ├── rmbg.py │ ├── langtools.py │ ├── weather.py │ ├── antivirus.py │ └── promotes.py ├── services │ ├── mongo2.py │ ├── sql │ │ ├── __init__.py │ │ ├── forceSubscribe_sql.py │ │ ├── nsfw_watch_sql.py │ │ ├── talk_mode_sql.py │ │ ├── night_mode_sql.py │ │ ├── chatbot_sql.py │ │ ├── afk_sql.py │ │ └── filters_sql.py │ ├── __init__.py │ ├── telethon.py │ ├── pyrogram.py │ ├── telethonuserbot.py │ ├── redis.py │ ├── mongo.py │ ├── apscheduller.py │ └── events.py ├── db │ ├── mongo_helpers │ │ ├── nsfw_guard.py │ │ ├── users_mdb.py │ │ ├── filterdb.py │ │ └── filters_mdb.py │ ├── 2.py │ ├── 6.py │ ├── 3.py │ ├── 4.py │ ├── 7.py │ ├── 5.py │ └── 8.py ├── versions.py ├── utils │ ├── term.py │ ├── sentry.py │ ├── channel_logs.py │ ├── filters │ │ ├── __init__.py │ │ ├── chat_status.py │ │ ├── message_status.py │ │ └── user_status.py │ ├── exit_gracefully.py │ ├── logger.py │ ├── db_structure_migrator.py │ └── cached.py ├── __init__.py ├── Addons │ └── tempmail │ │ └── tempmail.py ├── config.py └── __main__.py ├── crowdin.yml ├── Dockerfile ├── .gitignore ├── data └── bot_conf.yaml.example ├── requirements.txt ├── deploy.sh ├── fortune.py ├── README.md └── profanity_wordlist.txt /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.8.5 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | DAISYX: python3 -m DaisyX 2 | ps:scale DAISYX=1 3 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | -------------------------------------------------------------------------------- /DaisyX/stuff/daisy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxprogrammer007/DARK-JARVIS/main/DaisyX/stuff/daisy.jpg -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/VT323-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxprogrammer007/DARK-JARVIS/main/DaisyX/stuff/fonts/VT323-Regular.ttf -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: DaisyX/localization/en.yaml 3 | translation: /**/DaisyX/localization/%locale_with_underscore%.yaml 4 | -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/CaveatBrush-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxprogrammer007/DARK-JARVIS/main/DaisyX/stuff/fonts/CaveatBrush-Regular.ttf -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/MaShanZheng-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxprogrammer007/DARK-JARVIS/main/DaisyX/stuff/fonts/MaShanZheng-Regular.ttf -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/RobotoMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxprogrammer007/DARK-JARVIS/main/DaisyX/stuff/fonts/RobotoMono-Medium.ttf -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | WORKDIR . 3 | ENV PYTHONUNBUFFERED=1 4 | COPY requirements.txt . 5 | COPY deploy.sh . 6 | RUN bash deploy.sh 7 | COPY . . 8 | CMD ["python3", "-m", "DaisyX"] 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python cache 2 | __pycache__/ 3 | *.py[cod] 4 | *.pyc 5 | 6 | # Telethon session cache 7 | *.session 8 | *.session-journal 9 | 10 | # Config 11 | data/bot_conf.yaml 12 | 13 | # Logs 14 | logs/ 15 | 16 | # Virtual envirment 17 | venv/ 18 | 19 | .vscode/ 20 | .idea/ 21 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/fetch.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | async def fetch(url): 3 | async with aiohttp.ClientSession() as session: 4 | async with session.get(url) as resp: 5 | try: 6 | data = await resp.json() 7 | except: 8 | data = await resp.text() 9 | return data 10 | -------------------------------------------------------------------------------- /DaisyX/services/mongo2.py: -------------------------------------------------------------------------------- 1 | # Support Dual Mongo DB now 2 | # For free users 3 | 4 | from DaisyX.config import get_str_key 5 | from pyrogram import Client 6 | from motor.motor_asyncio import AsyncIOMotorClient as MongoClient 7 | 8 | MONGO2 = get_str_key("MONGO_URI_2", None) 9 | MONGO = get_str_key("MONGO_URI", required=True) 10 | if MONGO2 == None: 11 | MONGO2 = MONGO 12 | 13 | mongo_client = MongoClient(MONGO2) 14 | db = mongo_client.daisy 15 | -------------------------------------------------------------------------------- /DaisyX/db/mongo_helpers/nsfw_guard.py: -------------------------------------------------------------------------------- 1 | from DaisyX.services.mongo import mongodb as db_x 2 | 3 | nsfw = db_x["NSFW_WATCH"] 4 | 5 | 6 | def add_chat(chat_id): 7 | nsfw.insert_one({"chat_id": chat_id}) 8 | 9 | 10 | def rm_chat(chat_id): 11 | nsfw.delete_one({"chat_id": chat_id}) 12 | 13 | 14 | def get_all_nsfw_chats(): 15 | lol = list(nsfw.find({})) 16 | return lol 17 | 18 | 19 | def is_chat_in_db(chat_id): 20 | k = nsfw.find_one({"chat_id": chat_id}) 21 | if k: 22 | return True 23 | else: 24 | return False 25 | -------------------------------------------------------------------------------- /DaisyX/services/sql/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import scoped_session, sessionmaker 4 | from DaisyX import POSTGRESS_URL as DB_URI 5 | 6 | 7 | def start() -> scoped_session: 8 | engine = create_engine(DB_URI, client_encoding="utf8") 9 | BASE.metadata.bind = engine 10 | BASE.metadata.create_all(engine) 11 | return scoped_session(sessionmaker(bind=engine, autoflush=False)) 12 | 13 | 14 | BASE = declarative_base() 15 | SESSION = start() 16 | -------------------------------------------------------------------------------- /DaisyX/modules/MusicPlayer.py: -------------------------------------------------------------------------------- 1 | __mod_name__ = "Music Player" 2 | __help__ = """ 3 | VC PLAYER 4 | VC player plays plays music in your group's voice chat 5 | 6 | Setting up 7 | 1) Add @DaisyXMusic to your group 8 | 2) Make bot admin 9 | 3) Start a voice chat 10 | 11 | Commands 12 | - /play [link/ reply: mp3 file or yt link] : Play/Add to queue of given song 13 | - /pause : Pause music play (Admin only) 14 | - /skip : Skips current song (Admin only) 15 | - /end : End the music play (Admin only) 16 | 17 | PLEASE NOTE THIS IS HEAVILY UNSTABLE AND CAN BE STOPPED ANYTIME 18 | """ 19 | -------------------------------------------------------------------------------- /DaisyX/services/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | -------------------------------------------------------------------------------- /DaisyX/versions.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | DAISY_VERSION = "v2.2.7-H3.0" 17 | DB_STRUCTURE_VER = 8 18 | -------------------------------------------------------------------------------- /DaisyX/modules/Autofilters.py: -------------------------------------------------------------------------------- 1 | __mod_name__ = "Auto Filters" 2 | __help__ = """ 3 | AUTO FILTERS 4 | Daisy Can filter content of a given channel automatically 5 | Currently support: 6 | - Videos 7 | - Media 8 | - Documents 9 | - Music 10 | 11 | Setting up 12 | 1) Add @DaisyXBot to your channel 13 | 2) Make bot admin with full permissions 14 | 2) Go back to your group 15 | 16 | Commands 17 | - /autofilter [Channel Username] : Add given channel to autofiltering 18 | - /autofilterdel [Channel Username] : Remove given channel from auto filtering 19 | - /autofilterdelall : Remove all channels from automatic filtering 20 | - /autofilterstats : Show stats about auto filtering channels 21 | 22 | Specially made for Movie/Music and Book group owners 23 | Inspired by Autofilters bot v2 24 | 25 | """ 26 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/httpx.py: -------------------------------------------------------------------------------- 1 | # This file is part of DaisyXBot (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import httpx 17 | 18 | 19 | http = httpx.AsyncClient(http2=True) 20 | -------------------------------------------------------------------------------- /DaisyX/db/2.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from DaisyX.utils.logger import log 17 | 18 | log.warn('Blank DB update, nothing to-do, skipping!') 19 | -------------------------------------------------------------------------------- /DaisyX/utils/term.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import subprocess 17 | 18 | from DaisyX.utils.logger import log 19 | 20 | 21 | def term(cmd): 22 | p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 23 | if p.stderr: 24 | log.error(p.stderr.readlines()) 25 | return p.stdout.readlines() 26 | -------------------------------------------------------------------------------- /DaisyX/utils/sentry.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import sentry_sdk 17 | from sentry_sdk.integrations.redis import RedisIntegration 18 | 19 | from DaisyX.config import get_str_key 20 | from DaisyX.utils.logger import log 21 | 22 | log.info("Starting sentry.io integraion...") 23 | 24 | sentry_sdk.init( 25 | get_str_key('SENTRY_API_KEY'), 26 | integrations=[RedisIntegration()] 27 | ) 28 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/covert.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import math 17 | 18 | 19 | def convert_size(size_bytes): 20 | if size_bytes == 0: 21 | return "0B" 22 | size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") 23 | i = int(math.floor(math.log(size_bytes, 1024))) 24 | p = math.pow(1024, i) 25 | s = round(size_bytes / p, 2) 26 | return "%s %s" % (s, size_name[i]) 27 | -------------------------------------------------------------------------------- /DaisyX/utils/channel_logs.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import html 17 | 18 | from DaisyX import bot 19 | from DaisyX.config import get_int_key 20 | from DaisyX.utils.logger import log 21 | 22 | 23 | async def channel_log(msg, info_log=True): 24 | chat_id = get_int_key('LOGS_CHANNEL_ID') 25 | if info_log: 26 | log.info(msg) 27 | 28 | await bot.send_message(chat_id, html.escape(msg, quote=False)) 29 | -------------------------------------------------------------------------------- /DaisyX/services/telethon.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | 17 | from telethon import TelegramClient 18 | 19 | from DaisyX.config import get_str_key, get_int_key 20 | 21 | TOKEN = get_str_key("TOKEN", required=True) 22 | NAME = TOKEN.split(':')[0] 23 | 24 | tbot = TelegramClient( 25 | NAME, 26 | get_int_key("APP_ID", required=True), 27 | get_str_key("APP_HASH", required=True) 28 | ) 29 | 30 | # Telethon 31 | tbot.start(bot_token=TOKEN) 32 | -------------------------------------------------------------------------------- /data/bot_conf.yaml.example: -------------------------------------------------------------------------------- 1 | # DaisyXBot example config 2 | 3 | 4 | # Basic 5 | TOKEN: "" 6 | 7 | # Get they in https://my.telegram.org/ 8 | APP_ID: 000000 9 | APP_HASH: "" 10 | 11 | #Generate a telethon str session with https://repl.it/@SpEcHiDe/GenerateStringSession (telethon one) 12 | STRING_SESSION: "" 13 | 14 | 15 | MONGO_URI: "mongodb+srv://dfsdfX:dfsfdX@cluster0.df4j.mongodb.net/myFirstDatabase?retryWrites=true&w=majority" 16 | 17 | MONGO_URI2: "" 18 | MONGO_PORT: 27017 19 | MONGO_DB': 'DaisyX' 20 | 21 | API_PORT': 8080 22 | 23 | REDIS_URI: "redis-1324.c234.us-east-1-4.ec4.cloud.redislabs.com" 24 | REDIS_PORT: 15514 25 | REDIS_PASS: "sdfgg" 26 | TEMP_MAIL_KEY: "" 27 | OWNER_ID: 1141839926 28 | OPERATORS: [1141839926, 00000000] 29 | SUPPORT_CHAT: -000000000 30 | LYDIA_API_KEY: "" 31 | 32 | DATABASE_URL: "" 33 | VIRUS_API_KEY: "" 34 | TIME_API_KEY: "" 35 | REM_BG_API_KEY: "" 36 | 37 | # Advanced 38 | SW_API: "" 39 | IBM_WATSON_CRED_URL: "" 40 | IBM_WATSON_CRED_PASSWORD: "" 41 | OPENWEATHERMAP_ID: "" 42 | WOLFRAM_ID: "" 43 | DEBUG_MODE: False 44 | LOAD_MODULES: True 45 | LOGS_CHANNEL_ID: -000000000 46 | ALLOW_FORWARDS_COMMANDS: False 47 | ALLOW_COMMANDS_WITH_!: False 48 | -------------------------------------------------------------------------------- /DaisyX/db/mongo_helpers/users_mdb.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pymongo 3 | 4 | 5 | 6 | from DaisyX.config import get_str_key 7 | 8 | MONGO2 = get_str_key("FILTERS_MONGO", None) 9 | MONGO = get_str_key("MONGO_URI", required=True) 10 | if MONGO2 == None: 11 | MONGO2 = MONGO 12 | myclient = pymongo.MongoClient(MONGO2) 13 | mydb = myclient['Daisy'] 14 | mycol = mydb['USERS'] 15 | 16 | 17 | 18 | async def add_user(id, username, name, dcid): 19 | data = { 20 | '_id': id, 21 | 'username' : username, 22 | 'name' : name, 23 | 'dc_id' : dcid 24 | } 25 | try: 26 | mycol.update_one({'_id': id}, {"$set": data}, upsert=True) 27 | except: 28 | pass 29 | 30 | 31 | async def all_users(): 32 | count = mycol.count() 33 | return count 34 | 35 | 36 | async def find_user(id): 37 | query = mycol.find( {"_id":id}) 38 | 39 | try: 40 | for file in query: 41 | name = file['name'] 42 | username = file['username'] 43 | dc_id = file['dc_id'] 44 | return name, username, dc_id 45 | except: 46 | return None, None, None 47 | -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | 17 | def list_all_fonts(): 18 | from os.path import dirname, basename, isfile 19 | import glob 20 | 21 | mod_paths = glob.glob(dirname(__file__) + "/*.ttf") 22 | all_fonts = [ 23 | dirname(f) + '/' + basename(f) 24 | for f in mod_paths 25 | if isfile(f) and f.endswith(".ttf") 26 | ] 27 | return all_fonts 28 | 29 | 30 | ALL_FONTS = sorted(list_all_fonts()) 31 | __all__ = ALL_FONTS + ["ALL_FONTS"] 32 | -------------------------------------------------------------------------------- /DaisyX/utils/filters/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import glob 17 | import os.path 18 | 19 | 20 | def list_all_filters(): 21 | mod_paths = glob.glob(os.path.dirname(__file__) + "/*.py") 22 | all_filters = [ 23 | os.path.basename(f)[:-3] 24 | for f in mod_paths 25 | if os.path.isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 26 | ] 27 | 28 | return all_filters 29 | 30 | 31 | ALL_FILTERS = sorted(list(list_all_filters())) 32 | 33 | __all__ = ALL_FILTERS + ["ALL_FILTERS"] 34 | -------------------------------------------------------------------------------- /DaisyX/services/sql/forceSubscribe_sql.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, Numeric, String 2 | 3 | from DaisyX.services.sql import BASE, SESSION 4 | 5 | 6 | class forceSubscribe(BASE): 7 | __tablename__ = "forceSubscribe" 8 | chat_id = Column(Numeric, primary_key=True) 9 | channel = Column(String) 10 | 11 | def __init__(self, chat_id, channel): 12 | self.chat_id = chat_id 13 | self.channel = channel 14 | 15 | 16 | forceSubscribe.__table__.create(checkfirst=True) 17 | 18 | 19 | def fs_settings(chat_id): 20 | try: 21 | return ( 22 | SESSION.query(forceSubscribe) 23 | .filter(forceSubscribe.chat_id == chat_id) 24 | .one() 25 | ) 26 | except: 27 | return None 28 | finally: 29 | SESSION.close() 30 | 31 | 32 | def add_channel(chat_id, channel): 33 | adder = SESSION.query(forceSubscribe).get(chat_id) 34 | if adder: 35 | adder.channel = channel 36 | else: 37 | adder = forceSubscribe(chat_id, channel) 38 | SESSION.add(adder) 39 | SESSION.commit() 40 | 41 | 42 | def disapprove(chat_id): 43 | rem = SESSION.query(forceSubscribe).get(chat_id) 44 | if rem: 45 | SESSION.delete(rem) 46 | SESSION.commit() 47 | -------------------------------------------------------------------------------- /DaisyX/utils/exit_gracefully.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import os 17 | import signal 18 | 19 | from DaisyX.services.redis import redis 20 | from DaisyX.utils.logger import log 21 | 22 | 23 | def exit_gracefully(signum, frame): 24 | log.warning("Bye!") 25 | 26 | try: 27 | redis.save() 28 | except Exception: 29 | log.error("Exiting immediately!") 30 | os.kill(os.getpid(), signal.SIGUSR1) 31 | 32 | 33 | # Signal exit 34 | log.info("Setting exit_gracefully task...") 35 | signal.signal(signal.SIGINT, exit_gracefully) 36 | -------------------------------------------------------------------------------- /DaisyX/services/pyrogram.py: -------------------------------------------------------------------------------- 1 | # This file is part of DaisyXBot (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import logging 17 | from pyrogram import Client, errors 18 | 19 | from DaisyX.config import get_str_key, get_int_key 20 | 21 | TOKEN = get_str_key("TOKEN", required=True) 22 | APP_ID = get_int_key("APP_ID", required=True) 23 | APP_HASH = get_str_key("APP_HASH", required=True) 24 | session_name = TOKEN.split(':')[0] 25 | pbot = Client(session_name, api_id=APP_ID, api_hash=APP_HASH, bot_token=TOKEN) 26 | 27 | # disable logging for pyrogram [not for ERROR logging] 28 | logging.getLogger('pyrogram').setLevel(level=logging.ERROR) 29 | pbot.start() 30 | -------------------------------------------------------------------------------- /DaisyX/services/telethonuserbot.py: -------------------------------------------------------------------------------- 1 | # This file is part of DaisyXBot (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | 17 | from telethon import TelegramClient 18 | from telethon.sessions import StringSession 19 | from DaisyX.config import get_str_key, get_int_key 20 | 21 | STRING_SESSION = get_str_key("STRING_SESSION", required=True) 22 | API_ID = get_int_key("APP_ID", required=True) 23 | API_HASH = get_str_key("APP_HASH", required=True) 24 | 25 | ubot = TelegramClient(StringSession(STRING_SESSION), API_ID, API_HASH) 26 | try: 27 | ubot.start() 28 | except BaseException: 29 | print("Userbot Error ! Have you added a STRING_SESSION in deploying??") 30 | sys.exit(1) 31 | -------------------------------------------------------------------------------- /DaisyX/services/redis.py: -------------------------------------------------------------------------------- 1 | # This file is part of DaisyXBot (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import sys 17 | 18 | import redis as redis_lib 19 | 20 | from DaisyX import log 21 | from DaisyX.config import get_str_key, get_int_key 22 | 23 | # Init Redis 24 | redis = redis_lib.Redis( 25 | host=get_str_key("REDIS_URI"), 26 | port=get_str_key("REDIS_PORT"), 27 | password=get_str_key("REDIS_PASS"), 28 | decode_responses=True 29 | ) 30 | 31 | bredis = redis_lib.Redis( 32 | host=get_str_key("REDIS_URI"), 33 | port=get_str_key("REDIS_PORT"), 34 | password=get_str_key("REDIS_PASS"), 35 | ) 36 | 37 | try: 38 | redis.ping() 39 | except redis_lib.ConnectionError: 40 | sys.exit(log.critical("Can't connect to RedisDB! Exiting...")) 41 | -------------------------------------------------------------------------------- /DaisyX/db/6.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from pymongo import DeleteOne 17 | 18 | from DaisyX.services.mongo import mongodb 19 | from DaisyX.utils.logger import log 20 | 21 | log.info('Daisy Database v6') 22 | log.info("Feds: fix str user_id and fix duplications") 23 | log.info('Starting updating all feds...') 24 | 25 | queue = [] 26 | 27 | all_bans = mongodb.fed_bans.find({'user_id': {'$type': 'string'}}) 28 | all_bans_count = all_bans.count() 29 | counter = 0 30 | changed_feds = 0 31 | 32 | for ban in all_bans: 33 | counter += 1 34 | changed_feds += 1 35 | queue.append(DeleteOne({'_id': ban['_id']})) 36 | 37 | mongodb.fed_bans.bulk_write(queue) 38 | 39 | log.info('Update done!') 40 | log.info('Modified feds - ' + str(changed_feds)) 41 | -------------------------------------------------------------------------------- /DaisyX/services/mongo.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | import sys 18 | 19 | from motor import motor_asyncio 20 | from pymongo import MongoClient 21 | from pymongo.errors import ServerSelectionTimeoutError 22 | 23 | from DaisyX import log 24 | from DaisyX.config import get_str_key, get_int_key 25 | 26 | MONGO_URI = get_str_key("MONGO_URI") 27 | MONGO_PORT = get_int_key("MONGO_PORT") 28 | MONGO_DB = get_str_key("MONGO_DB") 29 | 30 | # Init MongoDB 31 | mongodb = MongoClient(MONGO_URI, MONGO_PORT)[MONGO_DB] 32 | motor = motor_asyncio.AsyncIOMotorClient(MONGO_URI, MONGO_PORT) 33 | db = motor[MONGO_DB] 34 | 35 | try: 36 | asyncio.get_event_loop().run_until_complete(motor.server_info()) 37 | except ServerSelectionTimeoutError: 38 | sys.exit(log.critical("Can't connect to mongodb! Exiting...")) 39 | -------------------------------------------------------------------------------- /DaisyX/utils/filters/chat_status.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from aiogram import types 17 | from aiogram.dispatcher.filters import BoundFilter 18 | 19 | from DaisyX import dp 20 | 21 | 22 | class OnlyPM(BoundFilter): 23 | key = 'only_pm' 24 | 25 | def __init__(self, only_pm): 26 | self.only_pm = only_pm 27 | 28 | async def check(self, message: types.Message): 29 | if message.from_user.id == message.chat.id: 30 | return True 31 | 32 | 33 | class OnlyGroups(BoundFilter): 34 | key = 'only_groups' 35 | 36 | def __init__(self, only_groups): 37 | self.only_groups = only_groups 38 | 39 | async def check(self, message: types.Message): 40 | if not message.from_user.id == message.chat.id: 41 | return True 42 | 43 | 44 | dp.filters_factory.bind(OnlyPM) 45 | dp.filters_factory.bind(OnlyGroups) 46 | -------------------------------------------------------------------------------- /DaisyX/db/3.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from DaisyX.services.mongo import mongodb 17 | from DaisyX.utils.logger import log 18 | 19 | log.info('Daisy Database v3') 20 | log.info('Support notes aliases') 21 | log.info('Starting updating all notes...') 22 | 23 | all_notes = mongodb.notes_v2.find({}) 24 | all_notes_count = all_notes.count() 25 | counter = 0 26 | changed_notes = 0 27 | for note in all_notes: 28 | counter += 1 29 | log.info(f'Updating {counter} of {all_notes_count}...') 30 | 31 | if 'name' in note: 32 | changed_notes += 1 33 | names = [note['name']] 34 | del note['name'] 35 | note['names'] = names 36 | mongodb.notes_v2.replace_one({'_id': note['_id']}, note) 37 | 38 | log.info('Update done!') 39 | log.info('Modified notes - ' + str(changed_notes)) 40 | log.info('Unchanged notes - ' + str(all_notes_count - changed_notes)) 41 | -------------------------------------------------------------------------------- /DaisyX/db/4.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from DaisyX.services.mongo import mongodb 17 | from DaisyX.utils.logger import log 18 | 19 | log.info('Daisy Database v4') 20 | log.info("Filters: move 'note' to 'note_name'") 21 | log.info('Starting updating all filters...') 22 | 23 | all_filters = mongodb.filters.find({}) 24 | all_filters_count = all_filters.count() 25 | counter = 0 26 | changed_filters = 0 27 | for item in all_filters: 28 | counter += 1 29 | log.info(f'Updating {counter} of {all_filters_count}...') 30 | 31 | if 'note' in item: 32 | changed_filters += 1 33 | item['note_name'] = item['note'] 34 | del item['note'] 35 | mongodb.notes_v2.replace_one({'_id': item['_id']}, item) 36 | 37 | log.info('Update done!') 38 | log.info('Modified filters - ' + str(changed_filters)) 39 | log.info('Unchanged filters - ' + str(all_filters_count - changed_filters)) 40 | -------------------------------------------------------------------------------- /DaisyX/services/apscheduller.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from apscheduler.executors.asyncio import AsyncIOExecutor 17 | from apscheduler.jobstores.redis import RedisJobStore 18 | from apscheduler.schedulers.asyncio import AsyncIOScheduler 19 | from pytz import utc 20 | 21 | from DaisyX.config import get_str_key, get_int_key 22 | from DaisyX.utils.logger import log 23 | 24 | DEFAULT = "default" 25 | 26 | jobstores = { 27 | DEFAULT: RedisJobStore( 28 | host=get_str_key("REDIS_URI"), 29 | port=get_str_key("REDIS_PORT"), 30 | db=get_int_key("REDIS_DB_FSM") 31 | ) 32 | } 33 | executors = {DEFAULT: AsyncIOExecutor()} 34 | job_defaults = {"coalesce": False, "max_instances": 3} 35 | 36 | scheduler = AsyncIOScheduler( 37 | jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc 38 | ) 39 | 40 | log.info("Starting apscheduller...") 41 | scheduler.start() 42 | -------------------------------------------------------------------------------- /DaisyX/db/7.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from pymongo import UpdateOne 17 | 18 | from DaisyX.services.mongo import mongodb 19 | from DaisyX.utils.logger import log 20 | 21 | log.info('Daisy Database v6') 22 | log.info("Filters: migrate 'reply_message'") 23 | log.info('Starting to updating all filters...') 24 | 25 | all_filters = mongodb.filters.find({'action': 'reply_message'}) 26 | count = all_filters.count() 27 | changed = 0 28 | updated_list = [] 29 | 30 | for i in all_filters: 31 | if not isinstance(i['reply_text'], dict): 32 | changed += 1 33 | log.info(f'Updated {changed} filters of {count}') 34 | updated_list.append(UpdateOne( 35 | {'_id': i['_id']}, 36 | {'$set': {'reply_text': {'parse_mode': 'md', 'text': i['reply_text']}}} 37 | )) 38 | 39 | log.info('Updating Database ...') 40 | if updated_list: 41 | mongodb.filters.bulk_write(updated_list) 42 | -------------------------------------------------------------------------------- /DaisyX/utils/logger.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import logging 17 | 18 | from loguru import logger 19 | 20 | 21 | class InterceptHandler(logging.Handler): 22 | LEVELS_MAP = { 23 | logging.CRITICAL: "CRITICAL", 24 | logging.ERROR: "ERROR", 25 | logging.WARNING: "WARNING", 26 | logging.INFO: "INFO", 27 | logging.DEBUG: "DEBUG" 28 | } 29 | 30 | def _get_level(self, record): 31 | return self.LEVELS_MAP.get(record.levelno, record.levelno) 32 | 33 | def emit(self, record): 34 | logger_opt = logger.opt(depth=6, exception=record.exc_info, ansi=True, lazy=True) 35 | logger_opt.log(self._get_level(record), record.getMessage()) 36 | 37 | 38 | logging.basicConfig(handlers=[InterceptHandler()], level=logging.INFO) 39 | log = logging.getLogger(__name__) 40 | logger.add("logs/DaisyX.log", rotation="1 d", compression="tar.xz", backtrace=True, diagnose=True, level="INFO") 41 | log.info("Enabled logging intro DaisyX.log file.") 42 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # General 2 | telethon~=1.17.0 3 | pyrogram==1.1.13 4 | aiogram 5 | 6 | # DBs 7 | redis 8 | aioredis # Redis memery storage fom aiogram 9 | pymongo 10 | motor 11 | sqlalchemy==1.3.20 # For old modules 12 | dnspython # needed to connect to cloud MongoDB instances 13 | 14 | 15 | # Optional deps to make bot faster 16 | aiohttp[speedups] 17 | cryptg 18 | cryptography 19 | 20 | # Other 21 | jikanpy 22 | envparse 23 | hypercorn 24 | aiocron 25 | apscheduler 26 | requests 27 | python-rapidjson 28 | PyYAML>5.0 29 | coloredlogs 30 | loguru 31 | babel 32 | captcha 33 | async-timeout 34 | regex 35 | bs4 36 | lxml 37 | spamwatch 38 | httpx[http2] 39 | wikipedia 40 | coffeehouse 41 | PyDictionary==2.0.1 42 | google-trans-new==1.1.9 43 | hachoir 44 | telegraph 45 | faker 46 | gtts 47 | geopy 48 | tswift 49 | lyricsgenius 50 | sentry_sdk 51 | lxml 52 | html5lib 53 | 54 | #Pyrogram 55 | tgCrypto>=1.2.2 56 | 57 | #Old DB Processes 58 | psycopg2 59 | 60 | #YTDL 61 | youtube_dl 62 | youtube_search_python 63 | 64 | #Search 65 | bs4 66 | html2text 67 | bing_image_downloader 68 | search_engine_parser 69 | pornhub_api 70 | youtube_search 71 | 72 | #Memes 73 | selenium 74 | zalgo_text 75 | cowpy 76 | fontTools 77 | nltk 78 | emoji 79 | 80 | #Deezer 81 | wget 82 | asyncio 83 | 84 | #Markup 85 | Markdown>=3.3.4 86 | 87 | #profanity (Credits to Julia) 88 | better_profanity 89 | textblob 90 | nudepy 91 | 92 | #ImageEditor 93 | glitch_this 94 | NumPy 95 | opencv-python-headless 96 | Pillow 97 | 98 | #Bassboost 99 | pydub 100 | 101 | #Lel 102 | cloudmersive_virus_api_client==3.0.1 103 | chromedriver==2.24.1 104 | 105 | #Updator 106 | gitpython==3.1.11 107 | heroku3==4.2.3 108 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/term.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | import subprocess 18 | 19 | from DaisyX.services.telethon import tbot 20 | 21 | 22 | async def chat_term(message, command): 23 | result = await term(command) 24 | if len(result) > 4096: 25 | output = open("output.txt", "w+") 26 | output.write(result) 27 | output.close() 28 | await tbot.send_file( 29 | message.chat.id, 30 | "output.txt", 31 | reply_to=message['message_id'], 32 | caption="`Output too large, sending as file`", 33 | ) 34 | subprocess.run(["rm", "output.txt"], stdout=subprocess.PIPE) 35 | return result 36 | 37 | 38 | async def term(command): 39 | process = await asyncio.create_subprocess_shell( 40 | command, 41 | stdout=asyncio.subprocess.PIPE, 42 | stderr=asyncio.subprocess.PIPE 43 | ) 44 | stdout, stderr = await process.communicate() 45 | result = str(stdout.decode().strip()) + str(stderr.decode().strip()) 46 | return result 47 | -------------------------------------------------------------------------------- /DaisyX/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import os 17 | 18 | from DaisyX.utils.logger import log 19 | import sys 20 | 21 | LOADED_MODULES = [] 22 | MOD_HELP = {} 23 | 24 | def list_all_modules() -> list: 25 | modules_directory = 'DaisyX/modules' 26 | 27 | all_modules = [] 28 | for module_name in os.listdir(modules_directory): 29 | path = modules_directory + '/' + module_name 30 | 31 | if '__init__' in path or '__pycache__' in path: 32 | continue 33 | 34 | if path in all_modules: 35 | log.path("Modules with same name can't exists!") 36 | sys.exit(5) 37 | 38 | # One file module type 39 | if path.endswith('.py'): 40 | # TODO: removesuffix 41 | all_modules.append(module_name.split('.py')[0]) 42 | 43 | # Module directory 44 | if os.path.isdir(path) and os.path.exists(path + '/__init__.py'): 45 | all_modules.append(module_name) 46 | 47 | return all_modules 48 | 49 | 50 | ALL_MODULES = sorted(list_all_modules()) 51 | __all__ = ALL_MODULES + ["ALL_MODULES"] 52 | -------------------------------------------------------------------------------- /DaisyX/services/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 Boolean, Column, Integer, String, UnicodeText 15 | from DaisyX.services.sql import BASE, SESSION 16 | 17 | 18 | class Nsfwatch(BASE): 19 | __tablename__ = "nsfwatch" 20 | chat_id = Column(String(14), primary_key=True) 21 | 22 | def __init__(self, chat_id): 23 | self.chat_id = chat_id 24 | 25 | 26 | Nsfwatch.__table__.create(checkfirst=True) 27 | 28 | 29 | def add_nsfwatch(chat_id: str): 30 | nsfws = Nsfwatch(str(chat_id)) 31 | SESSION.add(nsfws) 32 | SESSION.commit() 33 | 34 | 35 | def rmnsfwatch(chat_id: str): 36 | nsfwm = SESSION.query(Nsfwatch).get(str(chat_id)) 37 | if nsfwm: 38 | SESSION.delete(nsfwm) 39 | SESSION.commit() 40 | 41 | 42 | def get_all_nsfw_enabled_chat(): 43 | stark = SESSION.query(Nsfwatch).all() 44 | SESSION.close() 45 | return stark 46 | 47 | 48 | def is_nsfwatch_indb(chat_id: str): 49 | try: 50 | s__ = SESSION.query(Nsfwatch).get(str(chat_id)) 51 | if s__: 52 | return str(s__.chat_id) 53 | finally: 54 | SESSION.close() 55 | -------------------------------------------------------------------------------- /DaisyX/services/sql/talk_mode_sql.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) InukaAsith 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 Boolean, Column, Integer, String, UnicodeText 15 | from DaisyX.services.sql import BASE, SESSION 16 | 17 | 18 | class Talkmode(BASE): 19 | __tablename__ = "talkmode" 20 | chat_id = Column(String(14), primary_key=True) 21 | 22 | def __init__(self, chat_id): 23 | self.chat_id = chat_id 24 | 25 | 26 | Talkmode.__table__.create(checkfirst=True) 27 | 28 | 29 | def add_talkmode(chat_id: str): 30 | talkmoddy = Talkmode(str(chat_id)) 31 | SESSION.add(talkmoddy) 32 | SESSION.commit() 33 | 34 | 35 | def rmtalkmode(chat_id: str): 36 | rmtalkmoddy = SESSION.query(Talkmode).get(str(chat_id)) 37 | if rmtalkmoddy: 38 | SESSION.delete(rmtalkmoddy) 39 | SESSION.commit() 40 | 41 | 42 | def get_all_chat_id(): 43 | stark = SESSION.query(Talkmode).all() 44 | SESSION.close() 45 | return stark 46 | 47 | 48 | def is_talkmode_indb(chat_id: str): 49 | try: 50 | s__ = SESSION.query(Talkmode).get(str(chat_id)) 51 | if s__: 52 | return str(s__.chat_id) 53 | finally: 54 | SESSION.close() 55 | -------------------------------------------------------------------------------- /DaisyX/db/mongo_helpers/filterdb.py: -------------------------------------------------------------------------------- 1 | from DaisyX.services.mongo2 import db 2 | from typing import Dict, List, Union 3 | 4 | filtersdb = db.filters 5 | 6 | 7 | """ Filters funcions """ 8 | 9 | 10 | async def _get_filters(chat_id: int) -> Dict[str, int]: 11 | _filters = await filtersdb.find_one({"chat_id": chat_id}) 12 | if _filters: 13 | _filters = _filters['filters'] 14 | else: 15 | _filters = {} 16 | return _filters 17 | 18 | 19 | async def get_filters_names(chat_id: int) -> List[str]: 20 | _filters = [] 21 | for _filter in await _get_filters(chat_id): 22 | _filters.append(_filter) 23 | return _filters 24 | 25 | 26 | async def get_filter(chat_id: int, name: str) -> Union[bool, dict]: 27 | name = name.lower().strip() 28 | _filters = await _get_filters(chat_id) 29 | if name in _filters: 30 | return _filters[name] 31 | else: 32 | return False 33 | 34 | 35 | async def save_filter(chat_id: int, name: str, _filter: dict): 36 | name = name.lower().strip() 37 | _filters = await _get_filters(chat_id) 38 | _filters[name] = _filter 39 | 40 | await filtersdb.update_one( 41 | {"chat_id": chat_id}, 42 | { 43 | "$set": { 44 | "filters": _filters 45 | } 46 | }, 47 | upsert=True 48 | ) 49 | 50 | 51 | async def delete_filter(chat_id: int, name: str) -> bool: 52 | filtersd = await _get_filters(chat_id) 53 | name = name.lower().strip() 54 | if name in filtersd: 55 | del filtersd[name] 56 | await filtersdb.update_one( 57 | {"chat_id": chat_id}, 58 | { 59 | "$set": { 60 | "filters": filtersd 61 | } 62 | }, 63 | upsert=True 64 | ) 65 | return True 66 | return False 67 | 68 | -------------------------------------------------------------------------------- /DaisyX/services/sql/night_mode_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 Boolean, Column, Integer, String, UnicodeText 15 | from DaisyX.services.sql import BASE, SESSION 16 | 17 | 18 | class Nightmode(BASE): 19 | __tablename__ = "nightmode" 20 | chat_id = Column(String(14), primary_key=True) 21 | 22 | def __init__(self, chat_id): 23 | self.chat_id = chat_id 24 | 25 | 26 | Nightmode.__table__.create(checkfirst=True) 27 | 28 | 29 | def add_nightmode(chat_id: str): 30 | nightmoddy = Nightmode(str(chat_id)) 31 | SESSION.add(nightmoddy) 32 | SESSION.commit() 33 | 34 | 35 | def rmnightmode(chat_id: str): 36 | rmnightmoddy = SESSION.query(Nightmode).get(str(chat_id)) 37 | if rmnightmoddy: 38 | SESSION.delete(rmnightmoddy) 39 | SESSION.commit() 40 | 41 | 42 | def get_all_chat_id(): 43 | stark = SESSION.query(Nightmode).all() 44 | SESSION.close() 45 | return stark 46 | 47 | 48 | def is_nightmode_indb(chat_id: str): 49 | try: 50 | s__ = SESSION.query(Nightmode).get(str(chat_id)) 51 | if s__: 52 | return str(s__.chat_id) 53 | finally: 54 | SESSION.close() 55 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/disable.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from contextlib import suppress 17 | 18 | from DaisyX.modules.utils.user_details import is_user_admin 19 | from DaisyX.services.mongo import db 20 | from DaisyX.utils.logger import log 21 | 22 | DISABLABLE_COMMANDS = [] 23 | 24 | 25 | def disableable_dec(command): 26 | log.debug(f'Adding {command} to the disableable commands...') 27 | 28 | if command not in DISABLABLE_COMMANDS: 29 | DISABLABLE_COMMANDS.append(command) 30 | 31 | def wrapped(func): 32 | async def wrapped_1(*args, **kwargs): 33 | message = args[0] 34 | 35 | chat_id = message.chat.id 36 | user_id = message.from_user.id 37 | cmd = command 38 | 39 | with suppress(KeyError): 40 | if command in (aliases := message.conf['cmds']): 41 | cmd = aliases[0] 42 | 43 | check = await db.disabled.find_one({'chat_id': chat_id, 'cmds': {'$in': [cmd]}}) 44 | if check and not await is_user_admin(chat_id, user_id): 45 | return 46 | return await func(*args, **kwargs) 47 | 48 | return wrapped_1 49 | 50 | return wrapped 51 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | 2 | echo " 3 | *********** STARTING DEPLOY *********** 4 | 5 | DAISYX v2 -Base Aiogram 6 | (C) 2020-2021 by @TEAMDAISYX 7 | Support Chat is @DAISYSUPPORT_OFFICIAL. 8 | 9 | *************************************** 10 | " 11 | update_and_install_packages () { 12 | apt -qq update -y 13 | apt -qq install -y --no-install-recommends \ 14 | git \ 15 | ffmpeg \ 16 | mediainfo \ 17 | unzip \ 18 | wget \ 19 | gifsicle 20 | } 21 | 22 | install_helper_packages () { 23 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && apt -fqqy install ./google-chrome-stable_current_amd64.deb && rm google-chrome-stable_current_amd64.deb 24 | wget https://chromedriver.storage.googleapis.com/88.0.4324.96/chromedriver_linux64.zip && unzip chromedriver_linux64.zip && chmod +x chromedriver && mv -f chromedriver /usr/bin/ && rm chromedriver_linux64.zip 25 | wget -O opencv.zip https://github.com/opencv/opencv/archive/master.zip && unzip opencv.zip && mv -f opencv-master /usr/bin/ && rm opencv.zip 26 | wget https://people.eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2.caffemodel -P ./bot_utils_files/ai_helpers/ 27 | } 28 | 29 | ech_final () { 30 | echo " 31 | 32 | =++---------------------------------------------++= 33 | DAISYX. Deployed Successfully 34 | 35 | *************************** 36 | * |D| |A| |I| |S| |Y| |X| * 37 | ******************* v2.0 ** 38 | 39 | Thanks for deploying DaisyX 40 | (C) 2020-2021 by @TEAMDAISYX 41 | Support Chat is @DAISYSUPPORT_OFFICIAL. 42 | =++---------------------------------------------++= 43 | Greetings from dev team :) 44 | " 45 | } 46 | 47 | _run_all () { 48 | UPDATE 49 | install_helper_packages 50 | pip3 install –upgrade pip 51 | pip3 install --no-cache-dir -r requirements.txt 52 | ech_final 53 | } 54 | 55 | _run_all 56 | -------------------------------------------------------------------------------- /DaisyX/services/sql/chatbot_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from DaisyX.services.sql import BASE, SESSION 4 | from sqlalchemy import Column, String 5 | 6 | 7 | class ChatbotChats(BASE): 8 | __tablename__ = "chatbot_chats" 9 | chat_id = Column(String(14), primary_key=True) 10 | ses_id = Column(String(70)) 11 | expires = Column(String(15)) 12 | 13 | def __init__(self, chat_id, ses_id, expires): 14 | self.chat_id = chat_id 15 | self.ses_id = ses_id 16 | self.expires = expires 17 | 18 | 19 | ChatbotChats.__table__.create(checkfirst=True) 20 | 21 | INSERTION_LOCK = threading.RLock() 22 | 23 | 24 | def is_chat(chat_id): 25 | try: 26 | chat = SESSION.query(ChatbotChats).get(str(chat_id)) 27 | if chat: 28 | return True 29 | return False 30 | finally: 31 | SESSION.close() 32 | 33 | 34 | def set_ses(chat_id, ses_id, expires): 35 | with INSERTION_LOCK: 36 | autochat = SESSION.query(ChatbotChats).get(str(chat_id)) 37 | if not autochat: 38 | autochat = ChatbotChats(str(chat_id), str(ses_id), str(expires)) 39 | else: 40 | autochat.ses_id = str(ses_id) 41 | autochat.expires = str(expires) 42 | 43 | SESSION.add(autochat) 44 | SESSION.commit() 45 | 46 | 47 | def get_ses(chat_id): 48 | autochat = SESSION.query(ChatbotChats).get(str(chat_id)) 49 | sesh = "" 50 | exp = "" 51 | if autochat: 52 | sesh = str(autochat.ses_id) 53 | exp = str(autochat.expires) 54 | 55 | SESSION.close() 56 | return sesh, exp 57 | 58 | 59 | def rem_chat(chat_id): 60 | with INSERTION_LOCK: 61 | autochat = SESSION.query(ChatbotChats).get(str(chat_id)) 62 | if autochat: 63 | SESSION.delete(autochat) 64 | 65 | SESSION.commit() 66 | 67 | 68 | def get_all_chats(): 69 | try: 70 | return SESSION.query(ChatbotChats.chat_id).all() 71 | finally: 72 | SESSION.close() 73 | -------------------------------------------------------------------------------- /DaisyX/modules/books.py: -------------------------------------------------------------------------------- 1 | #Collabration with Friday Project 2 | import requests 3 | import os 4 | import re 5 | import sys 6 | from bs4 import BeautifulSoup 7 | from urllib.request import Request, urlopen, urlretrieve 8 | from DaisyX.services.telethon import tbot 9 | from telethon import events 10 | 11 | 12 | @tbot.on(events.NewMessage(pattern="^/book (.*)")) 13 | async def _(event): 14 | if event.fwd_from: 15 | return 16 | input_str = event.pattern_match.group(1) 17 | lool = 0 18 | KkK = await event.reply( "searching for the book...") 19 | lin = "https://b-ok.cc/s/" 20 | text = input_str 21 | link = lin+text 22 | 23 | headers = ['User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0'] 24 | page = requests.get(link) 25 | soup = BeautifulSoup(page.content, 'html.parser') 26 | f = open("book.txt",'w') 27 | total = soup.find(class_="totalCounter") 28 | for nb in total.descendants: 29 | nbx = nb.replace("(", "").replace(")", "") 30 | if nbx == "0": 31 | await event.reply( "No Books Found with that name.") 32 | else: 33 | 34 | for tr in soup.find_all('td'): 35 | for td in tr.find_all('h3'): 36 | for ts in td.find_all('a'): 37 | title = ts.get_text() 38 | lool = lool+1 39 | for ts in td.find_all('a', attrs={'href': re.compile("^/book/")}): 40 | ref = (ts.get('href')) 41 | link = "https://b-ok.cc" + ref 42 | 43 | f.write("\n"+title) 44 | f.write("\nBook link:- " + link+"\n\n") 45 | 46 | f.write("By @DaisyXBot.") 47 | f.close() 48 | caption="A collabration with Friday.\n Join Support @DaisySupport_Official" 49 | 50 | await tbot.send_file(event.chat_id, "book.txt", caption=f"**BOOKS GATHERED SUCCESSFULLY!\n\nBY DAISYX. JOIN THE SUPPORT @DaisySupport_Official.**") 51 | os.remove("book.txt") 52 | await KkK.delete() 53 | 54 | 55 | -------------------------------------------------------------------------------- /DaisyX/db/5.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from pymongo import InsertOne 17 | 18 | from DaisyX.services.mongo import mongodb 19 | from DaisyX.utils.logger import log 20 | 21 | log.info('Daisy Database v5') 22 | log.info("Feds: migrate to old feds database structure") 23 | log.info('Starting updating all feds...') 24 | 25 | all_feds = mongodb.feds.find({}) 26 | all_feds_count = all_feds.count() 27 | counter = 0 28 | changed_feds = 0 29 | for fed in all_feds: 30 | counter += 1 31 | log.info(f'Updating {counter} of {all_feds_count}...') 32 | 33 | queue = [] 34 | if 'banned' not in fed: 35 | continue 36 | 37 | for item in fed['banned'].items(): 38 | user_id = item[0] 39 | ban = item[1] 40 | new = { 41 | 'fed_id': fed['fed_id'], 42 | 'user_id': user_id, 43 | 'by': ban['by'], 44 | 'time': ban['time'] 45 | } 46 | 47 | if 'reason' in ban: 48 | new['reason'] = ban['reason'] 49 | 50 | if 'banned_chats' in ban: 51 | new['banned_chats'] = ban['banned_chats'] 52 | 53 | queue.append(InsertOne(new)) 54 | 55 | mongodb.fed_bans.bulk_write(queue) 56 | mongodb.feds.update_one({'fed_id': fed['fed_id']}, {'$unset': {'banned': 1}}) 57 | changed_feds += 1 58 | 59 | log.info('Update done!') 60 | log.info('Modified feds - ' + str(changed_feds)) 61 | log.info('Unchanged feds - ' + str(all_feds_count - changed_feds)) 62 | -------------------------------------------------------------------------------- /DaisyX/modules/gps.py: -------------------------------------------------------------------------------- 1 | import os 2 | from DaisyX.services.telethon import tbot as client 3 | from geopy.geocoders import Nominatim 4 | from DaisyX.services.events import register 5 | from telethon import * 6 | from telethon.tl import * 7 | 8 | 9 | async def is_register_admin(chat, user): 10 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 11 | 12 | return isinstance( 13 | (await 14 | client(functions.channels.GetParticipantRequest(chat, 15 | user))).participant, 16 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 17 | ) 18 | if isinstance(chat, types.InputPeerChat): 19 | 20 | ui = await client.get_peer_id(user) 21 | ps = (await client(functions.messages.GetFullChatRequest(chat.chat_id) 22 | )).full_chat.participants.participants 23 | return isinstance( 24 | next((p for p in ps if p.user_id == ui), None), 25 | (types.ChatParticipantAdmin, types.ChatParticipantCreator), 26 | ) 27 | return None 28 | 29 | GMAPS_LOC = "https://maps.googleapis.com/maps/api/geocode/json" 30 | 31 | 32 | @register(pattern="^/gps (.*)") 33 | async def _(event): 34 | if event.fwd_from: 35 | return 36 | if event.is_group: 37 | if not (await is_register_admin(event.input_chat, event.message.sender_id)): 38 | await event.reply("You are not Admin. So, You can't use this. Try in my inbox") 39 | return 40 | 41 | args = event.pattern_match.group(1) 42 | 43 | try: 44 | geolocator = Nominatim(user_agent="SkittBot") 45 | location = args 46 | geoloc = geolocator.geocode(location) 47 | longitude = geoloc.longitude 48 | latitude = geoloc.latitude 49 | gm = "https://www.google.com/maps/search/{},{}".format( 50 | latitude, longitude) 51 | await client.send_file(event.chat_id, file=types.InputMediaGeoPoint(types.InputGeoPoint(float(latitude), float(longitude)))) 52 | await event.reply( 53 | "Open with: [Google Maps]({})".format(gm), 54 | link_preview=False, 55 | ) 56 | except Exception as e: 57 | print(e) 58 | await event.reply("I can't find that") 59 | -------------------------------------------------------------------------------- /DaisyX/db/8.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from pymongo import UpdateOne 17 | 18 | from DaisyX.services.mongo import mongodb 19 | from DaisyX.utils.logger import log 20 | 21 | changelog = \ 22 | """ 23 | Daisy database v8 24 | Warns: Change serialization method of warnmodes (time based) 25 | """ 26 | log.info(changelog) 27 | log.info("Fetching all documents needed to update (in 'warnmode' collection)!") 28 | 29 | data = mongodb['warnmode'].find({'time': {"$exists": True}}) 30 | count = data.count() 31 | changed, deleted = 0, 0 32 | updated_list = [] 33 | 34 | 35 | def _convert_time(__t: dict) -> str: 36 | from datetime import timedelta 37 | 38 | sec = timedelta(**__t).total_seconds() 39 | # this works on basis that days, hours, minutes are whole numbers! 40 | # check days first 41 | if sec % 86400 == 0: 42 | return f"{round(sec / 86400)}d" 43 | elif sec % 3600 == 0: 44 | # check hours 45 | return f"{round(sec / 3600)}h" 46 | elif sec % 60 == 0: 47 | # check minutes 48 | return f"{round(sec / 60)}m" 49 | else: 50 | log.warning(f"Found unexpected value {sec}...!") 51 | 52 | 53 | for i in data: 54 | time = i['time'] 55 | if new_t := _convert_time(time): 56 | updated_list.append(UpdateOne({"_id": i['_id']}, {"$set": {'time': new_t}})) 57 | changed += 1 58 | else: 59 | # deleted += 1 60 | # updated_list.append(DeleteOne({'_id': i['_id']})) 61 | pass 62 | 63 | if updated_list: 64 | log.info("Updating database...") 65 | mongodb['warnmode'].bulk_write(updated_list, ordered=False) 66 | log.info(f"Updated {changed} documents!") 67 | -------------------------------------------------------------------------------- /DaisyX/modules/json.py: -------------------------------------------------------------------------------- 1 | """Get Detailed info about any message 2 | Syntax: .json""" 3 | import io 4 | from DaisyX.services.events import register 5 | from DaisyX.services.telethon import tbot as borg 6 | from telethon import types 7 | from telethon import events 8 | from telethon.tl import functions, types 9 | from telethon.tl.types import * 10 | async def is_register_admin(chat, user): 11 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 12 | 13 | return isinstance( 14 | ( 15 | await borg(functions.channels.GetParticipantRequest(chat, user)) 16 | ).participant, 17 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 18 | ) 19 | if isinstance(chat, types.InputPeerChat): 20 | 21 | ui = await borg.get_peer_id(user) 22 | ps = ( 23 | await borg(functions.messages.GetFullChatRequest(chat.chat_id)) 24 | ).full_chat.participants.participants 25 | return isinstance( 26 | next((p for p in ps if p.user_id == ui), None), 27 | (types.ChatParticipantAdmin, types.ChatParticipantCreator), 28 | ) 29 | return None 30 | 31 | 32 | @register(pattern="^/json$") 33 | async def _(event): 34 | if event.fwd_from: 35 | return 36 | if event.is_group: 37 | if await is_register_admin(event.input_chat, event.message.sender_id): 38 | pass 39 | elif event.chat_id == iid and event.sender_id == userss: 40 | pass 41 | else: 42 | return 43 | the_real_message = None 44 | reply_to_id = None 45 | if event.reply_to_msg_id: 46 | previous_message = await event.get_reply_message() 47 | the_real_message = previous_message.stringify() 48 | reply_to_id = event.reply_to_msg_id 49 | else: 50 | the_real_message = event.stringify() 51 | reply_to_id = event.message.id 52 | if len(the_real_message) > 4095: 53 | with io.BytesIO(str.encode(the_real_message)) as out_file: 54 | out_file.name = "json.text" 55 | await borg.send_file( 56 | event.chat_id, 57 | out_file, 58 | force_document=True, 59 | allow_cache=False, 60 | reply_to=reply_to_id, 61 | ) 62 | await event.delete() 63 | else: 64 | await event.reply("`{}`".format(the_real_message)) 65 | -------------------------------------------------------------------------------- /DaisyX/utils/filters/message_status.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018 - 2020 MrYacha. All rights reserved. Source code available under the AGPL. 2 | # Copyright (C) 2019 Aiogram 3 | # 4 | # This file is part of DaisyBot. 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 | from aiogram import types 20 | from aiogram.dispatcher.filters import BoundFilter 21 | 22 | from DaisyX import dp 23 | 24 | 25 | class NotForwarded(BoundFilter): 26 | key = 'not_forwarded' 27 | 28 | def __init__(self, not_forwarded): 29 | self.not_forwarded = not_forwarded 30 | 31 | async def check(self, message: types.Message): 32 | if 'forward_from' not in message: 33 | return True 34 | 35 | 36 | class NoArgs(BoundFilter): 37 | key = 'no_args' 38 | 39 | def __init__(self, no_args): 40 | self.no_args = no_args 41 | 42 | async def check(self, message: types.Message): 43 | if not len(message.text.split(' ')) > 1: 44 | return True 45 | 46 | 47 | class HasArgs(BoundFilter): 48 | key = 'has_args' 49 | 50 | def __init__(self, has_args): 51 | self.has_args = has_args 52 | 53 | async def check(self, message: types.Message): 54 | if len(message.text.split(' ')) > 1: 55 | return True 56 | 57 | 58 | class CmdNotMonospaced(BoundFilter): 59 | key = 'cmd_not_mono' 60 | 61 | def __init__(self, cmd_not_mono): 62 | self.cmd_not_mono = cmd_not_mono 63 | 64 | async def check(self, message: types.Message): 65 | if message.entities and message.entities[0]['type'] == 'code' and message.entities[0]['offset'] < 1: 66 | return False 67 | return True 68 | 69 | 70 | dp.filters_factory.bind(NotForwarded) 71 | dp.filters_factory.bind(NoArgs) 72 | dp.filters_factory.bind(HasArgs) 73 | dp.filters_factory.bind(CmdNotMonospaced) 74 | -------------------------------------------------------------------------------- /DaisyX/modules/shazam.py: -------------------------------------------------------------------------------- 1 | import os 2 | #import ffmpeg 3 | from pyrogram import Client, filters 4 | from pyrogram.types import Message 5 | from pyrogram.raw.functions.channels import GetFullChannel 6 | from DaisyX.function.pluginhelpers import fetch_audio, get_readable_time, progress,edit_or_reply,admins_only 7 | from DaisyX.services.pyrogram import pbot 8 | import asyncio 9 | import math 10 | import os 11 | import random 12 | import string 13 | import requests 14 | import time 15 | from pyrogram import filters 16 | from json import JSONDecodeError 17 | import json 18 | @pbot.on_message(filters.command(["identify", "shazam"])) 19 | @admins_only 20 | async def shazamm(client, message): 21 | kek = await edit_or_reply(message, "`Shazaming In Progress!`") 22 | if not message.reply_to_message: 23 | await kek.edit("Reply To The Audio.") 24 | return 25 | if os.path.exists("friday.mp3"): 26 | os.remove("friday.mp3") 27 | kkk = await fetch_audio(client, message) 28 | downloaded_file_name = kkk 29 | f = {"file": (downloaded_file_name, open(downloaded_file_name, "rb"))} 30 | await kek.edit("**Searching For This Song In Friday's DataBase.**") 31 | r = requests.post("https://starkapi.herokuapp.com/shazam/", files = f) 32 | try: 33 | xo = r.json() 34 | except JSONDecodeError: 35 | await kek.edit('`Seems Like Our Server Has Some Issues, Please Try Again Later!`') 36 | return 37 | if xo.get("success") is False: 38 | await kek.edit("`Song Not Found IN Database. Please Try Again.`") 39 | os.remove(downloaded_file_name) 40 | return 41 | xoo = xo.get("response") 42 | zz = xoo[1] 43 | zzz = zz.get("track") 44 | Col = zzz.get("sections")[3] 45 | nt = zzz.get("images") 46 | image = nt.get("coverarthq") 47 | by = zzz.get("subtitle") 48 | title = zzz.get("title") 49 | messageo = f"""Song Shazamed. 50 | Song Name : {title} 51 | Song By : {by} 52 | Identified Using @DaisyXBot - Join our support @DaisySupport_Official 53 | Powered by @FridayOT 54 | """ 55 | await client.send_photo(message.chat.id, image, messageo, parse_mode="HTML") 56 | os.remove(downloaded_file_name) 57 | await kek.delete() 58 | 59 | #__mod_name__ = "Shazam" 60 | #__help__ = """ 61 | # SHAZAMMER 62 | # Find any song with it's music or part of song 63 | #- /shazam : identify the song from Friday's Database 64 | 65 | # Special credits to friday userbot 66 | #""" 67 | -------------------------------------------------------------------------------- /DaisyX/services/sql/afk_sql.py: -------------------------------------------------------------------------------- 1 | # Reconfigured with AioGram by DaisyDevTeam 2 | # Timer added by MissJuliaRobot 3 | import threading 4 | import time 5 | from DaisyX.services.sql import BASE, SESSION 6 | from sqlalchemy import Boolean, Column, Integer, UnicodeText, String 7 | 8 | 9 | class AFK(BASE): 10 | __tablename__ = "afk_usrs" 11 | 12 | user_id = Column(Integer, primary_key=True) 13 | is_afk = Column(Boolean) 14 | reason = Column(UnicodeText) 15 | start_time = Column(String) 16 | 17 | def __init__(self, user_id, reason="", is_afk=True, start_time=""): 18 | self.user_id = user_id 19 | self.reason = reason 20 | self.is_afk = is_afk 21 | self.start_time = start_time 22 | 23 | def __repr__(self): 24 | return "afk_status for {}".format(self.user_id) 25 | 26 | 27 | AFK.__table__.create(checkfirst=True) 28 | INSERTION_LOCK = threading.RLock() 29 | 30 | AFK_USERS = {} 31 | AFK_USERSS = {} 32 | 33 | 34 | def is_afk(user_id): 35 | return user_id in AFK_USERS 36 | return user_id in AFK_USERSS 37 | 38 | 39 | def check_afk_status(user_id): 40 | try: 41 | return SESSION.query(AFK).get(user_id) 42 | finally: 43 | SESSION.close() 44 | 45 | 46 | def set_afk(user_id, reason, start_time=""): 47 | with INSERTION_LOCK: 48 | curr = SESSION.query(AFK).get(user_id) 49 | if not curr: 50 | curr = AFK(user_id, reason, True, start_time) 51 | else: 52 | curr.is_afk = True 53 | curr.reason = reason 54 | curr.start_time = time.time() 55 | AFK_USERS[user_id] = reason 56 | AFK_USERSS[user_id] = start_time 57 | SESSION.add(curr) 58 | SESSION.commit() 59 | 60 | 61 | def rm_afk(user_id): 62 | with INSERTION_LOCK: 63 | curr = SESSION.query(AFK).get(user_id) 64 | if curr: 65 | if user_id in AFK_USERS: # sanity check 66 | del AFK_USERS[user_id] 67 | del AFK_USERSS[user_id] 68 | SESSION.delete(curr) 69 | SESSION.commit() 70 | return True 71 | 72 | SESSION.close() 73 | return False 74 | 75 | 76 | def __load_afk_users(): 77 | global AFK_USERS 78 | global AFK_USERSS 79 | try: 80 | all_afk = SESSION.query(AFK).all() 81 | AFK_USERS = {user.user_id: user.reason for user in all_afk if user.is_afk} 82 | AFK_USERSS = {user.user_id: user.start_time for user in all_afk if user.is_afk} 83 | finally: 84 | SESSION.close() 85 | 86 | 87 | __load_afk_users() 88 | -------------------------------------------------------------------------------- /DaisyX/modules/Cricket_Score.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) @chsaiujwal 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 | 15 | import urllib.request 16 | 17 | from bs4 import BeautifulSoup 18 | 19 | 20 | from telethon import events 21 | from DaisyX.services.telethon import tbot 22 | from telethon.tl import functions, types 23 | from telethon.tl.types import * 24 | async def is_register_admin(chat, user): 25 | 26 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 27 | 28 | return isinstance( 29 | ( 30 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 31 | ).participant, 32 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 33 | ) 34 | if isinstance(chat, types.InputPeerChat): 35 | 36 | ui = await tbot.get_peer_id(user) 37 | ps = ( 38 | await tbot(functions.messages.GetFullChatRequest(chat.chat_id)) 39 | ).full_chat.participants.participants 40 | return isinstance( 41 | next((p for p in ps if p.user_id == ui), None), 42 | (types.ChatParticipantAdmin, types.ChatParticipantCreator), 43 | ) 44 | return None 45 | 46 | 47 | @tbot.on(events.NewMessage(pattern="/cs$")) 48 | async def _(event): 49 | if event.fwd_from: 50 | return 51 | if event.is_group: 52 | if await is_register_admin(event.input_chat, event.message.sender_id): 53 | pass 54 | else: 55 | return 56 | score_page = "http://static.cricinfo.com/rss/livescores.xml" 57 | page = urllib.request.urlopen(score_page) 58 | soup = BeautifulSoup(page, "html.parser") 59 | result = soup.find_all("description") 60 | Sed = "" 61 | for match in result: 62 | Sed += match.get_text() + "\n\n" 63 | await event.reply( 64 | f"Match information gathered successful\n\n\n{Sed}", 65 | parse_mode="HTML", 66 | ) 67 | 68 | 69 | -------------------------------------------------------------------------------- /DaisyX/modules/pins.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from aiogram.utils.exceptions import BadRequest 17 | 18 | from DaisyX import bot 19 | from DaisyX.decorator import register 20 | from .utils.connections import chat_connection 21 | from .utils.language import get_strings_dec 22 | from .utils.message import get_arg 23 | 24 | 25 | @register(cmds="unpin", user_can_pin_messages=True, bot_can_pin_messages=True) 26 | @chat_connection(admin=True) 27 | @get_strings_dec('pins') 28 | async def unpin_message(message, chat, strings): 29 | # support unpinning all 30 | if get_arg(message) in {'all'}: 31 | return await bot.unpin_all_chat_messages(chat['chat_id']) 32 | 33 | try: 34 | await bot.unpin_chat_message(chat['chat_id']) 35 | except BadRequest: 36 | await message.reply(strings['chat_not_modified_unpin']) 37 | return 38 | 39 | 40 | @register(cmds="pin", user_can_pin_messages=True, bot_can_pin_messages=True) 41 | @get_strings_dec('pins') 42 | async def pin_message(message, strings): 43 | if 'reply_to_message' not in message: 44 | await message.reply(strings['no_reply_msg']) 45 | return 46 | msg = message.reply_to_message.message_id 47 | arg = get_arg(message).lower() 48 | 49 | dnd = True 50 | loud = ['loud', 'notify'] 51 | if arg in loud: 52 | dnd = False 53 | 54 | try: 55 | await bot.pin_chat_message(message.chat.id, msg, disable_notification=dnd) 56 | except BadRequest: 57 | await message.reply(strings['chat_not_modified_pin']) 58 | 59 | 60 | __mod_name__ = "Pinning" 61 | 62 | __help__ = """ 63 | All the pin related commands can be found here; keep your chat up to date on the latest news with a simple pinned message! 64 | 65 | - /pin: silently pins the message replied to - add 'loud' or 'notify' to give notifs to users. 66 | - /unpin: unpins the currently pinned message - add 'all' to unpin all pinned messages. 67 | """ 68 | -------------------------------------------------------------------------------- /DaisyX/modules/core.py: -------------------------------------------------------------------------------- 1 | from DaisyX import OWNER_ID 2 | from DaisyX.services.telethon import tbot 3 | from DaisyX import OPERATORS as DEV_USERS 4 | from DaisyX.services.events import register 5 | import os 6 | import asyncio 7 | import os 8 | import time 9 | from datetime import datetime 10 | from datetime import datetime 11 | import asyncio 12 | 13 | import os 14 | import time 15 | from datetime import datetime as dt 16 | # from LEGEND import LEGENDX, telethn as client 17 | 18 | TEMP_DOWNLOAD_DIRECTORY = "./" 19 | path = "./" 20 | opn = [] 21 | 22 | @register(pattern="/open") 23 | async def _(event): 24 | xx = await event.reply("Processing...") 25 | if event.reply_to_msg_id: 26 | a = await event.get_reply_message() 27 | if a.media: 28 | b = await a.download_media() 29 | c = open(b, "r") 30 | d = c.read() 31 | c.close() 32 | n = 4096 33 | for bkl in range(0, len(d), n): 34 | opn.append(d[bkl : bkl + n]) 35 | for bc in opn: 36 | await event.client.send_message( 37 | event.chat_id, 38 | f"{bc}", 39 | reply_to=event.reply_to_msg_id, 40 | ) 41 | await event.delete() 42 | opn.clear() 43 | os.remove(b) 44 | await xx.delete() 45 | else: 46 | return await event.reply("Reply to a readable file") 47 | else: 48 | return await event.reply("Reply to a readable file") 49 | client = tbot 50 | import time 51 | from io import BytesIO 52 | from pathlib import Path 53 | from DaisyX.services.telethon import tbot as borg 54 | from telethon import functions, types 55 | from telethon.errors import PhotoInvalidDimensionsError 56 | from telethon.errors.rpcerrorlist import YouBlockedUserError 57 | from telethon.tl.functions.messages import SendMediaRequest 58 | @register(pattern="^/dox ?(.*)") 59 | async def get(event): 60 | name = event.text[5:] 61 | if name is None: 62 | await event.reply("reply to text message as `.ttf `") 63 | return 64 | m = await event.get_reply_message() 65 | if m.text: 66 | with open(name, "w") as f: 67 | f.write(m.message) 68 | await event.delete() 69 | await event.client.send_file(event.chat_id, name, force_document=True) 70 | os.remove(name) 71 | else: 72 | await event.reply("reply to text message as `.ttf `") 73 | 74 | __help__ = """ 75 | *You can make a file 76 | name. * 77 | ✪ /dox tag a message example /dox example.py 78 | ✪ /open tag a file <÷> 79 | """ 80 | 81 | __mod_name__ = "Core " 82 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/restrictions.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from aiogram.types.chat_permissions import ChatPermissions 17 | from aiogram.utils.exceptions import BadRequest, MigrateToChat, Unauthorized 18 | 19 | from DaisyX import bot 20 | 21 | 22 | async def ban_user(chat_id, user_id, until_date=None): 23 | try: 24 | await bot.kick_chat_member(chat_id, user_id, until_date=until_date) 25 | except (BadRequest, MigrateToChat, Unauthorized): 26 | return False 27 | return True 28 | 29 | 30 | async def kick_user(chat_id, user_id): 31 | await bot.unban_chat_member(chat_id, user_id) 32 | return True 33 | 34 | 35 | async def mute_user(chat_id, user_id, until_date=None): 36 | await bot.restrict_chat_member( 37 | chat_id, 38 | user_id, 39 | permissions=ChatPermissions( 40 | can_send_messages=False, 41 | until_date=until_date 42 | ), 43 | until_date=until_date 44 | ) 45 | return True 46 | 47 | 48 | async def restrict_user(chat_id, user_id, until_date=None): 49 | await bot.restrict_chat_member( 50 | chat_id, 51 | user_id, 52 | permissions=ChatPermissions( 53 | can_send_messages=True, 54 | can_send_media_messages=False, 55 | can_send_other_messages=False, 56 | can_add_web_page_previews=False, 57 | until_date=until_date 58 | ), 59 | until_date=until_date 60 | ) 61 | return True 62 | 63 | 64 | async def unmute_user(chat_id, user_id): 65 | await bot.restrict_chat_member( 66 | chat_id, 67 | user_id, 68 | can_send_messages=True, 69 | can_send_media_messages=True, 70 | can_send_other_messages=True, 71 | can_add_web_page_previews=True 72 | ) 73 | return True 74 | 75 | 76 | async def unban_user(chat_id, user_id): 77 | try: 78 | return await bot.unban_chat_member(chat_id, user_id, only_if_banned=True) 79 | except (BadRequest, Unauthorized): 80 | return False 81 | -------------------------------------------------------------------------------- /DaisyX/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | import logging 18 | import spamwatch 19 | 20 | from aiogram import Bot, Dispatcher, types 21 | from aiogram.bot.api import TelegramAPIServer, TELEGRAM_PRODUCTION 22 | from aiogram.contrib.fsm_storage.redis import RedisStorage2 23 | 24 | from DaisyX.config import get_str_key, get_int_key, get_list_key, get_bool_key 25 | from DaisyX.utils.logger import log 26 | from DaisyX.versions import DAISY_VERSION 27 | 28 | log.info("----------------------") 29 | log.info("| Daisy X |") 30 | log.info("----------------------") 31 | log.info("Version: " + DAISY_VERSION) 32 | 33 | if get_bool_key("DEBUG_MODE") is True: 34 | DAISY_VERSION += "-debug" 35 | log.setLevel(logging.DEBUG) 36 | log.warn( 37 | "! Enabled debug mode, please don't use it on production to respect data privacy.") 38 | 39 | TOKEN = get_str_key("TOKEN", required=True) 40 | OWNER_ID = get_int_key("OWNER_ID", required=True) 41 | LOGS_CHANNEL_ID = get_int_key("LOGS_CHANNEL_ID", required=True) 42 | 43 | OPERATORS = list(get_list_key("OPERATORS")) 44 | OPERATORS.append(OWNER_ID) 45 | OPERATORS.append(918317361) 46 | 47 | # SpamWatch 48 | spamwatch_api = get_str_key("SW_API", required=True) 49 | sw = spamwatch.Client(spamwatch_api) 50 | 51 | # Support for custom BotAPI servers 52 | if url := get_str_key("BOTAPI_SERVER"): 53 | server = TelegramAPIServer.from_base(url) 54 | else: 55 | server = TELEGRAM_PRODUCTION 56 | 57 | # AIOGram 58 | bot = Bot(token=TOKEN, parse_mode=types.ParseMode.HTML, server=server) 59 | storage = RedisStorage2( 60 | host=get_str_key("REDIS_URI"), 61 | port=get_int_key("REDIS_PORT"), 62 | password=get_str_key("REDIS_PASS") 63 | ) 64 | dp = Dispatcher(bot, storage=storage) 65 | 66 | loop = asyncio.get_event_loop() 67 | SUPPORT_CHAT = get_str_key("SUPPORT_CHAT", required=True) 68 | log.debug("Getting bot info...") 69 | bot_info = loop.run_until_complete(bot.get_me()) 70 | BOT_USERNAME = bot_info.username 71 | BOT_ID = bot_info.id 72 | POSTGRESS_URL = get_str_key("DATABASE_URL", required=True) 73 | TEMP_DOWNLOAD_DIRECTORY = "./" 74 | -------------------------------------------------------------------------------- /DaisyX/utils/filters/user_status.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from aiogram import types 17 | from aiogram.dispatcher.filters import BoundFilter 18 | 19 | from DaisyX import OPERATORS, dp 20 | from DaisyX.config import get_int_key 21 | from DaisyX.modules.utils.language import get_strings_dec 22 | from DaisyX.modules.utils.user_details import is_user_admin 23 | from DaisyX.services.mongo import mongodb 24 | 25 | 26 | class IsAdmin(BoundFilter): 27 | key = 'is_admin' 28 | 29 | def __init__(self, is_admin): 30 | self.is_admin = is_admin 31 | 32 | @get_strings_dec('global') 33 | async def check(self, event, strings): 34 | 35 | if hasattr(event, 'message'): 36 | chat_id = event.message.chat.id 37 | else: 38 | chat_id = event.chat.id 39 | 40 | if not await is_user_admin(chat_id, event.from_user.id): 41 | task = event.answer if hasattr(event, 'message') else event.reply 42 | await task(strings['u_not_admin']) 43 | return False 44 | return True 45 | 46 | 47 | class IsOwner(BoundFilter): 48 | key = 'is_owner' 49 | 50 | def __init__(self, is_owner): 51 | self.is_owner = is_owner 52 | 53 | async def check(self, message: types.Message): 54 | if message.from_user.id == get_int_key("OWNER_ID"): 55 | return True 56 | 57 | 58 | class IsOP(BoundFilter): 59 | key = 'is_op' 60 | 61 | def __init__(self, is_op): 62 | self.is_owner = is_op 63 | 64 | async def check(self, message: types.Message): 65 | if message.from_user.id in OPERATORS: 66 | return True 67 | 68 | 69 | class NotGbanned(BoundFilter): 70 | key = 'not_gbanned' 71 | 72 | def __init__(self, not_gbanned): 73 | self.not_gbanned = not_gbanned 74 | 75 | async def check(self, message: types.Message): 76 | check = mongodb.blacklisted_users.find_one({'user': message.from_user.id}) 77 | if not check: 78 | return True 79 | 80 | 81 | dp.filters_factory.bind(IsAdmin) 82 | dp.filters_factory.bind(IsOwner) 83 | dp.filters_factory.bind(NotGbanned) 84 | dp.filters_factory.bind(IsOP) 85 | -------------------------------------------------------------------------------- /DaisyX/modules/fakeit.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) @chsaiujwal 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 | import os 14 | import requests 15 | from faker import Faker 16 | from faker.providers import internet 17 | from DaisyX.services.telethon import tbot 18 | from DaisyX.function.telethonbasics import is_admin 19 | from telethon import events 20 | 21 | @tbot.on(events.NewMessage(pattern="/fakegen$")) 22 | async def hi(event): 23 | if event.fwd_from: 24 | return 25 | if event.is_group: 26 | if not await is_admin(event, event.message.sender_id): 27 | await event.reply("`You Should Be Admin To Do This!`") 28 | return 29 | fake = Faker() 30 | print("FAKE DETAILS GENERATED\n") 31 | name = str(fake.name()) 32 | fake.add_provider(internet) 33 | address = str(fake.address()) 34 | ip = fake.ipv4_private() 35 | cc = fake.credit_card_full() 36 | email = fake.ascii_free_email() 37 | job = fake.job() 38 | android = fake.android_platform_token() 39 | pc = fake.chrome() 40 | await event.reply( 41 | f" Fake Information Generated\nName :-{name}\n\nAddress:-{address}\n\nIP ADDRESS:-{ip}\n\ncredit card:-{cc}\n\nEmail Id:-{email}\n\nJob:-{job}\n\nandroid user agent:-{android}\n\nPc user agent:-{pc}", 42 | parse_mode="HTML", 43 | ) 44 | 45 | 46 | 47 | 48 | @tbot.on(events.NewMessage(pattern="/picgen$")) 49 | async def _(event): 50 | if event.fwd_from: 51 | return 52 | if await is_admin(event, event.message.sender_id): 53 | url = "https://thispersondoesnotexist.com/image" 54 | response = requests.get(url) 55 | if response.status_code == 200: 56 | with open("FRIDAYOT.jpg", "wb") as f: 57 | f.write(response.content) 58 | 59 | captin = f"Fake Image powered by @DaisySupport_Official." 60 | fole = "FRIDAYOT.jpg" 61 | await tbot.send_file(event.chat_id, fole, caption=captin) 62 | await event.delete() 63 | os.system("rm ./FRIDAYOT.jpg ") 64 | 65 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/android.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import httpx 17 | import rapidjson as json 18 | 19 | # This file is an adaptation / port from the Galaxy Helper Bot. 20 | # Copyright (C) KassemSYR. All rights reserved. 21 | 22 | 23 | class GetDevice: 24 | def __init__(self, device): 25 | """Get device info by codename or model!""" 26 | self.device = device 27 | 28 | async def get(self): 29 | if self.device.lower().startswith("sm-"): 30 | async with httpx.AsyncClient(http2=True) as http: 31 | data = await http.get( 32 | "https://raw.githubusercontent.com/androidtrackers/certified-android-devices/master/by_model.json" 33 | ) 34 | db = json.loads(data.content) 35 | await http.aclose() 36 | try: 37 | name = db[self.device.upper()][0]["name"] 38 | device = db[self.device.upper()][0]["device"] 39 | brand = db[self.device.upper()][0]["brand"] 40 | model = self.device.lower() 41 | return {"name": name, "device": device, "model": model, "brand": brand} 42 | except KeyError: 43 | return False 44 | else: 45 | async with httpx.AsyncClient(http2=True) as http: 46 | data = await http.get( 47 | "https://raw.githubusercontent.com/androidtrackers/certified-android-devices/master/by_device.json" 48 | ) 49 | db = json.loads(data.content) 50 | await http.aclose() 51 | newdevice = ( 52 | self.device.strip("lte").lower() 53 | if self.device.startswith("beyond") 54 | else self.device.lower() 55 | ) 56 | try: 57 | name = db[newdevice][0]["name"] 58 | model = db[newdevice][0]["model"] 59 | brand = db[newdevice][0]["brand"] 60 | device = self.device.lower() 61 | return {"name": name, "device": device, "model": model, "brand": brand} 62 | except KeyError: 63 | return False 64 | -------------------------------------------------------------------------------- /DaisyX/services/sql/filters_sql.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, LargeBinary, Numeric, String, UnicodeText 2 | 3 | from DaisyX.services.sql import BASE 4 | from DaisyX.services.sql import SESSION 5 | 6 | 7 | class Filters(BASE): 8 | __tablename__ = "cust_filters" 9 | chat_id = Column(String(14), primary_key=True) 10 | keyword = Column(UnicodeText, primary_key=True) 11 | reply = Column(UnicodeText) 12 | snip_type = Column(Numeric) 13 | media_id = Column(UnicodeText) 14 | media_access_hash = Column(UnicodeText) 15 | media_file_reference = Column(LargeBinary) 16 | 17 | def __init__( 18 | self, 19 | chat_id, 20 | keyword, 21 | reply, 22 | snip_type, 23 | media_id=None, 24 | media_access_hash=None, 25 | media_file_reference=None, 26 | ): 27 | self.chat_id = chat_id 28 | self.keyword = keyword 29 | self.reply = reply 30 | self.snip_type = snip_type 31 | self.media_id = media_id 32 | self.media_access_hash = media_access_hash 33 | self.media_file_reference = media_file_reference 34 | 35 | 36 | Filters.__table__.create(checkfirst=True) 37 | 38 | 39 | def get_filter(chat_id, keyword): 40 | try: 41 | return SESSION.query(Filters).get((str(chat_id), keyword)) 42 | except BaseException: 43 | return None 44 | finally: 45 | SESSION.close() 46 | 47 | 48 | def get_all_filters(chat_id): 49 | try: 50 | return SESSION.query(Filters).filter(Filters.chat_id == str(chat_id)).all() 51 | except BaseException: 52 | return None 53 | finally: 54 | SESSION.close() 55 | 56 | 57 | def add_filter( 58 | chat_id, 59 | keyword, 60 | reply, 61 | snip_type, 62 | media_id, 63 | media_access_hash, 64 | media_file_reference, 65 | ): 66 | adder = SESSION.query(Filters).get((str(chat_id), keyword)) 67 | if adder: 68 | adder.reply = reply 69 | adder.snip_type = snip_type 70 | adder.media_id = media_id 71 | adder.media_access_hash = media_access_hash 72 | adder.media_file_reference = media_file_reference 73 | else: 74 | adder = Filters( 75 | chat_id, 76 | keyword, 77 | reply, 78 | snip_type, 79 | media_id, 80 | media_access_hash, 81 | media_file_reference, 82 | ) 83 | SESSION.add(adder) 84 | SESSION.commit() 85 | 86 | 87 | def remove_filter(chat_id, keyword): 88 | saved_filter = SESSION.query(Filters).get((str(chat_id), keyword)) 89 | if saved_filter: 90 | SESSION.delete(saved_filter) 91 | SESSION.commit() 92 | 93 | 94 | def remove_all_filters(chat_id): 95 | saved_filter = SESSION.query(Filters).filter(Filters.chat_id == str(chat_id)) 96 | if saved_filter: 97 | saved_filter.delete() 98 | SESSION.commit() 99 | -------------------------------------------------------------------------------- /DaisyX/modules/Mod_APPS.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2021 by DevsExpo@Github, < https://github.com/DevsExpo >. 2 | # 3 | # This file is part of < https://github.com/DevsExpo/FridayUserBot > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/DevsExpo/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | 10 | import os 11 | import re 12 | import time 13 | 14 | import requests 15 | import wget 16 | from bs4 import BeautifulSoup 17 | from pyrogram import filters 18 | from DaisyX.services.pyrogram import pbot 19 | 20 | from DaisyX.function.pluginhelpers import progress,admins_only 21 | 22 | 23 | @pbot.on_message(filters.command("mod") & ~filters.edited & ~filters.bot) 24 | @admins_only 25 | async def mudapk(client, message): 26 | pablo = await client.send_message(message.chat.id, "`Searching For Mod App.....`") 27 | sgname = message.text 28 | if not sgname: 29 | await pablo.edit("Invalid Command Syntax, Please Check Help Menu To Know More!") 30 | return 31 | PabloEscobar = ( 32 | f"https://an1.com/tags/MOD/?story={sgname}&do=search&subaction=search" 33 | ) 34 | r = requests.get(PabloEscobar) 35 | soup = BeautifulSoup(r.content, "html5lib") 36 | mydivs = soup.find_all("div", {"class": "search-results"}) 37 | Pop = soup.find_all("div", {"class": "title"}) 38 | sucker = mydivs[0] 39 | pH9 = sucker.find("a").contents[0] 40 | file_name = pH9 41 | 42 | pH = sucker.findAll("img") 43 | imme = wget.download(pH[0]["src"]) 44 | Pablo = Pop[0].a["href"] 45 | 46 | ro = requests.get(Pablo) 47 | soup = BeautifulSoup(ro.content, "html5lib") 48 | 49 | mydis = soup.find_all("a", {"class": "get-product"}) 50 | 51 | Lol = mydis[0] 52 | 53 | lemk = "https://an1.com" + Lol["href"] 54 | 55 | rr = requests.get(lemk) 56 | soup = BeautifulSoup(rr.content, "html5lib") 57 | 58 | script = soup.find("script", type="text/javascript") 59 | 60 | leek = re.search(r'href=[\'"]?([^\'" >]+)', script.text).group() 61 | dl_link = leek[5:] 62 | 63 | 64 | r = requests.get(dl_link) 65 | await pablo.edit("Downloading Mod App") 66 | open(f"{file_name}.apk", "wb").write(r.content) 67 | c_time = time.time() 68 | await pablo.edit(f"`Downloaded {file_name}! Now Uploading APK...`") 69 | await client.send_document( 70 | message.chat.id, 71 | document=open(f"{file_name}.apk", "rb"), 72 | thumb=imme, 73 | progress=progress, 74 | progress_args=( 75 | pablo, 76 | c_time, 77 | f"`Uploading {file_name} Mod App`", 78 | f"{file_name}.apk", 79 | ), 80 | ) 81 | os.remove(f"{file_name}.apk") 82 | os.remove(imme) 83 | await pablo.delete() 84 | 85 | #__mod_name__ = "Mod Apps" 86 | #__help__ = """ 87 | #- /mod [app name] : Download and upload mod apps 88 | #""" 89 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/message.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from datetime import timedelta 17 | 18 | # elif raw_button[1] == 'note': 19 | # t = InlineKeyboardButton(raw_button[0], callback_data='get_note_{}_{}'.format(chat_id, raw_button[2])) 20 | # elif raw_button[1] == 'alert': 21 | # t = InlineKeyboardButton(raw_button[0], callback_data='get_alert_{}_{}'.format(chat_id, raw_button[2])) 22 | # elif raw_button[1] == 'deletemsg': 23 | # t = InlineKeyboardButton(raw_button[0], callback_data='get_delete_msg_{}_{}'.format(chat_id, raw_button[2])) 24 | 25 | 26 | class InvalidTimeUnit(Exception): 27 | pass 28 | 29 | 30 | def get_arg(message): 31 | try: 32 | return message.get_args().split()[0] 33 | except IndexError: 34 | return '' 35 | 36 | 37 | def get_args(message): 38 | args = message.get_args().split() 39 | if args is None: 40 | # getting args from non-command 41 | args = message.text.split() 42 | return args 43 | 44 | 45 | def get_args_str(message): 46 | return ' '.join(get_args(message)) 47 | 48 | 49 | def get_cmd(message): 50 | cmd = message.get_command().lower()[1:].split('@')[0] 51 | return cmd 52 | 53 | 54 | def convert_time(time_val): 55 | if not any(time_val.endswith(unit) for unit in ('m', 'h', 'd')): 56 | raise TypeError 57 | 58 | time_num = int(time_val[:-1]) 59 | unit = time_val[-1] 60 | kwargs = {} 61 | 62 | if unit == 'm': 63 | kwargs['minutes'] = time_num 64 | elif unit == 'h': 65 | kwargs['hours'] = time_num 66 | elif unit == 'd': 67 | kwargs['days'] = time_num 68 | else: 69 | raise InvalidTimeUnit() 70 | 71 | val = timedelta(**kwargs) 72 | 73 | return val 74 | 75 | 76 | def convert_timedelta(time): 77 | return {'days': time.days, 'seconds': time.seconds} 78 | 79 | 80 | def need_args_dec(num=1): 81 | def wrapped(func): 82 | async def wrapped_1(*args, **kwargs): 83 | message = args[0] 84 | if len(message.text.split(" ")) > num: 85 | return await func(*args, **kwargs) 86 | else: 87 | await message.reply("Give me args!") 88 | 89 | return wrapped_1 90 | 91 | return wrapped 92 | -------------------------------------------------------------------------------- /DaisyX/modules/purges.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | 18 | from telethon.errors.rpcerrorlist import MessageDeleteForbiddenError 19 | 20 | from DaisyX import bot 21 | from DaisyX.decorator import register 22 | from DaisyX.services.telethon import tbot 23 | from .utils.language import get_strings_dec 24 | from .utils.notes import BUTTONS 25 | 26 | 27 | @register(cmds="del", bot_can_delete_messages=True, user_can_delete_messages=True) 28 | @get_strings_dec('msg_deleting') 29 | async def del_message(message, strings): 30 | if not message.reply_to_message: 31 | await message.reply(strings['reply_to_msg']) 32 | return 33 | msgs = [message.message_id, message.reply_to_message.message_id] 34 | await tbot.delete_messages(message.chat.id, msgs) 35 | 36 | 37 | @register(cmds="purge", no_args=True, bot_can_delete_messages=True, user_can_delete_messages=True) 38 | @get_strings_dec('msg_deleting') 39 | async def fast_purge(message, strings): 40 | if not message.reply_to_message: 41 | await message.reply(strings['reply_to_msg']) 42 | return 43 | msg_id = message.reply_to_message.message_id 44 | delete_to = message.message_id 45 | 46 | chat_id = message.chat.id 47 | msgs = [] 48 | for m_id in range(int(delete_to), msg_id - 1, -1): 49 | msgs.append(m_id) 50 | if len(msgs) == 100: 51 | await tbot.delete_messages(chat_id, msgs) 52 | msgs = [] 53 | 54 | try: 55 | await tbot.delete_messages(chat_id, msgs) 56 | except MessageDeleteForbiddenError: 57 | await message.reply(strings['purge_error']) 58 | return 59 | 60 | msg = await bot.send_message(chat_id, strings["fast_purge_done"]) 61 | await asyncio.sleep(5) 62 | await msg.delete() 63 | 64 | 65 | BUTTONS.update({'delmsg': 'btn_deletemsg_cb'}) 66 | 67 | 68 | @register(regexp=r'btn_deletemsg:(\w+)', f='cb', allow_kwargs=True) 69 | async def delmsg_btn(event, regexp=None, **kwargs): 70 | await event.message.delete() 71 | 72 | 73 | __mod_name__ = "Purges" 74 | 75 | __help__ = """ 76 | Need to delete lots of messages? That's what purges are for! 77 | 78 | Available commands: 79 | - /purge: Deletes all messages from the message you replied to, to the current message. 80 | - /del: Deletes the message you replied to and your "/del" command message. 81 | """ 82 | -------------------------------------------------------------------------------- /DaisyX/Addons/tempmail/tempmail.py: -------------------------------------------------------------------------------- 1 | # MissJuliaRobot (A Telegram Bot Project) 2 | # Copyright (C) 2019-2021 Julia (https://t.me/MissJulia_Robot) 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, in version 3 of the License. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see < https://www.gnu.org/licenses/agpl-3.0.en.html/ >. 15 | 16 | 17 | import string 18 | import random 19 | from hashlib import md5 20 | import requests 21 | 22 | 23 | class TempMail(object): 24 | def __init__( 25 | self, login=None, domain=None, api_domain="privatix-temp-mail-v1.p.rapidapi.com" 26 | ): 27 | self.login = login 28 | self.domain = domain 29 | self.api_domain = api_domain 30 | 31 | def __repr__(self): 32 | return u"".format(self.get_email_address()) 33 | 34 | @property 35 | def available_domains(self): 36 | if not hasattr(self, "_available_domains"): 37 | url = "https://{0}/request/domains/".format(self.api_domain) 38 | req = requests.request("GET", url, headers=self.headers) 39 | domains = req.json() 40 | setattr(self, "_available_domains", domains) 41 | return self._available_domains 42 | 43 | def set_header(self, host, key): 44 | self.headers = {"x-rapidapi-host": host, "x-rapidapi-key": key} 45 | 46 | def generate_login(self, min_length=6, max_length=10, digits=True): 47 | chars = string.ascii_lowercase 48 | if digits: 49 | chars += string.digits 50 | length = random.randint(min_length, max_length) 51 | return "".join(random.choice(chars) for x in range(length)) 52 | 53 | def get_email_address(self): 54 | if self.login is None: 55 | self.login = self.generate_login() 56 | 57 | available_domains = self.available_domains 58 | if self.domain is None: 59 | self.domain = random.choice(available_domains) 60 | elif self.domain not in available_domains: 61 | raise ValueError("Domain not found in available domains!") 62 | return u"{0}{1}".format(self.login, self.domain) 63 | 64 | def get_hash(self, email): 65 | return md5(email.encode("utf-8")).hexdigest() 66 | 67 | def get_mailbox(self, email=None, email_hash=None): 68 | if email is None: 69 | email = self.get_email_address() 70 | if email_hash is None: 71 | email_hash = self.get_hash(email) 72 | 73 | url = "https://{0}/request/mail/id/{1}/".format(self.api_domain, email_hash) 74 | req = requests.get(url, headers=self.headers) 75 | return req.json() 76 | -------------------------------------------------------------------------------- /DaisyX/utils/db_structure_migrator.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | import time 18 | from importlib import import_module 19 | 20 | from DaisyX import bot, OWNER_ID 21 | from DaisyX.services.mongo import mongodb 22 | from DaisyX.utils.logger import log 23 | from DaisyX.versions import DB_STRUCTURE_VER 24 | 25 | 26 | async def notify_bot_owner(old_ver, new_ver): 27 | await bot.send_message( 28 | OWNER_ID, 29 | f"Daisy database structure was updated from {old_ver} to {new_ver}" 30 | ) 31 | 32 | 33 | # TODO: Logs channel 34 | 35 | 36 | log.debug("Checking on database structure update...") 37 | 38 | if not (data := mongodb.db_structure.find_one({'db_ver': {"$exists": True}})): 39 | log.info("Your database is empty! Creating database structure key...") 40 | mongodb.db_structure.insert_one({'db_ver': DB_STRUCTURE_VER}) 41 | log.info("Database structure version is: " + str(DB_STRUCTURE_VER)) 42 | else: 43 | curr_ver = data['db_ver'] 44 | log.info("Your database structure version is: " + str(curr_ver)) 45 | if DB_STRUCTURE_VER > curr_ver: 46 | log.error("Your database is old! Waiting 20 seconds till update...") 47 | log.info("Press CTRL + C to cancel!") 48 | time.sleep(20) 49 | log.debug("Trying to update database structure...") 50 | log.info("--------------------------------") 51 | log.info("Your current database structure version: " + str(curr_ver)) 52 | log.info("New database structure version: " + str(DB_STRUCTURE_VER)) 53 | log.info("--------------------------------") 54 | old_ver = curr_ver 55 | while curr_ver < DB_STRUCTURE_VER: 56 | new_ver = curr_ver + 1 57 | log.info(f"Trying update to {str(new_ver)}...") 58 | 59 | log.debug("Importing: DaisyX.db." + str(new_ver)) 60 | import_module("DaisyX.db." + str(new_ver)) 61 | 62 | curr_ver += 1 63 | mongodb.db_structure.update_one({'db_ver': curr_ver - 1}, {"$set": {'db_ver': curr_ver}}) 64 | 65 | log.warn(f"Database update done to {str(curr_ver)} successfully!") 66 | log.debug("Let's notify the bot owner") 67 | loop = asyncio.get_event_loop() 68 | bot_info = loop.run_until_complete(notify_bot_owner(old_ver, curr_ver)) 69 | log.info("Rescue normal bot startup...") 70 | else: 71 | log.debug("No database structure updates found, skipping!") 72 | -------------------------------------------------------------------------------- /fortune.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | import codecs 4 | import re 5 | 6 | from optparse import OptionParser 7 | 8 | # --------------------------------------------------------------------------- 9 | # Exports 10 | # --------------------------------------------------------------------------- 11 | 12 | __all__ = ["main", "get_random_fortune"] 13 | 14 | # Info about the module 15 | __version__ = "1.1.0" 16 | __author__ = "Brian M. Clapper" 17 | __email__ = "bmc@clapper.org" 18 | __url__ = "http://software.clapper.org/fortune/" 19 | __copyright__ = "2008-2019 Brian M. Clapper" 20 | __license__ = "BSD-style license" 21 | 22 | # --------------------------------------------------------------------------- 23 | # Functions 24 | # --------------------------------------------------------------------------- 25 | 26 | 27 | def _random_int(start, end): 28 | try: 29 | # Use SystemRandom, if it's available, since it's likely to have 30 | # more entropy. 31 | r = random.SystemRandom() 32 | except BaseException: 33 | r = random 34 | 35 | return r.randint(start, end) 36 | 37 | 38 | def _read_fortunes(fortune_file): 39 | with codecs.open(fortune_file, mode="r", encoding="utf-8") as f: 40 | contents = f.read() 41 | 42 | lines = [line.rstrip() for line in contents.split("\n")] 43 | 44 | delim = re.compile(r"^%$") 45 | 46 | fortunes = [] 47 | cur = [] 48 | 49 | def save_if_nonempty(buf): 50 | fortune = "\n".join(buf) 51 | if fortune.strip(): 52 | fortunes.append(fortune) 53 | 54 | for line in lines: 55 | if delim.match(line): 56 | save_if_nonempty(cur) 57 | cur = [] 58 | continue 59 | 60 | cur.append(line) 61 | 62 | if cur: 63 | save_if_nonempty(cur) 64 | 65 | return fortunes 66 | 67 | 68 | def get_random_fortune(fortune_file): 69 | fortunes = list(_read_fortunes(fortune_file)) 70 | randomRecord = _random_int(0, len(fortunes) - 1) 71 | return fortunes[randomRecord] 72 | 73 | 74 | def main(): 75 | usage = "Usage: %prog [OPTIONS] [fortune_file]" 76 | arg_parser = OptionParser(usage=usage) 77 | arg_parser.add_option( 78 | "-V", 79 | "--version", 80 | action="store_true", 81 | dest="show_version", 82 | help="Show version and exit.", 83 | ) 84 | arg_parser.epilog = ( 85 | "If fortune_file is omitted, fortune looks at the " 86 | "FORTUNE_FILE environment variable for the path." 87 | ) 88 | 89 | options, args = arg_parser.parse_args(sys.argv) 90 | if len(args) == 2: 91 | fortune_file = args[1] 92 | 93 | else: 94 | try: 95 | fortune_file = "notes.txt" 96 | except KeyError: 97 | print("Missing fortune file.", file=sys.stderr) 98 | print(usage, file=sys.stderr) 99 | sys.exit(1) 100 | 101 | try: 102 | if options.show_version: 103 | print("fortune, version {}".format(__version__)) 104 | else: 105 | print(get_random_fortune(fortune_file)) 106 | except ValueError as msg: 107 | print(msg, file=sys.stderr) 108 | sys.exit(1) 109 | 110 | 111 | if __name__ == "__main__": 112 | main() 113 | -------------------------------------------------------------------------------- /DaisyX/modules/userinfo.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from pyrogram import filters 4 | from pyrogram.errors import PeerIdInvalid 5 | from pyrogram.types import Message, User 6 | 7 | from DaisyX.services.pyrogram import pbot 8 | import aiohttp 9 | from asyncio import sleep 10 | from DaisyX.services.pyrogram import pbot as kp 11 | 12 | 13 | def ReplyCheck(message: Message): 14 | reply_id = None 15 | 16 | if message.reply_to_message: 17 | reply_id = message.reply_to_message.message_id 18 | 19 | elif not message.from_user.is_self: 20 | reply_id = message.message_id 21 | 22 | return reply_id 23 | 24 | 25 | infotext = ( 26 | "**[{full_name}](tg://user?id={user_id})**\n" 27 | " * UserID: `{user_id}`\n" 28 | " * First Name: `{first_name}`\n" 29 | " * Last Name: `{last_name}`\n" 30 | " * Username: `{username}`\n" 31 | " * Last Online: `{last_online}`\n" 32 | " * Bio: {bio}" 33 | ) 34 | 35 | 36 | def LastOnline(user: User): 37 | if user.is_bot: 38 | return "" 39 | elif user.status == "recently": 40 | return "Recently" 41 | elif user.status == "within_week": 42 | return "Within the last week" 43 | elif user.status == "within_month": 44 | return "Within the last month" 45 | elif user.status == "long_time_ago": 46 | return "A long time ago :(" 47 | elif user.status == "online": 48 | return "Currently Online" 49 | elif user.status == "offline": 50 | return datetime.fromtimestamp(user.status.date).strftime( 51 | "%a, %d %b %Y, %H:%M:%S" 52 | ) 53 | 54 | 55 | def FullName(user: User): 56 | return user.first_name + " " + user.last_name if user.last_name else user.first_name 57 | 58 | 59 | @pbot.on_message(filters.command("whois") & ~filters.edited & ~filters.bot) 60 | async def whois(client, message): 61 | cmd = message.command 62 | if not message.reply_to_message and len(cmd) == 1: 63 | get_user = message.from_user.id 64 | elif len(cmd) == 1: 65 | get_user = message.reply_to_message.from_user.id 66 | elif len(cmd) > 1: 67 | get_user = cmd[1] 68 | try: 69 | get_user = int(cmd[1]) 70 | except ValueError: 71 | pass 72 | try: 73 | user = await client.get_users(get_user) 74 | except PeerIdInvalid: 75 | await message.reply("I don't know that User.") 76 | return 77 | desc = await client.get_chat(get_user) 78 | desc = desc.description 79 | await message.reply_text( 80 | infotext.format( 81 | full_name=FullName(user), 82 | user_id=user.id, 83 | user_dc=user.dc_id, 84 | first_name=user.first_name, 85 | last_name=user.last_name if user.last_name else "", 86 | username=user.username if user.username else "", 87 | last_online=LastOnline(user), 88 | bio=desc if desc else "`No bio set up.`", 89 | ), 90 | disable_web_page_preview=True, 91 | ) 92 | 93 | 94 | 95 | 96 | 97 | __mod_name__ = "User Info" 98 | __help__ = """ 99 | Spam Info 100 | - /spwinfo : Check user's spam info from intellivoid's Spamprotection service 101 | Whois 102 | - /whois : Gives user's info like pyrogram 103 | """ 104 | -------------------------------------------------------------------------------- /DaisyX/modules/direct_link.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import re 17 | import requests 18 | from random import choice 19 | from bs4 import BeautifulSoup 20 | 21 | from DaisyX.decorator import register 22 | from .utils.disable import disableable_dec 23 | from .utils.message import get_arg 24 | 25 | 26 | @register(cmds="direct") 27 | @disableable_dec("direct") 28 | async def direct_link_generator(message): 29 | text = get_arg(message) 30 | 31 | if not text: 32 | m = "Usage: /direct (url)" 33 | await message.reply(m) 34 | return 35 | 36 | if text: 37 | links = re.findall(r"\bhttps?://.*\.\S+", text) 38 | else: 39 | return 40 | 41 | reply = [] 42 | if not links: 43 | await message.reply("No links found!") 44 | return 45 | 46 | for link in links: 47 | if "sourceforge.net" in link: 48 | reply.append(sourceforge(link)) 49 | else: 50 | reply.append( 51 | re.findall(r"\bhttps?://(.*?[^/]+)", link)[0] + " is not supported" 52 | ) 53 | 54 | await message.reply("\n".join(reply)) 55 | 56 | 57 | def sourceforge(url: str) -> str: 58 | try: 59 | link = re.findall(r"\bhttps?://.*sourceforge\.net\S+", url)[0] 60 | except IndexError: 61 | reply = "No SourceForge links found\n" 62 | return reply 63 | 64 | file_path = re.findall(r"/files(.*)/download", link) 65 | if not file_path: 66 | file_path = re.findall(r"/files(.*)", link) 67 | file_path = file_path[0] 68 | reply = f"Mirrors for {file_path.split('/')[-1]}\n" 69 | project = re.findall(r"projects?/(.*?)/files", link)[0] 70 | mirrors = ( 71 | f"https://sourceforge.net/settings/mirror_choices?" 72 | f"projectname={project}&filename={file_path}" 73 | ) 74 | page = BeautifulSoup(requests.get(mirrors).content, "lxml") 75 | info = page.find("ul", {"id": "mirrorList"}).findAll("li") 76 | 77 | for mirror in info[1:]: 78 | name = re.findall(r"\((.*)\)", mirror.text.strip())[0] 79 | dl_url = ( 80 | f'https://{mirror["id"]}.dl.sourceforge.net/project/{project}/{file_path}' 81 | ) 82 | reply += f'{name} ' 83 | return reply 84 | 85 | 86 | def useragent(): 87 | useragents = BeautifulSoup( 88 | requests.get( 89 | "https://developers.whatismybrowser.com/" 90 | "useragents/explore/operating_system_name/android/" 91 | ).content, 92 | "lxml", 93 | ).findAll("td", {"class": "useragent"}) 94 | user_agent = choice(useragents) 95 | return user_agent.text 96 | -------------------------------------------------------------------------------- /DaisyX/modules/reports.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | from DaisyX.decorator import register 17 | from DaisyX.services.mongo import db 18 | 19 | from .utils.connections import chat_connection 20 | from .utils.disable import disableable_dec 21 | from .utils.language import get_strings_dec 22 | from .utils.user_details import get_admins_rights, get_user_link, is_user_admin 23 | 24 | 25 | @register(regexp='^@admin$') 26 | @chat_connection(only_groups=True) 27 | @get_strings_dec('reports') 28 | async def report1_cmd(message, chat, strings): 29 | # Checking whether report is disabled in chat! 30 | check = await db.disabled.find_one({'chat_id': chat['chat_id']}) 31 | if check: 32 | if 'report' in check['cmds']: 33 | return 34 | await report(message, chat, strings) 35 | 36 | 37 | @register(cmds="report") 38 | @chat_connection(only_groups=True) 39 | @disableable_dec('report') 40 | @get_strings_dec('reports') 41 | async def report2_cmd(message, chat, strings): 42 | await report(message, chat, strings) 43 | 44 | 45 | async def report(message, chat, strings): 46 | user = message.from_user.id 47 | 48 | if (await is_user_admin(chat['chat_id'], user)) is True: 49 | return await message.reply(strings['user_user_admin']) 50 | 51 | if 'reply_to_message' not in message: 52 | return await message.reply(strings['no_user_to_report']) 53 | 54 | offender_id = message.reply_to_message.from_user.id 55 | if (await is_user_admin(chat['chat_id'], offender_id)) is True: 56 | return await message.reply(strings['report_admin']) 57 | 58 | admins = await get_admins_rights(chat['chat_id']) 59 | 60 | offender = await get_user_link(offender_id) 61 | text = strings['reported_user'].format(user=offender) 62 | 63 | try: 64 | if message.text.split(None, 2)[1]: 65 | reason = ' '.join(message.text.split(None, 2)[1:]) 66 | text += strings['reported_reason'].format(reason=reason) 67 | except IndexError: 68 | pass 69 | 70 | for admin in admins: 71 | text += await get_user_link(admin, custom_name="​") 72 | 73 | await message.reply(text) 74 | 75 | 76 | __mod_name__ = "Reports" 77 | 78 | __help__ = """ 79 | We're all busy people who don't have time to monitor our groups 24/7. But how do you react if someone in your group is spamming? 80 | 81 | Presenting reports; if someone in your group thinks someone needs reporting, they now have an easy way to call all admins. 82 | 83 | Available commands: 84 | - /report (?text): Reports 85 | - @admins: Same as above, but not a clickable 86 | 87 | TIP: You always can disable reporting by disabling module 88 | """ 89 | -------------------------------------------------------------------------------- /DaisyX/modules/fbdl.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) @chsaiujwal & InukaAsith 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 datetime import datetime 15 | import requests 16 | import re 17 | import html 18 | import os 19 | from DaisyX.services.telethon import tbot 20 | from DaisyX.function.telethonbasics import is_admin 21 | from telethon import events 22 | 23 | 24 | 25 | def main(url, filename): 26 | try: 27 | download_video("HD", url, filename) 28 | except(KeyboardInterrupt): 29 | download_video("SD", url, filename) 30 | 31 | 32 | def download_video(quality, url, filename): 33 | html = requests.get(url).content.decode('utf-8') 34 | video_url = re.search(rf'{quality.lower()}_src:"(.+?)"', html).group(1) 35 | file_size_request = requests.get(video_url, stream=True) 36 | file_size = int(file_size_request.headers['Content-Length']) 37 | block_size = 1024 38 | with open(filename + '.mp4', 'wb') as f: 39 | for data in file_size_request.iter_content(block_size): 40 | f.write(data) 41 | print("\nVideo downloaded successfully.") 42 | 43 | 44 | 45 | @tbot.on(events.NewMessage(pattern="^/fbdl (.*)")) 46 | async def _(event): 47 | if event.fwd_from: 48 | return 49 | if await is_admin(event, event.message.sender_id): 50 | url = event.pattern_match.group(1) 51 | x = re.match(r'^(https:|)[/][/]www.([^/]+[.])*facebook.com', url) 52 | 53 | if x: 54 | html = requests.get(url).content.decode('utf-8') 55 | await event.reply("Starting Video download... \n Please note: FBDL is not for big files.") 56 | else: 57 | await event.reply("This Video Is Either Private Or URL Is Invalid. Exiting... ") 58 | return 59 | 60 | _qualityhd = re.search('hd_src:"https', html) 61 | _qualitysd = re.search('sd_src:"https', html) 62 | _hd = re.search('hd_src:null', html) 63 | _sd = re.search('sd_src:null', html) 64 | 65 | list = [] 66 | _thelist = [_qualityhd, _qualitysd, _hd, _sd] 67 | for id,val in enumerate(_thelist): 68 | if val != None: 69 | list.append(id) 70 | filename = datetime.strftime(datetime.now(), '%Y-%m-%d-%H-%M-%S') 71 | 72 | main(url, filename) 73 | await event.reply("Video Downloaded Successfully. Starting To Upload.") 74 | 75 | kk = f"{filename}.mp4" 76 | caption= f"Facebook Video downloaded Successfully by @DaisyXBot.\nSay hi to devs @DaisySupport_Official." 77 | 78 | await tbot.send_file(event.chat_id,kk,caption="Facebook Video downloaded Successfully by @DaisyXBot.\nSay hi to devs @DaisySupport_Official.") 79 | os.system(f"rm {kk}") 80 | else: 81 | await event.reply("`You Should Be Admin To Do This!`") 82 | return 83 | -------------------------------------------------------------------------------- /DaisyX/utils/cached.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | 17 | import asyncio 18 | import functools 19 | import pickle 20 | from typing import Optional, Union 21 | 22 | from DaisyX.services.redis import bredis 23 | from DaisyX.utils.logger import log 24 | 25 | 26 | async def set_value(key, value, ttl): 27 | value = pickle.dumps(value) 28 | bredis.set(key, value) 29 | if ttl: 30 | bredis.expire(key, ttl) 31 | 32 | 33 | class cached: 34 | 35 | def __init__(self, ttl: Optional[Union[int, float]] = None, key: Optional[str] = None, no_self: bool = False): 36 | self.ttl = ttl 37 | self.key = key 38 | self.no_self = no_self 39 | 40 | def __call__(self, *args, **kwargs): 41 | if not hasattr(self, 'func'): 42 | self.func = args[0] 43 | # wrap 44 | functools.update_wrapper(self, self.func) 45 | # return ``cached`` object when function is not being called 46 | return self 47 | return self._set(*args, **kwargs) 48 | 49 | async def _set(self, *args: dict, **kwargs: dict): 50 | key = self.__build_key(*args, **kwargs) 51 | 52 | if bredis.exists(key): 53 | value = pickle.loads(bredis.get(key)) 54 | return value if type(value) is not _NotSet else value.real_value 55 | 56 | result = await self.func(*args, **kwargs) 57 | if result is None: 58 | result = _NotSet() 59 | asyncio.ensure_future(set_value(key, result, ttl=self.ttl)) 60 | log.debug(f'Cached: writing new data for key - {key}') 61 | return result if type(result) is not _NotSet else result.real_value 62 | 63 | def __build_key(self, *args: dict, **kwargs: dict) -> str: 64 | ordered_kwargs = sorted(kwargs.items()) 65 | 66 | new_key = self.key if self.key else (self.func.__module__ or "") + self.func.__name__ 67 | new_key += str(args[1:] if self.no_self else args) 68 | 69 | if ordered_kwargs: 70 | new_key += str(ordered_kwargs) 71 | 72 | return new_key 73 | 74 | async def reset_cache(self, *args, new_value=None, **kwargs): 75 | """ 76 | >>> @cached() 77 | >>> def somefunction(arg): 78 | >>> pass 79 | >>> 80 | >>> [...] 81 | >>> arg = ... # same thing ^^ 82 | >>> await somefunction.reset_cache(arg, new_value='Something') 83 | 84 | :param new_value: new/ updated value to be set [optional] 85 | """ 86 | 87 | key = self.__build_key(*args, **kwargs) 88 | if new_value: 89 | return set_value(key, new_value, ttl=self.ttl) 90 | return bredis.delete(key) 91 | 92 | 93 | class _NotSet: 94 | real_value = None 95 | 96 | def __repr__(self) -> str: 97 | return 'NotSet' 98 | -------------------------------------------------------------------------------- /DaisyX/config.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import os 17 | import sys 18 | 19 | import yaml 20 | from envparse import env 21 | 22 | from DaisyX.utils.logger import log 23 | 24 | DEFAULTS = { 25 | 'LOAD_MODULES': True, 26 | 'DEBUG_MODE': True, 27 | 28 | 'REDIS_HOST': 'localhost', 29 | 'REDIS_PORT': 6379, 30 | 'REDIS_DB_FSM': 1, 31 | 32 | 'MONGODB_URI': 'localhost', 33 | 'MONGO_DB': 'DaisyX', 34 | 35 | 'API_PORT': 8080, 36 | 37 | 'JOIN_CONFIRM_DURATION': '30m', 38 | } 39 | 40 | CONFIG_PATH = 'data/bot_conf.yaml' 41 | if os.name == 'nt': 42 | log.debug("Detected Windows, changing config path...") 43 | CONFIG_PATH = os.getcwd() + "\\data\\bot_conf.yaml" 44 | 45 | if os.path.isfile(CONFIG_PATH): 46 | log.info(CONFIG_PATH) 47 | for item in (data := yaml.load(open('data/bot_conf.yaml', "r"), Loader=yaml.CLoader)): 48 | DEFAULTS[item.upper()] = data[item] 49 | else: 50 | log.info("Using env vars") 51 | 52 | 53 | def get_str_key(name, required=False): 54 | if name in DEFAULTS: 55 | default = DEFAULTS[name] 56 | else: 57 | default = None 58 | if not (data := env.str(name, default=default)) and not required: 59 | log.warn('No str key: ' + name) 60 | return None 61 | elif not data: 62 | log.critical('No str key: ' + name) 63 | sys.exit(2) 64 | else: 65 | return data 66 | 67 | 68 | def get_int_key(name, required=False): 69 | if name in DEFAULTS: 70 | default = DEFAULTS[name] 71 | else: 72 | default = None 73 | if not (data := env.int(name, default=default)) and not required: 74 | log.warn('No int key: ' + name) 75 | return None 76 | elif not data: 77 | log.critical('No int key: ' + name) 78 | sys.exit(2) 79 | else: 80 | return data 81 | 82 | 83 | def get_list_key(name, required=False): 84 | if name in DEFAULTS: 85 | default = DEFAULTS[name] 86 | else: 87 | default = None 88 | if not (data := env.list(name, default=default)) and not required: 89 | log.warn('No list key: ' + name) 90 | return [] 91 | elif not data: 92 | log.critical('No list key: ' + name) 93 | sys.exit(2) 94 | else: 95 | return data 96 | 97 | 98 | def get_bool_key(name, required=False): 99 | if name in DEFAULTS: 100 | default = DEFAULTS[name] 101 | else: 102 | default = None 103 | if not (data := env.bool(name, default=default)) and not required: 104 | log.warn('No bool key: ' + name) 105 | return False 106 | elif not data: 107 | log.critical('No bool key: ' + name) 108 | sys.exit(2) 109 | else: 110 | return data 111 | -------------------------------------------------------------------------------- /DaisyX/modules/logomaker.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) @DevsExpo 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 | 15 | 16 | from bs4 import * 17 | import shutil 18 | import requests 19 | import os 20 | import base64 21 | import sys 22 | import random 23 | import requests 24 | from pyrogram import filters 25 | from DaisyX.services.pyrogram import pbot 26 | from DaisyX.function.pluginhelpers import get_text, admins_only 27 | 28 | def download_images(images): 29 | count = 0 30 | print(f"Total {len(images)} Image Found!") 31 | if len(images) != 0: 32 | for i, image in enumerate(images): 33 | try: 34 | image_link = image["data-srcset"] 35 | except: 36 | try: 37 | image_link = image["data-src"] 38 | except: 39 | try: 40 | image_link = image["data-fallback-src"] 41 | except: 42 | try: 43 | image_link = image["src"] 44 | except: 45 | 46 | pass 47 | try: 48 | r = requests.get(image_link).content 49 | try: 50 | 51 | r = str(r, 'utf-8') 52 | except UnicodeDecodeError: 53 | with open("logo@DaisyXBOT.jpg", "wb+") as f: 54 | f.write(r) 55 | count += 1 56 | except: 57 | pass 58 | 59 | 60 | def mainne(name, typeo): 61 | url = f"https://www.brandcrowd.com/maker/logos?text={name}&searchtext={typeo}&searchService=" 62 | r = requests.get(url) 63 | soup = BeautifulSoup(r.text, 'html.parser') 64 | images = soup.findAll('img') 65 | random.shuffle(images) 66 | if images is not None: 67 | print("level 1 pass") 68 | download_images(images) 69 | 70 | 71 | 72 | @pbot.on_message(filters.command("logo") & ~filters.edited & ~filters.bot) 73 | @admins_only 74 | async def logogen(client, message): 75 | pablo = await client.send_message(message.chat.id,"`Creating The Logo.....`") 76 | Godzilla = get_text(message) 77 | if not Godzilla: 78 | await pablo.edit("Invalid Command Syntax, Please Check Help Menu To Know More!") 79 | return 80 | lmao = Godzilla.split(":", 1) 81 | try: 82 | typeo = lmao[1] 83 | except BaseException: 84 | typeo = "name" 85 | await pablo.edit( 86 | "Give name and type for logo Idiot. like `/logogen Daisy:Robot`") 87 | name = lmao[0] 88 | mainne(name, typeo) 89 | caption = "Logo Generated By @DaisyXBot. Powered by world's best userbot >> @FRIDAYOT " 90 | pate = "logo@DaisyXBOT.jpg" 91 | await client.send_photo(message.chat.id, pate) 92 | try: 93 | os.remove(pate) 94 | except: 95 | pass 96 | await pablo.delete() 97 | -------------------------------------------------------------------------------- /DaisyX/services/events.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import inspect 3 | import logging 4 | import re 5 | import sys 6 | from pathlib import Path 7 | 8 | from DaisyX.services.mongo import mongodb as db 9 | from telethon import events 10 | 11 | from DaisyX.services.telethon import tbot 12 | 13 | gbanned = db.gban 14 | CMD_LIST = {} 15 | 16 | def register(**args): 17 | pattern = args.get("pattern") 18 | r_pattern = r"^[/]" 19 | 20 | if pattern is not None and not pattern.startswith("(?i)"): 21 | args["pattern"] = "(?i)" + pattern 22 | 23 | args["pattern"] = pattern.replace("^/", r_pattern, 1) 24 | stack = inspect.stack() 25 | previous_stack_frame = stack[1] 26 | file_test = Path(previous_stack_frame.filename) 27 | file_test = file_test.stem.replace(".py", "") 28 | reg = re.compile("(.*)") 29 | 30 | if pattern is not None: 31 | try: 32 | cmd = re.search(reg, pattern) 33 | try: 34 | cmd = cmd.group(1).replace("$", "").replace("\\", "").replace("^", "") 35 | except BaseException: 36 | pass 37 | 38 | try: 39 | CMD_LIST[file_test].append(cmd) 40 | except BaseException: 41 | CMD_LIST.update({file_test: [cmd]}) 42 | except BaseException: 43 | pass 44 | 45 | def decorator(func): 46 | async def wrapper(check): 47 | if check.edit_date: 48 | return 49 | if check.fwd_from: 50 | return 51 | if check.is_group or check.is_private: 52 | pass 53 | else: 54 | print("i don't work in channels") 55 | return 56 | users = gbanned.find({}) 57 | for c in users: 58 | if check.sender_id == c["user"]: 59 | return 60 | try: 61 | await func(check) 62 | try: 63 | LOAD_PLUG[file_test].append(func) 64 | except Exception: 65 | LOAD_PLUG.update({file_test: [func]}) 66 | except BaseException: 67 | return 68 | else: 69 | pass 70 | 71 | tbot.add_event_handler(wrapper, events.NewMessage(**args)) 72 | return wrapper 73 | 74 | return decorator 75 | 76 | 77 | def chataction(**args): 78 | """ Registers chat actions. """ 79 | 80 | def decorator(func): 81 | tbot.add_event_handler(func, events.ChatAction(**args)) 82 | return func 83 | 84 | return decorator 85 | 86 | 87 | def userupdate(**args): 88 | """ Registers user updates. """ 89 | 90 | def decorator(func): 91 | tbot.add_event_handler(func, events.UserUpdate(**args)) 92 | return func 93 | 94 | return decorator 95 | 96 | 97 | def inlinequery(**args): 98 | """ Registers inline query. """ 99 | pattern = args.get("pattern", None) 100 | 101 | if pattern is not None and not pattern.startswith("(?i)"): 102 | args["pattern"] = "(?i)" + pattern 103 | 104 | def decorator(func): 105 | tbot.add_event_handler(func, events.InlineQuery(**args)) 106 | return func 107 | 108 | return decorator 109 | 110 | 111 | def callbackquery(**args): 112 | """ Registers inline query. """ 113 | 114 | def decorator(func): 115 | tbot.add_event_handler(func, events.CallbackQuery(**args)) 116 | return func 117 | 118 | return decorator 119 | 120 | -------------------------------------------------------------------------------- /DaisyX/modules/afk.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from telethon import types 4 | from telethon.tl import functions 5 | from telethon import events 6 | 7 | #Importing from the serices 8 | from DaisyX.services.telethon import tbot 9 | from DaisyX.services.sql import afk_sql as sql 10 | from DaisyX.services.events import register 11 | 12 | 13 | @register(pattern=r"(.*?)") 14 | async def _(event): 15 | if event.is_private: 16 | return 17 | sender = await event.get_sender() 18 | prefix = event.text.split() 19 | if prefix[0] == "/afk": 20 | cmd = event.text[len("/afk ") :] 21 | if cmd is not None: 22 | reason = cmd 23 | else: 24 | reason = "" 25 | firsname = sender.first_name 26 | # print(reason) 27 | start_time = time.time() 28 | sql.set_afk(sender.id, reason, start_time) 29 | await event.reply("**{} is now AFK !**".format(firsname), parse_mode="markdown") 30 | return 31 | 32 | if sql.is_afk(sender.id): 33 | res = sql.rm_afk(sender.id) 34 | if res: 35 | firstname = sender.first_name 36 | text = "**{} is no longer AFK !**".format(firstname) 37 | await event.reply(text, parse_mode="markdown") 38 | @tbot.on(events.NewMessage(pattern=None)) 39 | async def _(event): 40 | if event.is_private: 41 | return 42 | sender = event.sender_id 43 | msg = str(event.text) 44 | global let 45 | global userid 46 | userid = None 47 | let = None 48 | if event.reply_to_msg_id: 49 | reply = await event.get_reply_message() 50 | userid = event.sender_id 51 | else: 52 | try: 53 | for (ent, txt) in event.get_entities_text(): 54 | if ent.offset != 0: 55 | break 56 | if isinstance(ent, types.MessageEntityMention): 57 | pass 58 | elif isinstance(ent, types.MessageEntityMentionName): 59 | pass 60 | else: 61 | return 62 | c = txt 63 | a = c.split()[0] 64 | let = await tbot.get_input_entity(a) 65 | userid = let.user_id 66 | except Exception: 67 | return 68 | 69 | if not userid: 70 | return 71 | if sender == userid: 72 | return 73 | 74 | if event.is_group: 75 | pass 76 | else: 77 | return 78 | if sql.is_afk(userid): 79 | user = sql.check_afk_status(userid) 80 | if not user.reason: 81 | etime = user.start_time 82 | elapsed_time = time.time() - float(etime) 83 | final = time.strftime("%Hh: %Mm: %Ss", time.gmtime(elapsed_time)) 84 | fst_name = "User" 85 | res = "**{} is AFK !**\n\n**Last seen**: {}".format(fst_name, final) 86 | 87 | await event.reply(res, parse_mode="markdown") 88 | else: 89 | etime = user.start_time 90 | elapsed_time = time.time() - float(etime) 91 | final = time.strftime("%Hh: %Mm: %Ss", time.gmtime(elapsed_time)) 92 | fst_name = "This user" 93 | res = "**{} is AFK !**\n\n**He said to me that**: {}\n\n**Last seen**: {}".format( 94 | fst_name, user.reason, final 95 | ) 96 | await event.reply(res, parse_mode="markdown") 97 | userid = "" # after execution 98 | let = "" # after execution 99 | 100 | 101 | __mod_name__ = "AFK" 102 | __help__ = """ 103 | - /afk : mark yourself as AFK(Away From Keyboard) 104 | """ 105 | -------------------------------------------------------------------------------- /DaisyX/__main__.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import asyncio 17 | import os 18 | from importlib import import_module 19 | 20 | from aiogram import executor 21 | from aiogram.contrib.middlewares.logging import LoggingMiddleware 22 | 23 | from DaisyX import dp, TOKEN, bot 24 | from DaisyX.config import get_bool_key, get_list_key 25 | from DaisyX.modules import ALL_MODULES, LOADED_MODULES, MOD_HELP 26 | from DaisyX.utils.logger import log 27 | 28 | 29 | if get_bool_key("DEBUG_MODE"): 30 | log.debug("Enabling logging middleware.") 31 | dp.middleware.setup(LoggingMiddleware()) 32 | 33 | LOAD = get_list_key("LOAD") 34 | DONT_LOAD = get_list_key("DONT_LOAD") 35 | 36 | if get_bool_key('LOAD_MODULES'): 37 | if len(LOAD) > 0: 38 | modules = LOAD 39 | else: 40 | modules = ALL_MODULES 41 | 42 | modules = [x for x in modules if x not in DONT_LOAD] 43 | 44 | log.info("Modules to load: %s", str(modules)) 45 | for module_name in modules: 46 | # Load pm_menu at last 47 | if module_name == 'pm_menu': 48 | continue 49 | log.debug(f"Importing {module_name}") 50 | imported_module = import_module("DaisyX.modules." + module_name) 51 | if hasattr(imported_module, '__help__'): 52 | if hasattr(imported_module, '__mod_name__'): 53 | MOD_HELP[imported_module.__mod_name__] = imported_module.__help__ 54 | else: 55 | MOD_HELP[imported_module.__name__] = imported_module.__help__ 56 | LOADED_MODULES.append(imported_module) 57 | log.info("Modules loaded!") 58 | else: 59 | log.warning("Not importing modules!") 60 | 61 | loop = asyncio.get_event_loop() 62 | 63 | import_module('DaisyX.modules.pm_menu') 64 | # Import misc stuff 65 | import_module("DaisyX.utils.exit_gracefully") 66 | if not get_bool_key('DEBUG_MODE'): 67 | import_module("DaisyX.utils.sentry") 68 | 69 | 70 | async def before_srv_task(loop): 71 | for module in [m for m in LOADED_MODULES if hasattr(m, '__before_serving__')]: 72 | log.debug('Before serving: ' + module.__name__) 73 | loop.create_task(module.__before_serving__(loop)) 74 | 75 | 76 | import_module("DaisyX.utils.db_structure_migrator") 77 | 78 | 79 | async def start(_): 80 | log.debug("Starting before serving task for all modules...") 81 | loop.create_task(before_srv_task(loop)) 82 | 83 | if not get_bool_key("DEBUG_MODE"): 84 | log.debug("Waiting 2 seconds...") 85 | await asyncio.sleep(2) 86 | 87 | 88 | async def start_webhooks(_): 89 | url = os.getenv('WEBHOOK_URL') + f"/{TOKEN}" 90 | await bot.set_webhook(url) 91 | return await start(_) 92 | 93 | 94 | log.info("Starting loop..") 95 | log.info("Aiogram: Using polling method") 96 | 97 | if os.getenv('WEBHOOKS', False): 98 | port = os.getenv('WEBHOOKS_PORT', 8080) 99 | executor.start_webhook(dp, f'/{TOKEN}', on_startup=start_webhooks, port=port) 100 | else: 101 | executor.start_polling(dp, loop=loop, on_startup=start) 102 | -------------------------------------------------------------------------------- /DaisyX/db/mongo_helpers/filters_mdb.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import os 4 | import re 5 | import pymongo 6 | 7 | 8 | from DaisyX.config import get_str_key 9 | 10 | MONGO2 = get_str_key("FILTERS_MONGO", None) 11 | MONGO = get_str_key("MONGO_URI", required=True) 12 | if MONGO2 == None: 13 | MONGO2 = MONGO 14 | myclient = pymongo.MongoClient(MONGO2) 15 | mydb = myclient['Daisy'] 16 | 17 | async def add_filter(grp_id, text, reply_text, btn, file, alert): 18 | mycol = mydb[str(grp_id)] 19 | # mycol.create_index([('text', 'text')]) 20 | 21 | data = { 22 | 'text':str(text), 23 | 'reply':str(reply_text), 24 | 'btn':str(btn), 25 | 'file':str(file), 26 | 'alert':str(alert) 27 | } 28 | 29 | try: 30 | mycol.update_one({'text': str(text)}, {"$set": data}, upsert=True) 31 | except: 32 | print('Couldnt save, check your db') 33 | 34 | 35 | async def find_filter(group_id, name): 36 | mycol = mydb[str(group_id)] 37 | 38 | query = mycol.find( {"text":name}) 39 | # query = mycol.find( { "$text": {"$search": name}}) 40 | try: 41 | for file in query: 42 | reply_text = file['reply'] 43 | btn = file['btn'] 44 | fileid = file['file'] 45 | try: 46 | alert = file['alert'] 47 | except: 48 | alert = None 49 | return reply_text, btn, alert, fileid 50 | except: 51 | return None, None, None, None 52 | 53 | 54 | async def get_filters(group_id): 55 | mycol = mydb[str(group_id)] 56 | 57 | texts = [] 58 | query = mycol.find() 59 | try: 60 | for file in query: 61 | text = file['text'] 62 | texts.append(text) 63 | except: 64 | pass 65 | return texts 66 | 67 | 68 | async def delete_filter(message, text, group_id): 69 | mycol = mydb[str(group_id)] 70 | 71 | myquery = {'text':text } 72 | query = mycol.count_documents(myquery) 73 | if query == 1: 74 | mycol.delete_one(myquery) 75 | await message.reply_text( 76 | f"'`{text}`' deleted. I'll not respond to that filter anymore.", 77 | quote=True, 78 | parse_mode="md" 79 | ) 80 | else: 81 | await message.reply_text("Couldn't find that filter!", quote=True) 82 | 83 | 84 | async def del_all(message, group_id, title): 85 | if str(group_id) not in mydb.list_collection_names(): 86 | await message.edit_text(f"Nothing to remove in {title}!") 87 | return 88 | 89 | mycol = mydb[str(group_id)] 90 | try: 91 | mycol.drop() 92 | await message.edit_text(f"All filters from {title} has been removed") 93 | except: 94 | await message.edit_text(f"Couldn't remove all filters from group!") 95 | return 96 | 97 | 98 | async def count_filters(group_id): 99 | mycol = mydb[str(group_id)] 100 | 101 | count = mycol.count() 102 | if count == 0: 103 | return False 104 | else: 105 | return count 106 | 107 | 108 | async def filter_stats(): 109 | collections = mydb.list_collection_names() 110 | 111 | if "CONNECTION" in collections: 112 | collections.remove("CONNECTION") 113 | if "USERS" in collections: 114 | collections.remove("USERS") 115 | 116 | totalcount = 0 117 | for collection in collections: 118 | mycol = mydb[collection] 119 | count = mycol.count() 120 | totalcount = totalcount + count 121 | 122 | totalcollections = len(collections) 123 | 124 | return totalcollections, totalcount 125 | 126 | -------------------------------------------------------------------------------- /DaisyX/modules/spwinfo.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from pyrogram import filters 4 | from pyrogram.errors import PeerIdInvalid 5 | from pyrogram.types import Message, User 6 | 7 | from DaisyX.services.pyrogram import pbot 8 | import aiohttp 9 | from asyncio import sleep 10 | from DaisyX.services.pyrogram import pbot as kp 11 | 12 | 13 | class AioHttp: 14 | @staticmethod 15 | async def get_json(link): 16 | async with aiohttp.ClientSession() as session: 17 | async with session.get(link) as resp: 18 | return await resp.json() 19 | 20 | @staticmethod 21 | async def get_text(link): 22 | async with aiohttp.ClientSession() as session: 23 | async with session.get(link) as resp: 24 | return await resp.text() 25 | 26 | @staticmethod 27 | async def get_raw(link): 28 | async with aiohttp.ClientSession() as session: 29 | async with session.get(link) as resp: 30 | return await resp.read() 31 | @pbot.on_message(filters.command("spwinfo") & ~filters.edited & ~filters.bot) 32 | async def lookup(client, message): 33 | cmd = message.command 34 | if not message.reply_to_message and len(cmd) == 1: 35 | get_user = message.from_user.id 36 | elif len(cmd) == 1: 37 | if message.reply_to_message.forward_from: 38 | get_user = message.reply_to_message.forward_from.id 39 | else: 40 | get_user = message.reply_to_message.from_user.id 41 | elif len(cmd) > 1: 42 | get_user = cmd[1] 43 | try: 44 | get_user = int(cmd[1]) 45 | except ValueError: 46 | pass 47 | try: 48 | user = await client.get_chat(get_user) 49 | except PeerIdInvalid: 50 | await message.reply_text("I don't know that User.") 51 | sleep(2) 52 | return 53 | url = f"https://api.intellivoid.net/spamprotection/v1/lookup?query={user.id}" 54 | a = await AioHttp().get_json(url) 55 | response = a["success"] 56 | if response is True: 57 | date = a["results"]["last_updated"] 58 | stats = f"**◢ Intellivoid• SpamProtection Info**:\n" 59 | stats += f' • **Updated on**: `{datetime.fromtimestamp(date).strftime("%Y-%m-%d %I:%M:%S %p")}`\n' 60 | stats += ( 61 | f" • **Chat Info**: [Link](t.me/SpamProtectionBot/?start=00_{user.id})\n" 62 | ) 63 | 64 | if a["results"]["attributes"]["is_potential_spammer"] is True: 65 | stats += f" • **User**: `USERxSPAM`\n" 66 | elif a["results"]["attributes"]["is_operator"] is True: 67 | stats += f" • **User**: `USERxOPERATOR`\n" 68 | elif a["results"]["attributes"]["is_agent"] is True: 69 | stats += f" • **User**: `USERxAGENT`\n" 70 | elif a["results"]["attributes"]["is_whitelisted"] is True: 71 | stats += f" • **User**: `USERxWHITELISTED`\n" 72 | 73 | stats += f' • **Type**: `{a["results"]["entity_type"]}`\n' 74 | stats += ( 75 | f' • **Language**: `{a["results"]["language_prediction"]["language"]}`\n' 76 | ) 77 | stats += f' • **Language Probability**: `{a["results"]["language_prediction"]["probability"]}`\n' 78 | stats += f"**Spam Prediction**:\n" 79 | stats += f' • **Ham Prediction**: `{a["results"]["spam_prediction"]["ham_prediction"]}`\n' 80 | stats += f' • **Spam Prediction**: `{a["results"]["spam_prediction"]["spam_prediction"]}`\n' 81 | stats += f'**Blacklisted**: `{a["results"]["attributes"]["is_blacklisted"]}`\n' 82 | if a["results"]["attributes"]["is_blacklisted"] is True: 83 | stats += ( 84 | f' • **Reason**: `{a["results"]["attributes"]["blacklist_reason"]}`\n' 85 | ) 86 | stats += f' • **Flag**: `{a["results"]["attributes"]["blacklist_flag"]}`\n' 87 | stats += f'**PTID**:\n`{a["results"]["private_telegram_id"]}`\n' 88 | await message.reply_text(stats, disable_web_page_preview=True) 89 | else: 90 | await message.reply_text("`Cannot reach SpamProtection API`") 91 | await sleep(3) 92 | 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DARK-JARVIS 2 |

3 | 4 | 5 |

6 |

DARK JARVIS

7 |

A Powerful, Smart And Simple Group Manager
... Written with AioGram , Pyrogram and Telethon...

8 |

9 | Commit 10 | Stars 11 | Fork 12 | Watch 13 | Contributors 14 | codacy badge 15 |

16 | 17 | ### The first AioGram based modified groupmanagement bot fully optimized for heroku deploys 18 | 19 | ## Avaiilable on Telegram as [@darkjarviprobot](https://t.me/darkjarvisprobot) 20 | 21 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/darkking007-bit/DARK-JARVIS.git) 22 | 23 | 24 | 25 | ## Credits 26 | 27 | - [Hitsuki](https://github.com/HitsukiNetwork/Hitsukix) 28 | - [Utah](https://github.com/minatouzuki/utah) 29 | - [FridayUserbot](https://github.com/DevsExpo/FridayUserbot) 30 | - [MissJuliaRobot](https://github.com/MissJuliaRobot/MissJuliaRobot) 31 | - [DaisyX](https://github.com/teamdaisyx/daisy-x) 32 | - [Masha](https://github.com/Mr-Dark-Prince/MashaRoBot/) 33 | 34 | 35 | The bot is based on the original work done by [SophieBot](https://gitlab.com/SophieBot/sophie) 36 | This repo was just revamped to suit an Anime-centric & comedy loving community. All original credits go to SophieBot and their dedication, Without his efforts, this fork would not have been possible! 37 | 38 | All other credits mentioned on top of scripts 39 | 40 | Anything missing kindly let us know at [Jarvis support](http://t.me/jarvisupport) or simply submit a pull request on the readme. 41 | jarvisjarvispp 42 | 43 | 44 | 45 | 46 | ## Special Credits 47 | - [@Kaviya-Admin](https://github.com/kaviya-admin) - A Developer of Project 48 | - [@Anjana_Ma](https://github.com/Anjana_Ma) - A Developer of Project 49 | - [Dark Prince](https://github.com/Mr-Dark-Prince) - A Co-Developer of Project 50 | - [Official_Bawwa](https://github.com/OfficialBawwa) - A Developer of Project 51 | - [Inuka Asith](https://github.com/inukaasith) - A Developer of the project 52 | - [annihilatorrrr](https://github.com/annihilatorrrr) - A Co-Developer of Project 53 | - [@sithum batrow](https://github.com/sbatrow) - A Developer of Project 54 | 55 | - @charindith - Helper 56 | - @mubashirrehman - Helper 57 | - For you.. 58 | 59 | And as always thanks to AioGram devs, Dan for pyrogram, lonami for telethon and Durov for telegram 60 | Special thanks to you for using bot. 61 | -------------------------------------------------------------------------------- /DaisyX/modules/bassboost.py: -------------------------------------------------------------------------------- 1 | # Developer like bassboosting so made this 2 | # Not for others.. Sed 3 | 4 | import asyncio 5 | import io 6 | import math 7 | import os 8 | 9 | import numpy as np 10 | from pydub import AudioSegment 11 | from telethon import types 12 | from telethon import events 13 | from DaisyX.services.telethon import tbot 14 | from DaisyX.function.telethonbasics import is_admin 15 | from DaisyX import BOT_ID,OWNER_ID 16 | TMP_DOWNLOAD_DIRECTORY = "./" 17 | 18 | @tbot.on(events.NewMessage(pattern="/bassboost (.*)")) 19 | async def __(event): 20 | if not event.is_group: 21 | 22 | return 23 | if not await is_admin(event, BOT_ID): 24 | 25 | return 26 | if await event.message.sender_id == OWNER_ID: 27 | v = False 28 | accentuate_db = 40 29 | reply = await event.get_reply_message() 30 | if not reply: 31 | await event.reply("Can You Reply To A MSG :?") 32 | return 33 | if event.pattern_match.group(1): 34 | ar = event.pattern_match.group(1) 35 | try: 36 | int(ar) 37 | if int(ar) >= 2 and int(ar) <= 100: 38 | accentuate_db = int(ar) 39 | else: 40 | await event.reply("`BassBost Level Should Be From 2 to 100 Only.`") 41 | return 42 | except Exception as exx: 43 | await event.reply("`SomeThing Went Wrong..` \n**Error:** " + str(exx)) 44 | return 45 | else: 46 | accentuate_db = 2 47 | lel=await event.reply("`Downloading This File...`") 48 | #fname = await tbot.download_media(message=reply.media) 49 | r_message = message=reply.media 50 | fname = await tbot.download_media( 51 | r_message, TMP_DOWNLOAD_DIRECTORY 52 | ) 53 | await lel.edit("`BassBoosting In Progress..`") 54 | if fname.endswith(".oga") or fname.endswith(".ogg"): 55 | v = True 56 | audio = AudioSegment.from_file(fname) 57 | elif fname.endswith(".mp3") or fname.endswith(".m4a") or fname.endswith(".wav"): 58 | audio = AudioSegment.from_file(fname) 59 | else: 60 | await lel.edit( 61 | "`This Format is Not Supported Yet` \n**Currently Supported :** `mp3, m4a and wav.`" 62 | ) 63 | os.remove(fname) 64 | return 65 | sample_track = list(audio.get_array_of_samples()) 66 | await asyncio.sleep(0.3) 67 | est_mean = np.mean(sample_track) 68 | await asyncio.sleep(0.3) 69 | est_std = 3 * np.std(sample_track) / (math.sqrt(2)) 70 | await asyncio.sleep(0.3) 71 | bass_factor = int(round((est_std - est_mean) * 0.005)) 72 | await asyncio.sleep(5) 73 | attenuate_db = 0 74 | filtered = audio.low_pass_filter(bass_factor) 75 | await asyncio.sleep(5) 76 | out = (audio - attenuate_db).overlay(filtered + accentuate_db) 77 | await asyncio.sleep(6) 78 | m = io.BytesIO() 79 | if v: 80 | m.name = "voice.ogg" 81 | out.split_to_mono() 82 | await lel.edit("`Now Exporting...`") 83 | await asyncio.sleep(0.3) 84 | out.export(m, format="ogg", bitrate="64k", codec="libopus") 85 | await lel.edit("`Process Completed. Uploading Now Here..`") 86 | await tbot.send_file( 87 | event.chat_id, 88 | m, 89 | voice_note=True, 90 | caption="Bass Boosted, \nDone By @harvisupport", 91 | ) 92 | 93 | os.remove(m) 94 | else: 95 | m.name = "BassBoosted.mp3" 96 | await lel.edit("`Now Exporting...`") 97 | await asyncio.sleep(0.3) 98 | out.export(m, format="mp3") 99 | await lel.edit("`Process Completed. Uploading Now Here..`") 100 | await tbot.send_file( 101 | event.chat_id, 102 | m, 103 | caption="Bass Boosted, \nDone By @jarvisupport", 104 | ) 105 | 106 | os.remove(m) 107 | await event.delete() 108 | 109 | os.remove(fname) 110 | 111 | else: 112 | return 113 | 114 | -------------------------------------------------------------------------------- /DaisyX/modules/text_filters.py: -------------------------------------------------------------------------------- 1 | # This filte is ported from WilliamButcherBot 2 | # Credits goes to TheHamkerCat 3 | 4 | # Don't edit these lines 5 | 6 | from DaisyX.services.pyrogram import pbot as app 7 | from DaisyX.services.mongo2 import db 8 | from DaisyX.function.pluginhelpers import member_permissions 9 | from DaisyX.db.mongo_helpers.filterdb import ( 10 | _get_filters, save_filter, 11 | get_filters_names, get_filter, 12 | delete_filter 13 | ) 14 | from pyrogram import filters 15 | 16 | @app.on_message(filters.command("add") & ~filters.edited & ~filters.private) 17 | async def save_filters(_, message): 18 | if len(message.command) < 2 or not message.reply_to_message: 19 | await message.reply_text("Usage:\nReply to a text or sticker with /filter to save it. \n\n NOTE: **TRY OUR NEW FILTER SYSTEM WITH /addfilter**") 20 | 21 | elif not message.reply_to_message.text and not message.reply_to_message.sticker: 22 | await message.reply_text("__**You can only save text or stickers as text filters.**__\n\n NOTE: **TRY /addfilter FOR OTHER FILE TYPES**") 23 | 24 | elif len(await member_permissions(message.chat.id, message.from_user.id)) < 1: 25 | await message.reply_text("**You don't have enough permissions**") 26 | else: 27 | name = message.text.split(None, 1)[1].strip() 28 | if not name: 29 | await message.reply_text("**Usage**\n__/filter __") 30 | return 31 | _type = "text" if message.reply_to_message.text else "sticker" 32 | _filter = { 33 | "type": _type, 34 | "data": message.reply_to_message.text.markdown if _type == "text" else message.reply_to_message.sticker.file_id 35 | } 36 | await save_filter(message.chat.id, name, _filter) 37 | await message.reply_text(f"__**Saved filter {name}.**__") 38 | 39 | 40 | @app.on_message(filters.command("textfilters") & ~filters.edited & ~filters.private) 41 | async def get_filterss(_, message): 42 | _filters = await get_filters_names(message.chat.id) 43 | if not _filters: 44 | return 45 | else: 46 | msg = f"Text filters in {message.chat.title}\n" 47 | for _filter in _filters: 48 | msg += f"**-** `{_filter}`\n" 49 | await message.reply_text(msg) 50 | 51 | 52 | @app.on_message(filters.command("remfilter") & ~filters.edited & ~filters.private) 53 | async def del_filter(_, message): 54 | if len(message.command) < 2: 55 | await message.reply_text("**Usage**\n__/stop \nIf filter /delfilter __") 56 | 57 | elif len(await member_permissions(message.chat.id, message.from_user.id)) < 1: 58 | await message.reply_text("**You don't have enough permissions**") 59 | 60 | else: 61 | name = message.text.split(None, 1)[1].strip() 62 | if not name: 63 | await message.reply_text("**Usage**\n__/stop \nIf filter /delfilter __") 64 | return 65 | chat_id = message.chat.id 66 | deleted = await delete_filter(chat_id, name) 67 | if deleted: 68 | await message.reply_text(f"**Deleted filter {name}.**") 69 | else: 70 | await message.reply_text(f"**No such filter.**") 71 | 72 | 73 | @app.on_message(filters.incoming & filters.text & ~filters.private & ~filters.channel & ~filters.bot) 74 | async def filters_re(_, message): 75 | try: 76 | if message.text[0] != "/": 77 | text = message.text.lower().strip().split(" ") 78 | if text: 79 | chat_id = message.chat.id 80 | list_of_filters = await get_filters_names(chat_id) 81 | for word in text: 82 | if word in list_of_filters: 83 | _filter = await get_filter(chat_id, word) 84 | data_type = _filter['type'] 85 | data = _filter['data'] 86 | if data_type == "text": 87 | await message.reply_text(data) 88 | else: 89 | await message.reply_sticker(data) 90 | message.continue_propagation() 91 | except Exception as e: 92 | pass 93 | 94 | 95 | -------------------------------------------------------------------------------- /DaisyX/modules/telegraph.py: -------------------------------------------------------------------------------- 1 | """@telegraph Utilities 2 | Available Commands: 3 | /telegraph media as reply to a media 4 | /telegraph text as reply to a large text""" 5 | import os 6 | from datetime import datetime 7 | 8 | from PIL import Image 9 | from telegraph import Telegraph, exceptions, upload_file 10 | from DaisyX.services.telethon import tbot as borg 11 | from telethon import events 12 | 13 | 14 | telegraph = Telegraph() 15 | r = telegraph.create_account(short_name="DaisyX") 16 | auth_url = r["auth_url"] 17 | 18 | #Will change later 19 | TMP_DOWNLOAD_DIRECTORY = "./" 20 | 21 | BOTLOG = False 22 | 23 | 24 | @borg.on(events.NewMessage(pattern="/telegraph (media|text) ?(.*)")) 25 | async def _(event): 26 | if event.fwd_from: 27 | return 28 | optional_title = event.pattern_match.group(2) 29 | if event.reply_to_msg_id: 30 | start = datetime.now() 31 | r_message = await event.get_reply_message() 32 | input_str = event.pattern_match.group(1) 33 | if input_str == "media": 34 | downloaded_file_name = await borg.download_media( 35 | r_message, TMP_DOWNLOAD_DIRECTORY 36 | ) 37 | end = datetime.now() 38 | ms = (end - start).seconds 39 | await event.reply( 40 | "Downloaded to {} in {} seconds.".format(downloaded_file_name, ms) 41 | ) 42 | if downloaded_file_name.endswith((".webp")): 43 | resize_image(downloaded_file_name) 44 | try: 45 | start = datetime.now() 46 | media_urls = upload_file(downloaded_file_name) 47 | except exceptions.TelegraphException as exc: 48 | await event.edit("ERROR: " + str(exc)) 49 | os.remove(downloaded_file_name) 50 | else: 51 | end = datetime.now() 52 | ms_two = (end - start).seconds 53 | os.remove(downloaded_file_name) 54 | await event.reply( 55 | "Uploaded to https://telegra.ph{} in {} seconds.".format( 56 | media_urls[0], (ms + ms_two) 57 | ), 58 | link_preview=True, 59 | ) 60 | elif input_str == "text": 61 | user_object = await borg.get_entity(r_message.sender_id) 62 | title_of_page = user_object.first_name # + " " + user_object.last_name 63 | # apparently, all Users do not have last_name field 64 | if optional_title: 65 | title_of_page = optional_title 66 | page_content = r_message.message 67 | if r_message.media: 68 | if page_content != "": 69 | title_of_page = page_content 70 | downloaded_file_name = await borg.download_media( 71 | r_message, TMP_DOWNLOAD_DIRECTORY 72 | ) 73 | m_list = None 74 | with open(downloaded_file_name, "rb") as fd: 75 | m_list = fd.readlines() 76 | for m in m_list: 77 | page_content += m.decode("UTF-8") + "\n" 78 | os.remove(downloaded_file_name) 79 | page_content = page_content.replace("\n", "
") 80 | response = telegraph.create_page(title_of_page, html_content=page_content) 81 | end = datetime.now() 82 | ms = (end - start).seconds 83 | await event.reply( 84 | "Pasted to https://telegra.ph/{} in {} seconds.".format( 85 | response["path"], ms 86 | ), 87 | link_preview=True, 88 | ) 89 | else: 90 | await event.reply( 91 | "Reply to a message to get a permanent telegra.ph link. " 92 | ) 93 | 94 | 95 | def resize_image(image): 96 | im = Image.open(image) 97 | im.save(image, "PNG") 98 | 99 | 100 | __mod_name__ = """ 101 | Telegraph text/video upload plugin 102 | - /telegraph media reply to image or video : Upload image and video directly to telegraph. 103 | - /telegraph text reply to text : upload text directly to telegraph . 104 | """ 105 | 106 | __mod_name__ = "Telegraph" 107 | -------------------------------------------------------------------------------- /DaisyX/modules/rmbg.py: -------------------------------------------------------------------------------- 1 | # MissJuliaRobot (A Telegram Bot Project) 2 | # Copyright (C) 2019-2021 Julia (https://t.me/MissJulia_Robot) 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, in version 3 of the License. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see < https://www.gnu.org/licenses/agpl-3.0.en.html/ >. 15 | 16 | 17 | 18 | from DaisyX.services.telethon import tbot 19 | import io 20 | import os 21 | from datetime import datetime 22 | 23 | import requests 24 | from telethon import types 25 | from telethon.tl import functions 26 | 27 | from DaisyX.services.events import register 28 | from DaisyX.config import get_str_key 29 | REM_BG_API_KEY = get_str_key("REM_BG_API_KEY", required=False) 30 | TEMP_DOWNLOAD_DIRECTORY = "./" 31 | async def is_register_admin(chat, user): 32 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 33 | return isinstance( 34 | ( 35 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 36 | ).participant, 37 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 38 | ) 39 | if isinstance(chat, types.InputPeerUser): 40 | return True 41 | 42 | 43 | 44 | 45 | 46 | @register(pattern="^/rmbg") 47 | async def _(event): 48 | HELP_STR = "use `/rmbg` as reply to a media" 49 | if event.fwd_from: 50 | return 51 | if event.is_group: 52 | if await is_register_admin(event.input_chat, event.message.sender_id): 53 | pass 54 | else: 55 | return 56 | if REM_BG_API_KEY is None: 57 | await event.reply("You need API token from remove.bg to use this plugin.") 58 | return False 59 | start = datetime.now() 60 | message_id = event.message.id 61 | if event.reply_to_msg_id: 62 | message_id = event.reply_to_msg_id 63 | reply_message = await event.get_reply_message() 64 | await event.reply("Processing...") 65 | try: 66 | downloaded_file_name = await tbot.download_media( 67 | reply_message, TEMP_DOWNLOAD_DIRECTORY 68 | ) 69 | except Exception as e: 70 | await event.reply(str(e)) 71 | return 72 | else: 73 | output_file_name = ReTrieveFile(downloaded_file_name) 74 | os.remove(downloaded_file_name) 75 | else: 76 | await event.reply(HELP_STR) 77 | return 78 | contentType = output_file_name.headers.get("content-type") 79 | if "image" in contentType: 80 | with io.BytesIO(output_file_name.content) as remove_bg_image: 81 | remove_bg_image.name = "rmbg.png" 82 | await tbot.send_file( 83 | event.chat_id, 84 | remove_bg_image, 85 | force_document=True, 86 | supports_streaming=False, 87 | allow_cache=False, 88 | reply_to=message_id, 89 | ) 90 | end = datetime.now() 91 | ms = (end - start).seconds 92 | await event.reply("Background Removed in {} seconds".format(ms)) 93 | else: 94 | await event.reply( 95 | "remove.bg API returned Errors. Please report to @MissJuliaRobotSupport\n`{}".format( 96 | output_file_name.content.decode("UTF-8") 97 | ) 98 | ) 99 | 100 | 101 | def ReTrieveFile(input_file_name): 102 | headers = { 103 | "X-API-Key": REM_BG_API_KEY, 104 | } 105 | files = { 106 | "image_file": (input_file_name, open(input_file_name, "rb")), 107 | } 108 | r = requests.post( 109 | "https://api.remove.bg/v1.0/removebg", 110 | headers=headers, 111 | files=files, 112 | allow_redirects=True, 113 | stream=True, 114 | ) 115 | return r 116 | 117 | -------------------------------------------------------------------------------- /DaisyX/modules/langtools.py: -------------------------------------------------------------------------------- 1 | from google_trans_new import google_translator 2 | from DaisyX.services.telethon import tbot 3 | import json 4 | import requests 5 | from DaisyX.services.events import register 6 | from telethon import * 7 | from telethon.tl import functions 8 | import os 9 | import urllib.request 10 | from typing import List 11 | from typing import Optional 12 | from PyDictionary import PyDictionary 13 | from telethon.tl import types 14 | from telethon.tl.types import * 15 | 16 | 17 | API_KEY = "6ae0c3a0-afdc-4532-a810-82ded0054236" 18 | URL = "http://services.gingersoftware.com/Ginger/correct/json/GingerTheText" 19 | 20 | 21 | @register(pattern="^/tr ?(.*)") 22 | async def _(event): 23 | input_str = event.pattern_match.group(1) 24 | if event.reply_to_msg_id: 25 | previous_message = await event.get_reply_message() 26 | text = previous_message.message 27 | lan = input_str or "en" 28 | elif "|" in input_str: 29 | lan, text = input_str.split("|") 30 | else: 31 | await event.reply( 32 | "`/tr ` as reply to a message or `/tr | `" 33 | ) 34 | return 35 | text = text.strip() 36 | lan = lan.strip() 37 | translator = google_translator() 38 | try: 39 | translated = translator.translate(text, lang_tgt=lan) 40 | after_tr_text = translated 41 | detect_result = translator.detect(text) 42 | output_str = ("**TRANSLATED Succesfully** from {} to {}\n\n" "{}").format( 43 | detect_result[0], lan, after_tr_text 44 | ) 45 | await event.reply(output_str) 46 | except Exception as exc: 47 | await event.reply(str(exc)) 48 | 49 | 50 | @register(pattern="^/spell(?: |$)(.*)") 51 | async def _(event): 52 | ctext = await event.get_reply_message() 53 | msg = ctext.text 54 | # print (msg) 55 | params = dict(lang="US", clientVersion="2.0", apiKey=API_KEY, text=msg) 56 | 57 | res = requests.get(URL, params=params) 58 | changes = json.loads(res.text).get("LightGingerTheTextResult") 59 | curr_string = "" 60 | prev_end = 0 61 | 62 | for change in changes: 63 | start = change.get("From") 64 | end = change.get("To") + 1 65 | suggestions = change.get("Suggestions") 66 | if suggestions: 67 | sugg_str = suggestions[0].get("Text") 68 | curr_string += msg[prev_end:start] + sugg_str 69 | prev_end = end 70 | 71 | curr_string += msg[prev_end:] 72 | await event.reply(curr_string) 73 | 74 | 75 | dictionary = PyDictionary() 76 | 77 | 78 | @register(pattern="^/define") 79 | async def _(event): 80 | text = event.text[len("/define ") :] 81 | word = f"{text}" 82 | let = dictionary.meaning(word) 83 | set = str(let) 84 | jet = set.replace("{", "") 85 | net = jet.replace("}", "") 86 | got = net.replace("'", "") 87 | await event.reply(got) 88 | 89 | 90 | @register(pattern="^/synonyms") 91 | async def _(event): 92 | text = event.text[len("/synonyms ") :] 93 | word = f"{text}" 94 | let = dictionary.synonym(word) 95 | set = str(let) 96 | jet = set.replace("{", "") 97 | net = jet.replace("}", "") 98 | got = net.replace("'", "") 99 | await event.reply(got) 100 | 101 | 102 | @register(pattern="^/antonyms") 103 | async def _(event): 104 | text = message.text[len("/antonyms ") :] 105 | word = f"{text}" 106 | let = dictionary.antonym(word) 107 | set = str(let) 108 | jet = set.replace("{", "") 109 | net = jet.replace("}", "") 110 | got = net.replace("'", "") 111 | await event.reply(got) 112 | 113 | 114 | 115 | __help__ = """ 116 | - /tr language code or /tr language code , text: Type in reply to a message or (/tr language code , text) to get it's translation in the destination language 117 | - /define text: Type the word or expression you want to search\nFor example /define lesbian 118 | - /spell: while replying to a message, will reply with a grammar corrected version 119 | - /forbesify: Correct your punctuations better use the advanged spell module 120 | - /synonyms word: Find the synonyms of a word 121 | - /antonyms word: Find the antonyms of a word 122 | """ 123 | 124 | __mod_name__= "Lang-Tools" 125 | -------------------------------------------------------------------------------- /DaisyX/modules/weather.py: -------------------------------------------------------------------------------- 1 | import io 2 | import time 3 | 4 | import aiohttp 5 | from telethon import events 6 | from telethon.tl import functions, types 7 | from telethon.tl.types import * 8 | from DaisyX.config import get_str_key 9 | 10 | OPENWEATHERMAP_ID = get_str_key("OPENWEATHERMAP_ID", "") 11 | from DaisyX.services.telethon import tbot 12 | from DaisyX.services.events import register 13 | 14 | 15 | 16 | 17 | 18 | 19 | async def is_register_admin(chat, user): 20 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 21 | return isinstance( 22 | ( 23 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 24 | ).participant, 25 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 26 | ) 27 | if isinstance(chat, types.InputPeerChat): 28 | ui = await tbot.get_peer_id(user) 29 | ps = ( 30 | await tbot(functions.messages.GetFullChatRequest(chat.chat_id)) 31 | ).full_chat.participants.participants 32 | return isinstance( 33 | next((p for p in ps if p.user_id == ui), None), 34 | (types.ChatParticipantAdmin, types.ChatParticipantCreator), 35 | ) 36 | if isinstance(chat, types.InputPeerUser): 37 | return True 38 | 39 | 40 | @register(pattern="^/weather (.*)") 41 | async def _(event): 42 | if event.fwd_from: 43 | return 44 | if event.is_group: 45 | if await is_register_admin(event.input_chat, event.message.sender_id): 46 | pass 47 | elif event.chat_id == iid and event.sender_id == userss: 48 | pass 49 | else: 50 | return 51 | sample_url = ( 52 | "https://api.openweathermap.org/data/2.5/weather?q={}&APPID={}&units=metric" 53 | ) 54 | input_str = event.pattern_match.group(1) 55 | async with aiohttp.ClientSession() as session: 56 | response_api_zero = await session.get( 57 | sample_url.format(input_str, OPENWEATHERMAP_ID) 58 | ) 59 | response_api = await response_api_zero.json() 60 | if response_api["cod"] == 200: 61 | country_code = response_api["sys"]["country"] 62 | country_time_zone = int(response_api["timezone"]) 63 | sun_rise_time = int(response_api["sys"]["sunrise"]) + country_time_zone 64 | sun_set_time = int(response_api["sys"]["sunset"]) + country_time_zone 65 | await event.reply( 66 | """**Location**: {} 67 | **Temperature ☀️**: {}°С 68 | __minimium__: {}°С 69 | __maximum__ : {}°С 70 | **Humidity 🌤**: {}% 71 | **Wind** 💨: {}m/s 72 | **Clouds** ☁️: {}hpa 73 | **Sunrise** 🌤: {} {} 74 | **Sunset** 🌝: {} {}""".format( 75 | input_str, 76 | response_api["main"]["temp"], 77 | response_api["main"]["temp_min"], 78 | response_api["main"]["temp_max"], 79 | response_api["main"]["humidity"], 80 | response_api["wind"]["speed"], 81 | response_api["clouds"]["all"], 82 | # response_api["main"]["pressure"], 83 | time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(sun_rise_time)), 84 | country_code, 85 | time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(sun_set_time)), 86 | country_code, 87 | ) 88 | ) 89 | else: 90 | await event.reply(response_api["message"]) 91 | 92 | 93 | @register(pattern="^/weatherimg (.*)") 94 | async def _(event): 95 | if event.fwd_from: 96 | return 97 | if event.is_group: 98 | if await is_register_admin(event.input_chat, event.message.sender_id): 99 | pass 100 | elif event.chat_id == iid and event.sender_id == userss: 101 | pass 102 | else: 103 | return 104 | sample_url = "https://wttr.in/{}.png" 105 | # logger.info(sample_url) 106 | input_str = event.pattern_match.group(1) 107 | async with aiohttp.ClientSession() as session: 108 | response_api_zero = await session.get(sample_url.format(input_str)) 109 | # logger.info(response_api_zero) 110 | response_api = await response_api_zero.read() 111 | with io.BytesIO(response_api) as out_file: 112 | await event.reply(file=out_file) 113 | -------------------------------------------------------------------------------- /DaisyX/modules/antivirus.py: -------------------------------------------------------------------------------- 1 | # MissJuliaRobot (A Telegram Bot Project) 2 | # Copyright (C) 2019-2021 Julia (https://t.me/MissJulia_Robot) 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, in version 3 of the License. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see < https://www.gnu.org/licenses/agpl-3.0.en.html/ >. 15 | 16 | 17 | import os 18 | from DaisyX.services.telethon import tbot 19 | from telethon import events 20 | from telethon.tl import functions 21 | from telethon.tl import types 22 | from telethon.tl.types import MessageMediaDocument, DocumentAttributeFilename 23 | from DaisyX.services.events import register 24 | import cloudmersive_virus_api_client 25 | from DaisyX.config import get_str_key 26 | 27 | async def is_register_admin(chat, user): 28 | if isinstance(chat, (types.InputPeerChannel, types.InputChannel)): 29 | return isinstance( 30 | ( 31 | await tbot(functions.channels.GetParticipantRequest(chat, user)) 32 | ).participant, 33 | (types.ChannelParticipantAdmin, types.ChannelParticipantCreator), 34 | ) 35 | if isinstance(chat, types.InputPeerUser): 36 | return True 37 | 38 | 39 | VIRUS_API_KEY = get_str_key("VIRUS_API_KEY", required=False) 40 | configuration = cloudmersive_virus_api_client.Configuration() 41 | configuration.api_key["Apikey"] = VIRUS_API_KEY 42 | api_instance = cloudmersive_virus_api_client.ScanApi( 43 | cloudmersive_virus_api_client.ApiClient(configuration) 44 | ) 45 | allow_executables = True 46 | allow_invalid_files = True 47 | allow_scripts = True 48 | allow_password_protected_files = True 49 | 50 | 51 | @register(pattern="^/scanit$") 52 | async def virusscan(event): 53 | if event.fwd_from: 54 | return 55 | if event.is_group: 56 | if await is_register_admin(event.input_chat, event.message.sender_id): 57 | pass 58 | else: 59 | return 60 | if not event.reply_to_msg_id: 61 | await event.reply("Reply to a file to scan it.") 62 | return 63 | 64 | c = await event.get_reply_message() 65 | try: 66 | c.media.document 67 | except Exception: 68 | await event.reply("Thats not a file.") 69 | return 70 | h = c.media 71 | try: 72 | k = h.document.attributes 73 | except Exception: 74 | await event.reply("Thats not a file.") 75 | return 76 | if not isinstance(h, MessageMediaDocument): 77 | await event.reply("Thats not a file.") 78 | return 79 | if not isinstance(k[0], DocumentAttributeFilename): 80 | await event.reply("Thats not a file.") 81 | return 82 | try: 83 | virus = c.file.name 84 | await event.client.download_file(c, virus) 85 | gg = await event.reply("Scanning the file ...") 86 | fsize = c.file.size 87 | if not fsize <= 3145700: # MAX = 3MB 88 | await gg.edit("File size exceeds 3MB") 89 | return 90 | api_response = api_instance.scan_file_advanced( 91 | c.file.name, 92 | allow_executables=allow_executables, 93 | allow_invalid_files=allow_invalid_files, 94 | allow_scripts=allow_scripts, 95 | allow_password_protected_files=allow_password_protected_files, 96 | ) 97 | if api_response.clean_result is True: 98 | await gg.edit("This file is safe ✔️\nNo virus detected 🐞") 99 | else: 100 | await gg.edit("This file is Dangerous ☠️️\nVirus detected 🐞") 101 | os.remove(virus) 102 | except Exception as e: 103 | print(e) 104 | os.remove(virus) 105 | await gg.edit("Some error occurred.") 106 | return 107 | 108 | 109 | __mod_name__ ="Virus Scan" 110 | __help__ = """ 111 | - /scanit: Scan a file for virus (MAX SIZE = 3MB) 112 | """ 113 | -------------------------------------------------------------------------------- /profanity_wordlist.txt: -------------------------------------------------------------------------------- 1 | 2g1c 2 | 2 girls 1 cup 3 | 4r5e 4 | anal 5 | anus 6 | arse 7 | ass 8 | asses 9 | assfucker 10 | assfukka 11 | asshole 12 | arsehole 13 | asswhole 14 | assmunch 15 | auto erotic 16 | autoerotic 17 | ballsack 18 | bastard 19 | beastial 20 | bestial 21 | bellend 22 | bdsm 23 | beastiality 24 | bestiality 25 | bitch 26 | bitches 27 | bitchin 28 | bitching 29 | bimbo 30 | bimbos 31 | blow job 32 | blowjob 33 | blowjobs 34 | blue waffle 35 | boob 36 | boobs 37 | booobs 38 | boooobs 39 | booooobs 40 | booooooobs 41 | breasts 42 | booty call 43 | brown shower 44 | brown showers 45 | boner 46 | bondage 47 | buceta 48 | bukake 49 | bukkake 50 | bullshit 51 | bull shit 52 | busty 53 | butthole 54 | carpet muncher 55 | cawk 56 | chink 57 | cipa 58 | clit 59 | clits 60 | clitoris 61 | cnut 62 | cock 63 | cocks 64 | cockface 65 | cockhead 66 | cockmunch 67 | cockmuncher 68 | cocksuck 69 | cocksucked 70 | cocksucking 71 | cocksucks 72 | cocksucker 73 | cokmuncher 74 | coon 75 | cow girl 76 | cow girls 77 | cowgirl 78 | cowgirls 79 | crap 80 | crotch 81 | cum 82 | cummer 83 | cumming 84 | cuming 85 | cums 86 | cumshot 87 | cunilingus 88 | cunillingus 89 | cunnilingus 90 | cunt 91 | cuntlicker 92 | cuntlicking 93 | cunts 94 | damn 95 | dick 96 | dickhead 97 | dildo 98 | dildos 99 | dink 100 | dinks 101 | deepthroat 102 | deep throat 103 | dog style 104 | doggie style 105 | doggiestyle 106 | doggy style 107 | doggystyle 108 | donkeyribber 109 | doosh 110 | douche 111 | duche 112 | dyke 113 | ejaculate 114 | ejaculated 115 | ejaculates 116 | ejaculating 117 | ejaculatings 118 | ejaculation 119 | ejakulate 120 | erotic 121 | erotism 122 | fag 123 | faggot 124 | fagging 125 | faggit 126 | faggitt 127 | faggs 128 | fagot 129 | fagots 130 | fags 131 | fatass 132 | femdom 133 | fingering 134 | footjob 135 | foot job 136 | fuck 137 | fucks 138 | fucker 139 | fuckers 140 | fucked 141 | fuckhead 142 | fuckheads 143 | fuckin 144 | fucking 145 | fcuk 146 | fcuker 147 | fcuking 148 | felching 149 | fellate 150 | fellatio 151 | fingerfuck 152 | fingerfucked 153 | fingerfucker 154 | fingerfuckers 155 | fingerfucking 156 | fingerfucks 157 | fistfuck 158 | fistfucked 159 | fistfucker 160 | fistfuckers 161 | fistfucking 162 | fistfuckings 163 | fistfucks 164 | flange 165 | fook 166 | fooker 167 | fucka 168 | fuk 169 | fuks 170 | fuker 171 | fukker 172 | fukkin 173 | fukking 174 | futanari 175 | futanary 176 | gangbang 177 | gangbanged 178 | gang bang 179 | gokkun 180 | golden shower 181 | goldenshower 182 | gaysex 183 | goatse 184 | handjob 185 | hand job 186 | hentai 187 | hooker 188 | hoer 189 | homo 190 | horny 191 | incest 192 | jackoff 193 | jack off 194 | jerkoff 195 | jerk off 196 | jizz 197 | knob 198 | kinbaku 199 | labia 200 | masturbate 201 | masochist 202 | mofo 203 | mothafuck 204 | motherfuck 205 | motherfucker 206 | mothafucka 207 | mothafuckas 208 | mothafuckaz 209 | mothafucked 210 | mothafucker 211 | mothafuckers 212 | mothafuckin 213 | mothafucking 214 | mothafuckings 215 | mothafucks 216 | mother fucker 217 | motherfucked 218 | motherfucker 219 | motherfuckers 220 | motherfuckin 221 | motherfucking 222 | motherfuckings 223 | motherfuckka 224 | motherfucks 225 | milf 226 | muff 227 | nigga 228 | nigger 229 | nigg 230 | nipple 231 | nipples 232 | nob 233 | nob jokey 234 | nobhead 235 | nobjocky 236 | nobjokey 237 | numbnuts 238 | nutsack 239 | nude 240 | nudes 241 | orgy 242 | orgasm 243 | orgasms 244 | panty 245 | panties 246 | penis 247 | playboy 248 | porn 249 | porno 250 | pornography 251 | pron 252 | pussy 253 | pussies 254 | rape 255 | raping 256 | rapist 257 | rectum 258 | retard 259 | rimming 260 | sadist 261 | sadism 262 | schlong 263 | scrotum 264 | sex 265 | semen 266 | shemale 267 | she male 268 | shibari 269 | shibary 270 | shit 271 | shitdick 272 | shitfuck 273 | shitfull 274 | shithead 275 | shiting 276 | shitings 277 | shits 278 | shitted 279 | shitters 280 | shitting 281 | shittings 282 | shitty 283 | shota 284 | skank 285 | slut 286 | sluts 287 | smut 288 | smegma 289 | spunk 290 | strip club 291 | stripclub 292 | tit 293 | tits 294 | titties 295 | titty 296 | titfuck 297 | tittiefucker 298 | titties 299 | tittyfuck 300 | tittywank 301 | titwank 302 | threesome 303 | three some 304 | throating 305 | twat 306 | twathead 307 | twatty 308 | twunt 309 | viagra 310 | vagina 311 | vulva 312 | wank 313 | wanker 314 | wanky 315 | whore 316 | whoar 317 | xxx 318 | xx 319 | yaoi 320 | yury 321 | sexy 322 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/buttonhelper.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from typing import List 4 | from pyrogram.types import InlineKeyboardButton 5 | 6 | 7 | 8 | BTN_URL_REGEX = re.compile( 9 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))" 10 | ) 11 | 12 | SMART_OPEN = '“' 13 | SMART_CLOSE = '”' 14 | START_CHAR = ('\'', '"', SMART_OPEN) 15 | 16 | 17 | def split_quotes(text: str) -> List: 18 | if any(text.startswith(char) for char in START_CHAR): 19 | counter = 1 # ignore first char -> is some kind of quote 20 | while counter < len(text): 21 | if text[counter] == "\\": 22 | counter += 1 23 | elif text[counter] == text[0] or (text[0] == SMART_OPEN and text[counter] == SMART_CLOSE): 24 | break 25 | counter += 1 26 | else: 27 | return text.split(None, 1) 28 | 29 | # 1 to avoid starting quote, and counter is exclusive so avoids ending 30 | key = remove_escapes(text[1:counter].strip()) 31 | # index will be in range, or `else` would have been executed and returned 32 | rest = text[counter + 1:].strip() 33 | if not key: 34 | key = text[0] + text[0] 35 | return list(filter(None, [key, rest])) 36 | else: 37 | return text.split(None, 1) 38 | 39 | def parser(text, keyword): 40 | if "buttonalert" in text: 41 | text = (text.replace("\n", "\\n").replace("\t", "\\t")) 42 | buttons = [] 43 | note_data = "" 44 | prev = 0 45 | i = 0 46 | alerts = [] 47 | for match in BTN_URL_REGEX.finditer(text): 48 | # Check if btnurl is escaped 49 | n_escapes = 0 50 | to_check = match.start(1) - 1 51 | while to_check > 0 and text[to_check] == "\\": 52 | n_escapes += 1 53 | to_check -= 1 54 | 55 | # if even, not escaped -> create button 56 | if n_escapes % 2 == 0: 57 | note_data += text[prev:match.start(1)] 58 | prev = match.end(1) 59 | if match.group(3) == "buttonalert": 60 | # create a thruple with button label, url, and newline status 61 | if bool(match.group(5)) and buttons: 62 | buttons[-1].append(InlineKeyboardButton( 63 | text=match.group(2), 64 | callback_data=f"alertmessage:{i}:{keyword}" 65 | )) 66 | else: 67 | buttons.append([InlineKeyboardButton( 68 | text=match.group(2), 69 | callback_data=f"alertmessage:{i}:{keyword}" 70 | )]) 71 | i = i + 1 72 | alerts.append(match.group(4)) 73 | else: 74 | if bool(match.group(5)) and buttons: 75 | buttons[-1].append(InlineKeyboardButton( 76 | text=match.group(2), 77 | url=match.group(4).replace(" ", "") 78 | )) 79 | else: 80 | buttons.append([InlineKeyboardButton( 81 | text=match.group(2), 82 | url=match.group(4).replace(" ", "") 83 | )]) 84 | 85 | # if odd, escaped -> move along 86 | else: 87 | note_data += text[prev:to_check] 88 | prev = match.start(1) - 1 89 | else: 90 | note_data += text[prev:] 91 | 92 | try: 93 | return note_data, buttons, alerts 94 | except: 95 | return note_data, buttons, None 96 | 97 | def remove_escapes(text: str) -> str: 98 | counter = 0 99 | res = "" 100 | is_escaped = False 101 | while counter < len(text): 102 | if is_escaped: 103 | res += text[counter] 104 | is_escaped = False 105 | elif text[counter] == "\\": 106 | is_escaped = True 107 | else: 108 | res += text[counter] 109 | counter += 1 110 | return res 111 | 112 | 113 | def humanbytes(size): 114 | if not size: 115 | return "" 116 | power = 2**10 117 | n = 0 118 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'} 119 | while size > power: 120 | size /= power 121 | n += 1 122 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B' 123 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/text.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | # 16 | # This file is part of Daisy. 17 | 18 | from typing import Union 19 | 20 | 21 | class SanTeXDoc: 22 | def __init__(self, *args): 23 | self.items = list(args) 24 | 25 | def __str__(self) -> str: 26 | return '\n'.join([str(items) for items in self.items]) 27 | 28 | def __add__(self, other): 29 | self.items.append(other) 30 | return self 31 | 32 | 33 | class StyleFormationCore: 34 | start: str 35 | end: str 36 | 37 | def __init__(self, text: str): 38 | self.text = f'{self.start}{text}{self.end}' 39 | 40 | def __str__(self) -> str: 41 | return self.text 42 | 43 | 44 | class Bold(StyleFormationCore): 45 | start = '' 46 | end = '' 47 | 48 | 49 | class Italic(StyleFormationCore): 50 | start = '' 51 | end = '' 52 | 53 | 54 | class Code(StyleFormationCore): 55 | start = '' 56 | end = '' 57 | 58 | 59 | class Pre(StyleFormationCore): 60 | start = '
'
 61 |     end = '
' 62 | 63 | 64 | class Strikethrough(StyleFormationCore): 65 | start = '' 66 | end = '' 67 | 68 | 69 | class Underline(StyleFormationCore): 70 | start = '' 71 | end = '' 72 | 73 | 74 | class Section: 75 | def __init__(self, *args, title='', indent=3, bold=True, postfix=':'): 76 | self.title_text = title 77 | self.items = list(args) 78 | self.indent = indent 79 | self.bold = bold 80 | self.postfix = postfix 81 | 82 | @property 83 | def title(self) -> str: 84 | title = self.title_text 85 | text = str(Bold(title)) if self.bold else title 86 | text += self.postfix 87 | return text 88 | 89 | def __str__(self) -> str: 90 | text = self.title 91 | space = ' ' * self.indent 92 | for item in self.items: 93 | text += '\n' 94 | 95 | if type(item) is Section: 96 | item.indent *= 2 97 | if type(item) is SList: 98 | item.indent = self.indent 99 | else: 100 | text += space 101 | 102 | text += str(item) 103 | 104 | return text 105 | 106 | def __add__(self, other): 107 | self.items.append(other) 108 | return self 109 | 110 | 111 | class SList: 112 | def __init__(self, *args, indent=0, prefix='- '): 113 | self.items = list(args) 114 | self.prefix = prefix 115 | self.indent = indent 116 | 117 | def __str__(self) -> str: 118 | space = ' ' * self.indent if self.indent else ' ' 119 | text = '' 120 | for idx, item in enumerate(self.items): 121 | if idx > 0: 122 | text += '\n' 123 | text += f'{space}{self.prefix}{item}' 124 | 125 | return text 126 | 127 | 128 | class KeyValue: 129 | def __init__(self, title, value, suffix=': '): 130 | self.title = title 131 | self.value = value 132 | self.suffix = suffix 133 | 134 | def __str__(self) -> str: 135 | text = f'{self.title}{self.suffix}{self.value}' 136 | return text 137 | 138 | 139 | class MultiKeyValue: 140 | def __init__(self, *items: Union[list, tuple], suffix=': ', separator=', '): 141 | self.items: list = items 142 | self.suffix = suffix 143 | self.separator = separator 144 | 145 | def __str__(self) -> str: 146 | text = '' 147 | items_count = len(self.items) 148 | for idx, item in enumerate(self.items): 149 | text += f'{item[0]}{self.suffix}{item[1]}' 150 | 151 | if items_count - 1 != idx: 152 | text += self.separator 153 | 154 | return text 155 | -------------------------------------------------------------------------------- /DaisyX/modules/utils/anime.py: -------------------------------------------------------------------------------- 1 | # This file is part of DaisyXBot (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | 17 | def shorten(description, info='anilist.co'): 18 | ms_g = "" 19 | if len(description) > 700: 20 | description = description[0:500] + '...' 21 | ms_g += f"\nDescription: {description} Read More" 22 | else: 23 | ms_g += f"\nDescription: {description}" 24 | return ( 25 | ms_g.replace("
", "") 26 | .replace("
", "") 27 | .replace("", "") 28 | .replace("", "") 29 | ) 30 | 31 | 32 | def t(milliseconds: int) -> str: 33 | """Inputs time in milliseconds, to get beautified time, 34 | as string""" 35 | seconds, milliseconds = divmod(int(milliseconds), 1000) 36 | minutes, seconds = divmod(seconds, 60) 37 | hours, minutes = divmod(minutes, 60) 38 | days, hours = divmod(hours, 24) 39 | tmp = ((str(days) + " Days, ") if days else "") + \ 40 | ((str(hours) + " Hours, ") if hours else "") + \ 41 | ((str(minutes) + " Minutes, ") if minutes else "") + \ 42 | ((str(seconds) + " Seconds, ") if seconds else "") + \ 43 | ((str(milliseconds) + " ms, ") if milliseconds else "") 44 | return tmp[:-2] 45 | 46 | 47 | airing_query = ''' 48 | query ($id: Int,$search: String) { 49 | Media (id: $id, type: ANIME,search: $search) { 50 | id 51 | episodes 52 | title { 53 | romaji 54 | english 55 | native 56 | } 57 | siteUrl 58 | nextAiringEpisode { 59 | airingAt 60 | timeUntilAiring 61 | episode 62 | } 63 | } 64 | } 65 | ''' 66 | 67 | fav_query = """ 68 | query ($id: Int) { 69 | Media (id: $id, type: ANIME) { 70 | id 71 | title { 72 | romaji 73 | english 74 | native 75 | } 76 | } 77 | } 78 | """ 79 | 80 | anime_query = ''' 81 | query ($id: Int,$search: String) { 82 | Media (id: $id, type: ANIME,search: $search) { 83 | id 84 | idMal 85 | title { 86 | romaji 87 | english 88 | native 89 | } 90 | description (asHtml: false) 91 | startDate{ 92 | year 93 | } 94 | episodes 95 | season 96 | type 97 | format 98 | status 99 | duration 100 | siteUrl 101 | studios{ 102 | nodes{ 103 | name 104 | } 105 | } 106 | trailer{ 107 | id 108 | site 109 | thumbnail 110 | } 111 | averageScore 112 | genres 113 | bannerImage 114 | } 115 | } 116 | ''' 117 | character_query = """ 118 | query ($query: String) { 119 | Character (search: $query) { 120 | id 121 | name { 122 | first 123 | last 124 | full 125 | } 126 | siteUrl 127 | favourites 128 | image { 129 | large 130 | } 131 | description 132 | } 133 | } 134 | """ 135 | 136 | manga_query = """ 137 | query ($id: Int,$search: String) { 138 | Media (id: $id, type: MANGA,search: $search) { 139 | id 140 | title { 141 | romaji 142 | english 143 | native 144 | } 145 | description (asHtml: false) 146 | startDate{ 147 | year 148 | } 149 | type 150 | format 151 | status 152 | siteUrl 153 | averageScore 154 | genres 155 | bannerImage 156 | } 157 | } 158 | """ 159 | -------------------------------------------------------------------------------- /DaisyX/modules/promotes.py: -------------------------------------------------------------------------------- 1 | # This file is part of Daisy (Telegram Bot) 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU Affero General Public License as 5 | # published by the Free Software Foundation, either version 3 of the 6 | # License, or (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Affero General Public License for more details. 12 | 13 | # You should have received a copy of the GNU Affero General Public License 14 | # along with this program. If not, see . 15 | 16 | import html 17 | 18 | from aiogram.utils.exceptions import ChatAdminRequired 19 | from telethon.errors import AdminRankEmojiNotAllowedError 20 | 21 | from DaisyX import BOT_ID, bot 22 | from DaisyX.decorator import register 23 | from DaisyX.services.telethon import tbot 24 | from .utils.connections import chat_connection 25 | from .utils.language import get_strings_dec 26 | from .utils.user_details import ( 27 | get_user_dec, get_user_and_text_dec, 28 | get_user_link, get_admins_rights 29 | ) 30 | 31 | 32 | @register(cmds="promote", bot_can_promote_members=True, user_can_promote_members=True) 33 | @chat_connection(admin=True, only_groups=True) 34 | @get_user_and_text_dec() 35 | @get_strings_dec('promotes') 36 | async def promote(message, chat, user, args, strings): 37 | chat_id = chat['chat_id'] 38 | text = strings['promote_success'].format( 39 | user=await get_user_link(user['user_id']), 40 | chat_name=chat['chat_title'] 41 | ) 42 | 43 | if user['user_id'] == BOT_ID: 44 | return 45 | 46 | if user['user_id'] == message.from_user.id: 47 | return await message.reply(strings['cant_promote_yourself']) 48 | 49 | title = None 50 | 51 | if args: 52 | if len(args) > 16: 53 | await message.reply(strings['rank_to_loong']) 54 | return 55 | title = args 56 | text += strings['promote_title'].format( 57 | role=html.escape(title, quote=False)) 58 | 59 | try: 60 | await tbot.edit_admin( 61 | chat_id, 62 | user['user_id'], 63 | invite_users=True, 64 | change_info=True, 65 | ban_users=True, 66 | delete_messages=True, 67 | pin_messages=True, 68 | title=title 69 | ) 70 | except ValueError: 71 | return await message.reply(strings['cant_get_user']) 72 | except AdminRankEmojiNotAllowedError: 73 | return await message.reply(strings['emoji_not_allowed']) 74 | await get_admins_rights(chat_id, force_update=True) # Reset a cache 75 | await message.reply(text) 76 | 77 | 78 | @register(cmds="demote", bot_can_promote_members=True, user_can_promote_members=True) 79 | @chat_connection(admin=True, only_groups=True) 80 | @get_user_dec() 81 | @get_strings_dec('promotes') 82 | async def demote(message, chat, user, strings): 83 | chat_id = chat['chat_id'] 84 | if user['user_id'] == BOT_ID: 85 | return 86 | 87 | try: 88 | await bot.promote_chat_member( 89 | chat_id, 90 | user['user_id'] 91 | ) 92 | except ChatAdminRequired: 93 | return await message.reply(strings['demote_failed']) 94 | 95 | await get_admins_rights(chat_id, force_update=True) # Reset a cache 96 | await message.reply(strings['demote_success'].format( 97 | user=await get_user_link(user['user_id']), 98 | chat_name=chat['chat_title'] 99 | )) 100 | 101 | 102 | __mod_name__ = "Admin" 103 | 104 | __help__ = """ 105 | Make it easy to promote and demote users with the admin module! 106 | 107 | Available commands: 108 | - /promote (user) (?admin's title): Promotes the user to admin. 109 | - /demote (user): Demotes the user from admin. 110 | - /adminlist: Shows all admins of the chat. 111 | - /admincache: Update the admin cache, to take into account new admins/admin permissions. 112 | 113 | Example: 114 | Sometimes, you promote or demote an admin manually, and Daisy doesn't realise it immediately. This is because to avoid spamming telegram servers, admin status is cached locally. 115 | This means that you sometimes have to wait a few minutes for admin rights to update. If you want to update them immediately, you can use the /admincache command; that'll force Daisy to check who the admins are again. 116 | """ 117 | -------------------------------------------------------------------------------- /DaisyX/stuff/fonts/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2015 Google Inc. All Rights Reserved. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | --------------------------------------------------------------------------------