diff --git a/.github/workflows/autotranslate.yml b/.github/workflows/autotranslate.yml deleted file mode 100644 index 58de97e1f8b8c850372fa49efa4b3cab417d3c88..0000000000000000000000000000000000000000 --- a/.github/workflows/autotranslate.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Strings Translation - -on: - workflow_dispatch: - push: - branches: [ dev ] - paths: - - strings/strings/en.yml - -env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -jobs: - analyze: - name: Checkout Strings - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: 3.9.x - - name: Update Translations - run: | - git config --global user.email "newdev0@outlook.com" - git config --global user.name "New-Dev0" - git branch translation && git checkout translation - pip install pyyaml requests telethon - wget -O run.py https://gist.githubusercontent.com/New-dev0/c7d0d1eb514d311e8e3b687ae5cbe5f3/raw/350cc6d451a02a4b07d0f9bbc27b0e7c9465d3d4/updater.py - python3 run.py - rm run.py - git add . && git commit -m "[Auto] Translate" && git push --set-upstream origin translation - gh pr create --title "[Auto] Translation" -B dev --body "Update Translation" diff --git a/.github/workflows/pylint.yaml b/.github/workflows/pylint.yaml index 23fcec8a249e81ff4260550f5b17560f074b6551..8c71add5c50692cd21911df7d46a8c3e3c91d114 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/pylint.yaml @@ -13,6 +13,7 @@ jobs: uses: actions/setup-python@v1 with: python-version: 3.8 + cache: "pip" - name: Install Python lint libraries run: pip install autopep8 autoflake isort black - name: Check for showstoppers diff --git a/.gitignore b/.gitignore index 26e851a55c3b07d4f024517eaf496d9540692971..794eba8b5a534f7b44a7b32f51a0ccb82f2cdbf4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,12 +8,14 @@ test* *.webp *.mp4 *.tgs +*.txt /*.jpg /*.png /*.mp4 *.log target/npmlist.json package-lock.json +ultroid.json resources/extras/thumbnail.jpg # Directories diff --git a/README.md b/README.md index 1488acf7885596685daac61575940019eb8b83c3..b60ac89d0d597f4fb4232fc23d820da120acc914 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A stable pluggable Telegram userbot + Voice & Video Call music bot, based on Telethon. -[![](https://img.shields.io/badge/Ultroid-v0.7-darkgreen)](#) +[![](https://img.shields.io/badge/Ultroid-v0.8-crimson)](#) [![Stars](https://img.shields.io/github/stars/TeamUltroid/Ultroid?style=flat-square&color=yellow)](https://github.com/TeamUltroid/Ultroid/stargazers) [![Forks](https://img.shields.io/github/forks/TeamUltroid/Ultroid?style=flat-square&color=orange)](https://github.com/TeamUltroid/Ultroid/fork) [![Size](https://img.shields.io/github/repo-size/TeamUltroid/Ultroid?style=flat-square&color=green)](https://github.com/TeamUltroid/Ultroid/) @@ -84,20 +84,6 @@ Get the [Necessary Variables](#Necessary-Variables) and then click the button be `bash startup` - Windows Users: `python(3) -m pyUltroid` -
-

[OUTDATED] Ultroid CLI

- -[Ultroid CLI](https://github.com/BLUE-DEVIL1134/UltroidCli) is a command-line interface for deploying Ultroid. - -- **Installing** - -Run the following code on a terminal, with curl installed. -`ver=$(curl https://raw.githubusercontent.com/BLUE-DEVIL1134/UltroidCli/main/version.txt) && curl -L -o ultroid https://github.com/BLUE-DEVIL1134/UltroidCli/releases/download/$ver/ultroid.exe` -OR -Go to [UltroidCli](https://github.com/BLUE-DEVIL1134/UltroidCli) and install the version release from the Github Releases. Add the executable to your system path as specified in the [Readme](https://github.com/BLUE-DEVIL1134/UltroidCli#how-to-use-ultroidcli-). - -- **Documentation** - -Take a look at the [`docs`](https://blue-devil1134.github.io/UltroidCli/) for more detailed information. -
--- ## Necessary Variables diff --git a/app.json b/app.json index 7ffa52c375e93893dd5f10a4499f65e6a5943bc5..d192badba483b4ed8a94535876f392c504624720 100644 --- a/app.json +++ b/app.json @@ -50,7 +50,7 @@ "formation": { "ultroid": { "quantity": 1, - "size": "free" + "size": "eco" } } } diff --git a/assistant/__init__.py b/assistant/__init__.py index d4d248aed02561e0e9d5ce286c6c488f700c6ba8..e98ddeb85d3070ece8788cde2f00ad4b9c608c66 100644 --- a/assistant/__init__.py +++ b/assistant/__init__.py @@ -25,7 +25,8 @@ AST_PLUGINS = {} async def setit(event, name, value): try: udB.set_key(name, value) - except BaseException: + except BaseException as er: + LOGS.exception(er) return await event.edit("`Something Went Wrong`") diff --git a/assistant/callbackstuffs.py b/assistant/callbackstuffs.py index 5829115980037ae4742f26eba46b3d7a02a7c0b0..316faa46a68fb26549e23542e926bbf5fb5d5761 100644 --- a/assistant/callbackstuffs.py +++ b/assistant/callbackstuffs.py @@ -5,7 +5,7 @@ # PLease read the GNU Affero General Public License in # . - +import ast import asyncio import re import sys @@ -426,9 +426,12 @@ async def convo_handler(event: events.CallbackQuery): back = get_["back"] async with event.client.conversation(event.sender_id) as conv: await conv.send_message(get_["text"]) - response = conv.wait_event(events.NewMessage(chats=event.sender_id)) - response = await response - themssg = response.message.message + response = await conv.get_response() + themssg = response.message + try: + themssg = ast.literal_eval(themssg) + except Exception: + pass if themssg == "/cancel": return await conv.send_message( "Cancelled!!", @@ -1182,7 +1185,7 @@ async def name(event): async def chon(event): var = "PMBOT" await setit(event, var, "True") - Loader(path="assistant/pmbot.py", key="PM Bot").load_single() + Loader(path="assistant/pmbot.py", key="PM Bot").load() if AST_PLUGINS.get("pmbot"): for i, e in AST_PLUGINS["pmbot"]: event.client.remove_event_handler(i) diff --git a/assistant/pmbot.py b/assistant/pmbot.py index b591adaf7aff461f676c2f276e37cb2395ecee03..62b06e20affe4850ac01d85cb8f59005ab2bd74d 100644 --- a/assistant/pmbot.py +++ b/assistant/pmbot.py @@ -18,12 +18,13 @@ from telethon.tl.functions.messages import GetFullChatRequest from telethon.tl.types import Channel, Chat from telethon.utils import get_display_name -from pyUltroid.dB.asst_fns import * +from pyUltroid.dB.base import KeyManager from pyUltroid.dB.botchat_db import * from pyUltroid.fns.helper import inline_mention from . import * +botb = KeyManager("BOTBLS", cast=list) FSUB = udB.get_key("PMBOT_FSUB") CACHE = {} # --------------------------------------- Incoming -------------------------------------------- # @@ -32,7 +33,7 @@ CACHE = {} @asst_cmd( load=AST_PLUGINS, incoming=True, - func=lambda e: e.is_private and not is_blacklisted(e.sender_id), + func=lambda e: e.is_private and not botb.contains(e.sender_id), ) async def on_new_mssg(event): who = event.sender_id @@ -49,6 +50,7 @@ async def on_new_mssg(event): if not MSG: MSG += get_string("pmbot_1") try: + uri = "" TAHC_ = await event.client.get_entity(chat) if hasattr(TAHC_, "username") and TAHC_.username: uri = f"t.me/{TAHC_.username}" @@ -119,10 +121,10 @@ async def banhammer(event): if not event.is_reply: return await event.reply(get_string("pmbot_2")) target = get_who(event.reply_to_msg_id) - if is_blacklisted(target): + if botb.contains(target): return await event.reply(get_string("pmbot_3")) - blacklist_user(target) + botb.add(target) await event.reply(f"#BAN\nUser : {target}") await asst.send_message(target, get_string("pmbot_4")) @@ -137,10 +139,10 @@ async def unbanhammer(event): if not event.is_reply: return await event.reply(get_string("pmbot_5")) target = get_who(event.reply_to_msg_id) - if not is_blacklisted(target): + if not botb.contains(target): return await event.reply(get_string("pmbot_6")) - rem_blacklist(target) + botb.remove(target) await event.reply(f"#UNBAN\nUser : {target}") await asst.send_message(target, get_string("pmbot_7")) diff --git a/assistant/start.py b/assistant/start.py index cc224f6c6dbb22b0cbfc671262fcf574fd7f79f8..f3f16b05b5fae3273fc43350f13c7c8eab32f8cf 100644 --- a/assistant/start.py +++ b/assistant/start.py @@ -13,7 +13,7 @@ from telethon.errors.rpcerrorlist import MessageDeleteForbiddenError from telethon.utils import get_display_name from pyUltroid._misc import SUDO_M, owner_and_sudos -from pyUltroid.dB.asst_fns import * +from pyUltroid.dB.base import KeyManager from pyUltroid.fns.helper import inline_mention from strings import get_string @@ -87,8 +87,9 @@ async def closet(lol): @asst_cmd(pattern="start( (.*)|$)", forwards=False, func=lambda x: not x.is_group) async def ultroid(event): args = event.pattern_match.group(1).strip() - if not is_added(event.sender_id) and event.sender_id not in owner_and_sudos(): - add_user(event.sender_id) + keym = KeyManager("BOT_USERS", cast=list) + if not keym.contains(event.sender_id) and event.sender_id not in owner_and_sudos(): + keym.add(event.sender_id) kak_uiw = udB.get_key("OFF_START_LOG") if not kak_uiw or kak_uiw != True: msg = f"{inline_mention(event.sender)} `[{event.sender_id}]` started your [Assistant bot](@{asst.me.username})." @@ -158,7 +159,7 @@ async def ultroid(event): @callback("stat", owner=True) async def botstat(event): - ok = len(get_all_users("BOT_USERS")) + ok = len(udB.get_key("BOT_USERS") or []) msg = """Ultroid Assistant - Stats Total Users - {}""".format( ok, @@ -168,8 +169,9 @@ Total Users - {}""".format( @callback("bcast", owner=True) async def bdcast(event): - ok = get_all_users("BOT_USERS") - await event.edit(f"• Broadcast to {len(ok)} users.") + keym = KeyManager("BOT_USERS", cast=list) + total = keym.count() + await event.edit(f"• Broadcast to {total} users.") async with event.client.conversation(OWNER_ID) as conv: await conv.send_message( "Enter your broadcast message.\nUse /cancel to stop the broadcast.", @@ -179,9 +181,9 @@ async def bdcast(event): return await conv.send_message("Cancelled!!") success = 0 fail = 0 - await conv.send_message(f"Starting a broadcast to {len(ok)} users...") + await conv.send_message(f"Starting a broadcast to {total} users...") start = datetime.now() - for i in ok: + for i in keym.get(): try: await asst.send_message(int(i), response) success += 1 @@ -192,7 +194,7 @@ async def bdcast(event): await conv.send_message( f""" **Broadcast completed in {time_taken} seconds.** -Total Users in Bot - {len(ok)} +Total Users in Bot - {total} **Sent to** : `{success} users.` **Failed for** : `{fail} user(s).`""", ) diff --git a/installer.sh b/installer.sh index e8067a73ccbb70a03adc1e39612cfc10b14e3ce0..5c2b8f00f3a7532327adc6a64ed1571ff4e71030 100644 --- a/installer.sh +++ b/installer.sh @@ -1,99 +1,241 @@ #!/usr/bin/env bash REPO="https://github.com/TeamUltroid/Ultroid.git" +CURRENT_DIR="$(pwd)" +ENV_FILE_PATH=".env" DIR="/root/TeamUltroid" -spinner(){ - local pid=$! - while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; - do - for i in "Ooooo" "oOooo" "ooOoo" "oooOo" "ooooO" "oooOo" "ooOoo" "oOooo" "Ooooo" - do - echo -ne "\r• $i" - sleep 0.2 - done - done +while [ $# -gt 0 ]; do + case "$1" in + --dir=*) + DIR="${1#*=}" || DIR="/root/TeamUltroid" + ;; + --branch=*) + BRANCH="${1#*=}" || BRANCH="main" + ;; + --env-file=*) + ENV_FILE_PATH="${1#*=}" || ENV_FILE_PATH=".env" + ;; + --no-root) + NO_ROOT=true + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +check_dependencies() { + # check if debian + echo "Checking dependencies..." + # read file with root access + if ! [[ $(ls -l "/etc/sudoers" | cut -d " " -f1) =~ "r" ]]; then + # check dependencies if installed + echo -e "Root access not found. Checking if dependencies are installed." >&2 + if ! [ -x "$(command -v python3)" ] || ! [ -x "$(command -v python)" ]; then + echo -e "Python3 isn't installed. Please install python3.8 or higher to run this bot." >&2 + exit 1 + fi + if [ $(python3 -c "import sys; print(sys.version_info[1])") -lt 8 ] || [ $(python -c "import sys; print(sys.version_info[1])") -lt 8 ]; then + echo -e "Python 3.8 or higher is required to run this bot." >&2 + exit 1 + fi + # check if any of ffmpeg, mediainfo, neofetch, git is not installed + if ! command -v ffmpeg &>/dev/null || ! command -v mediainfo &>/dev/null || ! command -v neofetch &>/dev/null || ! command -v git &>/dev/null; then + echo -e "Some dependencies aren't installed. Please install ffmpeg, mediainfo, neofetch and git to run this bot." >&2 + exit 1 + fi + fi + if [ -x "$(command -v apt-get)" ]; then + echo -e "Installing dependencies..." + # check if any of ffmpeg, mediainfo, neofetch, git is not installed via dpkg + if dpkg -l | grep -q ffmpeg || dpkg -l | grep -q mediainfo || dpkg -l | grep -q neofetch || dpkg -l | grep -q git; then + sudo apt-get -qq -o=Dpkg::Use-Pty=0 update + sudo apt-get install -qq -o=Dpkg::Use-Pty=0 python3 python3-pip ffmpeg mediainfo neofetch git -y + fi + elif [ -x "$(command -v pacman)" ]; then + echo -e "Installing dependencies..." + if pacman -Q | grep -q ffmpeg || pacman -Q | grep -q mediainfo || pacman -Q | grep -q neofetch || pacman -Q | grep -q git; then + sudo pacman -Sy python python-pip git ffmpeg mediainfo neofetch --noconfirm + fi + else + echo -e "Unknown OS. Checking if dependecies are installed" >&2 + if ! [ -x "$(command -v python3)" ] || ! [ -x "$(command -v python)" ]; then + echo -e "Python3 isn't installed. Please install python3.8 or higher to run this bot." >&2 + exit 1 + fi + if [ $(python3 -c "import sys; print(sys.version_info[1])") -lt 8 ] || [ $(python -c "import sys; print(sys.version_info[1])") -lt 8 ]; then + echo -e "Python 3.8 or higher is required to run this bot." >&2 + exit 1 + fi + if ! command -v ffmpeg &>/dev/null || ! command -v mediainfo &>/dev/null || ! command -v neofetch &>/dev/null || ! command -v git &>/dev/null; then + echo -e "Some dependencies aren't installed. Please install ffmpeg, mediainfo, neofetch and git to run this bot." >&2 + exit 1 + fi + fi } -clone_repo(){ - if [ ! $BRANCH ] - then export BRANCH="main" +check_python() { + # check if python is installed + if ! command -v python3 &>/dev/null; then + echo -e "Python3 isn't installed. Please install python3.8 or higher to run this bot." + exit 1 + elif ! command -v python &>/dev/null; then + echo -e "Python3 isn't installed. Please install python3.8 or higher to run this bot." + exit 1 + fi + if [ $(python3 -c "import sys; print(sys.version_info[1])") -lt 8 ]; then + echo -e "Python 3.8 or higher is required to run this bot." + exit 1 + elif [ $(python -c "import sys; print(sys.version_info[1])") -lt 3 ]; then + if [ $(python -c "import sys; print(sys.version_info[1])") -lt 8 ]; then + echo -e "Python 3.8 or higher is required to run this bot." + exit 1 + fi fi - if [ -d $DIR ] - then - echo -e $DIR "Already exists.." +} + +clone_repo() { + # check if pyultroid, startup, plugins folders exist + cd $DIR + if [ -d $DIR ]; then + if [ -d $DIR/.git ]; then + echo -e "Updating Ultroid ${BRANCH}... " cd $DIR git pull currentbranch="$(git rev-parse --abbrev-ref HEAD)" - if [ currentbranch != $BRANCH ] - then - git checkout $BRANCH + if [ ! $BRANCH ]; then + export BRANCH=$currentbranch fi - if [ -d "addons" ] - then - cd addons - git pull - fi - return + case $currentbranch in + $BRANCH) + # do nothing + ;; + *) + echo -e "Switching to branch ${BRANCH}... " + echo -e $currentbranch + git checkout $BRANCH + ;; + esac + else + rm -rf $DIR + exit 1 + fi + if [ -d "addons" ]; then + cd addons + git pull + fi + return + else + if [ ! $BRANCH ]; then + export BRANCH="main" + fi + mkdir -p $DIR + echo -e "Cloning Ultroid ${BRANCH}... " + git clone -b $BRANCH $REPO $DIR fi - echo -e "Cloning Ultroid ${BRANCH}... " - git clone -b $BRANCH $REPO $DIR } -install_requirements(){ - pip install --upgrade pip +install_requirements() { + pip3 install -q --upgrade pip echo -e "\n\nInstalling requirements... " pip3 install -q --no-cache-dir -r $DIR/requirements.txt pip3 install -q -r $DIR/resources/startup/optional-requirements.txt } -railways_dep(){ - if [ $RAILWAY_STATIC_URL ] - then - echo -e "Installing YouTube dependency... " - pip3 install -q yt-dlp +railways_dep() { + if [ $RAILWAY_STATIC_URL ]; then + echo -e "Installing YouTube dependency... " + pip3 install -q yt-dlp fi } -misc_install(){ - if [ $OKTETO_TOKEN ] - then - echo -e "Installing Okteto-CLI... " - curl https://get.okteto.com -sSfL | sh - elif [ $VCBOT ] - then - if [ -d $DIR/vcbot ] - then - cd $DIR/vcbot - git pull - else - echo -e "Cloning VCBOT.." - git clone https://github.com/TeamUltroid/VcBot $DIR/vcbot - fi - pip3 install pytgcalls>=3.0.0.dev21 && pip3 install av -q --no-binary av +misc_install() { + if [ $SETUP_PLAYWRIGHT ] + then + echo -e "Installing playwright." + pip3 install playwright + playwright install + fi + if [ $OKTETO_TOKEN ]; then + echo -e "Installing Okteto-CLI... " + curl https://get.okteto.com -sSfL | sh + elif [ $VCBOT ]; then + if [ -d $DIR/vcbot ]; then + cd $DIR/vcbot + git pull + else + echo -e "Cloning VCBOT.." + git clone https://github.com/TeamUltroid/VcBot $DIR/vcbot + fi + pip3 install pytgcalls==3.0.0.dev23 && pip3 install av -q --no-binary av fi } -dep_install(){ +dep_install() { echo -e "\n\nInstalling DB Requirement..." - if [ $MONGO_URI ] - then - pip3 install -q pymongo[srv] - elif [ $DATABASE_URL ] - then - pip3 install -q psycopg2-binary - elif [ $REDIS_URI ] - then - pip3 install -q redis hiredis + if [ $MONGO_URI ]; then + echo -e " Installing MongoDB Requirements..." + pip3 install -q pymongo[srv] + elif [ $DATABASE_URL ]; then + echo -e " Installing PostgreSQL Requirements..." + pip3 install -q psycopg2-binary + elif [ $REDIS_URI ]; then + echo -e " Installing Redis Requirements..." + pip3 install -q redis hiredis fi } -main(){ +main() { + echo -e "Starting Ultroid Setup..." + if [ -d "pyUltroid" ] && [ -d "resources" ] && [ -d "plugins" ]; then + DIR=$CURRENT_DIR + fi + if [ -f $ENV_FILE_PATH ] + then + set -a + source <(cat $ENV_FILE_PATH | sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g") + set +a + cp $ENV_FILE_PATH .env + fi + (check_dependencies) + (check_python) (clone_repo) (install_requirements) (railways_dep) (dep_install) (misc_install) + echo -e "\n\nSetup Completed." } -main +if [ $NO_ROOT ]; then + echo -e "Running with non root" + main + return 0 +elif [ -t 0 ]; then + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) machine=Linux;; + Darwin*) machine=Mac;; + CYGWIN*) machine=Cygwin;; + MINGW*) machine=MinGw;; + *) machine="UNKNOWN:${unameOut}" + esac + if machine != "Linux"; then + echo -e "This script is only for Linux. Please use the Windows installer." + exit 1 + fi + # check if sudo is installed + if ! command -v sudo &>/dev/null; then + echo -e "Sudo isn't installed. Please install sudo to run this bot." + exit 1 + fi + sudo echo "Sudo permission granted." + main +else + echo "Not an interactive terminal, skipping sudo." + # run main function + main +fi diff --git a/plugins/__init__.py b/plugins/__init__.py index 66476549322bb360f568caf640a5a229c6b6ad84..e4314ca9df303d362651a8a786858aefde58bad6 100644 --- a/plugins/__init__.py +++ b/plugins/__init__.py @@ -20,18 +20,23 @@ from pyUltroid._misc._decorators import ultroid_cmd from pyUltroid._misc._wrappers import eod, eor from pyUltroid.dB import DEVLIST, ULTROID_IMAGES from pyUltroid.fns.helper import * -from pyUltroid.fns.info import * from pyUltroid.fns.misc import * from pyUltroid.fns.tools import * +from pyUltroid.startup._database import _BaseDatabase as Database from pyUltroid.version import __version__, ultroid_version from strings import get_help, get_string +udB: Database + Redis = udB.get_key con = TgConverter quotly = Quotly() OWNER_NAME = ultroid_bot.full_name OWNER_ID = ultroid_bot.uid +ultroid_bot: UltroidClient +asst: UltroidClient + LOG_CHANNEL = udB.get_key("LOG_CHANNEL") diff --git a/plugins/_chatactions.py b/plugins/_chatactions.py index 94fd7b34f0889c8d6288b596ca7d0e23966a57fd..9f7f6965f21a676965b70c573fe70f54bf27f80d 100644 --- a/plugins/_chatactions.py +++ b/plugins/_chatactions.py @@ -13,6 +13,7 @@ from telethon.tl.functions.channels import GetParticipantRequest from telethon.utils import get_display_name from pyUltroid.dB import stickers +from pyUltroid.dB.echo_db import check_echo from pyUltroid.dB.forcesub_db import get_forcesetting from pyUltroid.dB.gban_mute_db import is_gbanned from pyUltroid.dB.greetings_db import get_goodbye, get_welcome, must_thank @@ -90,8 +91,7 @@ async def DummyHandler(ult): user.id, view_messages=False, ) - await ult.client.send_message( - chat.id, + await ult.respond( f'**@UltroidBans:** Banned user detected and banned!\n`{str(is_banned)}`.\nBan reason: {is_banned["reason"]}', ) @@ -196,8 +196,13 @@ async def DummyHandler(ult): @ultroid_bot.on(events.NewMessage(incoming=True)) async def chatBot_replies(e): sender = await e.get_sender() - if not isinstance(sender, types.User): + if not isinstance(sender, types.User) or sender.bot: return + if check_echo(e.chat_id, e.sender_id): + try: + await e.respond(e) + except Exception as er: + LOGS.exception(er) key = udB.get_key("CHATBOT_USERS") or {} if e.text and key.get(e.chat_id) and sender.id in key[e.chat_id]: msg = await get_chatbot_reply(e.message.message) @@ -206,12 +211,10 @@ async def chatBot_replies(e): await asyncio.sleep(sleep) await e.reply(msg) chat = await e.get_chat() - if e.is_group and not sender.bot: - if sender.username: - await uname_stuff(e.sender_id, sender.username, sender.first_name) - elif e.is_private and not sender.bot: - if chat.username: - await uname_stuff(e.sender_id, chat.username, chat.first_name) + if e.is_group and sender.username: + await uname_stuff(e.sender_id, sender.username, sender.first_name) + elif e.is_private and chat.username: + await uname_stuff(e.sender_id, chat.username, chat.first_name) if detector and is_profan(e.chat_id) and e.text: x, y = detector(e.text) if y: @@ -220,7 +223,7 @@ async def chatBot_replies(e): @ultroid_bot.on(events.Raw(types.UpdateUserName)) async def uname_change(e): - await uname_stuff(e.user_id, e.username, e.first_name) + await uname_stuff(e.user_id, e.usernames[0] if e.usernames else None, e.first_name) async def uname_stuff(id, uname, name): diff --git a/plugins/_userlogs.py b/plugins/_userlogs.py index d2fcdde1ce7d52bb03129843e41c19e7cb0182fb..61491445d55eed2e3fe018872e3ee43da55d2bef 100644 --- a/plugins/_userlogs.py +++ b/plugins/_userlogs.py @@ -51,10 +51,7 @@ async def all_messages_catcher(e): return if not udB.get_key("TAG_LOG"): return - try: - NEEDTOLOG = int(udB.get_key("TAG_LOG")) - except Exception: - return LOGS.info(get_string("userlogs_1")) + NEEDTOLOG = udB.get_key("TAG_LOG") buttons = await parse_buttons(e) try: sent = await asst.send_message(NEEDTOLOG, e.message, buttons=buttons) @@ -63,7 +60,8 @@ async def all_messages_catcher(e): else: TAG_EDITS.update({e.chat_id: {e.id: {"id": sent.id, "msg": e}}}) tag_add(sent.id, e.chat_id, e.id) - except MediaEmptyError: + except MediaEmptyError as er: + LOGS.debug(f"handling {er}.") try: msg = await asst.get_messages(e.chat_id, ids=e.id) sent = await asst.send_message(NEEDTOLOG, msg, buttons=buttons) @@ -89,7 +87,8 @@ async def all_messages_catcher(e): except Exception as er: LOGS.exception(er) await asst.send_message(NEEDTOLOG, get_string("com_4"), buttons=buttons) - except (PeerIdInvalidError, ValueError): + except (PeerIdInvalidError, ValueError) as er: + LOGS.exception(er) try: CACHE_SPAM[NEEDTOLOG] except KeyError: @@ -225,7 +224,7 @@ async def when_added_or_joined(event): text = f"#APPROVAL_LOG\n\n{inline_mention(user)} just got Chat Join Approval to {chat}." else: text = f"#JOIN_LOG\n\n{inline_mention(user)} just joined {chat}." - await asst.send_message(int(udB.get_key("LOG_CHANNEL")), text, buttons=buttons) + await asst.send_message(udB.get_key("LOG_CHANNEL"), text, buttons=buttons) asst.add_event_handler( diff --git a/plugins/_wspr.py b/plugins/_wspr.py index d30da90c12c3170a30311c4fe430aafdfc8d2923..19323558ca68e65bae9215730a58205567c3bf09 100644 --- a/plugins/_wspr.py +++ b/plugins/_wspr.py @@ -66,7 +66,7 @@ async def _(e): if not isinstance(logi, types.User): raise ValueError("Invalid Username.") except IndexError: - sur = e.builder.article( + sur = await e.builder.article( title="Give Username", description="You Didn't Type Username or id.", text="You Didn't Type Username or id.", @@ -74,7 +74,7 @@ async def _(e): return await e.answer([sur]) except ValueError as er: LOGS.exception(er) - sur = e.builder.article( + sur = await e.builder.article( title="User Not Found", description="Make sure username or id is correct.", text="Make sure username or id is correct.", @@ -83,14 +83,23 @@ async def _(e): try: desc = zzz[2] except IndexError: - sur = e.builder.article(title="Type ur msg", text="You Didn't Type Your Msg") + sur = await e.builder.article( + title="Type ur msg", text="You Didn't Type Your Msg" + ) return await e.answer([sur]) button = [ - Button.inline("Secret Msg", data=f"dd_{e.id}"), - Button.inline("Delete Msg", data=f"del_{e.id}"), + [ + Button.inline("Secret Msg", data=f"dd_{e.id}"), + Button.inline("Delete Msg", data=f"del_{e.id}"), + ], + [ + Button.switch_inline( + "New", query=f"wspr {logi.username or logi.id}", same_peer=True + ) + ], ] us = logi.username or logi.first_name - sur = e.builder.article( + sur = await e.builder.article( title=logi.first_name, description=desc, text=get_string("wspr_1").format(us), diff --git a/plugins/admintools.py b/plugins/admintools.py index 75224dc0cb5879f294c75f2a50ebc29d0ed73cf7..bb4c6d0e71c20e903d4a5c24575283433b1a4247 100644 --- a/plugins/admintools.py +++ b/plugins/admintools.py @@ -20,18 +20,9 @@ from telethon.utils import get_display_name from pyUltroid.dB import DEVLIST from pyUltroid.fns.admins import ban_time +from pyUltroid.fns.info import get_uinfo -from . import ( - HNDLR, - LOGS, - eod, - eor, - get_string, - get_uinfo, - inline_mention, - types, - ultroid_cmd, -) +from . import HNDLR, LOGS, eod, eor, get_string, inline_mention, types, ultroid_cmd @ultroid_cmd( diff --git a/plugins/afk.py b/plugins/afk.py index 99d466f9055031ba21e53174fdc7bd813138a405..30028387e8f912cca842f4608d53d552bc52cb9d 100644 --- a/plugins/afk.py +++ b/plugins/afk.py @@ -16,7 +16,7 @@ from telegraph import upload_file as uf from telethon import events from pyUltroid.dB.afk_db import add_afk, del_afk, is_afk -from pyUltroid.dB.pmpermit_db import is_approved +from pyUltroid.dB.base import KeyManager from . import ( LOG_CHANNEL, @@ -32,6 +32,8 @@ from . import ( old_afk_msg = [] +is_approved = KeyManager("PMPERMIT", cast=list).contains + @ultroid_cmd(pattern="afk( (.*)|$)", owner_only=True) async def set_afk(event): diff --git a/plugins/audiotools.py b/plugins/audiotools.py index 79ea7ce85454256a39225cb928e63bd84234aed2..ab87e86e907ee687ae8ec427db0f92c42e1a4d66 100644 --- a/plugins/audiotools.py +++ b/plugins/audiotools.py @@ -151,12 +151,10 @@ async def ex_aud(e): except FileNotFoundError: return await eor(msg, get_string("audiotools_9")) - await e.client.send_file( - e.chat_id, - fo, - caption=get_string("audiotools_10"), + await e.reply( + get_string("audiotools_10"), + file=fo, thumb=ULTConfig.thumb, attributes=attributes, - reply_to=e.reply_to_msg_id, ) await msg.delete() diff --git a/plugins/autoban.py b/plugins/autoban.py index ce64f1edd40c326d987ad38002d29052b8ead670..0c3e2e3a37f683049225882ab0a86ee6815274f6 100644 --- a/plugins/autoban.py +++ b/plugins/autoban.py @@ -10,43 +10,26 @@ from . import get_help __doc__ = get_help("help_autoban") from telethon import events -from telethon.tl.types import Channel -from pyUltroid.dB import autoban_db, dnd_db -from pyUltroid.fns.admins import get_update_linked_chat +from pyUltroid.dB.base import KeyManager -from . import LOGS, asst, get_string, inline_mention, ultroid_bot, ultroid_cmd +from . import LOGS, asst, ultroid_bot, ultroid_cmd +Keym = KeyManager("DND_CHATS", cast=list) -async def dnd_func(event): - if event.chat_id in dnd_db.get_dnd_chats(): - for user in event.users: - try: - await ( - await event.client.kick_participant(event.chat_id, user) - ).delete() - except Exception as ex: - LOGS.error("Error in DND:") - LOGS.exception(ex) - await event.delete() + +def join_func(e): + return e.user_joined and Keym.contains(e.chat_id) -async def channel_del(event): - if not autoban_db.is_autoban_enabled(event.chat_id): - return - if autoban_db.is_whitelisted(event.chat_id, event.sender_id): - return - linked = await get_update_linked_chat(event) - if linked == event.sender.id: - return - if event.chat.creator or event.chat.admin_rights.ban_users: +async def dnd_func(event): + for user in event.users: try: - await event.client.edit_permissions( - event.chat_id, event.sender_id, view_messages=False - ) - except Exception as er: - LOGS.exception(er) - await event.try_delete() + await (await event.client.kick_participant(event.chat_id, user)).delete() + except Exception as ex: + LOGS.error("Error in DND:") + LOGS.exception(ex) + await event.delete() @ultroid_cmd( @@ -59,84 +42,18 @@ async def channel_del(event): async def _(event): match = event.pattern_match.group(1) if match == "on": - if dnd_db.chat_in_dnd(event.chat_id): + if Keym.contains(event.chat_id): return await event.eor("`Chat already in do not disturb mode.`", time=3) - dnd_db.add_dnd(event.chat_id) - event.client.add_handler( - dnd_func, events.ChatAction(func=lambda x: x.user_joined) - ) + Keym.add(event.chat_id) + event.client.add_handler(dnd_func, events.ChatAction(func=join_func)) await event.eor("`Do not disturb mode activated for this chat.`", time=3) elif match == "off": - if not dnd_db.chat_in_dnd(event.chat_id): + if not Keym.contains(event.chat_id): return await event.eor("`Chat is not in do not disturb mode.`", time=3) - dnd_db.del_dnd(event.chat_id) + Keym.remove(event.chat_id) await event.eor("`Do not disturb mode deactivated for this chat.`", time=3) -@ultroid_cmd(pattern="cban$", admins_only=True) -async def ban_cha(ult): - if autoban_db.is_autoban_enabled(ult.chat_id): - autoban_db.del_channel(ult.chat_id) - return await ult.eor("`Disabled Auto ChannelBan...`") - if not ( - ult.chat.creator - or (ult.chat.admin_rights.delete_messages or ult.chat.admin_rights.ban_users) - ): - return await ult.eor( - "You are missing required admin rights!\nYou can't use ChannelBan without Ban/del privilege..`" - ) - autoban_db.add_channel(ult.chat_id) - await ult.eor("`Enabled Auto ChannelBan Successfully!`") - ult.client.add_handler( - channel_del, - events.NewMessage( - func=lambda x: not x.is_private and isinstance(x.sender, Channel) - ), - ) - - -@ultroid_cmd(pattern="(list|add|rem)wl( (.*)|$)") -async def do_magic(event): - match = event.pattern_match.group(1) - msg = await event.eor(get_string("com_1")) - if match == "list": - cha = autoban_db.get_whitelisted_channels(event.chat_id) - if not cha: - return await msg.edit("`No Whitelisted channels for current chat.`") - Msg = "**Whitelist Channels in Current Chat**\n\n" - for ch in cha: - Msg += f"(`{ch}`) " - try: - Msg += inline_mention(await event.client.get_entity(ch)) - except Exception: - Msg += "\n" - return await msg.edit(Msg) - usea = event.pattern_match.group(2).strip() - if not usea: - return await Msg.edit( - "`Please provide a channel username/id to add/remove to/from whitelist..`" - ) - try: - u_id = await event.client.parse_id(usea) - cha = await event.client.get_entity(u_id) - except Exception as er: - LOGS.exception(er) - return await msg.edit(f"Error Broke Out!\n`{er}`") - if match == "add": - autoban_db.add_to_whitelist(event.chat_id, u_id) - return await msg.edit(f"`Added` {inline_mention(cha)} `to WhiteList..`") - autoban_db.del_from_whitelist(event.chat_id, u_id) - await msg.edit(f"`Removed` {inline_mention(cha)} `from WhiteList.`") - - -if dnd_db.get_dnd_chats(): - ultroid_bot.add_handler(dnd_func, events.ChatAction(func=lambda x: x.user_joined)) - asst.add_handler(dnd_func, events.ChatAction(func=lambda x: x.user_joined)) - -if autoban_db.get_all_channels(): - ultroid_bot.add_handler( - channel_del, - events.NewMessage( - func=lambda x: not x.is_private and isinstance(x.sender, Channel) - ), - ) +if Keym.get(): + ultroid_bot.add_handler(dnd_func, events.ChatAction(func=join_func)) + asst.add_handler(dnd_func, events.ChatAction(func=join_func)) diff --git a/plugins/autopic.py b/plugins/autopic.py index 17faeb9e0518ac6978c4daf6db11d10783f00dcc..a3ca45231b0b993a6d8a038fbf051cc468484109 100644 --- a/plugins/autopic.py +++ b/plugins/autopic.py @@ -9,12 +9,12 @@ import asyncio import os import random -from glob import glob from random import shuffle from telethon.tl.functions.photos import UploadProfilePhotoRequest -from pyUltroid.fns.google_image import googleimagesdownload +from pyUltroid.fns.helper import download_file +from pyUltroid.fns.tools import get_google_images from . import LOGS, get_help, get_string, udB, ultroid_bot, ultroid_cmd @@ -59,35 +59,20 @@ async def autopic(e): if search := udB.get_key("AUTOPIC"): - gi = googleimagesdownload() - args = { - "keywords": search, - "limit": 50, - "format": "jpg", - "output_directory": "./resources/downloads/", - } - images = [] - if os.path.exists(f"./resources/downloads/{search}"): - images = glob(f"resources/downloads/{search}/*") + images = {} sleep = udB.get_key("SLEEP_TIME") or 1221 async def autopic_func(): - if udB.get_key("AUTOPIC") != search: + search = udB.get_key("AUTOPIC") + if images.get(search) is None: + images[search] = await get_google_images(search) + if not images.get(search): return - if not images: - try: - pth = await gi.download(args) - ok = pth[0][search] - images.extend(ok) - except Exception as er: - LOGS.exception(er) - return - else: - ok = images - img = random.choice(ok) - file = await ultroid_bot.upload_file(img) + img = random.choice(images[search]) + filee = await download_file(img["original"], "resources/downloads/autopic.jpg") + file = await ultroid_bot.upload_file(filee) await ultroid_bot(UploadProfilePhotoRequest(file)) - shuffle(ok) + os.remove(filee) try: from apscheduler.schedulers.asyncio import AsyncIOScheduler diff --git a/plugins/beautify.py b/plugins/beautify.py index 023116c8f25d7f58f3af973222ceec868907b4ee..939da5c256548dc44e7c2f26ff076af901b4b425 100644 --- a/plugins/beautify.py +++ b/plugins/beautify.py @@ -10,11 +10,12 @@ from . import get_help __doc__ = get_help("help_beautify") +import os import random from telethon.utils import get_display_name -from . import Carbon, eor, get_string, inline_mention, os, ultroid_cmd +from . import Carbon, ultroid_cmd, get_string, inline_mention _colorspath = "resources/colorlist.txt" @@ -28,7 +29,7 @@ else: @ultroid_cmd( pattern="(rc|c)arbon", ) -async def crbn(event): +async def cr_bn(event): xxxx = await event.eor(get_string("com_1")) te = event.pattern_match.group(1) col = random.choice(all_col) if te[0] == "r" else "White" @@ -45,8 +46,11 @@ async def crbn(event): try: code = event.text.split(" ", maxsplit=1)[1] except IndexError: - return await eor(xxxx, get_string("carbon_2")) + return await xxxx.eor(get_string("carbon_2")) xx = await Carbon(code=code, file_name="ultroid_carbon", backgroundColor=col) + if isinstance(xx, dict): + await xxxx.edit(f"`{xx}`") + return await xxxx.delete() await event.reply( f"Carbonised by {inline_mention(event.sender)}", @@ -77,7 +81,7 @@ async def crbn(event): code = match[1] match = match[0] except IndexError: - return await eor(msg, get_string("carbon_2")) + return await msg.eor(get_string("carbon_2")) xx = await Carbon(code=code, backgroundColor=match) await msg.delete() await event.reply( @@ -125,7 +129,7 @@ async def pass_on(ult): theme = random.choice(RaySoTheme) if ult.is_reply: msg = await ult.get_reply_message() - text = msg.text + text = msg.message title = get_display_name(msg.sender) await ult.reply( file=await Carbon(text, rayso=True, title=title, theme=theme, darkMode=dark) diff --git a/plugins/blacklist.py b/plugins/blacklist.py index 306351eb66129ba4a19741965fffe5ff2e14bde2..ac31c8d265cbeb7ee8ee9e881658988590a33a6b 100644 --- a/plugins/blacklist.py +++ b/plugins/blacklist.py @@ -57,14 +57,12 @@ async def lsnote(e): async def blacklist(e): if x := get_blacklist(e.chat_id): - for z in e.text.lower().split(): - for zz in x: - if z == zz: - try: - await e.delete() - break - except BaseException: - break + text = e.text.lower().split() + if any((z in text) for z in x): + try: + await e.delete() + except BaseException: + pass if udB.get_key("BLACKLIST_DB"): diff --git a/plugins/bot.py b/plugins/bot.py index 792511407c33b1fccd5e787b671ca9e5d1b4a27a..6886de72d4352f9311390580bea9eb30214f8d79 100644 --- a/plugins/bot.py +++ b/plugins/bot.py @@ -84,7 +84,7 @@ The Ultroid Userbot ◍ Telethon - {} """ -in_alive = "{}\n\n🌀 Ultroid Version -> {}\n🌀 PyUltroid -> {}\n🌀 Python -> {}\n🌀 Uptime -> {}\n🌀 Branch -> [ {} ]\n\n• Join @TeamUltroid" +in_alive = "{}\n\n🌀 Ultroid Version -> {}\n🌀 PyUltroid -> {}\n🌀 Python -> {}\n🌀 Uptime -> {}\n🌀 Branch ->[ {} ]\n\n• Join @TeamUltroid" @callback("alive") @@ -243,6 +243,9 @@ async def _(event): code=code, backgroundColor=choice(ATRA_COL), ) + if isinstance(file, dict): + await event.eor(f"`{file}`") + return await event.reply("**Ultroid Logs.**", file=file) elif opt == "open": with open("ultroid.log", "r") as f: @@ -296,7 +299,7 @@ async def inline_alive(ult): ] return await ult.answer(results) except BaseException as er: - LOGS.info(er) + LOGS.exception(er) result = [ await builder.article( "Alive", text=als, parse_mode="html", link_preview=False, buttons=buttons diff --git a/plugins/broadcast.py b/plugins/broadcast.py index 6e97036ba2e56bb652cc69b106ee9ad067c0db51..a10c996d556370f39ba0fefd5e3a92374eeeb2cb 100644 --- a/plugins/broadcast.py +++ b/plugins/broadcast.py @@ -15,10 +15,12 @@ import io from telethon.utils import get_display_name -from pyUltroid.dB.broadcast_db import * +from pyUltroid.dB.base import KeyManager from . import HNDLR, LOGS, eor, get_string, udB, ultroid_bot, ultroid_cmd +KeyM = KeyManager("BROADCAST", cast=list) + @ultroid_cmd( pattern="addch( (.*)|$)", @@ -40,14 +42,14 @@ async def broadcast_adder(event): if ( i.broadcast and (i.creator or i.admin_rights) - and not is_channel_added(i.id) + and not KeyM.contains(i.id) ): new += 1 cid = f"-100{i.id}" - add_channel(int(cid)) + KeyM.add(int(cid)) except Exception as Ex: LOGS.exception(Ex) - await x.edit(get_string("bd_3").format(get_no_channels(), new)) + await x.edit(get_string("bd_3").format(KeyM.count(), new)) return if event.reply_to_msg_id: previous_message = await event.get_reply_message() @@ -56,8 +58,8 @@ async def broadcast_adder(event): length = len(lines) for line_number in range(1, length - 2): channel_id = lines[line_number][4:-1] - if not is_channel_added(channel_id): - add_channel(channel_id) + if not KeyM.contains(channel_id): + KeyM.add(channel_id) await x.edit(get_string("bd_4")) await asyncio.sleep(3) await event.delete() @@ -65,9 +67,9 @@ async def broadcast_adder(event): chat_id = event.chat_id if chat_id == udB.get_key("LOG_CHANNEL"): return - if is_channel_added(chat_id): + if KeyM.contains(chat_id): await x.edit(get_string("bd_6")) - elif xx := add_channel(chat_id): + elif xx := KeyM.add(chat_id): await x.edit(get_string("bd_5")) else: await x.edit(get_string("sf_8")) @@ -87,8 +89,8 @@ async def broadcast_remover(event): udB.del_key("BROADCAST") await x.edit("Database cleared.") return - if is_channel_added(chat_id): - rem_channel(chat_id) + if KeyM.contains(chat_id): + KeyM.remove(chat_id) await x.edit(get_string("bd_7")) else: await x.edit(get_string("bd_9")) @@ -101,8 +103,8 @@ async def broadcast_remover(event): ) async def list_all(event): x = await event.eor(get_string("com_1")) - channels = get_channels() - num = len(channels) + channels = KeyM.get() + num = KeyM.count() if not channels: return await eor(x, "No chats were added.", time=5) msg = "Channels in database:\n" @@ -137,14 +139,13 @@ async def forw(event): if not event.is_reply: return await event.eor(get_string("ex_1")) ultroid_bot = event.client - channels = get_channels() + channels = KeyM.get() x = await event.eor("Sending...") if not channels: return await x.edit(f"Please add channels by using `{HNDLR}add` in them.") error_count = 0 sent_count = 0 - if event.reply_to_msg_id: - previous_message = await event.get_reply_message() + previous_message = await event.get_reply_message() error_count = 0 for channel in channels: try: @@ -156,7 +157,7 @@ async def forw(event): except Exception: try: await ultroid_bot.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"Error in sending at {channel}.", ) except Exception as Em: @@ -168,7 +169,7 @@ async def forw(event): await x.edit(f"{sent_count} messages sent with {error_count} errors.") if error_count > 0: await ultroid_bot.send_message( - int(udB.get_key("LOG_CHANNEL")), f"{error_count} Errors" + udB.get_key("LOG_CHANNEL"), f"{error_count} Errors" ) @@ -180,7 +181,7 @@ async def sending(event): x = await event.eor(get_string("com_1")) if not event.is_reply: return await x.edit(get_string("ex_1")) - channels = get_channels() + channels = KeyM.get() if not channels: return await x.edit(f"Please add channels by using `{HNDLR}add` in them.") await x.edit("Sending....") @@ -199,7 +200,6 @@ async def sending(event): f"Sent : {sent_count}\nError : {error_count}\nTotal : {len(channels)}", ) except Exception as error: - await ultroid_bot.send_message( udB.get_key("LOG_CHANNEL"), f"Error in sending at {channel}.\n\n{error}", @@ -211,6 +211,6 @@ async def sending(event): await x.edit(f"{sent_count} messages sent with {error_count} errors.") if error_count > 0: await ultroid_bot.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"{error_count} Errors", ) diff --git a/plugins/channelhacks.py b/plugins/channelhacks.py index b814d2432e305e6a5d8de595289357700b76732c..712c18b08a6fc18dafc34ed2b6f929dcb4fa0651 100644 --- a/plugins/channelhacks.py +++ b/plugins/channelhacks.py @@ -15,32 +15,23 @@ import io from telethon.errors.rpcerrorlist import FloodWaitError from telethon.utils import get_display_name, get_peer_id -from pyUltroid.dB.ch_db import ( - add_destination, - add_source_channel, - get_destinations, - get_no_destinations, - get_no_source_channels, - get_source_channels, - is_destination_added, - is_source_channel_added, - rem_destination, - rem_source_channel, -) +from pyUltroid.dB.base import KeyManager from . import LOGS, asst, eor, events, get_string, udB, ultroid_bot, ultroid_cmd ERROR = {} +SourceM = KeyManager("CH_SOURCE", cast=list) +DestiM = KeyManager("CH_DESTINATIONS", cast=list) async def autopost_func(e): if not udB.get_key("AUTOPOST"): return - x = get_source_channels() + x = SourceM.get() th = await e.get_chat() if get_peer_id(th) not in x: return - y = get_destinations() + y = DestiM.get() for ys in y: try: await e.client.send_message(int(ys), e.message) @@ -91,11 +82,11 @@ async def source(e): return else: y = e.chat_id - if not is_source_channel_added(y): - add_source_channel(y) + if not SourceM.contains(y): + SourceM.add(y) await e.eor(get_string("cha_2")) ultroid_bot.add_handler(autopost_func, events.NewMessage()) - elif is_source_channel_added(y): + else: await e.eor(get_string("cha_3")) @@ -116,24 +107,21 @@ async def dd(event): return else: y = event.chat_id - if is_source_channel_added(y): - rem_source_channel(y) - await eor(x, get_string("cha_5"), time=3) - elif is_source_channel_added(y): - rem_source_channel(y) + if SourceM.contains(y): + SourceM.remove(y) await eor(x, get_string("cha_5"), time=5) - elif not is_source_channel_added(y): + else: await eor(x, "Source channel is already removed from database. ", time=3) @ultroid_cmd(pattern="listsource") async def list_all(event): x = await event.eor(get_string("com_1")) - num = get_no_source_channels() + num = SourceM.count() if not num: return await eor(x, "No chats were added.", time=5) msg = get_string("cha_8") - channels = get_source_channels() + channels = SourceM.get() for channel in channels: name = "" try: @@ -141,18 +129,16 @@ async def list_all(event): except BaseException: name = "" msg += f"\n=> **{name}** [`{channel}`]" - msg += f"\nTotal {get_no_source_channels()} channels." + msg += f"\nTotal {num} channels." if len(msg) > 4096: MSG = msg.replace("*", "").replace("`", "") with io.BytesIO(str.encode(MSG)) as out_file: out_file.name = "channels.txt" - await event.client.send_file( - event.chat_id, - out_file, + await event.reply( + "Channels in database", + file=out_file, force_document=True, allow_cache=False, - caption="Channels in database", - reply_to=event, ) await x.delete() else: @@ -169,10 +155,10 @@ async def destination(e): return else: y = e.chat_id - if not is_destination_added(y): - add_destination(y) + if not DestiM.contains(y): + DestiM.add(y) await e.eor("Destination added succesfully") - elif is_destination_added(y): + else: await e.eor("Destination channel already added") @@ -193,13 +179,10 @@ async def dd(event): return else: y = event.chat_id - if is_destination_added(y): - rem_destination(y) + if DestiM.contains(y): + DestiM.remove(y) await eor(x, "Destination removed from database") - elif is_destination_added(y): - rem_destination(y) - await eor(x, "Destination removed from database", time=5) - elif not is_destination_added(y): + else: await eor(x, "Destination channel is already removed from database. ", time=5) @@ -207,8 +190,8 @@ async def dd(event): async def list_all(event): ultroid_bot = event.client x = await event.eor(get_string("com_1")) - channels = get_destinations() - num = get_no_destinations() + channels = DestiM.get() + num = len(channels) if not num: return await eor(x, "No chats were added.", time=5) msg = get_string("cha_7") @@ -219,7 +202,7 @@ async def list_all(event): except BaseException: name = "" msg += f"\n=> **{name}** [`{channel}`]" - msg += f"\nTotal {get_no_destinations()} channels." + msg += f"\nTotal {num} channels." if len(msg) > 4096: MSG = msg.replace("*", "").replace("`", "") with io.BytesIO(str.encode(MSG)) as out_file: diff --git a/plugins/chatbot.py b/plugins/chatbot.py index 75ade5571ea3dadf310b2e5e7997ff4f61d939ec..705eeb2bd2f84e63fe402e80eb1e263889e304cf 100644 --- a/plugins/chatbot.py +++ b/plugins/chatbot.py @@ -12,7 +12,7 @@ __doc__ = get_help("help_chatbot") from pyUltroid.fns.tools import get_chatbot_reply -from . import eod, get_string, inline_mention, udB, ultroid_cmd, LOGS +from . import LOGS, eod, get_string, inline_mention, udB, ultroid_cmd @ultroid_cmd(pattern="repai") @@ -67,8 +67,8 @@ async def chat_bot_fn(event, type_): user_ = event.chat if event.is_private else None if not user_: return await eod( - event, - get_string("chab_1"), + event, + get_string("chab_1"), ) key = udB.get_key("CHATBOT_USERS") or {} chat = event.chat_id diff --git a/plugins/cleanaction.py b/plugins/cleanaction.py index b174789f3c270cdb6233ceba5fdb4d94620f04b9..d6efd0beb99878234aaf03541657c27cffb5ccd6 100644 --- a/plugins/cleanaction.py +++ b/plugins/cleanaction.py @@ -44,6 +44,5 @@ async def _(e): except BaseException: title = get_string("clan_3") o += f"{x} {title}\n" - await e.eor(o) - else: - await e.eor(get_string("clan_4"), time=5) + return await e.eor(o) + await e.eor(get_string("clan_4"), time=5) diff --git a/plugins/devtools.py b/plugins/devtools.py index f128c579c8003f17c414c01f7edff244dd10c382..bc3cd5a734fb6bef69cc639cee4ae4c2ebc82bc8 100644 --- a/plugins/devtools.py +++ b/plugins/devtools.py @@ -50,22 +50,28 @@ async def _(e): x, y = await bash("neofetch|sed 's/\x1B\\[[0-9;\\?]*[a-zA-Z]//g' >> neo.txt") if y and y.endswith("NOT_FOUND"): return await xx.edit(f"Error: `{y}`") - with open("neo.txt", "r") as neo: + with open("neo.txt", "r", encoding="utf-8") as neo: p = (neo.read()).replace("\n\n", "") haa = await Carbon(code=p, file_name="neofetch", backgroundColor=choice(ATRA_COL)) - await e.reply(file=haa) - await xx.delete() + if isinstance(haa, dict): + await xx.edit(f"`{haa}`") + else: + await e.reply(file=haa) + await xx.delete() remove("neo.txt") @ultroid_cmd(pattern="bash", fullsudo=True, only_devs=True) async def _(event): - carb, yamlf = None, False + carb, rayso, yamlf = None, None, False try: cmd = event.text.split(" ", maxsplit=1)[1] if cmd.split()[0] in ["-c", "--carbon"]: cmd = cmd.split(maxsplit=1)[1] carb = True + if cmd.split()[0] in ["-r", "--rayso"]: + cmd = cmd.split(maxsplit=1)[1] + rayso = True except IndexError: return await event.eor(get_string("devs_1"), time=10) xx = await event.eor(get_string("com_1")) @@ -88,6 +94,33 @@ async def _(event): download=True, backgroundColor=choice(ATRA_COL), ) + if isinstance(li, dict): + await xx.edit( + f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" + ) + return + url = f"https://graph.org{uf(li)[-1]}" + OUT = f"[\xad]({url}){OUT}" + out = "**• OUTPUT:**" + remove(li) + elif (rayso or udB.get_key("RAYSO_ON_BASH")) and ( + event.is_private + or event.chat.admin_rights + or event.chat.creator + or event.chat.default_banned_rights.embed_links + ): + li = await Carbon( + code=stdout, + file_name="bash", + download=True, + backgroundColor=choice(ATRA_COL), + rayso=True, + ) + if isinstance(li, dict): + await xx.edit( + f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" + ) + return url = f"https://graph.org{uf(li)[-1]}" OUT = f"[\xad]({url}){OUT}" out = "**• OUTPUT:**" @@ -136,7 +169,7 @@ bot = ultroid = ultroid_bot class u: - ... + _ = "" def _parse_eval(value=None): @@ -152,6 +185,14 @@ def _parse_eval(value=None): return json_parser(value, indent=1) except BaseException: pass + elif isinstance(value, list): + newlist = "[" + for index, child in enumerate(value): + newlist += "\n " + str(_parse_eval(child)) + if index < len(value) - 1: + newlist += "," + newlist += "\n]" + return newlist return str(value) @@ -161,7 +202,8 @@ async def _(event): cmd = event.text.split(maxsplit=1)[1] except IndexError: return await event.eor(get_string("devs_2"), time=5) - silent, gsource, xx = False, False, None + xx = None + mode = "" spli = cmd.split() async def get_(): @@ -174,17 +216,19 @@ async def _(event): if spli[0] in ["-s", "--silent"]: await event.delete() - silent = True - cmd = await get_() + mode = "silent" elif spli[0] in ["-n", "-noedit"]: - cmd = await get_() + mode = "no-edit" xx = await event.reply(get_string("com_1")) elif spli[0] in ["-gs", "--source"]: - gsource = True + mode = "gsource" + elif spli[0] in ["-ga", "--args"]: + mode = "g-args" + if mode: cmd = await get_() if not cmd: return - if not silent and not xx: + if not mode == "silent" and not xx: xx = await event.eor(get_string("com_1")) if black: try: @@ -220,13 +264,20 @@ async def _(event): stderr = redirected_error.getvalue() sys.stdout = old_stdout sys.stderr = old_stderr - if value and gsource: + if value: try: - exc = inspect.getsource(value) + if mode == "gsource": + exc = inspect.getsource(value) + elif mode == "g-args": + args = inspect.signature(value).parameters.values() + name = "" + if hasattr(value, "__name__"): + name = value.__name__ + exc = f"**{name}**\n\n" + "\n ".join([str(arg) for arg in args]) except Exception: exc = traceback.format_exc() evaluation = exc or stderr or stdout or _parse_eval(value) or get_string("instu_4") - if silent: + if mode == "silent": if exc: msg = f"• EVAL ERROR\n\n• CHAT: {get_display_name(event.chat)} [{event.chat_id}]" msg += f"\n\n∆ CODE:\n{cmd}\n\n∆ ERROR:\n{exc}" diff --git a/plugins/echo.py b/plugins/echo.py index 168d256cd4a7ef053ca8cde2d93333c0c0730b3c..04c7dd4a0f37191acfb6f7ff2fe5af357e345ec1 100644 --- a/plugins/echo.py +++ b/plugins/echo.py @@ -14,7 +14,7 @@ from telethon.utils import get_display_name from pyUltroid.dB.echo_db import add_echo, check_echo, list_echo, rem_echo -from . import LOGS, events, ultroid_bot, ultroid_cmd +from . import inline_mention, ultroid_cmd @ultroid_cmd(pattern="addecho( (.*)|$)") @@ -36,7 +36,7 @@ async def echo(e): return await e.eor("Echo already activated for this user.", time=5) add_echo(e.chat_id, user) ok = await e.client.get_entity(user) - user = f"[{get_display_name(ok)}](tg://user?id={ok.id})" + user = inline_mention(ok) await e.eor(f"Activated Echo For {user}.") @@ -63,16 +63,6 @@ async def rm(e): await e.eor("Echo not activated for this user") -@ultroid_bot.on(events.NewMessage(incoming=True)) -async def okk(e): - if check_echo(e.chat_id, e.sender_id): - try: - ok = await e.client.get_messages(e.chat_id, ids=e.id) - return await e.client.send_message(e.chat_id, ok) - except Exception as er: - LOGS.info(er) - - @ultroid_cmd(pattern="listecho$") async def lstecho(e): if k := list_echo(e.chat_id): diff --git a/plugins/fontgen.py b/plugins/fontgen.py index 507de3b5c5cc2742b325844632003fe0faf76555..b284862e56790bc5b101072df6027abcc6189dab 100644 --- a/plugins/fontgen.py +++ b/plugins/fontgen.py @@ -11,7 +11,7 @@ __doc__ = get_help("help_fontgen") import string -from . import HNDLR, eod, ultroid_cmd +from . import eod, ultroid_cmd _default = string.ascii_letters Fonts = { diff --git a/plugins/giftools.py b/plugins/giftools.py index abd60f711e153e58ebe07ac07321b7e19117101c..f9e2687bea850065dc343875ada5422188b35396 100644 --- a/plugins/giftools.py +++ b/plugins/giftools.py @@ -60,7 +60,7 @@ async def igif(e): async def reverse_gif(event): a = await event.get_reply_message() if not (a and a.media) and "video" not in mediainfo(a.media): - return await e.eor("`Reply To Video only`", time=5) + return await event.eor("`Reply To Video only`", time=5) msg = await event.eor(get_string("com_1")) file = await a.download_media() await bash(f'ffmpeg -i "{file}" -vf reverse -af areverse reversed.mp4 -y') diff --git a/plugins/glitch.py b/plugins/glitch.py index eeb3c5671f3609811773004a249301533d0b4429..c59192f9916ffea39cdcee32ea3587ca7fb312a0 100644 --- a/plugins/glitch.py +++ b/plugins/glitch.py @@ -35,7 +35,7 @@ async def _(e): else: return await xx.eor(get_string("com_4")) cmd = f"glitch_me gif --line_count 200 -f 10 -d 50 '{ok}' ult.gif" - stdout, stderr = await bash(cmd) + await bash(cmd) await e.reply(file="ult.gif", force_document=False) await xx.delete() os.remove(ok) diff --git a/plugins/globaltools.py b/plugins/globaltools.py index 67f1de6a1cedc4972147c333423cae60fb0896bb..074aad9c36f2e7d091bac1820afbd1d731f6685c 100644 --- a/plugins/globaltools.py +++ b/plugins/globaltools.py @@ -45,6 +45,7 @@ from telethon.tl.functions.contacts import BlockRequest, UnblockRequest from telethon.tl.types import ChatAdminRights, User from pyUltroid.dB import DEVLIST +from pyUltroid.dB.base import KeyManager from pyUltroid.dB.gban_mute_db import ( gban, gmute, @@ -54,11 +55,6 @@ from pyUltroid.dB.gban_mute_db import ( ungban, ungmute, ) -from pyUltroid.dB.gcast_blacklist_db import ( - add_gblacklist, - is_gblacklisted, - rem_gblacklist, -) from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button from . import ( @@ -93,6 +89,8 @@ _gdemote_rights = ChatAdminRights( pin_messages=False, ) +keym = KeyManager("GBLACKLISTS", cast=list) + @ultroid_cmd(pattern="gpromote( (.*)|$)", fullsudo=True) async def _(e): @@ -462,7 +460,7 @@ async def gcast(event): if x.is_group: chat = x.entity.id if ( - not is_gblacklisted(chat) + not keym.contains(chat) and int(f"-100{str(chat)}") not in NOSPAM_CHAT and ( ( @@ -545,7 +543,7 @@ async def gucast(event): for x in dialog: if x.is_user and not x.entity.bot: chat = x.id - if not is_gblacklisted(chat): + if not keym.contains(chat): try: if btn: bt = create_tl_btn(btn) @@ -749,7 +747,7 @@ async def gblacker(event, type_): except IndexError: chat_id = event.chat_id if type_ == "add": - add_gblacklist(chat_id) + keym.add(chat_id) elif type_ == "remove": - rem_gblacklist(chat_id) + keym.remove(chat_id) await event.eor(f"Global Broadcasts: \n{type_}ed {chat_id}") diff --git a/plugins/imagetools.py b/plugins/imagetools.py index fda7619ac19dfe5b9fd22ba30d83911b77d718f2..fa65830b1dbec946fc3ea51fcc02a4d06fbe9f75 100644 --- a/plugins/imagetools.py +++ b/plugins/imagetools.py @@ -177,11 +177,9 @@ async def ult_tools(event): ish = centers[labels.flatten()] ultroid = ish.reshape(ult.shape) cv2.imwrite("ult.jpg", ultroid) - await event.client.send_file( - event.chat_id, - "ult.jpg", + await ureply.reply( + file="ult.jpg", force_document=False, - reply_to=event.reply_to_msg_id, ) await xx.delete() os.remove("ult.jpg") @@ -196,9 +194,7 @@ async def sampl(ult): try: try: await ult.delete() - await ult.client.send_message( - ult.chat_id, f"Colour Sample for `{color}` !", file="csample.png" - ) + await ult.respond(f"Colour Sample for `{color}` !", file="csample.png") except MessageDeleteForbiddenError: await ult.reply(f"Colour Sample for `{color}` !", file="csample.png") except ChatSendMediaForbiddenError: @@ -275,7 +271,7 @@ async def ok(event): @ultroid_cmd(pattern="pixelator( (.*)|$)") async def pixelator(event): reply_message = await event.get_reply_message() - if not (reply_message and reply_message.photo): + if not (reply_message and (reply_message.photo or reply_message.sticker)): return await event.eor("`Reply to a photo`") hw = 50 try: diff --git a/plugins/instagram.py b/plugins/instagram.py deleted file mode 100644 index 74286603e944c08a0efa7800b80a7ff903165c3f..0000000000000000000000000000000000000000 --- a/plugins/instagram.py +++ /dev/null @@ -1,267 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . -""" -✘ Commands Available - - -• `{i}instadl ` - `Download Instagram Media...` - -• `{i}instadata ` - `Get Instagram Data of someone or self` - -• `{i}instaul ` - `Upload Media to Instagram...` - -• `{i}igtv ` - `Upload Media to Igtv...` - -• `{i}reels ` - `Upload Media to Instagram reels...` - -• Go Inline with Your Assistant with query `instatm` - To get home page's posts... - -• Fill `INSTA_USERNAME` and `INSTA_PASSWORD` - before using it.. -""" - -import os -from re import compile - -from telethon.errors.rpcerrorlist import ChatSendInlineForbiddenError -from telethon.tl.types import ( - DocumentAttributeFilename, - InputWebDocument, - MessageMediaWebPage, - WebPage, -) - -from pyUltroid.fns.helper import numerize -from pyUltroid.fns.misc import create_instagram_client - -from . import ( - LOGS, - Button, - asst, - callback, - eor, - get_string, - in_pattern, - udB, - ultroid_cmd, -) - - -@ultroid_cmd(pattern="instadl( (.*)|$)") -async def insta_dl(e): - match = e.pattern_match.group(1).strip() - replied = await e.get_reply_message() - tt = await e.eor(get_string("com_1")) - if match: - text = match - elif e.is_reply and "insta" in replied.message: - text = replied.message - else: - return await eor(tt, "Provide a Link to Download...") - CL = await create_instagram_client(e) - if CL: - try: - mpk = CL.media_pk_from_url(text) - media = CL.media_info(mpk) - if media.media_type == 1: # photo - media = CL.photo_download(mpk) - elif media.media_type == 2 and media.product_type == "feed": # video: - media = CL.video_download(mpk) - elif media.media_type == 2 and media.product_type == "igtv": # igtv: - media = CL.igtv_download(mpk) - elif ( - media.media_type == 2 and media.product_type == "clips" - ): # clips/reels: - media = CL.clip_download(mpk) - elif media.media_type == 8: # Album: - media = CL.album_download(mpk) - else: - LOGS.info(f"UnPredictable Media Type : {mpk}") - return - await e.reply( - f"**• Uploaded Successfully\n• Link :** {text}\n", - file=media, - ) - await tt.delete() - if not isinstance(media, list): - os.remove(media) - else: - [os.remove(media) for media in media] - return - except Exception as B: - LOGS.exception(B) - return await eor(tt, str(B)) - if isinstance(e.media, MessageMediaWebPage) and isinstance( - e.media.webpage, WebPage - ): - if photo := e.media.webpage.photo or e.media.webpage.document: - await tt.delete() - return await e.reply( - f"**Link** :{text}\n\nIf This Wasnt Excepted Result, Please Fill `INSTA_USERNAME` and `INSTA_PASSWORD`...", - file=photo, - ) - # await eor(tt, "Please Fill Instagram Credential to Use this Command...") - - -@ultroid_cmd(pattern="instadata( (.*)|$)") -async def soon_(e): - cl = await create_instagram_client(e) - if not cl: - return - match = e.pattern_match.group(1).strip() - ew = await e.eor(get_string("com_1")) - if match: - try: - iid = cl.user_id_from_username(match) - data = cl.user_info(iid) - except Exception as g: - return await eor(ew, f"**ERROR** : `{g}`") - else: - data = cl.account_info() - data = cl.user_info(data.pk) - photo = data.profile_pic_url - unam = f"https://instagram.com/{data.username}" - msg = f"• **Full Name** : __{data.full_name}__" - if hasattr(data, "biography") and data.biography: - msg += f"\n• **Bio** : `{data.biography}`" - msg += f"\n• **UserName** : [@{data.username}]({unam})" - msg += f"\n• **Verified** : {data.is_verified}" - msg += f"\n• **Posts Count** : {numerize(data.media_count)}" - msg += f"\n• **Followers** : {numerize(data.follower_count)}" - msg += f"\n• **Following** : {numerize(data.following_count)}" - msg += f"\n• **Category** : {data.category_name}" - await e.reply( - msg, - file=photo, - force_document=True, - attributes=[DocumentAttributeFilename("InstaUltroid.jpg")], - ) - await ew.delete() - - -@ultroid_cmd(pattern="(instaul|reels|igtv)( (.*)|$)") -async def insta_karbon(event): - cl = await create_instagram_client(event) - if not cl: - return - msg = await event.eor(get_string("com_1")) - replied = await event.get_reply_message() - type_ = event.pattern_match.group(1).strip() - if not (replied and (replied.photo or replied.video)): - return await event.eor("`Reply to Photo Or Video...`") - caption = ( - event.pattern_match.group(2) + "\n\n• By #Ultroid" - or replied.message + "\n\n• By #Ultroid" - or "Telegram To Instagram Upload\nBy #Ultroid.." - ) - dle = await replied.download_media() - title = None - if replied.photo: - method = cl.photo_upload - elif type_ == "instaul": - method = cl.video_upload - elif type_ == "igtv": - method = cl.igtv_upload - title = caption - elif type_ == "reels": - method = cl.clip_upload - else: - return await eor(msg, "`Use In Proper Format...`") - try: - if title: - uri = method(dle, caption=caption, title=title) - else: - uri = method(dle, caption=caption) - os.remove(dle) - except Exception as er: - LOGS.exception(er) - return await msg.edit(str(er)) - if not event.client._bot: - try: - que = await event.client.inline_query( - asst.me.username, f"instp-{uri.code}_{uri.pk}" - ) - await que[0].click(event.chat_id, reply_to=replied.id) - await msg.delete() - except ChatSendInlineForbiddenError: - pass - except Exception as er: - return await msg.edit(str(er)) - await msg.edit( - f"__Uploaded To Instagram!__\n~ https://instagram.com/p/{uri.code}", - buttons=Button.inline("•Delete•", f"instd{uri.pk}"), - link_preview=False, - ) - - -@in_pattern("instp-(.*)", owner=True) -async def instapl(event): - match = event.pattern_match.group(1).strip().split("_") - uri = f"https://instagram.com/p/{match[0]}" - await event.answer( - [ - await event.builder.article( - title="Instagram Post", - text="**Uploaded on Instagram**", - buttons=[ - Button.url("•View•", uri), - Button.inline("•Delete•", f"instd{match[1]}"), - ], - ) - ] - ) - - -@callback(compile("instd(.*)"), owner=True) -async def dele_post(event): - CL = await create_instagram_client(event) - if not CL: - return await event.answer("Fill Instagram Credentials", alert=True) - await event.answer("• Deleting...") - try: - CL.media_delete(event.data_match.group(1).decode("utf-8")) - except Exception as er: - return await event.edit(f"ERROR: {str(er)}") - await event.edit("**• Deleted!**") - - -@in_pattern(pattern="instatm", owner=True) -async def bhoot_ayaa(event): - if not udB.get_key("INSTA_SET"): - return await event.answer( - [], switch_pm="Fill Instagram Credentials First.", switch_pm_param="start" - ) - insta = await create_instagram_client(event) - posts = insta.get_timeline_feed() - res = [] - switch_pm = f"Showing {posts['num_results']} Feeds.." - for rp in posts["feed_items"]: - try: - me = rp["media_or_ad"] - url = me["image_versions2"]["candidates"][1]["url"] + ".jpg" - text = ( - f"| Instagram Inline Search |\n~ https://instagram.com/p/{me['code']}" - ) - file = InputWebDocument(url, 0, "image/jpeg", []) - res.append( - await event.builder.article( - title="Instagram", - type="photo", - content=file, - thumb=file, - text=text, - include_media=True, - ) - ) - except Exception as er: - LOGS.exception(er) - await event.answer(res, gallery=True, switch_pm=switch_pm, switch_pm_param="start") diff --git a/plugins/logo.py b/plugins/logo.py index 49b949bb3afc1af0e2bc93c19ce90803274ba330..69c0866f8561a45423bd410201c85b2b42209a09 100644 --- a/plugins/logo.py +++ b/plugins/logo.py @@ -19,6 +19,10 @@ import random from telethon.tl.types import InputMessagesFilterPhotos +try: + from PIL import Image +except ImportError: + Image = None from pyUltroid.fns.misc import unsplashsearch from pyUltroid.fns.tools import LogoHelper @@ -45,9 +49,22 @@ async def logo_gen(event): bg_ = await temp.download_media() if not bg_: if event.client._bot: - SRCH = ["blur background", "background", "neon lights", "wallpaper"] + SRCH = [ + "blur background", + "background", + "neon lights", + "nature", + "abstract", + "space", + "3d render", + ] res = await unsplashsearch(random.choice(SRCH), limit=1) - bg_ = await download_file(res[0], "resources/downloads/logo.png") + bg_, _ = await download_file(res[0], "resources/downloads/logo.png") + newimg = "resources/downloads/unsplash-temp.jpg" + img_ = Image.open(bg_) + img_.resize((5000, 5000)).save(newimg) + os.remove(bg_) + bg_ = newimg else: pics = [] async for i in event.client.iter_messages( diff --git a/plugins/mediatools.py b/plugins/mediatools.py index 3ed6d301373f46b42e89c8600cb3b7c0c79d44b1..3c47efe7016a4696f00726dae1e686fb1714abeb 100644 --- a/plugins/mediatools.py +++ b/plugins/mediatools.py @@ -73,7 +73,8 @@ async def mi(e): else: naam = await r.download_media() elif match and ( - os.path.isfile(match) or (match.startswith("https://") and is_url_ok(match)) + os.path.isfile(match) + or (match.startswith("https://") and (await is_url_ok(match))) ): naam, xx = match, "file" else: @@ -123,18 +124,18 @@ async def rotate_(ult): reply = await ult.get_reply_message() msg = await ult.eor(get_string("com_1")) photo = reply.game.photo if reply.game else None - if photo or reply.photo or reply.sticker: - media = await ult.client.download_media(photo or reply) - img = cv2.imread(media) - new_ = rotate_image(img, match) - file = "ult.png" - cv2.imwrite(file, new_) - elif reply.video: + if reply.video: media = await reply.download_media() file = f"{media}.mp4" await bash( f'ffmpeg -i "{media}" -c copy -metadata:s:v:0 rotate={match} "{file}" -y' ) + elif photo or reply.photo or reply.sticker: + media = await ult.client.download_media(photo or reply) + img = cv2.imread(media) + new_ = rotate_image(img, match) + file = "ult.png" + cv2.imwrite(file, new_) else: return await msg.edit("`Unsupported Media..\nReply to Photo/Video`") if os.path.exists(file): diff --git a/plugins/mute.py b/plugins/mute.py index 18fc2320cdb0704a08fa0e859ee5cc5de20e427c..c80d19726e0158dc280aa380cf7bea6110cda2f5 100644 --- a/plugins/mute.py +++ b/plugins/mute.py @@ -109,16 +109,16 @@ async def _(e): except IndexError: return await xx.eor("`Time till mute?`", time=5) try: - input = huh[2] + input_ = huh[2] except IndexError: - pass + input_ = "" chat = await e.get_chat() if e.reply_to_msg_id: reply = await e.get_reply_message() userid = reply.sender_id name = (await reply.get_sender()).first_name - elif input: - userid = await e.client.parse_id(input) + elif input_: + userid = await e.client.parse_id(input_) name = (await e.client.get_entity(userid)).first_name else: return await xx.eor(get_string("tban_1"), time=3) diff --git a/plugins/nightmode.py b/plugins/nightmode.py index 7fd7a5e2c4ee3211fdf5a489af0e184fc7d89266..f96f1eda5c447538d0d04dd04a472689372c654b 100644 --- a/plugins/nightmode.py +++ b/plugins/nightmode.py @@ -40,10 +40,12 @@ except ImportError: from telethon.tl.functions.messages import EditChatDefaultBannedRightsRequest from telethon.tl.types import ChatBannedRights -from pyUltroid.dB.night_db import * +from pyUltroid.dB.base import KeyManager from . import get_string, udB, ultroid_bot, ultroid_cmd +keym = KeyManager("NIGHT_CHATS", cast=list) + @ultroid_cmd(pattern="nmtime( (.*)|$)") async def set_time(e): @@ -64,29 +66,29 @@ async def set_time(e): async def add_grp(e): if pat := e.pattern_match.group(1).strip(): try: - add_night((await ultroid_bot.get_entity(pat)).id) + keym.add((await ultroid_bot.get_entity(pat)).id) return await e.eor(f"Done, Added {pat} To Night Mode.") except BaseException: return await e.eor(get_string("nightm_5"), time=5) - add_night(e.chat_id) + keym.add(e.chat_id) await e.eor(get_string("nightm_3")) @ultroid_cmd(pattern="remnm( (.*)|$)") -async def rem_grp(e): +async def r_em_grp(e): if pat := e.pattern_match.group(1).strip(): try: - rem_night((await ultroid_bot.get_entity(pat)).id) + keym.remove((await ultroid_bot.get_entity(pat)).id) return await e.eor(f"Done, Removed {pat} To Night Mode.") except BaseException: return await e.eor(get_string("nightm_5"), time=5) - rem_night(e.chat_id) + keym.remove(e.chat_id) await e.eor(get_string("nightm_4")) @ultroid_cmd(pattern="listnm$") async def rem_grp(e): - chats = night_grps() + chats = keym.get() name = "NightMode Groups Are-:\n\n" for x in chats: try: @@ -98,8 +100,7 @@ async def rem_grp(e): async def open_grp(): - chats = night_grps() - for chat in chats: + for chat in keym.get(): try: await ultroid_bot( EditChatDefaultBannedRightsRequest( @@ -122,11 +123,10 @@ async def open_grp(): async def close_grp(): - chats = night_grps() - h1, m1, h2, m2 = 0, 0, 7, 0 + __, _, h2, m2 = 0, 0, 7, 0 if udB.get_key("NIGHT_TIME"): - h1, m1, h2, m2 = eval(udB.get_key("NIGHT_TIME")) - for chat in chats: + _, __, h2, m2 = eval(udB.get_key("NIGHT_TIME")) + for chat in keym.get(): try: await ultroid_bot( EditChatDefaultBannedRightsRequest( @@ -144,7 +144,7 @@ async def close_grp(): LOGS.info(er) -if AsyncIOScheduler and night_grps(): +if AsyncIOScheduler and keym.get(): try: h1, m1, h2, m2 = 0, 0, 7, 0 if udB.get_key("NIGHT_TIME"): diff --git a/plugins/pdftools.py b/plugins/pdftools.py index b8e2257c8e4ba40a5f1c523c71616617364db71e..1e5d00bab1e56792fb7c528e37abda5c1cf9e407 100644 --- a/plugins/pdftools.py +++ b/plugins/pdftools.py @@ -8,21 +8,22 @@ ✘ Commands Available - • `{i}pdf ` - Extract nd Send page as a Image.(note-: For Extraction all pages just use .pdf) - You Can use multi pages too like `{i}pdf 1-7` + Extract & send page as an Image.(note-: For extracting all pages, just use .pdf) + to upload selected range `{i}pdf 1-7` • `{i}pdtext ` Extract Text From the Pdf.(note-: For Extraction all text just use .pdtext) - You Can use multi pages too like `{i}pdf 1-7` + to extract selected pages `{i}pdf 1-7` • `{i}pdscan ` - It scan, crop nd send img as pdf. + It scan, crop & send image(s) as pdf. • `{i}pdsave ` - It scan, crop nd save file to merge u can merge many pages as a single pdf. + It scan, crop & save file to merge. + you can merge many pages in a single pdf. • `{i}pdsend ` - Merge nd send the Pdf to collected from .pdsave. + Merge & send the pdf, collected from .pdsave. """ import glob import os diff --git a/plugins/pmpermit.py b/plugins/pmpermit.py index b4620b8528c597a54603694f0921593d872ddf51..8749f6ee022a76f9acadc861f0586cf0f7ce0c3c 100644 --- a/plugins/pmpermit.py +++ b/plugins/pmpermit.py @@ -43,8 +43,6 @@ import re from os import remove from pyUltroid.dB import DEVLIST -from pyUltroid.dB.logusers_db import * -from pyUltroid.dB.pmpermit_db import * try: from tabulate import tabulate @@ -60,6 +58,8 @@ from telethon.tl.functions.contacts import ( from telethon.tl.functions.messages import ReportSpamRequest from telethon.utils import get_display_name, resolve_bot_file_id +from pyUltroid.dB.base import KeyManager + from . import * # ========================= CONSTANTS ============================= @@ -68,6 +68,11 @@ COUNT_PM = {} LASTMSG = {} WARN_MSGS = {} U_WARNS = {} +if isinstance(udB.get_key("PMPERMIT"), (int, str)): + value = [udB.get_key("PMPERMIT")] + udB.set_key("PMPERMIT", value) +keym = KeyManager("PMPERMIT", cast=list) +Logm = KeyManager("LOGUSERS", cast=list) PMPIC = udB.get_key("PMPIC") LOG_CHANNEL = udB.get_key("LOG_CHANNEL") UND = get_string("pmperm_1") @@ -127,10 +132,10 @@ if udB.get_key("PMLOG"): async def _(e): if not e.is_private: return await e.eor("`Use me in Private.`", time=3) - if not is_logger(e.chat_id): + if not Logm.contains(e.chat_id): return await e.eor("`Wasn't logging msgs from here.`", time=3) - nolog_user(e.chat_id) + Logm.remove(e.chat_id) return await e.eor("`Now I Will log msgs from here.`", time=3) @ultroid_cmd( @@ -139,10 +144,10 @@ if udB.get_key("PMLOG"): async def _(e): if not e.is_private: return await e.eor("`Use me in Private.`", time=3) - if is_logger(e.chat_id): + if Logm.contains(e.chat_id): return await e.eor("`Wasn't logging msgs from here.`", time=3) - log_user(e.chat_id) + Logm.add(e.chat_id) return await e.eor("`Now I Won't log msgs from here.`", time=3) @ultroid_bot.on( @@ -153,7 +158,7 @@ if udB.get_key("PMLOG"): ) async def permitpm(event): user = await event.get_sender() - if user.bot or user.is_self or user.verified or is_logger(user.id): + if user.bot or user.is_self or user.verified or Logm.contains(user.id): return await event.forward_to(udB.get_key("PMLOGGROUP") or LOG_CHANNEL) @@ -171,9 +176,9 @@ if udB.get_key("PMSETTING"): miss = await e.get_chat() if miss.bot or miss.is_self or miss.verified or miss.id in DEVLIST: return - if is_approved(miss.id): + if keym.contains(miss.id): return - approve_user(miss.id) + keym.add(miss.id) await delete_pm_warn_msgs(miss.id) try: await ultroid_bot.edit_folder(miss.id, folder=0) @@ -209,7 +214,7 @@ if udB.get_key("PMSETTING"): async def permitpm(event): inline_pm = Redis("INLINE_PM") or False user = event.sender - if not is_approved(user.id) and event.text != UND: + if not keym.contains(user.id) and event.text != UND: if Redis("MOVE_ARCHIVE"): try: await ultroid_bot.edit_folder(user.id, folder=1) @@ -221,11 +226,11 @@ if udB.get_key("PMSETTING"): fullname = get_display_name(user) username = f"@{user.username}" mention = inline_mention(user) - count = len(get_approved()) + count = keym.count() try: wrn = COUNT_PM[user.id] + 1 await asst.edit_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), _not_approved[user.id], f"Incoming PM from **{mention}** [`{user.id}`] with **{wrn}/{WARNS}** warning!", buttons=[ @@ -235,7 +240,7 @@ if udB.get_key("PMSETTING"): ) except KeyError: _not_approved[user.id] = await asst.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"Incoming PM from **{mention}** [`{user.id}`] with **1/{WARNS}** warning!", buttons=[ Button.inline("Approve PM", data=f"approve_{user.id}"), @@ -366,14 +371,14 @@ if udB.get_key("PMSETTING"): del LASTMSG[user.id] except KeyError: await asst.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), "PMPermit is messed! Pls restart the bot!!", ) return LOGS.info("COUNT_PM is messed.") await ultroid_bot(BlockRequest(user.id)) await ultroid_bot(ReportSpamRequest(peer=user.id)) await asst.edit_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), _not_approved[user.id], f"**{mention}** [`{user.id}`] was Blocked for spamming.", ) @@ -407,8 +412,8 @@ if udB.get_key("PMSETTING"): apprvpm, "Lol, He is my Developer\nHe is auto Approved", ) - if not is_approved(user.id): - approve_user(user.id) + if not keym.contains(user.id): + keym.add(user.id) try: await delete_pm_warn_msgs(user.id) await apprvpm.client.edit_folder(user.id, folder=0) @@ -421,7 +426,7 @@ if udB.get_key("PMSETTING"): ) try: await asst.edit_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), _not_approved[user.id], f"#APPROVED\n\n{inline_mention(user, html=True)} [{user.id}] was approved to PM you!", buttons=[ @@ -432,7 +437,7 @@ if udB.get_key("PMSETTING"): ) except KeyError: _not_approved[user.id] = await asst.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"#APPROVED\n\n{inline_mention(user, html=True)} [{user.id}] was approved to PM you!", buttons=[ Button.inline("Disapprove PM", data=f"disapprove_{user.id}"), @@ -458,8 +463,8 @@ if udB.get_key("PMSETTING"): e, "`Lol, He is my Developer\nHe Can't Be DisApproved.`", ) - if is_approved(user.id): - disapprove_user(user.id) + if keym.contains(user.id): + keym.remove(user.id) await eod( e, f"{inline_mention(user, html=True)} Disapproved to PM!", @@ -467,7 +472,7 @@ if udB.get_key("PMSETTING"): ) try: await asst.edit_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), _not_approved[user.id], f"#DISAPPROVED\n\n{inline_mention(user, html=True)} [{user.id}] was disapproved to PM you.", buttons=[ @@ -478,7 +483,7 @@ if udB.get_key("PMSETTING"): ) except KeyError: _not_approved[user.id] = await asst.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"#DISAPPROVED\n\n{inline_mention(user, html=True)} [{user.id}] was disapproved to PM you.", buttons=[ Button.inline("Approve PM", data=f"approve_{user.id}"), @@ -515,12 +520,12 @@ async def blockpm(block): aname = await block.client.get_entity(user) await block.eor(f"{inline_mention(aname)} [`{user}`] `has been blocked!`") try: - disapprove_user(user) + keym.remove(user) except AttributeError: pass try: await asst.edit_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), _not_approved[user], f"#BLOCKED\n\n{inline_mention(aname)} [`{user}`] has been **blocked**.", buttons=[ @@ -529,7 +534,7 @@ async def blockpm(block): ) except KeyError: _not_approved[user] = await asst.send_message( - int(udB.get_key("LOG_CHANNEL")), + udB.get_key("LOG_CHANNEL"), f"#BLOCKED\n\n{inline_mention(aname)} [`{user}`] has been **blocked**.", buttons=[ Button.inline("UnBlock", data=f"unblock_{user}"), @@ -604,7 +609,7 @@ async def unblockpm(event): @ultroid_cmd(pattern="listapproved$", owner=True) async def list_approved(event): xx = await event.eor(get_string("com_1")) - all = get_approved() + all = keym.get() if not all: return await xx.eor("`You haven't approved anyone yet!`", time=5) users = [] @@ -641,8 +646,8 @@ async def apr_in(event): uid = int(event.data_match.group(1).decode("UTF-8")) if uid in DEVLIST: await event.edit("It's a dev! Approved!") - if not is_approved(uid): - approve_user(uid) + if not keym.contains(uid): + keym.add(uid) try: await ultroid_bot.edit_folder(uid, folder=0) except BaseException: @@ -683,8 +688,8 @@ async def apr_in(event): ) async def disapr_in(event): uid = int(event.data_match.group(1).decode("UTF-8")) - if is_approved(uid): - disapprove_user(uid) + if keym.contains(uid): + keym.remove(uid) try: user = await ultroid_bot.get_entity(uid) except BaseException: diff --git a/plugins/polls.py b/plugins/polls.py index 159c73a0de25fc37e20682f280c9df2707ad87ca..138645c8ddce29a9ab5979fff9482c1602641b76 100644 --- a/plugins/polls.py +++ b/plugins/polls.py @@ -58,9 +58,8 @@ async def uri_poll(e): return await e.eor("`Options Should be More than 1..`", time=5) m = await e.eor(get_string("com_1")) OUT = [PollAnswer(option[on], str(on).encode()) for on in range(len(option))] - await e.client.send_file( - e.chat_id, - InputMediaPoll( + await e.respond( + file=InputMediaPoll( Poll(20, ques, OUT, multiple_choice=mpp, public_voters=publ, quiz=quizo), correct_answers=karzo, ), diff --git a/plugins/profanityfilter.py b/plugins/profanityfilter.py index a93e21e7e2ea1b9ab5f2b47ccdeb46fdcbb08721..7272b2c93fda2be6f76121d755f2f1fe4807b206 100644 --- a/plugins/profanityfilter.py +++ b/plugins/profanityfilter.py @@ -20,13 +20,13 @@ from pyUltroid.dB.nsfw_db import profan_chat, rem_profan from . import get_string, ultroid_cmd -@ultroid_cmd(pattern="addprofanity$", admins_only=True) +@ultroid_cmd(pattern="(add|rem)profanity$", admins_only=True) async def addp(e): - profan_chat(e.chat_id, "mute") - await e.eor(get_string("prof_1"), time=10) - - -@ultroid_cmd(pattern="remprofanity", admins_only=True) -async def remp(e): + cas = e.pattern_match.group(1) + add = cas == "add" + if add: + profan_chat(e.chat_id, "mute") + await e.eor(get_string("prof_1"), time=10) + return rem_profan(e.chat_id) await e.eor(get_string("prof_2"), time=10) diff --git a/plugins/profile.py b/plugins/profile.py index 51739508d147316a823a0059800a96b2424c9bfd..d9aa5a5871305fcb6cc9b382349f4bdee3173b40 100644 --- a/plugins/profile.py +++ b/plugins/profile.py @@ -19,7 +19,10 @@ • `{i}delpfp (optional)` Delete one profile pic, if no value given, else delete n number of pics. -• `{i}poto ` +• `{i}poto /reply` + `{i}poto /all` + + Ex: `{i}poto 10` - uploads starting 10 pfps of user. Upload the photo of Chat/User if Available. """ import os @@ -51,8 +54,7 @@ async def _(ult): @ultroid_cmd(pattern="setname ?((.|//)*)", fullsudo=True) async def _(ult): ok = await ult.eor("...") - names = ult.pattern_match.group(1).strip() - first_name = names + names = first_name = ult.pattern_match.group(1).strip() last_name = "" if "//" in names: first_name, last_name = names.split("//", 1) @@ -111,21 +113,56 @@ async def remove_profilepic(delpfp): @ultroid_cmd(pattern="poto( (.*)|$)") async def gpoto(e): ult = e.pattern_match.group(1).strip() + + if e.is_reply: + gs = await e.get_reply_message() + user_id = gs.sender_id + elif ult: + split = ult.split() + user_id = split[0] + if len(ult) > 1: + ult = ult[-1] + else: + ult = None + else: + user_id = e.chat_id + a = await e.eor(get_string("com_1")) + limit = None + just_dl = ult in ["-dl", "--dl"] if just_dl: ult = None - if not ult: - if e.is_reply: - gs = await e.get_reply_message() - ult = gs.sender_id - else: - ult = e.chat_id - okla = await e.client.download_profile_photo(ult) + + if ult and ult != "all": + try: + limit = int(ult) + except ValueError: + pass + + if not limit or e.client._bot: + okla = await e.client.download_profile_photo(user_id) + else: + okla = [] + if limit == "all": + limit = None + async for photo in e.client.iter_profile_photos(user_id, limit=limit): + photo_path = await e.client.download_media(photo) + if photo.video_sizes: + await e.respond(file=photo_path) + os.remove(photo_path) + else: + okla.append(photo_path) if not okla: return await eor(a, "`Pfp Not Found...`") if not just_dl: await a.delete() await e.reply(file=okla) - return os.remove(okla) + if not isinstance(okla, list): + okla = [okla] + for file in okla: + os.remove(file) + return + if isinstance(okla, list): + okla = "\n".join(okla) await a.edit(f"Downloaded pfp to [ `{okla}` ].") diff --git a/plugins/qrcode.py b/plugins/qrcode.py index 529da6edff5926fec09fd43025e4a6c453682e54..5335ee9a73c036482601bf732e283f76b7d7f589 100644 --- a/plugins/qrcode.py +++ b/plugins/qrcode.py @@ -28,7 +28,6 @@ except ImportError: import qrcode from PIL import Image from telethon.tl.types import MessageMediaDocument as doc -from telethon.tl.types import MessageMediaPhoto as photu from . import check_filename, get_string, ultroid_bot, ultroid_cmd @@ -70,11 +69,10 @@ async def cd(e): async def qrwater(e): msg = e.pattern_match.group(1).strip() r = await e.get_reply_message() - if isinstance(r.media, photu): - dl = await e.client.download_media(r.media) - elif isinstance(r.media, doc): - dl = await e.client.download_media(r, thumb=-1) - else: + dl = await e.client.download_media( + r, thumb=-1 if isinstance(r.media, doc) else None + ) + if not dl: return await e.eor("`Reply Any Media and Give Text`", time=5) kk = await e.eor(get_string("com_1")) img_bg = Image.open(dl) @@ -96,11 +94,10 @@ async def decod(e): if not (r and r.media): return await e.eor("`Reply to Qrcode Media`", time=5) kk = await e.eor(get_string("com_1")) - if isinstance(r.media, photu): - dl = await r.download_media() - elif isinstance(r.media, doc): - dl = await r.download_media(thumb=-1) - else: + dl = await e.client.download_media( + r, thumb=-1 if isinstance(r.media, doc) else None + ) + if not dl: return im = cv2.imread(dl) try: diff --git a/plugins/resize.py b/plugins/resize.py index 6d7ba4d4ae555c465e05fdc8c2f895e7d701eb51..5654adbff7c0d1c6a94e976b3069d316c79f0e17 100644 --- a/plugins/resize.py +++ b/plugins/resize.py @@ -36,7 +36,7 @@ async def size(e): @ultroid_cmd(pattern="resize( (.*)|$)") -async def size(e): +async def resize(e): r = await e.get_reply_message() if not (r and r.media): return await e.eor(get_string("ascii_1")) diff --git a/plugins/schedulemsg.py b/plugins/schedulemsg.py index 1cfc5735736b31332ff3ee22482e6e6521d3d4bf..d2b2f89b187aa67698714ffd25debc153014d943 100644 --- a/plugins/schedulemsg.py +++ b/plugins/schedulemsg.py @@ -34,20 +34,18 @@ async def _(e): else: try: z = ban_time(y) - await e.client.send_message(e.chat_id, k, schedule=z) + await e.respond(k, schedule=z) await e.eor(get_string("schdl_1"), time=5) except BaseException: await e.eor(get_string("schdl_2"), time=5) elif xx and x: if x.isdigit(): - await e.client.send_message( - e.chat_id, xx, schedule=timedelta(seconds=int(x)) - ) + await e.respond(xx, schedule=timedelta(seconds=int(x))) await e.eor(get_string("schdl_1"), time=5) else: try: z = ban_time(x) - await e.client.send_message(e.chat_id, xx, schedule=z) + await e.respond(xx, schedule=z) await e.eor(get_string("schdl_1"), time=5) except BaseException: await e.eor(get_string("schdl_2"), time=5) diff --git a/plugins/search.py b/plugins/search.py index 9a7de1e75445930ef1db1d8433c894f48f521581..125734b4d99c3958d8a16ce1ca5bd8da162f91d6 100644 --- a/plugins/search.py +++ b/plugins/search.py @@ -24,7 +24,6 @@ Reply an Image or sticker to find its sauce. """ import os -from shutil import rmtree import requests from bs4 import BeautifulSoup as bs @@ -39,11 +38,10 @@ except ImportError: cv2 = None from telethon.tl.types import DocumentAttributeAudio -from pyUltroid.fns.google_image import googleimagesdownload from pyUltroid.fns.misc import google_search -from pyUltroid.fns.tools import saavn_search +from pyUltroid.fns.tools import get_google_images, saavn_search -from . import async_searcher, con, eod, fast_download, get_string, ultroid_cmd +from . import LOGS, async_searcher, con, eod, fast_download, get_string, ultroid_cmd @ultroid_cmd( @@ -122,20 +120,12 @@ async def goimg(event): query = query.split(";")[0] except BaseException: pass - try: - gi = googleimagesdownload() - args = { - "keywords": query, - "limit": lmt, - "format": "jpg", - "output_directory": "./resources/downloads/", - } - pth = await gi.download(args) - ok = pth[0][query] - except BaseException: - return await nn.edit(get_string("autopic_2").format(query)) - await event.reply(file=ok, message=query) - rmtree(f"./resources/downloads/{query}/") + images = await get_google_images(query) + for img in images[:lmt]: + try: + await event.client.send_file(event.chat_id, file=img["original"]) + except Exception as er: + LOGS.exception(er) await nn.delete() @@ -168,22 +158,16 @@ async def reverse(event): link = alls["href"] text = alls.text await ult.edit(f"`Dimension ~ {x} : {y}`\nSauce ~ [{text}](google.com{link})") - gi = googleimagesdownload() - args = { - "keywords": text, - "limit": 2, - "format": "jpg", - "output_directory": "./resources/downloads/", - } - pth = await gi.download(args) - ok = pth[0][text] - await event.client.send_file( - event.chat_id, - ok, - album=True, - caption="Similar Images Realted to Search", - ) - rmtree(f"./resources/downloads/{text}/") + images = await get_google_images(text) + for z in images[:2]: + try: + await event.client.send_file( + event.chat_id, + file=z["original"], + caption="Similar Images Realted to Search", + ) + except Exception as er: + LOGS.exception(er) os.remove(file) diff --git a/plugins/snips.py b/plugins/snips.py index 90788c74459148ea93f755727b76abb60c3919e6..d876b25a51d973ca90565300f708af0669a13e1f 100644 --- a/plugins/snips.py +++ b/plugins/snips.py @@ -88,9 +88,8 @@ async def rs(e): async def lsnote(e): if x := list_snip(): sd = "SNIPS Found :\n\n" - await e.eor(sd + x) - else: - await e.eor("No Snips Found Here") + return await e.eor(sd + x) + await e.eor("No Snips Found Here") async def add_snips(e): diff --git a/plugins/specialtools.py b/plugins/specialtools.py index b7a1c2bb3be8db2d4140556d3e300f8128a9009b..8cabf4fdf76fed3073745ab9da056b92dda7ae87 100644 --- a/plugins/specialtools.py +++ b/plugins/specialtools.py @@ -35,14 +35,12 @@ import os import time from datetime import datetime as dt from random import choice -from shutil import rmtree import pytz from bs4 import BeautifulSoup as bs from telethon.tl.types import DocumentAttributeVideo -from pyUltroid.fns.google_image import googleimagesdownload -from pyUltroid.fns.tools import metadata +from pyUltroid.fns.tools import get_google_images, metadata from . import ( HNDLR, @@ -284,17 +282,9 @@ async def wall(event): return await event.eor("`Give me something to search..`") nn = await event.eor(get_string("com_1")) query = f"hd {inp}" - gi = googleimagesdownload() - args = { - "keywords": query, - "limit": 10, - "format": "jpg", - "output_directory": "./resources/downloads/", - } - await gi.download(args) - xx = choice(os.listdir(os.path.abspath(f"./resources/downloads/{query}/"))) - await event.client.send_file(event.chat_id, f"./resources/downloads/{query}/{xx}") - rmtree(f"./resources/downloads/{query}/") + images = await get_google_images(query) + for z in range(5): + await event.client.send_file(event.chat_id, file=images[z]["original"]) await nn.delete() diff --git a/plugins/tools.py b/plugins/tools.py index 030ca7cb5972b0e3912b685b10ea0d8b2d2232b6..4171a134ed04bd459d37afe6a10695f47573b0df 100644 --- a/plugins/tools.py +++ b/plugins/tools.py @@ -39,6 +39,7 @@ import glob import io import os +import secrets from asyncio.exceptions import TimeoutError as AsyncTimeout try: @@ -46,10 +47,15 @@ try: except ImportError: cv2 = None +try: + from playwright.async_api import async_playwright +except ImportError: + async_playwright = None try: from htmlwebshot import WebShot except ImportError: WebShot = None + from telethon.errors.rpcerrorlist import MessageTooLongError, YouBlockedUserError from telethon.tl.types import ( ChannelParticipantAdmin, @@ -67,12 +73,12 @@ from . import ( bash, check_filename, con, + download_file, eor, - fast_download, get_string, ) from . import humanbytes as hb -from . import inline_mention, is_url_ok, mediainfo, ultroid_cmd +from . import inline_mention, is_url_ok, json_parser, mediainfo, ultroid_cmd @ultroid_cmd(pattern="tr( (.*)|$)", manager=True) @@ -337,16 +343,16 @@ async def _(e): ) async def lastname(steal): mat = steal.pattern_match.group(1).strip() - if not steal.is_reply and not mat: - return await steal.eor("`Use this command with reply or give Username/id...`") + message = await steal.get_reply_message() if mat: try: user_id = await steal.client.parse_id(mat) except ValueError: user_id = mat - message = await steal.get_reply_message() - if message: - user_id = message.sender.id + elif message: + user_id = message.sender_id + else: + return await steal.eor("`Use this command with reply or give Username/id...`") chat = "@SangMataInfo_bot" id = f"/search_id {user_id}" lol = await steal.eor(get_string("com_1")) @@ -389,20 +395,37 @@ async def webss(event): xurl = event.pattern_match.group(1).strip() if not xurl: return await xx.eor(get_string("wbs_1"), time=5) - if not is_url_ok(xurl): + if not (await is_url_ok(xurl)): return await xx.eor(get_string("wbs_2"), time=5) - try: - shot = WebShot( - quality=88, flags=["--enable-javascript", "--no-stop-slow-scripts"] - ) - pic = await shot.create_pic_async(url=xurl) - except FileNotFoundError: - pic = ( - await fast_download( - f"https://shot.screenshotapi.net/screenshot?&url={xurl}&output=image&file_type=png&wait_for_event=load", - filename=check_filename("shot.png"), + path, pic = check_filename("shot.png"), None + if async_playwright: + try: + async with async_playwright() as playwright: + chrome = await playwright.chromium.launch() + page = await chrome.new_page() + await page.goto(xurl) + await page.screenshot(path=path, full_page=True) + pic = path + except Exception as er: + LOGS.exception(er) + await xx.respond(f"Error with playwright:\n`{er}`") + if WebShot and not pic: + try: + shot = WebShot( + quality=88, flags=["--enable-javascript", "--no-stop-slow-scripts"] ) - )[0] + pic = await shot.create_pic_async(url=xurl) + except Exception as er: + LOGS.exception(er) + if not pic: + pic, msg = await download_file( + f"https://shot.screenshotapi.net/screenshot?&url={xurl}&output=image&file_type=png&wait_for_event=load", + path, + validate=True, + ) + if msg: + await xx.edit(json_parser(msg, indent=1)) + return if pic: await xx.reply( get_string("wbs_3").format(xurl), @@ -420,12 +443,10 @@ async def magic(event): match = event.text.split(maxsplit=1)[1].strip() except IndexError: return await event.eor("`Provide url to turn into tiny...`") - match, id_ = match.split(), None - data = {} - if len(match) > 1: - data["id"] = match[1] - url = match[0] - data["link"] = url + data = { + "url": match.split()[0], + "id": match[1] if len(match) > 1 else secrets.token_urlsafe(6), + } data = await async_searcher( "https://tiny.ultroid.tech/api/new", data=data, diff --git a/plugins/unsplash.py b/plugins/unsplash.py index 2a8980af5a758395df5aaeb89d5242c99785b2c5..c412af23814973f83558b68032c705ebfd696e22 100644 --- a/plugins/unsplash.py +++ b/plugins/unsplash.py @@ -30,9 +30,7 @@ async def searchunsl(ult): if not res: return await ult.eor(get_string("unspl_1"), time=5) CL = [download_file(rp, f"{match}-{e}.png") for e, rp in enumerate(res)] - imgs = [z for z in (await asyncio.gather(*CL)) if z] - await ult.client.send_file( - ult.chat_id, imgs, caption=f"Uploaded {len(imgs)} Images!" - ) + imgs = [z[0] for z in (await asyncio.gather(*CL)) if z] + await ult.respond(f"Uploaded {len(imgs)} Images!", file=imgs) await tep.delete() [os.remove(img) for img in imgs] diff --git a/plugins/utilities.py b/plugins/utilities.py index 7265ca8ec6332cb04031c54cb10de3030e8d06a6..ab4961fee0c9f88cac26e871ada6c37a0bac395e 100644 --- a/plugins/utilities.py +++ b/plugins/utilities.py @@ -82,9 +82,19 @@ from telethon.tl.functions.channels import ( from telethon.tl.functions.contacts import GetBlockedRequest from telethon.tl.functions.messages import AddChatUserRequest, GetAllStickersRequest from telethon.tl.functions.users import GetFullUserRequest -from telethon.tl.types import Channel, Chat, InputMediaPoll, Poll, PollAnswer, User +from telethon.tl.types import ( + Channel, + Chat, + InputMediaPoll, + Poll, + PollAnswer, + TLObject, + User, +) from telethon.utils import get_peer_id +from pyUltroid.fns.info import get_chat_info + from . import ( HNDLR, LOGS, @@ -97,7 +107,6 @@ from . import ( check_filename, eod, eor, - get_chat_info, get_paste, get_string, inline_mention, @@ -512,16 +521,28 @@ async def _(event): else: msg = event reply_to_id = event.message.id - if match and hasattr(msg, match): - msg = getattr(msg, match) - if hasattr(msg, "to_json"): - try: - msg = json_parser(msg.to_json(ensure_ascii=False), indent=1) - except Exception as e: - LOGS.exception(e) + if match and hasattr(msg, match.split()[0]): + msg = getattr(msg, match.split()[0]) + try: + if hasattr(msg, "to_json"): + msg = msg.to_json(ensure_ascii=False, indent=1) + elif hasattr(msg, "to_dict"): + msg = json_parser(msg.to_dict(), indent=1) + else: + msg = TLObject.stringify(msg) + except Exception: + pass msg = str(msg) else: msg = json_parser(msg.to_json(), indent=1) + if "-t" in match: + try: + data = json_parser(msg) + msg = json_parser( + {key: data[key] for key in data.keys() if data[key]}, indent=1 + ) + except Exception: + pass if len(msg) > 4096: with io.BytesIO(str.encode(msg)) as out_file: out_file.name = "json-ult.txt" diff --git a/plugins/videotools.py b/plugins/videotools.py index e95efac351e5a26d8d4adbcfd224d121a1bd168b..77e5578271a80a1bf760b2eed9e5100fa1461dfa 100644 --- a/plugins/videotools.py +++ b/plugins/videotools.py @@ -91,7 +91,7 @@ async def gen_shots(e): if not pic: text = "`Failed to Take Screenshots..`" pic = None - await e.client.send_message(e.chat_id, text, file=pic) + await e.respond(text, file=pic) await bash("rm -rf ss") await xxx.delete() diff --git a/pyUltroid/__init__.py b/pyUltroid/__init__.py index bde4d32e40a5c8eceb99c39c545258926230727c..b104de6da869451eb55bc83154e4d568f8e528ae 100644 --- a/pyUltroid/__init__.py +++ b/pyUltroid/__init__.py @@ -10,15 +10,15 @@ import sys from .version import __version__ -run_as_module = False +run_as_module = __package__ in sys.argv or sys.argv[0] == "-m" + class ULTConfig: lang = "en" thumb = "resources/extras/ultroid.jpg" -if sys.argv[0] == "-m": - run_as_module = True +if run_as_module: import time from .configs import Var @@ -49,6 +49,10 @@ if sys.argv[0] == "-m": BOT_MODE = udB.get_key("BOTMODE") DUAL_MODE = udB.get_key("DUAL_MODE") + USER_MODE = udB.get_key("USER_MODE") + if USER_MODE: + DUAL_MODE = False + if BOT_MODE: if DUAL_MODE: udB.del_key("DUAL_MODE") @@ -70,7 +74,10 @@ if sys.argv[0] == "-m": ) ultroid_bot.run_in_loop(autobot()) - asst = UltroidClient(None, bot_token=udB.get_key("BOT_TOKEN"), udB=udB) + if USER_MODE: + asst = ultroid_bot + else: + asst = UltroidClient(None, bot_token=udB.get_key("BOT_TOKEN"), udB=udB) if BOT_MODE: ultroid_bot = asst @@ -81,7 +88,7 @@ if sys.argv[0] == "-m": ) except Exception as er: LOGS.exception(er) - elif not asst.me.bot_inline_placeholder: + elif not asst.me.bot_inline_placeholder and asst._bot: ultroid_bot.run_in_loop(enable_inline(ultroid_bot, asst.me.username)) vcClient = vc_connection(udB, ultroid_bot) diff --git a/pyUltroid/__main__.py b/pyUltroid/__main__.py index 56a4d607e5fa534658a246dc473951521a66fb4d..c5249e86919e5f1f82933caecb8b6df8564e8502 100644 --- a/pyUltroid/__main__.py +++ b/pyUltroid/__main__.py @@ -13,17 +13,23 @@ def main(): import sys import time - from .fns.helper import time_formatter, updater, bash + from .fns.helper import bash, time_formatter, updater from .startup.funcs import ( WasItRestart, autopilot, customize, + fetch_ann, plug, ready, startup_stuff, ) from .startup.loader import load_other_plugins + try: + from apscheduler.schedulers.asyncio import AsyncIOScheduler + except ImportError: + AsyncIOScheduler = None + # Option to Auto Update On Restarts.. if ( udB.get_key("UPDATE_ON_RESTART") @@ -32,7 +38,7 @@ def main(): ): ultroid_bot.run_in_loop(bash("bash installer.sh")) - os.execl(sys.executable, "python3", "-m", "pyUltroid") + os.execl(sys.executable, sys.executable, "-m", "pyUltroid") ultroid_bot.run_in_loop(startup_stuff()) @@ -79,6 +85,10 @@ def main(): # Send/Ignore Deploy Message.. if not udB.get_key("LOG_OFF"): ultroid_bot.run_in_loop(ready()) + if AsyncIOScheduler: + scheduler = AsyncIOScheduler() + scheduler.add_job(fetch_ann, "interval", minutes=12 * 60) + scheduler.start() # Edit Restarting Message (if It's restarting) ultroid_bot.run_in_loop(WasItRestart(udB)) diff --git a/pyUltroid/_misc/_assistant.py b/pyUltroid/_misc/_assistant.py index c326ee73bc2f7cd2fd5858d7e8f28346986e54dc..83afa459d4b993113079caadef027dd6ac563929 100644 --- a/pyUltroid/_misc/_assistant.py +++ b/pyUltroid/_misc/_assistant.py @@ -50,9 +50,16 @@ def asst_cmd(pattern=None, load=None, owner=False, **kwargs): def ult(func): if pattern: kwargs["pattern"] = re.compile(f"^/{pattern}") - if owner: - kwargs["from_users"] = owner_and_sudos - asst.add_event_handler(func, NewMessage(**kwargs)) + + async def handler(event): + if owner and event.sender_id not in owner_and_sudos(): + return + try: + await func(event) + except Exception as er: + LOGS.exception(er) + + asst.add_event_handler(handler, NewMessage(**kwargs)) if load is not None: append_or_update(load, func, name, kwargs) diff --git a/pyUltroid/_misc/_decorators.py b/pyUltroid/_misc/_decorators.py index 72f1b87ed3aea4eaeecb32036097e644f1fcfdf6..bc93c9247e179037895556cddca8b1fdb03b6211 100644 --- a/pyUltroid/_misc/_decorators.py +++ b/pyUltroid/_misc/_decorators.py @@ -14,7 +14,6 @@ from pathlib import Path from time import gmtime, strftime from traceback import format_exc -from strings import get_string from telethon import Button from telethon import __version__ as telever from telethon import events @@ -35,6 +34,9 @@ from telethon.errors.rpcerrorlist import ( from telethon.events import MessageEdited, NewMessage from telethon.utils import get_display_name +from pyUltroid.exceptions import DependencyMissingError +from strings import get_string + from .. import * from .. import _ignore_eval from ..dB import DEVLIST @@ -96,19 +98,16 @@ def ultroid_cmd( and not (ult.sender_id in DEVLIST) ): return - if admins_only: - if ult.is_private: - return await eod(ult, get_string("py_d3")) - if not (chat.admin_rights or chat.creator): - return await eod(ult, get_string("py_d5")) + if ult.is_private and (groups_only or admins_only): + return await eod(ult, get_string("py_d3")) + elif admins_only and not (chat.admin_rights or chat.creator): + return await eod(ult, get_string("py_d5")) if only_devs and not udB.get_key("I_DEV"): return await eod( ult, get_string("py_d4").format(HNDLR), time=10, ) - if groups_only and ult.is_private: - return await eod(ult, get_string("py_d5")) try: await dec(ult) except FloodWaitError as fwerr: @@ -135,7 +134,7 @@ def ultroid_cmd( ult, get_string("py_d7"), ) - except (BotInlineDisabledError) as er: + except (BotInlineDisabledError, DependencyMissingError) as er: return await eod(ult, f"`{er}`") except ( MessageIdInvalidError, diff --git a/pyUltroid/_misc/_wrappers.py b/pyUltroid/_misc/_wrappers.py index 01c4378ee6eb7ee6db6aa8e86379a9550bca98de..ee6dd345d3ba9d6238a1691812e071d1eddd8733 100644 --- a/pyUltroid/_misc/_wrappers.py +++ b/pyUltroid/_misc/_wrappers.py @@ -19,7 +19,7 @@ async def eor(event, text=None, time=None, link_preview=False, edit_time=None, * if event.out and not isinstance(event, MessageService): if edit_time: await sleep(edit_time) - if "file" in args and args["file"] and not event.media: + if args.get("file") and not event.media: await event.delete() ok = await event.client.send_message( event.chat_id, diff --git a/pyUltroid/dB/asst_fns.py b/pyUltroid/dB/asst_fns.py deleted file mode 100644 index 9a6b933aa461908ab5bcc51844c0d8acd634c312..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/asst_fns.py +++ /dev/null @@ -1,38 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def get_all_users(key): - return udB.get_key(key) or [] - - -def is_added(id_): - return id_ in get_all_users("BOT_USERS") - - -def add_user(id_): - users = get_all_users("BOT_USERS") - users.append(id_) - return udB.set_key("BOT_USERS", users) - - -def is_blacklisted(id_): - return id_ in get_all_users("BOT_BLS") - - -def blacklist_user(id_): - users = get_all_users("BOT_BLS") - users.append(id_) - return udB.set_key("BOT_BLS", users) - - -def rem_blacklist(id_): - users = get_all_users("BOT_BLS") - users.remove(id_) - return udB.set_key("BOT_BLS", users) diff --git a/pyUltroid/dB/autoban_db.py b/pyUltroid/dB/autoban_db.py deleted file mode 100644 index dd91d21249830e2ee988f0a45782295ff55bb288..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/autoban_db.py +++ /dev/null @@ -1,55 +0,0 @@ -from .. import udB - - -def get_all_channels() -> dict: - """List all chats where channels are banned.""" - return udB.get_key("AUTOBAN_CHANNELS") or {} - - -def is_autoban_enabled(chat_id: int) -> bool: - """Check whether channels are banned in a specific chat or not.""" - return chat_id in get_all_channels() - - -def add_channel(chat_id: int) -> bool: - """Enable channel ban in a given chat.""" - if not is_autoban_enabled(int(chat_id)): - channels = get_all_channels() - channels[int(chat_id)] = [] - return udB.set_key("AUTOBAN_CHANNELS", channels) - - -def del_channel(chat_id: int) -> bool: - """Disable channel ban in a given chat.""" - if is_autoban_enabled(chat_id): - channels = get_all_channels() - channels.pop(int(chat_id)) - return udB.set_key("AUTOBAN_CHANNELS", channels) - - -def get_whitelisted_channels(chat_id: int) -> list: - """Get list of whitelisted channels in a given chat.""" - return get_all_channels()[chat_id] if is_autoban_enabled(chat_id) else [] - - -def is_whitelisted(chat_id: int, channel_id: int) -> bool: - """Check whether given channel is whitelisted in given chat or not.""" - return channel_id in get_whitelisted_channels(chat_id) - - -def add_to_whitelist(chat_id: int, channel_id: int) -> bool: - """Add a channel in whitelist in a chat.""" - if is_autoban_enabled(chat_id): - if not is_whitelisted(chat_id, channel_id): - channels = get_all_channels() - channels[int(chat_id)].append(int(channel_id)) - return udB.set_key("AUTOBAN_CHANNELS", channels) - - -def del_from_whitelist(chat_id: int, channel_id: int) -> bool: - """Remove a channel from whitelist in a chat.""" - if is_autoban_enabled(chat_id): - if is_whitelisted(chat_id, channel_id): - channels = get_all_channels() - channels[int(chat_id)].remove(int(channel_id)) - return udB.set_key("AUTOBAN_CHANNELS", channels) diff --git a/pyUltroid/dB/base.py b/pyUltroid/dB/base.py new file mode 100644 index 0000000000000000000000000000000000000000..de26c1542de1ee1144bd70f458e83a3f45e8b3d5 --- /dev/null +++ b/pyUltroid/dB/base.py @@ -0,0 +1,44 @@ +from .. import udB + + +class KeyManager: + def __init__(self, key, cast=None) -> None: + self._key = key + self._cast = cast + + def get(self): + _data = udB.get_key(self._key) + if self._cast and not isinstance(_data, self._cast): + return [_data] if self._cast == list else self._cast(_data) + return _data or (self._cast() if callable(self._cast) else self._cast) + + def get_child(self, key): + return self.get()[key] + + def count(self): + return len(self.get()) + + def add(self, item): + content = self.get() + if content == None and callable(type(item)): + content = type(item)() + if isinstance(content, dict) and isinstance(item, dict): + content.update(item) + elif isinstance(content, list) and item not in content: + content.append(item) + else: + return + udB.set_key(self._key, content) + + def remove(self, item): + content = self.get() + if isinstance(content, list) and item in content: + content.remove(item) + elif isinstance(content, dict) and content.get(item): + del content[item] + else: + return + udB.set_key(self._key, content) + + def contains(self, item): + return item in self.get() diff --git a/pyUltroid/dB/broadcast_db.py b/pyUltroid/dB/broadcast_db.py deleted file mode 100644 index d391aa3d5fe30293791944547a908bc0f7830550..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/broadcast_db.py +++ /dev/null @@ -1,33 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def get_channels(): # Returns List - return udB.get_key("BROADCAST") or [] - - -def is_channel_added(id_): - return id_ in get_channels() - - -def add_channel(id_): - channels = get_channels() - if id_ not in channels: - channels.append(id_) - udB.set_key("BROADCAST", channels) - return True - - -def rem_channel(id_): - channels = get_channels() - if id_ in channels: - channels.remove(id_) - udB.set_key("BROADCAST", channels) - return True - return False diff --git a/pyUltroid/dB/ch_db.py b/pyUltroid/dB/ch_db.py deleted file mode 100644 index 142a1b821af411e3e6c50357f56f7fe70b54a191..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/ch_db.py +++ /dev/null @@ -1,71 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def get_source_channels(): # Returns List - return udB.get_key("CH_SOURCE") or [] - - -def get_no_source_channels(): # Returns List - channels = udB.get_key("CH_SOURCE") or [] - return len(channels) - - -def is_source_channel_added(id_): - channels = get_source_channels() - return id_ in channels - - -def add_source_channel(id_): # Take int or str with numbers only , Returns Boolean - channels = get_source_channels() - if id_ not in channels: - channels.append(id_) - udB.set_key("CH_SOURCE", channels) - return True - - -def rem_source_channel(id_): - channels = get_source_channels() - if id_ in channels: - channels.remove(id_) - udB.set_key("CH_SOURCE", channels) - return True - - -######################### - - -def get_destinations(): # Returns List - return udB.get_key("CH_DESTINATION") or [] - - -def get_no_destinations(): # Returns List - channels = udB.get_key("CH_DESTINATION") or [] - return len(channels) - - -def is_destination_added(id_): - channels = get_destinations() - return id_ in channels - - -def add_destination(id_): # Take int or str with numbers only , Returns Boolean - channels = get_destinations() - if id_ not in channels: - channels.append(id_) - udB.set_key("CH_DESTINATION", channels) - return True - - -def rem_destination(id_): - channels = get_destinations() - if id_ in channels: - channels.remove(id_) - udB.set_key("CH_DESTINATION", channels) - return True diff --git a/pyUltroid/dB/dnd_db.py b/pyUltroid/dB/dnd_db.py deleted file mode 100644 index be49e9de710a8d85e44a86a6344c7a52d4b0fbae..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/dnd_db.py +++ /dev/null @@ -1,29 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - - -from .. import udB - - -def get_dnd_chats(): - return udB.get_key("DND_CHATS") or [] - - -def add_dnd(chat_id): - x = get_dnd_chats() - x.append(int(chat_id)) - return udB.set_key("DND_CHATS", x) - - -def del_dnd(chat_id): - x = get_dnd_chats() - x.remove(int(chat_id)) - return udB.set_key("DND_CHATS", x) - - -def chat_in_dnd(chat_id): - return int(chat_id) in get_dnd_chats() diff --git a/pyUltroid/dB/gcast_blacklist_db.py b/pyUltroid/dB/gcast_blacklist_db.py deleted file mode 100644 index 2622944bf7ec84657564c7ff41bced8fcfc846e2..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/gcast_blacklist_db.py +++ /dev/null @@ -1,29 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . -from .. import udB - - -def get_stuff(): - return udB.get_key("GBLACKLISTS") or [] - - -def add_gblacklist(id): - ok = get_stuff() - if id not in ok: - ok.append(id) - return udB.set_key("GBLACKLISTS", ok) - - -def rem_gblacklist(id): - ok = get_stuff() - if id in ok: - ok.remove(id) - return udB.set_key("GBLACKLISTS", ok) - - -def is_gblacklisted(id): - return id in get_stuff() diff --git a/pyUltroid/dB/logusers_db.py b/pyUltroid/dB/logusers_db.py deleted file mode 100644 index e77cba970dae7f78647967ffb9e761b0db580faa..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/logusers_db.py +++ /dev/null @@ -1,28 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def get_logger(): - return udB.get_key("LOGUSERS") or [] - - -def is_logger(id_): - return id_ in get_logger() - - -def log_user(id_): - pmperm = get_logger() - pmperm.append(id_) - return udB.set_key("LOGUSERS", pmperm) - - -def nolog_user(id_): - pmperm = get_logger() - pmperm.remove(id_) - return udB.set_key("LOGUSERS", pmperm) diff --git a/pyUltroid/dB/night_db.py b/pyUltroid/dB/night_db.py deleted file mode 100644 index daf2a113bed33ecde0e629689076c57621e7e052..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/night_db.py +++ /dev/null @@ -1,27 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def night_grps(): - return udB.get_key("NIGHT_CHATS") or [] - - -def add_night(chat): - chats = night_grps() - if chat not in chats: - chats.append(chat) - return udB.set_key("NIGHT_CHATS", chats) - return - - -def rem_night(chat): - chats = night_grps() - if chat in chats: - chats.remove(chat) - return udB.set_key("NIGHT_CHATS", chats) diff --git a/pyUltroid/dB/pmpermit_db.py b/pyUltroid/dB/pmpermit_db.py deleted file mode 100644 index 28842dccba81307f1ccd2f70a5882ce6de91ef15..0000000000000000000000000000000000000000 --- a/pyUltroid/dB/pmpermit_db.py +++ /dev/null @@ -1,31 +0,0 @@ -# Ultroid - UserBot -# Copyright (C) 2021-2022 TeamUltroid -# -# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > -# PLease read the GNU Affero General Public License in -# . - -from .. import udB - - -def get_approved(): - return udB.get_key("PMPERMIT") or [] - - -def approve_user(id): - ok = get_approved() - if id in ok: - return True - ok.append(id) - return udB.set_key("PMPERMIT", ok) - - -def disapprove_user(id): - ok = get_approved() - if id in ok: - ok.remove(id) - return udB.set_key("PMPERMIT", ok) - - -def is_approved(id): - return id in get_approved() diff --git a/pyUltroid/exceptions.py b/pyUltroid/exceptions.py index 3c14e4e9a2db226a1d2dfc7a891da234e3a65dc4..c53ea7d3c6a1722a2d36531c1a3a467c7c0ceb6e 100644 --- a/pyUltroid/exceptions.py +++ b/pyUltroid/exceptions.py @@ -14,10 +14,6 @@ class pyUltroidError(Exception): ... -class TelethonMissingError(ImportError): - ... - - class DependencyMissingError(ImportError): ... diff --git a/pyUltroid/fns/FastTelethon.py b/pyUltroid/fns/FastTelethon.py index fe3d7756433b326243f44ce1057a7d30ce8d2e1b..991b6175d51716992f143c3985c879b6aa123370 100644 --- a/pyUltroid/fns/FastTelethon.py +++ b/pyUltroid/fns/FastTelethon.py @@ -173,7 +173,7 @@ class ParallelTransferrer: def _get_connection_count( file_size: int, ) -> int: - full_size = 100 * (1024**2) + full_size = 100 * (1024 ** 2) if file_size > full_size: return 20 return math.ceil((file_size / full_size) * 20) @@ -283,7 +283,7 @@ class ParallelTransferrer: connection_count = connection_count or self._get_connection_count(file_size) part_size = (part_size_kb or utils.get_appropriated_part_size(file_size)) * 1024 part_count = (file_size + part_size - 1) // part_size - is_large = file_size > 10 * (1024**2) + is_large = file_size > 10 * (1024 ** 2) await self._init_upload(connection_count, file_id, part_count, is_large) return part_size, part_count, is_large diff --git a/pyUltroid/fns/executor.py b/pyUltroid/fns/executor.py index 4cd972769903d38352bbe1a920506f6f986e536e..06226842b577d0d8d8c3d29d026812227e1c8def 100644 --- a/pyUltroid/fns/executor.py +++ b/pyUltroid/fns/executor.py @@ -74,7 +74,3 @@ class Terminal: self._processes.pop(proc) except KeyError: pass - - -class Executor: - pass diff --git a/pyUltroid/fns/google_image.py b/pyUltroid/fns/google_image.py deleted file mode 100644 index b6e2a7384587487c69b5058b85c9bbfcf37941ce..0000000000000000000000000000000000000000 --- a/pyUltroid/fns/google_image.py +++ /dev/null @@ -1,1159 +0,0 @@ -#!/usr/bin/env python -# In[ ]: -# coding: utf-8 - -###### Searching and Downloading Google Images to the local disk ###### - - -import codecs -import datetime -import http.client -import json -import os -import re -import ssl -import sys -import time # Importing the time library to check the time of code execution -import urllib.request -from http.client import BadStatusLine -from urllib.parse import quote -from urllib.request import HTTPError, Request, URLError, urlopen - -# Import Libraries -from .. import LOGS -from .tools import async_searcher - -http.client._MAXHEADERS = 1000 - -args_list = [ - "keywords", - "keywords_from_file", - "prefix_keywords", - "suffix_keywords", - "limit", - "format", - "color", - "color_type", - "usage_rights", - "size", - "exact_size", - "aspect_ratio", - "type", - "time", - "time_range", - "delay", - "url", - "single_image", - "output_directory", - "image_directory", - "no_directory", - "proxy", - "similar_images", - "specific_site", - "metadata", - "extract_metadata", - "socket_timeout", - "thumbnail", - "thumbnail_only", - "language", - "prefix", - "chromedriver", - "related_images", - "safe_search", - "no_numbering", - "offset", - "no_download", - "save_source", - "ignore_urls", -] - - -class googleimagesdownload: - def __init__(self): - pass - - # Downloading entire Web Document (Raw Page Content) - async def download_page(self, url): - try: - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" - } - - # req = urllib.request.Request(url, headers=headers) - # resp = urllib.request.urlopen(req) - # return str(resp.read()) - resp = await async_searcher(url, re_content=True, headers=headers) - return str(resp) - except Exception as er: - LOGS.exception( - "Could not open URL. Please check your internet connection and/or ssl settings \n" - "If you are using proxy, make sure your proxy settings is configured correctly" - ) - raise er - - # Download Page for more than 100 images - - def download_extended_page(self, url, chromedriver): - from selenium import webdriver - from selenium.webdriver.common.keys import Keys - - options = webdriver.ChromeOptions() - options.add_argument("--no-sandbox") - options.add_argument("--headless") - - try: - browser = webdriver.Chrome(chromedriver, chrome_options=options) - except Exception as e: - LOGS.info( - "Looks like we cannot locate the path the 'chromedriver' (use the '--chromedriver' " - "argument to specify the path to the executable.) or google chrome browser is not " - "installed on your machine (exception: %s)" % e - ) - sys.exit() - browser.set_window_size(1024, 768) - - # Open the link - browser.get(url) - time.sleep(1) - - element = browser.find_element_by_tag_name("body") - # Scroll down - for i in range(30): - element.send_keys(Keys.PAGE_DOWN) - time.sleep(0.3) - - try: - browser.find_element_by_id("smb").click() - for _ in range(50): - element.send_keys(Keys.PAGE_DOWN) - time.sleep(0.3) # bot id protection - except BaseException: - for _ in range(10): - element.send_keys(Keys.PAGE_DOWN) - time.sleep(0.3) # bot id protection - - time.sleep(0.5) - - source = browser.page_source # page source - # close the browser - browser.close() - - return source - - # Correcting the escape characters for python2 - - def replace_with_byte(self, match): - return chr(int(match.group(0)[1:], 8)) - - def repair(self, brokenjson): - # up to 3 digits for byte values up to FF - invalid_escape = re.compile(r"\\[0-7]{1,3}") - return invalid_escape.sub(self.replace_with_byte, brokenjson) - - # Finding 'Next Image' from the given raw page - - def get_next_tab(self, s): - start_line = s.find('class="dtviD"') - if start_line == -1: # If no links are found then give an error! - end_quote = 0 - link = "no_tabs" - return link, "", end_quote - start_line = s.find('class="dtviD"') - start_content = s.find('href="', start_line + 1) - end_content = s.find('">', start_content + 1) - url_item = "https://www.google.com" + str(s[start_content + 6 : end_content]) - url_item = url_item.replace("&", "&") - start_line_2 = s.find('class="dtviD"') - s = s.replace("&", "&") - start_content_2 = s.find(":", start_line_2 + 1) - end_content_2 = s.find("&usg=", start_content_2 + 1) - url_item_name = str(s[start_content_2 + 1 : end_content_2]) - chars = url_item_name.find(",g_1:") - chars_end = url_item_name.find(":", chars + 6) - if chars_end == -1: - updated_item_name = (url_item_name[chars + 5 :]).replace("+", " ") - else: - updated_item_name = (url_item_name[chars + 5 : chars_end]).replace("+", " ") - return url_item, updated_item_name, end_content - - # Getting all links with the help of '_images_get_next_image' - - def get_all_tabs(self, page): - tabs = {} - while True: - item, item_name, end_content = self.get_next_tab(page) - if item == "no_tabs": - break - if len(item_name) > 100 or item_name == "background-color": - break - # Append all the links in the list named 'Links' - tabs[item_name] = item - # Timer could be used to slow down the request for image - # downloads - time.sleep(0.1) - page = page[end_content:] - return tabs - - # Format the object in readable format - - def format_object(self, object): - data = object[1] - main = data[3] - info = data[9] - return { - "image_height": main[2], - "image_width": main[1], - "image_link": main[0], - "image_format": main[0][-1 * (len(main[0]) - main[0].rfind(".") - 1) :], - "image_description": info["2003"][3], - "image_source": info["2003"][2], - "image_thumbnail_url": data[2][0], - } - - # function to download single image - - def single_image(self, image_url): - main_directory = "downloads" - extensions = (".jpg", ".gif", ".png", ".bmp", ".svg", ".webp", ".ico") - url = image_url - try: - os.makedirs(main_directory) - except OSError as e: - if e.errno != 17: - raise - req = Request( - url, - headers={ - "User-Agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.27 Safari/537.17" - }, - ) - - response = urlopen(req, None, 10) - data = response.read() - response.close() - - image_name = str(url[(url.rfind("/")) + 1 :]) - if "?" in image_name: - image_name = image_name[: image_name.find("?")] - # if ".jpg" in image_name or ".gif" in image_name or ".png" in - # image_name or ".bmp" in image_name or ".svg" in image_name or ".webp" - # in image_name or ".ico" in image_name: - if any(map(lambda extension: extension in image_name, extensions)): - file_name = main_directory + "/" + image_name - else: - file_name = main_directory + "/" + image_name + ".jpg" - image_name = image_name + ".jpg" - - try: - with open(file_name, "wb") as output_file: - output_file.write(data) - except OSError as e: - raise e - - def similar_images(self, similar_images): - try: - searchUrl = ( - "https://www.google.com/searchbyimage?site=search&sa=X&image_url=" - + similar_images - ) - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" - } - - req1 = urllib.request.Request(searchUrl, headers=headers) - resp1 = urllib.request.urlopen(req1) - content = str(resp1.read()) - l1 = content.find("AMhZZ") - l2 = content.find("&", l1) - urll = content[l1:l2] - - newurl = ( - "https://www.google.com/search?tbs=sbi:" + urll + "&site=search&sa=X" - ) - req2 = urllib.request.Request(newurl, headers=headers) - urllib.request.urlopen(req2) - l3 = content.find("/search?sa=X&q=") - l4 = content.find(";", l3 + 19) - return content[l3 + 19 : l4] - except BaseException: - return "Cloud not connect to Google Images endpoint" - - # Building URL parameters - def build_url_parameters(self, arguments): - if arguments["language"]: - lang = "&lr=" - lang_param = { - "Arabic": "lang_ar", - "Chinese (Simplified)": "lang_zh-CN", - "Chinese (Traditional)": "lang_zh-TW", - "Czech": "lang_cs", - "Danish": "lang_da", - "Dutch": "lang_nl", - "English": "lang_en", - "Estonian": "lang_et", - "Finnish": "lang_fi", - "French": "lang_fr", - "German": "lang_de", - "Greek": "lang_el", - "Hebrew": "lang_iw ", - "Hungarian": "lang_hu", - "Icelandic": "lang_is", - "Italian": "lang_it", - "Japanese": "lang_ja", - "Korean": "lang_ko", - "Latvian": "lang_lv", - "Lithuanian": "lang_lt", - "Norwegian": "lang_no", - "Portuguese": "lang_pt", - "Polish": "lang_pl", - "Romanian": "lang_ro", - "Russian": "lang_ru", - "Spanish": "lang_es", - "Swedish": "lang_sv", - "Turkish": "lang_tr", - } - lang_url = lang + lang_param[arguments["language"]] - else: - lang_url = "" - - if arguments["time_range"]: - json_acceptable_string = arguments["time_range"].replace("'", '"') - d = json.loads(json_acceptable_string) - time_range = ",cdr:1,cd_min:" + d["time_min"] + ",cd_max:" + d["time_max"] - else: - time_range = "" - - if arguments["exact_size"]: - size_array = [x.strip() for x in arguments["exact_size"].split(",")] - exact_size = ( - ",isz:ex,iszw:" + str(size_array[0]) + ",iszh:" + str(size_array[1]) - ) - else: - exact_size = "" - - built_url = "&tbs=" - counter = 0 - params = { - "color": [ - arguments["color"], - { - "red": "ic:specific,isc:red", - "orange": "ic:specific,isc:orange", - "yellow": "ic:specific,isc:yellow", - "green": "ic:specific,isc:green", - "teal": "ic:specific,isc:teel", - "blue": "ic:specific,isc:blue", - "purple": "ic:specific,isc:purple", - "pink": "ic:specific,isc:pink", - "white": "ic:specific,isc:white", - "gray": "ic:specific,isc:gray", - "black": "ic:specific,isc:black", - "brown": "ic:specific,isc:brown", - }, - ], - "color_type": [ - arguments["color_type"], - { - "full-color": "ic:color", - "black-and-white": "ic:gray", - "transparent": "ic:trans", - }, - ], - "usage_rights": [ - arguments["usage_rights"], - { - "labeled-for-reuse-with-modifications": "sur:fmc", - "labeled-for-reuse": "sur:fc", - "labeled-for-noncommercial-reuse-with-modification": "sur:fm", - "labeled-for-nocommercial-reuse": "sur:f", - }, - ], - "size": [ - arguments["size"], - { - "large": "isz:l", - "medium": "isz:m", - "icon": "isz:i", - ">400*300": "isz:lt,islt:qsvga", - ">640*480": "isz:lt,islt:vga", - ">800*600": "isz:lt,islt:svga", - ">1024*768": "visz:lt,islt:xga", - ">2MP": "isz:lt,islt:2mp", - ">4MP": "isz:lt,islt:4mp", - ">6MP": "isz:lt,islt:6mp", - ">8MP": "isz:lt,islt:8mp", - ">10MP": "isz:lt,islt:10mp", - ">12MP": "isz:lt,islt:12mp", - ">15MP": "isz:lt,islt:15mp", - ">20MP": "isz:lt,islt:20mp", - ">40MP": "isz:lt,islt:40mp", - ">70MP": "isz:lt,islt:70mp", - }, - ], - "type": [ - arguments["type"], - { - "face": "itp:face", - "photo": "itp:photo", - "clipart": "itp:clipart", - "line-drawing": "itp:lineart", - "animated": "itp:animated", - }, - ], - "time": [ - arguments["time"], - { - "past-24-hours": "qdr:d", - "past-7-days": "qdr:w", - "past-month": "qdr:m", - "past-year": "qdr:y", - }, - ], - "aspect_ratio": [ - arguments["aspect_ratio"], - { - "tall": "iar:t", - "square": "iar:s", - "wide": "iar:w", - "panoramic": "iar:xw", - }, - ], - "format": [ - arguments["format"], - { - "jpg": "ift:jpg", - "gif": "ift:gif", - "png": "ift:png", - "bmp": "ift:bmp", - "svg": "ift:svg", - "webp": "webp", - "ico": "ift:ico", - "raw": "ift:craw", - }, - ], - } - for value in params.values(): - if value[0] is not None: - ext_param = value[1][value[0]] - # counter will tell if it is first param added or not - if counter == 0: - # add it to the built url - built_url += ext_param - else: - built_url = built_url + "," + ext_param - counter += 1 - built_url = lang_url + built_url + exact_size + time_range - return built_url - - # building main search URL - - def build_search_url( - self, search_term, params, url, similar_images, specific_site, safe_search - ): - # check the args and choose the URL - if url: - url = url - elif similar_images: - keywordem = self.similar_images(similar_images) - url = ( - "https://www.google.com/search?q=" - + keywordem - + "&espv=2&biw=1366&bih=667&site=webhp&source=lnms&tbm=isch&sa=X&ei=XosDVaCXD8TasATItgE&ved=0CAcQ_AUoAg" - ) - elif specific_site: - url = ( - "https://www.google.com/search?q=" - + quote(search_term.encode("utf-8")) - + "&as_sitesearch=" - + specific_site - + "&espv=2&biw=1366&bih=667&site=webhp&source=lnms&tbm=isch" - + params - + "&sa=X&ei=XosDVaCXD8TasATItgE&ved=0CAcQ_AUoAg" - ) - else: - url = ( - "https://www.google.com/search?q=" - + quote(search_term.encode("utf-8")) - + "&espv=2&biw=1366&bih=667&site=webhp&source=lnms&tbm=isch" - + params - + "&sa=X&ei=XosDVaCXD8TasATItgE&ved=0CAcQ_AUoAg" - ) - - # safe search check - if safe_search: - # check safe_search - safe_search_string = "&safe=active" - url = url + safe_search_string - - return url - - # measures the file size - - def file_size(self, file_path): - if os.path.isfile(file_path): - file_info = os.stat(file_path) - size = file_info.st_size - for x in ["bytes", "KB", "MB", "GB", "TB"]: - if size < 1024.0: - return "%3.1f %s" % (size, x) - size /= 1024.0 - return size - - # keywords from file - def keywords_from_file(self, file_name): - search_keyword = [] - with codecs.open(file_name, "r", encoding="utf-8-sig") as f: - if ".csv" in file_name or ".txt" in file_name: - for line in f: - if line not in ["\n", "\r\n"]: - search_keyword.append(line.replace("\n", "").replace("\r", "")) - else: - LOGS.info( - "Invalid file type: Valid file types are either .txt or .csv \n" - "exiting..." - ) - sys.exit() - return search_keyword - - # make directories - def create_directories(self, main_directory, dir_name, thumbnail, thumbnail_only): - dir_name_thumbnail = dir_name + " - thumbnail" - # make a search keyword directory - try: - if not os.path.exists(main_directory): - os.makedirs(main_directory) - time.sleep(0.15) - path = dir_name - sub_directory = os.path.join(main_directory, path) - if not os.path.exists(sub_directory): - os.makedirs(sub_directory) - if thumbnail or thumbnail_only: - sub_directory_thumbnail = os.path.join( - main_directory, dir_name_thumbnail - ) - if not os.path.exists(sub_directory_thumbnail): - os.makedirs(sub_directory_thumbnail) - except OSError as e: - if e.errno != 17: - raise - - # Download Image thumbnails - - def download_image_thumbnail( - self, - image_url, - main_directory, - dir_name, - return_image_name, - socket_timeout, - no_download, - save_source, - img_src, - ): - if no_download: - return "success", "Printed url without downloading" - try: - req = Request( - image_url, - headers={ - "User-Agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.27 Safari/537.17" - }, - ) - try: - # timeout time to download an image - timeout = float(socket_timeout) if socket_timeout else 10 - response = urlopen(req, None, timeout) - data = response.read() - response.close() - - path = ( - main_directory - + "/" - + dir_name - + " - thumbnail" - + "/" - + return_image_name - ) - - try: - with open(path, "wb") as output_file: - output_file.write(data) - if save_source: - list_path = main_directory + "/" + save_source + ".txt" - with open(list_path, "a") as list_file: - list_file.write(path + "\t" + img_src + "\n") - except OSError as e: - download_status = "fail" - download_message = ( - "OSError on an image...trying next one..." + " Error: " + str(e) - ) - - download_status = "success" - download_message = ( - "Completed Image Thumbnail ====> " + return_image_name - ) - - except UnicodeEncodeError as e: - download_status = "fail" - download_message = ( - "UnicodeEncodeError on an image...trying next one..." - + " Error: " - + str(e) - ) - - except HTTPError as e: # If there is any HTTPError - download_status = "fail" - download_message = ( - "HTTPError on an image...trying next one..." + " Error: " + str(e) - ) - - except URLError as e: - download_status = "fail" - download_message = ( - "URLError on an image...trying next one..." + " Error: " + str(e) - ) - - except ssl.CertificateError as e: - download_status = "fail" - download_message = ( - "CertificateError on an image...trying next one..." - + " Error: " - + str(e) - ) - - except IOError as e: # If there is any IOError - download_status = "fail" - download_message = ( - "IOError on an image...trying next one..." + " Error: " + str(e) - ) - return download_status, download_message - - # Download Images - - def download_image( - self, - image_url, - image_format, - main_directory, - dir_name, - count, - socket_timeout, - prefix, - no_numbering, - no_download, - save_source, - img_src, - thumbnail_only, - format, - ignore_urls, - ): - if ignore_urls and any(url in image_url for url in ignore_urls.split(",")): - return ( - "fail", - "Image ignored due to 'ignore url' parameter", - None, - image_url, - ) - if thumbnail_only: - return ( - "success", - "Skipping image download...", - str(image_url[(image_url.rfind("/")) + 1 :]), - image_url, - ) - if no_download: - return "success", "Printed url without downloading", None, image_url - try: - req = Request( - image_url, - headers={ - "User-Agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.27 Safari/537.17" - }, - ) - try: - # timeout time to download an image - timeout = float(socket_timeout) if socket_timeout else 10 - response = urlopen(req, None, timeout) - data = response.read() - response.close() - - extensions = [ - ".jpg", - ".jpeg", - ".gif", - ".png", - ".bmp", - ".svg", - ".webp", - ".ico", - ] - # keep everything after the last '/' - image_name = str(image_url[(image_url.rfind("/")) + 1 :]) - if format and (not image_format or image_format != format): - download_status = "fail" - download_message = "Wrong image format returned. Skipping..." - return_image_name = "" - absolute_path = "" - return ( - download_status, - download_message, - return_image_name, - absolute_path, - ) - - if ( - image_format == "" - or not image_format - or "." + image_format not in extensions - ): - download_status = "fail" - download_message = "Invalid or missing image format. Skipping..." - return_image_name = "" - absolute_path = "" - return ( - download_status, - download_message, - return_image_name, - absolute_path, - ) - if image_name.lower().find("." + image_format) < 0: - image_name = image_name + "." + image_format - else: - image_name = image_name[ - : image_name.lower().find("." + image_format) - + (len(image_format) + 1) - ] - - # prefix name in image - prefix = prefix + " " if prefix else "" - if no_numbering: - path = main_directory + "/" + dir_name + "/" + prefix + image_name - else: - path = ( - main_directory - + "/" - + dir_name - + "/" - + prefix - + str(count) - + "." - + image_name - ) - try: - with open(path, "wb") as output_file: - output_file.write(data) - if save_source: - list_path = main_directory + "/" + save_source + ".txt" - with open(list_path, "a") as list_file: - list_file.write(path + "\t" + img_src + "\n") - absolute_path = os.path.abspath(path) - except OSError as e: - download_status = "fail" - download_message = ( - "OSError on an image...trying next one..." + " Error: " + str(e) - ) - return_image_name = "" - absolute_path = "" - - # return image name back to calling method to use it for - # thumbnail downloads - download_status = "success" - download_message = ( - "Completed Image ====> " + prefix + str(count) + "." + image_name - ) - return_image_name = prefix + str(count) + "." + image_name - - except UnicodeEncodeError as e: - download_status = "fail" - download_message = ( - "UnicodeEncodeError on an image...trying next one..." - + " Error: " - + str(e) - ) - return_image_name = "" - absolute_path = "" - - except URLError as e: - download_status = "fail" - download_message = ( - "URLError on an image...trying next one..." + " Error: " + str(e) - ) - return_image_name = "" - absolute_path = "" - - except BadStatusLine as e: - download_status = "fail" - download_message = ( - "BadStatusLine on an image...trying next one..." - + " Error: " - + str(e) - ) - return_image_name = "" - absolute_path = "" - - except HTTPError as e: # If there is any HTTPError - download_status = "fail" - download_message = ( - "HTTPError on an image...trying next one..." + " Error: " + str(e) - ) - return_image_name = "" - absolute_path = "" - - except URLError as e: - download_status = "fail" - download_message = ( - "URLError on an image...trying next one..." + " Error: " + str(e) - ) - return_image_name = "" - absolute_path = "" - - except ssl.CertificateError as e: - download_status = "fail" - download_message = ( - "CertificateError on an image...trying next one..." - + " Error: " - + str(e) - ) - return_image_name = "" - absolute_path = "" - - except IOError as e: # If there is any IOError - download_status = "fail" - download_message = ( - "IOError on an image...trying next one..." + " Error: " + str(e) - ) - return_image_name = "" - absolute_path = "" - - return download_status, download_message, return_image_name, absolute_path - - # Finding 'Next Image' from the given raw page - - def _get_next_item(self, s): - start_line = s.find("rg_meta notranslate") - if start_line == -1: # If no links are found then give an error! - end_quote = 0 - link = "no_links" - return link, end_quote - start_line = s.find('class="rg_meta notranslate">') - start_object = s.find("{", start_line + 1) - end_object = s.find("", start_object + 1) - object_raw = str(s[start_object:end_object]) - # remove escape characters based on python version - try: - object_decode = bytes(object_raw, "utf-8").decode("unicode_escape") - final_object = json.loads(object_decode) - except BaseException: - final_object = "" - return final_object, end_object - - # Getting all links with the help of '_images_get_next_image' - - def _get_image_objects(self, s): - start_line = s.find("AF_initDataCallback({key: \\'ds:1\\'") - 10 - start_object = s.find("[", start_line + 1) - end_object = s.find("", start_object + 1) - 4 - object_raw = str(s[start_object:end_object]) - object_decode = bytes(object_raw[:-1], "utf-8").decode("unicode_escape") - # LOGS.info(_format.paste_text(object_decode[:-15])) - return json.loads(object_decode[:-15])[31][0][12][2] - - def _get_all_items(self, page, main_directory, dir_name, limit, arguments): - items = [] - abs_path = [] - errorCount = 0 - i = 0 - count = 1 - # LOGS.info(f"page : {_format.paste_text(page)}") - image_objects = self._get_image_objects(page) - while count < limit + 1: - if not image_objects: - print("no_links") - break - else: - # format the item for readability - try: - object = self.format_object(image_objects[i]) - # download the images - ( - download_status, - download_message, - return_image_name, - absolute_path, - ) = self.download_image( - object["image_link"], - object["image_format"], - main_directory, - dir_name, - count, - arguments["socket_timeout"], - arguments["prefix"], - arguments["no_numbering"], - arguments["no_download"], - arguments["save_source"], - object["image_source"], - arguments["thumbnail_only"], - arguments["format"], - arguments["ignore_urls"], - ) - except (TypeError, IndexError) as er: - LOGS.debug(er) - download_status = None - - if download_status == "success": - - # download image_thumbnails - if arguments["thumbnail"] or arguments["thumbnail_only"]: - ( - download_status, - download_message_thumbnail, - ) = self.download_image_thumbnail( - object["image_thumbnail_url"], - main_directory, - dir_name, - return_image_name, - arguments["socket_timeout"], - arguments["no_download"], - arguments["save_source"], - object["image_source"], - arguments["ignore_urls"], - ) - - count += 1 - object["image_filename"] = return_image_name - # Append all the links in the list named 'Links' - items.append(object) - abs_path.append(absolute_path) - else: - errorCount += 1 - - # delay param - if arguments["delay"]: - time.sleep(int(arguments["delay"])) - i += 1 - if count < limit: - LOGS.info( - "\n\nUnfortunately all " - + str(limit) - + " could not be downloaded because some images were not downloadable. " - + str(count - 1) - + " is all we got for this search filter!" - ) - return items, errorCount, abs_path - - # Bulk Download - - async def download(self, arguments): - paths_agg = {} - # for input coming from other python files - if __name__ != "__main__": - # if the calling file contains config_file param - if "config_file" in arguments: - records = [] - json_file = json.load(open(arguments["config_file"])) - for item in json_file["Records"]: - arguments = {} - for i in args_list: - arguments[i] = None - for key, value in item.items(): - arguments[key] = value - records.append(arguments) - total_errors = 0 - for rec in records: - paths, errors = await self.download_executor(rec) - for i in paths: - paths_agg[i] = paths[i] - total_errors += errors - return paths_agg, total_errors - # if the calling file contains params directly - paths, errors = await self.download_executor(arguments) - for i in paths: - paths_agg[i] = paths[i] - return paths_agg, errors - # for input coming from CLI - paths, errors = await self.download_executor(arguments) - for i in paths: - paths_agg[i] = paths[i] - return paths_agg, errors - - async def download_executor(self, arguments): - paths = {} - errorCount = None - for arg in args_list: - if arg not in arguments: - arguments[arg] = None - # Initialization and Validation of user arguments - if arguments["keywords"]: - search_keyword = [str(item) for item in arguments["keywords"].split(",")] - - if arguments["keywords_from_file"]: - search_keyword = self.keywords_from_file(arguments["keywords_from_file"]) - - # both time and time range should not be allowed in the same query - if arguments["time"] and arguments["time_range"]: - raise ValueError( - "Either time or time range should be used in a query. Both cannot be used at the same time." - ) - - # both time and time range should not be allowed in the same query - if arguments["size"] and arguments["exact_size"]: - raise ValueError( - 'Either "size" or "exact_size" should be used in a query. Both cannot be used at the same time.' - ) - - # both image directory and no image directory should not be allowed in - # the same query - if arguments["image_directory"] and arguments["no_directory"]: - raise ValueError( - "You can either specify image directory or specify no image directory, not both!" - ) - - # Additional words added to keywords - if arguments["suffix_keywords"]: - suffix_keywords = [ - " " + str(sk) for sk in arguments["suffix_keywords"].split(",") - ] - else: - suffix_keywords = [""] - - # Additional words added to keywords - if arguments["prefix_keywords"]: - prefix_keywords = [ - str(sk) + " " for sk in arguments["prefix_keywords"].split(",") - ] - else: - prefix_keywords = [""] - - # Setting limit on number of images to be downloaded - limit = int(arguments["limit"]) if arguments["limit"] else 100 - if arguments["url"]: - current_time = str(datetime.datetime.now()).split(".")[0] - search_keyword = [current_time.replace(":", "_")] - - if arguments["similar_images"]: - current_time = str(datetime.datetime.now()).split(".")[0] - search_keyword = [current_time.replace(":", "_")] - - # If single_image or url argument not present then keywords is - # mandatory argument - if ( - arguments["single_image"] is None - and arguments["url"] is None - and arguments["similar_images"] is None - and arguments["keywords"] is None - and arguments["keywords_from_file"] is None - ): - LOGS.info( - "-------------------------------\n" - "Uh oh! Keywords is a required argument \n\n" - "Please refer to the documentation on guide to writing queries \n" - "https://github.com/hardikvasa/google-images-download#examples" - "\n\nexiting!\n" - "-------------------------------" - ) - sys.exit() - - # If this argument is present, set the custom output directory - main_directory = arguments["output_directory"] or "downloads" - # Proxy settings - if arguments["proxy"]: - os.environ["http_proxy"] = arguments["proxy"] - os.environ["https_proxy"] = arguments["proxy"] - # Initialization Complete - total_errors = 0 - for pky in prefix_keywords: # 1.for every prefix keywords - for sky in suffix_keywords: # 2.for every suffix keywords - for ii, e in enumerate(search_keyword): # 3.for every main keyword - iteration = ( - "\n" - + "Item no.: " - + str(ii + 1) - + " -->" - + " Item name = " - + (pky) - + (e) - + (sky) - ) - search_term = pky + e + sky - - if arguments["image_directory"]: - dir_name = arguments["image_directory"] - elif arguments["no_directory"]: - dir_name = "" - else: - dir_name = search_term + ( - "-" + arguments["color"] if arguments["color"] else "" - ) # sub-directory - - if not arguments["no_download"]: - self.create_directories( - main_directory, - dir_name, - arguments["thumbnail"], - arguments["thumbnail_only"], - ) # create directories in OS - - params = self.build_url_parameters( - arguments - ) # building URL with params - - url = self.build_search_url( - search_term, - params, - arguments["url"], - arguments["similar_images"], - arguments["specific_site"], - arguments["safe_search"], - ) # building main search url - - if limit < 101: - # download page - raw_html = await self.download_page(url) - else: - raw_html = self.download_extended_page( - url, arguments["chromedriver"] - ) - - items, errorCount, abs_path = self._get_all_items( - raw_html, main_directory, dir_name, limit, arguments - ) # get all image items and download images - paths[pky + e + sky] = abs_path - - # dumps into a json file - if arguments["extract_metadata"]: - try: - if not os.path.exists("logs"): - os.makedirs("logs") - except OSError as e: - LOGS.exception(e) - with open("logs/" + e + ".json", "w") as json_file: - json.dump(items, json_file, indent=4, sort_keys=True) - # Related images - if arguments["related_images"]: - tabs = self.get_all_tabs(raw_html) - for key, value in tabs.items(): - final_search_term = search_term + " - " + key - if limit < 101: - new_raw_html = await self.download_page( - value - ) # download page - else: - new_raw_html = self.download_extended_page( - value, arguments["chromedriver"] - ) - self.create_directories( - main_directory, - final_search_term, - arguments["thumbnail"], - arguments["thumbnail_only"], - ) - self._get_all_items( - new_raw_html, - main_directory, - search_term + " - " + key, - limit, - arguments, - ) - - total_errors += errorCount - return paths, total_errors diff --git a/pyUltroid/fns/helper.py b/pyUltroid/fns/helper.py index e787fcdcb920dddb79fe27f1364e4a6a202d7507..d9396d141356356e6a3bf92328ec52bd8a16fb3e 100644 --- a/pyUltroid/fns/helper.py +++ b/pyUltroid/fns/helper.py @@ -20,10 +20,11 @@ from .. import run_as_module if run_as_module: from ..configs import Var + try: - import aiohttp + from aiohttp import ClientSession as aiohttp_client except ImportError: - aiohttp = None + aiohttp_client = None try: import requests except ImportError: @@ -52,6 +53,7 @@ from telethon.utils import get_display_name from .._misc import CMD_HELP from .._misc._wrappers import eod, eor +from ..exceptions import DependencyMissingError from . import * if run_as_module: @@ -215,11 +217,10 @@ if run_as_module: await xx.delete() async def def_logs(ult, file): - await ult.client.send_file( - ult.chat_id, + await ult.respond( + "**Ultroid Logs.**", file=file, thumb=ULTConfig.thumb, - caption="**Ultroid Logs.**", ) async def updateme_requirements(): @@ -262,9 +263,8 @@ async def bash(cmd, run_code=0): err = stderr.decode().strip() or None out = stdout.decode().strip() if not run_code and err: - split = cmd.split()[0] - if f"{split}: not found" in err: - return out, f"{split.upper()}_NOT_FOUND" + if match := re.match("\/bin\/sh: (.*): ?(\w+): not found", err): + return out, f"{match.group(2).upper()}_NOT_FOUND" return out, err @@ -347,30 +347,70 @@ async def downloader(filename, file, event, taime, msg): return result +# ~~~~~~~~~~~~~~~Async Searcher~~~~~~~~~~~~~~~ +# @buddhhu + + +async def async_searcher( + url: str, + post: bool = False, + head: bool = False, + headers: dict = None, + evaluate=None, + object: bool = False, + re_json: bool = False, + re_content: bool = False, + *args, + **kwargs, +): + if aiohttp_client: + async with aiohttp_client(headers=headers) as client: + method = client.head if head else (client.post if post else client.get) + data = await method(url, *args, **kwargs) + if evaluate: + return await evaluate(data) + if re_json: + return await data.json() + if re_content: + return await data.read() + if head or object: + return data + return await data.text() + # elif requests: + # method = requests.head if head else (requests.post if post else requests.get) + # data = method(url, headers=headers, *args, **kwargs) + # if re_json: + # return data.json() + # if re_content: + # return data.content + # if head or object: + # return data + # return data.text + else: + raise DependencyMissingError("install 'aiohttp' to use this.") + + # ~~~~~~~~~~~~~~~~~~~~DDL Downloader~~~~~~~~~~~~~~~~~~~~ # @buddhhu @new-dev0 -async def download_file(link, name): +async def download_file(link, name, validate=False): """for files, without progress callback with aiohttp""" - if aiohttp: - async with aiohttp.ClientSession() as ses: - async with ses.get(link) as re_ses: - with open(name, "wb") as file: - file.write(await re_ses.read()) - elif requests: - content = requests.get(link).content + + async def _download(content): + if validate and "application/json" in content.headers.get("Content-Type"): + return None, await content.json() with open(name, "wb") as file: - file.write(content) - else: - raise Exception("Aiohttp or requests is not installed.") - return name + file.write(await content.read()) + return name, "" + + return await async_searcher(link, evaluate=_download) async def fast_download(download_url, filename=None, progress_callback=None): - if not aiohttp: - return await download_file(download_url, filename) - async with aiohttp.ClientSession() as session: + if not aiohttp_client: + return await download_file(download_url, filename)[0], None + async with aiohttp_client() as session: async with session.get(download_url, timeout=None) as response: if not filename: filename = unquote(download_url.rpartition("/")[-1]) @@ -467,6 +507,7 @@ def humanbytes(size): def numerize(number): if not number: return None + unit = "" for unit in ["", "K", "M", "B", "T"]: if number < 1000: break diff --git a/pyUltroid/fns/info.py b/pyUltroid/fns/info.py index 76a8f4c7439cd2bb396360889d783e26a56b2987..f57b8b0bbd48bc08d3d3e6c07e402a3eae06b63e 100644 --- a/pyUltroid/fns/info.py +++ b/pyUltroid/fns/info.py @@ -10,14 +10,7 @@ import math -from ..exceptions import TelethonMissingError - -try: - from telethon.tl import functions, types -except ImportError: - raise TelethonMissingError( - f"'Telethon is not Installed!'\nfunctions present in '{__name__}' needs telethon to be installed!" - ) +from telethon.tl import functions, types from .. import LOGS diff --git a/pyUltroid/fns/misc.py b/pyUltroid/fns/misc.py index d852025df6da9b711817c317b4dcd2ccdeece948..6438570c9cdc8e7d5090e2e19f6b664f994124fe 100644 --- a/pyUltroid/fns/misc.py +++ b/pyUltroid/fns/misc.py @@ -32,21 +32,13 @@ if run_as_module: from ..dB._core import LIST from . import some_random_headers -from .tools import async_searcher, check_filename, json_parser +from .helper import async_searcher +from .tools import check_filename, json_parser try: - import aiofiles import aiohttp except ImportError: aiohttp = None - aiofiles = None - -try: - from instagrapi import Client - from instagrapi.exceptions import LoginRequired, ManualInputRequired -except ImportError: - Client = None - ManualInputRequired = None try: from PIL import Image @@ -116,9 +108,9 @@ async def YtDataScraper(url: str): common_data["videoActions"]["menuRenderer"]["topLevelButtons"][0][ "toggleButtonRenderer" ]["defaultText"]["simpleText"] - or like_dislike[0]["toggleButtonRenderer"]["defaultText"]["accessibility"][ - "accessibilityData" - ]["label"] + # or like_dislike[0]["toggleButtonRenderer"]["defaultText"]["accessibility"][ + # "accessibilityData" + # ]["label"] ) to_return["description"] = description return to_return @@ -184,9 +176,8 @@ async def ReTrieveFile(input_file_name): return False, (await out.json()) name = check_filename("ult-rmbg.png") - file = await aiofiles.open(name, "wb") - await file.write(await out.read()) - await file.close() + with open(name, "wb") as file: + file.write(await out.read()) return True, name @@ -199,11 +190,10 @@ async def unsplashsearch(query, limit=None, shuf=True): link = "https://unsplash.com/s/photos/" + query extra = await async_searcher(link, re_content=True) res = BeautifulSoup(extra, "html.parser", from_encoding="utf-8") - all_ = res.find_all("img", "YVj9w") + all_ = res.find_all("img", srcset=re.compile("images.unsplash.com/photo")) if shuf: shuffle(all_) - all_ = all_[:limit] - return [image["src"] for image in all_] + return list(map(lambda e: e['src'], all_[:limit])) # ---------------- Random User Gen ---------------- @@ -278,96 +268,6 @@ async def get_synonyms_or_antonyms(word, type_of_words): return [y["term"] for y in li_1] -# --------------------- Instagram Plugin ------------------------- # -# @New-dev0 - -INSTA_CLIENT = [] - - -async def _insta_login(): - if "insta_creds" in ultroid_bot._cache: - return ultroid_bot._cache["insta_creds"] - username = udB.get_key("INSTA_USERNAME") - password = udB.get_key("INSTA_PASSWORD") - if username and password: - settings = eval(udB["INSTA_SET"]) if udB.get_key("INSTA_SET") else {} - cl = Client(settings) - try: - cl.login(username, password) - ultroid_bot._cache.update({"insta_creds": cl}) - except ManualInputRequired: - LOGS.exception(format_exc()) - # await get_insta_code(cl, username, password) - return False - except LoginRequired: - udB.del_key("INSTA_SET") - return await _insta_login() - except Exception: - udB.del_key(iter(["INSTA_USERNAME", "INSTA_PASSWORD"])) - LOGS.exception(format_exc()) - return False - udB.set_key("INSTA_SET", str(cl.get_settings())) - cl.logger.setLevel(WARNING) - return ultroid_bot._cache["insta_creds"] - return False - - -async def get_insta_code(username, choice): - from .. import asst, ultroid_bot - - async with asst.conversation(ultroid_bot.uid, timeout=60 * 2) as conv: - await conv.send_message( - "Enter The **Instagram Verification Code** Sent to Your Email.." - ) - ct = await conv.get_response() - while not ct.text.isdigit(): - if ct.message == "/cancel": - await conv.send_message("Cancelled Verification!") - return - await conv.send_message( - "CODE SHOULD BE INTEGER\nSend The Code Back or\nUse /cancel to Cancel Process..." - ) - ct = await conv.get_response() - return ct.text - - -async def create_instagram_client(event): - if not Client: - await event.eor("`Instagrapi not Found\nInstall it to use Instagram plugin...`") - return - try: - return INSTA_CLIENT[0] - except IndexError: - pass - from .. import udB - - username = udB.get_key("INSTA_USERNAME") - password = udB.get_key("INSTA_PASSWORD") - if not (username and password): - await event.eor("`Please Fill Instagram Credentials to Use This...`") - return - settings = udB.get_key("INSTA_SET") or {} - cl = Client(settings) - cl.challenge_code_handler = get_insta_code - try: - cl.login(username, password) - except ManualInputRequired: - await eor(event, f"Check Pm From @{asst.me.username}") - await get_insta_code(cl, username, password) - except LoginRequired: - # "login required" refers to relogin... - udB.del_key("INSTA_SET") - return await create_instagram_client(event) - except Exception as er: - LOGS.exception(er) - await eor(event, str(er)) - return False - udB.set_key("INSTA_SET", str(cl.get_settings())) - cl.logger.setLevel(WARNING) - INSTA_CLIENT.append(cl) - return cl - - # Quotly @@ -421,11 +321,9 @@ class Quotly: last_name = None if sender and sender.id not in DEVLIST: id_ = get_peer_id(sender) - name = get_display_name(sender) elif not is_fwd: id_ = event.sender_id sender = await event.get_sender() - name = get_display_name(sender) else: id_, sender = None, None name = is_fwd.from_name @@ -433,11 +331,12 @@ class Quotly: id_ = get_peer_id(is_fwd.from_id) try: sender = await event.client.get_entity(id_) - name = get_display_name(sender) except ValueError: pass - if sender and hasattr(sender, "last_name"): - last_name = sender.last_name + if sender: + name = get_display_name(sender) + if hasattr(sender, "last_name"): + last_name = sender.last_name entities = [] if event.entities: for entity in event.entities: @@ -455,6 +354,7 @@ class Quotly: text += f" in {rep.game.title}" elif isinstance(event.action, types.MessageActionPinMessage): text = "pinned a message." + # TODO: Are there any more events with sender? message = { "entities": entities, "chatId": id_, @@ -467,7 +367,7 @@ class Quotly: "username": sender.username if sender else None, "language_code": "en", "title": name, - "name": name or "Unknown", + "name": name or "Deleted Account", "type": type_, }, "text": text, @@ -483,7 +383,7 @@ class Quotly: async def create_quotly( self, event, - url="https://qoute-api-akashpattnaik.koyeb.app/generate", + url="https://bot.lyo.su/quote/generate", reply={}, bg=None, sender=None, @@ -531,9 +431,6 @@ class Quotly: raise Exception(str(request)) -# Some Sarcasm - - def split_list(List, index): new_ = [] while List: diff --git a/pyUltroid/fns/tools.py b/pyUltroid/fns/tools.py index e625ceac2018900b28c3deca484d55ab131fe637..646f738e0830b4f3fe3cc83b5bb6737d0b948496 100644 --- a/pyUltroid/fns/tools.py +++ b/pyUltroid/fns/tools.py @@ -16,9 +16,12 @@ from io import BytesIO from json.decoder import JSONDecodeError from traceback import format_exc +import requests + from .. import * from ..exceptions import DependencyMissingError -from .helper import bash, run_async +from . import some_random_headers +from .helper import async_searcher, bash, run_async try: import certifi @@ -33,11 +36,6 @@ except ImportError: from urllib.parse import quote, unquote -try: - import requests - from requests.exceptions import MissingSchema -except ImportError: - requests = None from telethon import Button from telethon.tl.types import DocumentAttributeAudio, DocumentAttributeVideo @@ -54,6 +52,11 @@ try: except ImportError: Telegraph = None +try: + from bs4 import BeautifulSoup +except ImportError: + BeautifulSoup = None + # ~~~~~~~~~~~~~~~~~~~~OFOX API~~~~~~~~~~~~~~~~~~~~ # @buddhhu @@ -69,46 +72,6 @@ async def get_ofox(codename): return device, releases -# ~~~~~~~~~~~~~~~Async Searcher~~~~~~~~~~~~~~~ -# @buddhhu - - -async def async_searcher( - url: str, - post: bool = None, - headers: dict = None, - params: dict = None, - json: dict = None, - data: dict = None, - ssl=None, - re_json: bool = False, - re_content: bool = False, - real: bool = False, - *args, - **kwargs, -): - try: - import aiohttp - except ImportError: - raise DependencyMissingError( - "'aiohttp' is not installed!\nthis function requires aiohttp to be installed." - ) - async with aiohttp.ClientSession(headers=headers) as client: - if post: - data = await client.post( - url, json=json, data=data, ssl=ssl, *args, **kwargs - ) - else: - data = await client.get(url, params=params, ssl=ssl, *args, **kwargs) - if re_json: - return await data.json() - if re_content: - return await data.read() - if real: - return data - return await data.text() - - # ~~~~~~~~~~~~~~~JSON Parser~~~~~~~~~~~~~~~ # @buddhhu @@ -138,18 +101,12 @@ def json_parser(data, indent=None, ascii=False): # ~~~~~~~~~~~~~~~~Link Checker~~~~~~~~~~~~~~~~~ -def is_url_ok(url: str): - try: - import requests - except ImportError: - raise DependencyMissingError("This function needs 'requests' to be installed.") +async def is_url_ok(url: str): try: - r = requests.head(url) - except MissingSchema: - return None - except BaseException: + return await async_searcher(url, head=True) + except BaseException as er: + LOGS.debug(er) return False - return r.ok # ~~~~~~~~~~~~~~~~ Metadata ~~~~~~~~~~~~~~~~~~~~ @@ -158,7 +115,9 @@ def is_url_ok(url: str): async def metadata(file): out, _ = await bash(f'mediainfo "{_unquote_text(file)}" --Output=JSON') if _ and _.endswith("NOT_FOUND"): - raise Exception(_) + raise DependencyMissingError( + f"'{_}' is not installed!\nInstall it to use this command." + ) data = {} _info = json.loads(out)["media"]["track"] info = _info[0] @@ -403,6 +362,77 @@ async def get_paste(data: str, extension: str = "txt"): return None, str(e) +# -------------------------------------- +# https://stackoverflow.com/a/74563494 + + +async def get_google_images(query): + soup = BeautifulSoup( + await async_searcher( + "https://google.com/search", + params={"q": query, "tbm": "isch"}, + headers={"User-Agent": random.choice(some_random_headers)}, + ), + "lxml", + ) + google_images = [] + all_script_tags = soup.select("script") + matched_images_data = "".join( + re.findall(r"AF_initDataCallback\(([^<]+)\);", str(all_script_tags)) + ) + matched_images_data_fix = json.dumps(matched_images_data) + matched_images_data_json = json.loads(matched_images_data_fix) + matched_google_image_data = re.findall( + r"\"b-GRID_STATE0\"(.*)sideChannel:\s?{}}", matched_images_data_json + ) + matched_google_images_thumbnails = ", ".join( + re.findall( + r"\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]", + str(matched_google_image_data), + ) + ).split(", ") + thumbnails = [ + bytes(bytes(thumbnail, "ascii").decode("unicode-escape"), "ascii").decode( + "unicode-escape" + ) + for thumbnail in matched_google_images_thumbnails + ] + removed_matched_google_images_thumbnails = re.sub( + r"\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]", + "", + str(matched_google_image_data), + ) + matched_google_full_resolution_images = re.findall( + r"(?:'|,),\[\"(https:|http.*?)\",\d+,\d+\]", + removed_matched_google_images_thumbnails, + ) + full_res_images = [ + bytes(bytes(img, "ascii").decode("unicode-escape"), "ascii").decode( + "unicode-escape" + ) + for img in matched_google_full_resolution_images + ] + for index, (metadata, thumbnail, original) in enumerate( + zip(soup.select(".isv-r.PNCib.MSM1fd.BUooTd"), thumbnails, full_res_images), + start=1, + ): + google_images.append( + { + "title": metadata.select_one(".VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb")[ + "title" + ], + "link": metadata.select_one(".VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb")[ + "href" + ], + "source": metadata.select_one(".fxgdke").text, + "thumbnail": thumbnail, + "original": original, + } + ) + random.shuffle(google_images) + return google_images + + # Thanks https://t.me/KukiUpdates/23 for ChatBotApi @@ -555,24 +585,29 @@ def make_html_telegraph(title, html=""): async def Carbon( code, - base_url="https://rayso-api-desvhu-33.koyeb.app/generate", + base_url="https://carbonara.vercel.app/api/cook", file_name="ultroid", download=False, rayso=False, **kwargs, ): - # if rayso: - kwargs["text"] = code - kwargs["theme"] = kwargs.get("theme", "meadow") - kwargs["darkMode"] = kwargs.get("darkMode", True) - kwargs["title"] = kwargs.get("title", "Ultroid") - # else: - # kwargs["code"] = code + if rayso: + base_url = "https://rayso-api-desvhu-33.koyeb.app/generate" + kwargs["text"] = code + kwargs["theme"] = kwargs.get("theme", "breeze") + kwargs["darkMode"] = kwargs.get("darkMode", True) + kwargs["title"] = kwargs.get("title", "Ultroid") + else: + kwargs["code"] = code con = await async_searcher(base_url, post=True, json=kwargs, re_content=True) if not download: file = BytesIO(con) file.name = file_name + ".jpg" else: + try: + return json_parser(con.decode()) + except Exception: + pass file = file_name + ".jpg" with open(file, "wb") as f: f.write(con) diff --git a/pyUltroid/loader.py b/pyUltroid/loader.py index aa1f4a8d14a0ba9e3e2dbfecf547f31e20c0b3e4..79e8374ba2bdef45d7fae8b2404c67703eb7811a 100644 --- a/pyUltroid/loader.py +++ b/pyUltroid/loader.py @@ -30,6 +30,7 @@ class Loader: after_load=None, load_all=False, ): + _single = os.path.isfile(self.path) if include: if log: self._logger.info("Including: {}".format("• ".join(include))) @@ -38,6 +39,8 @@ class Loader: path = f"{self.path}/{file}.py" if os.path.exists(path): files.append(path) + elif _single: + files = [self.path] else: if load_all: files = get_all_files(self.path, ".py") @@ -48,7 +51,7 @@ class Loader: if not path.startswith("_"): with contextlib.suppress(ValueError): files.remove(f"{self.path}/{path}.py") - if log: + if log and not _single: self._logger.info( f"• Installing {self.key} Plugins || Count : {len(files)} •" ) @@ -60,22 +63,15 @@ class Loader: except ModuleNotFoundError as er: modl = None self._logger.error(f"{plugin}: '{er.name}' not installed!") + continue except Exception as exc: modl = None self._logger.error(f"pyUltroid - {self.key} - ERROR - {plugin}") self._logger.exception(exc) + continue + if _single and log: + self._logger.info(f"Successfully Loaded {plugin}!") if callable(after_load): if func == import_module: plugin = plugin.split(".")[-1] after_load(self, modl, plugin_name=plugin) - - def load_single(self, log=False): - """To Load Single File""" - plugin = self.path.replace(".py", "").replace("/", ".") - try: - import_module(plugin) - except Exception as er: - self._logger.info(f"Error while Loading {plugin}") - return self._logger.exception(er) - if log and self._logger: - self._logger.info(f"Successfully Loaded {plugin}!") diff --git a/pyUltroid/startup/BaseClient.py b/pyUltroid/startup/BaseClient.py index 3d037b4f63737c48601ca28fbb9ae7d33392dcea..bcee8aee27b2f3dba811458b94057c372fae1cd8 100644 --- a/pyUltroid/startup/BaseClient.py +++ b/pyUltroid/startup/BaseClient.py @@ -114,7 +114,7 @@ class UltroidClient(TelegramClient): by_bot = self._bot size = os.path.getsize(file) # Don't show progress bar when file size is less than 5MB. - if size < 5 * 2**20: + if size < 5 * 2 ** 20: show_progress = False if use_cache and self._cache and self._cache.get("upload_cache"): for files in self._cache["upload_cache"]: @@ -170,11 +170,11 @@ class UltroidClient(TelegramClient): """Download files in a faster way""" # Set to True and pass event to show progress bar. show_progress = kwargs.get("show_progress", False) - filename = kwargs.get("filename", None) + filename = kwargs.get("filename", "") if show_progress: event = kwargs["event"] # Don't show progress bar when file size is less than 10MB. - if file.size < 10 * 2**20: + if file.size < 10 * 2 ** 20: show_progress = False import mimetypes diff --git a/pyUltroid/startup/__init__.py b/pyUltroid/startup/__init__.py index 313035633684c6e460fbfd101fdf7ca44252da63..30c3e92f3db60b4e83b34370c800683184a8cf52 100644 --- a/pyUltroid/startup/__init__.py +++ b/pyUltroid/startup/__init__.py @@ -11,6 +11,7 @@ import sys from logging import INFO, WARNING, FileHandler, StreamHandler, basicConfig, getLogger from .. import run_as_module +from ._extra import _ask_input if run_as_module: from ..configs import Var @@ -28,6 +29,8 @@ def where_hosted(): if os.getenv("KUBERNETES_PORT"): return "qovery | kubernetes" if os.getenv("RUNNER_USER") or os.getenv("HOSTNAME"): + if os.getenv("USER") == "codespace": + return "codespace" return "github actions" if os.getenv("ANDROID_ROOT"): return "termux" @@ -60,10 +63,7 @@ if run_as_module: _fix_logging(FileHandler) - if HOSTED_ON == "local": - from ._extra import _ask_input - - _ask_input() + _ask_input() _LOG_FORMAT = "%(asctime)s | %(name)s [%(levelname)s] : %(message)s" basicConfig( diff --git a/pyUltroid/startup/_database.py b/pyUltroid/startup/_database.py index 98a5be9d0b4553f36dc54e1254194be49fdad3e6..5a87bfdb3f505302e525f66ede8bf717b811cd9c 100644 --- a/pyUltroid/startup/_database.py +++ b/pyUltroid/startup/_database.py @@ -17,33 +17,33 @@ if run_as_module: Redis = MongoClient = psycopg2 = Database = None -if (Var.REDIS_URI or Var.REDISHOST): +if Var.REDIS_URI or Var.REDISHOST: try: from redis import Redis except ImportError: LOGS.info("Installing 'redis' for database.") - os.system("pip3 install -q redis hiredis") + os.system(f"{sys.executable} -m pip install -q redis hiredis") from redis import Redis elif Var.MONGO_URI: try: from pymongo import MongoClient except ImportError: LOGS.info("Installing 'pymongo' for database.") - os.system("pip3 install -q pymongo[srv]") + os.system(f"{sys.executable} -m pip install -q pymongo[srv]") from pymongo import MongoClient elif Var.DATABASE_URL: try: import psycopg2 except ImportError: LOGS.info("Installing 'pyscopg2' for database.") - os.system("pip3 install -q psycopg2-binary") + os.system(f"{sys.executable} -m pip install -q psycopg2-binary") import psycopg2 else: try: from localdb import Database except ImportError: LOGS.info("Using local file as database.") - os.system("pip3 install -q localdb.json") + os.system(f"{sys.executable} -m pip install -q localdb.json") from localdb import Database # --------------------------------------------------------------------------------------------- # @@ -84,16 +84,18 @@ class _BaseDatabase: def _get_data(self, key=None, data=None): if key: data = self.get(str(key)) - if data: + if data and isinstance(data, str): try: data = ast.literal_eval(data) except BaseException: pass return data - def set_key(self, key, value): + def set_key(self, key, value, cache_only=False): value = self._get_data(data=value) self._cache[key] = value + if cache_only: + return return self.set(str(key), str(value)) def rename(self, key1, key2): @@ -129,12 +131,11 @@ class MongoDB(_BaseDatabase): def keys(self): return self.db.list_collection_names() - def set_key(self, key, value): + def set(self, key, value): if key in self.keys(): self.db[key].replace_one({"_id": key}, {"value": str(value)}) else: self.db[key].insert_one({"_id": key, "value": str(value)}) - self._cache.update({key: value}) return True def delete(self, key): @@ -278,9 +279,9 @@ class RedisDB(_BaseDatabase): if var: hash_ = var.split("_", maxsplit=2)[1].split("_")[0] if hash: - kwargs["host"] = os.environ(f"QOVERY_REDIS_{hash_}_HOST") - kwargs["port"] = os.environ(f"QOVERY_REDIS_{hash_}_PORT") - kwargs["password"] = os.environ(f"QOVERY_REDIS_{hash_}_PASSWORD") + kwargs["host"] = os.environ.get(f"QOVERY_REDIS_{hash_}_HOST") + kwargs["port"] = os.environ.get(f"QOVERY_REDIS_{hash_}_PORT") + kwargs["password"] = os.environ.get(f"QOVERY_REDIS_{hash_}_PASSWORD") self.db = Redis(**kwargs) self.set = self.db.set self.get = self.db.get @@ -303,8 +304,15 @@ class RedisDB(_BaseDatabase): class LocalDB(_BaseDatabase): def __init__(self): self.db = Database("ultroid") + self.get = self.db.get + self.set = self.db.set + self.delete = self.db.delete super().__init__() + @property + def name(self): + return "LocalDB" + def keys(self): return self._cache.keys() @@ -315,6 +323,7 @@ class LocalDB(_BaseDatabase): def UltroidDB(): _er = False from .. import HOSTED_ON + try: if Redis: return RedisDB( @@ -337,8 +346,9 @@ def UltroidDB(): LOGS.critical( "No DB requirement fullfilled!\nPlease install redis, mongo or sql dependencies...\nTill then using local file as database." ) - if HOSTED_ON == "termux": + if HOSTED_ON == "local": return LocalDB() exit() + # --------------------------------------------------------------------------------------------- # diff --git a/pyUltroid/startup/connections.py b/pyUltroid/startup/connections.py index 521ec385acc85ec3545df2b85566d72ddc5d184b..fd9086aca8880abc1bc76a5f3d3b23ced6bb3dbb 100644 --- a/pyUltroid/startup/connections.py +++ b/pyUltroid/startup/connections.py @@ -32,6 +32,7 @@ DC_IPV4 = { def validate_session(session, logger=LOGS, _exit=True): from strings import get_string + if session: # Telethon Session if session.startswith(CURRENT_VERSION): @@ -39,18 +40,18 @@ def validate_session(session, logger=LOGS, _exit=True): logger.exception(get_string("py_c1")) sys.exit() return StringSession(session) + # Pyrogram Session elif len(session) in _PYRO_FORM.keys(): + data_ = struct.unpack( + _PYRO_FORM[len(session)], + base64.urlsafe_b64decode(session + "=" * (-len(session) % 4)), + ) if len(session) in [351, 356]: - dc_id, _, auth_key, _, _ = struct.unpack( - _PYRO_FORM[len(session)], - base64.urlsafe_b64decode(session + "=" * (-len(session) % 4)), - ) + auth_id = 2 else: - dc_id, _, _, auth_key, _, _ = struct.unpack( - _PYRO_FORM[len(session)], - base64.urlsafe_b64decode(session + "=" * (-len(session) % 4)), - ) + auth_id = 3 + dc_id, auth_key = data_[0], data_[auth_id] return StringSession( CURRENT_VERSION + base64.urlsafe_b64encode( @@ -74,6 +75,7 @@ def validate_session(session, logger=LOGS, _exit=True): def vc_connection(udB, ultroid_bot): from strings import get_string + VC_SESSION = Var.VC_SESSION or udB.get_key("VC_SESSION") if VC_SESSION and VC_SESSION != Var.SESSION: LOGS.info("Starting up VcClient.") @@ -81,7 +83,7 @@ def vc_connection(udB, ultroid_bot): return UltroidClient( validate_session(VC_SESSION, _exit=False), log_attempt=False, - exit_on_error=False + exit_on_error=False, ) except (AuthKeyDuplicatedError, EOFError): LOGS.info(get_string("py_c3")) diff --git a/pyUltroid/startup/funcs.py b/pyUltroid/startup/funcs.py index 530fd00d26556e679fda03cbb670f7d01797c703..f4ac3615ba9a11acd46e91e14be7b2a33b6e8e35 100644 --- a/pyUltroid/startup/funcs.py +++ b/pyUltroid/startup/funcs.py @@ -6,11 +6,14 @@ # . import asyncio -import os, shutil +import os import random +import shutil import time from random import randint +from ..configs import Var + try: from pytz import timezone except ImportError: @@ -46,7 +49,7 @@ db_url = 0 async def autoupdate_local_database(): - from .. import asst, udB, ultroid_bot, Var + from .. import Var, asst, udB, ultroid_bot global db_url db_url = ( @@ -88,7 +91,10 @@ def update_envs(): from .. import udB for envs in list(os.environ): - if envs in ["LOG_CHANNEL", "BOT_TOKEN"] or envs in udB.keys(): + if ( + envs in ["LOG_CHANNEL", "BOT_TOKEN", "BOTMODE", "DUAL_MODE", "language"] + or envs in udB.keys() + ): udB.set_key(envs, os.environ[envs]) @@ -302,7 +308,7 @@ async def autopilot(): LOGS.info("Error while promoting assistant in Log Channel..") LOGS.exception(er) if isinstance(chat.photo, ChatPhotoEmpty): - photo = await download_file( + photo, _ = await download_file( "https://graph.org/file/27c6812becf6f376cbb10.jpg", "channelphoto.jpg" ) ll = await ultroid_bot.upload_file(photo) @@ -340,7 +346,7 @@ async def customize(): ] ) if not os.path.exists(file): - file = await download_file(file, "profile.jpg") + file, _ = await download_file(file, "profile.jpg") rem = True msg = await asst.send_message( chat_id, "**Auto Customisation** Started on @Botfather" @@ -410,12 +416,12 @@ async def plug(plugin_channels): if x.text == "#IGNORE": continue plugin = await x.download_media(plugin) - try: - load_addons(plugin) - except Exception as e: - LOGS.info(f"Ultroid - PLUGIN_CHANNEL - ERROR - {plugin}") - LOGS.exception(e) - os.remove(plugin) + try: + load_addons(plugin) + except Exception as e: + LOGS.info(f"Ultroid - PLUGIN_CHANNEL - ERROR - {plugin}") + LOGS.exception(e) + os.remove(plugin) except Exception as er: LOGS.exception(er) @@ -423,9 +429,42 @@ async def plug(plugin_channels): # some stuffs +async def fetch_ann(): + from .. import asst, udB + from ..fns.tools import async_searcher + + get_ = udB.get_key("OLDANN") or [] + chat_id = udB.get_key("LOG_CHANNEL") + + try: + updts = await async_searcher( + "https://ultroid-api.vercel.app/announcements", post=True, re_json=True + ) + for upt in updts: + key = list(upt.keys())[0] + if key not in get_: + cont = upt[key] + if isinstance(cont, dict) and cont.get("lang"): + if cont["lang"] != (udB.get_key("language") or "en"): + continue + cont = cont["msg"] + if isinstance(cont, str): + await asst.send_message(chat_id, cont) + elif isinstance(cont, dict) and cont.get("chat"): + await asst.forward_messages(chat_id, cont["msg_id"], cont["chat"]) + else: + LOGS.info(cont) + LOGS.info( + "Invalid Type of Announcement Detected!\nMake sure you are on latest version.." + ) + get_.append(key) + udB.set_key("OLDANN", get_) + except Exception as er: + LOGS.exception(er) + + async def ready(): from .. import asst, udB, ultroid_bot - from ..fns.tools import async_searcher chat_id = udB.get_key("LOG_CHANNEL") spam_sent = None @@ -460,31 +499,10 @@ async def ready(): try: spam_sent = await ultroid_bot.send_message(chat_id, MSG) except Exception as ef: - LOGS.info(ef) + LOGS.exception(ef) if spam_sent and not spam_sent.media: udB.set_key("LAST_UPDATE_LOG_SPAM", spam_sent.id) - get_ = udB.get_key("OLDANN") or [] - try: - updts = await async_searcher( - "https://ultroid-api.vercel.app/announcements", post=True, re_json=True - ) - for upt in updts: - key = list(upt.keys())[0] - if key not in get_: - cont = upt[key] - if isinstance(cont, str): - await asst.send_message(chat_id, cont) - elif isinstance(cont, dict) and cont.get("chat"): - await asst.forward_messages(chat_id, cont["msg_id"], cont["chat"]) - else: - LOGS.info(cont) - LOGS.info( - "Invalid Type of Announcement Detected!\nMake sure you are on latest version.." - ) - get_.append(key) - udB.set_key("OLDANN", get_) - except Exception as er: - LOGS.exception(er) + await fetch_ann() async def WasItRestart(udb): diff --git a/pyUltroid/startup/loader.py b/pyUltroid/startup/loader.py index 021d12e0b48872ab419d39890a7ac2ad94f80f94..edf15a1d9f88ab261a90e85d94cf7a2532fdd5e9 100644 --- a/pyUltroid/startup/loader.py +++ b/pyUltroid/startup/loader.py @@ -5,11 +5,14 @@ # PLease read the GNU Affero General Public License in # . -import os, subprocess +import os +import subprocess +import sys from shutil import rmtree from decouple import config from git import Repo + from .. import * from ..dB._core import HELP from ..loader import Loader @@ -54,7 +57,7 @@ def load_other_plugins(addons=None, pmbot=None, manager=None, vcbot=None): Loader().load(include=_in_only, exclude=_exclude, after_load=_after_load) # for assistant - if not udB.get_key("DISABLE_AST_PLUGINS"): + if not USER_MODE and not udB.get_key("DISABLE_AST_PLUGINS"): _ast_exc = ["pmbot"] if _in_only and "games" not in _in_only: _ast_exc.append("games") @@ -86,7 +89,10 @@ def load_other_plugins(addons=None, pmbot=None, manager=None, vcbot=None): # subprocess.run( # "rm -rf /usr/local/lib/python3.*/site-packages/pip/_vendor/.wh*" # ) - subprocess.run("pip3 install --no-cache-dir -q -r ./addons/addons.txt", shell=True) + subprocess.run( + f"{sys.executable} -m pip install --no-cache-dir -q -r ./addons/addons.txt", + shell=True, + ) _exclude = udB.get_key("EXCLUDE_ADDONS") _exclude = _exclude.split() if _exclude else [] @@ -101,13 +107,14 @@ def load_other_plugins(addons=None, pmbot=None, manager=None, vcbot=None): load_all=True, ) - # group manager - if manager: - Loader(path="assistant/manager", key="Group Manager").load() + if not USER_MODE: + # group manager + if manager: + Loader(path="assistant/manager", key="Group Manager").load() - # chat via assistant - if pmbot: - Loader(path="assistant/pmbot.py").load_single(log=False) + # chat via assistant + if pmbot: + Loader(path="assistant/pmbot.py").load(log=False) # vc bot if vcbot and not vcClient._bot: @@ -120,7 +127,9 @@ def load_other_plugins(addons=None, pmbot=None, manager=None, vcbot=None): else: rmtree("vcbot") if not os.path.exists("vcbot"): - subprocess.run("git clone https://github.com/TeamUltroid/VcBot vcbot", shell=True) + subprocess.run( + "git clone https://github.com/TeamUltroid/VcBot vcbot", shell=True + ) try: if not os.path.exists("vcbot/downloads"): os.mkdir("vcbot/downloads") @@ -128,4 +137,4 @@ def load_other_plugins(addons=None, pmbot=None, manager=None, vcbot=None): except FileNotFoundError as e: LOGS.error(f"{e} Skipping VCBot Installation.") except ModuleNotFoundError: - LOGS.error("'pytgcalls' not installed!\nSkipping load of VcBot.") + LOGS.error("'pytgcalls' not installed!\nSkipping loading of VCBOT.") diff --git a/pyUltroid/startup/utils.py b/pyUltroid/startup/utils.py index 25503aa9503b21cc7a24aefc241fda2bfa1d70bc..95246afe7976abfdb5c2f70b5e8d7db352537ccb 100644 --- a/pyUltroid/startup/utils.py +++ b/pyUltroid/startup/utils.py @@ -10,14 +10,32 @@ from sys import modules # for addons +configPaths = [ + "ub", + "var", + "support", + "userbot", + "telebot", + "fridaybot", + "uniborg.util", + "telebot.utils", + "userbot.utils", + "userbot.events", + "userbot.config", + "fridaybot.utils", + "fridaybot.Config", + "userbot.uniborgConfig", +] + def load_addons(plugin_name): base_name = plugin_name.split("/")[-1].split("\\")[-1].replace(".py", "") if base_name.startswith("__"): return - from .. import HNDLR, LOGS, asst, udB, ultroid_bot - from .._misc import _supporter as xxx from pyUltroid import fns + + from .. import HNDLR, LOGS, asst, udB, ultroid_bot + from .._misc import _supporter as config from .._misc._assistant import asst_cmd, callback, in_pattern from .._misc._decorators import ultroid_cmd from .._misc._supporter import Config, admin_cmd, sudo_cmd @@ -25,9 +43,12 @@ def load_addons(plugin_name): from ..configs import Var from ..dB._core import HELP - name = plugin_name.replace("/", ".").replace("\\", ".").replace(".py","") + name = plugin_name.replace("/", ".").replace("\\", ".").replace(".py", "") spec = util.spec_from_file_location(name, plugin_name) mod = util.module_from_spec(spec) + for path in configPaths: + modules[path] = config + modules["pyUltroid.functions"] = fns mod.LOG_CHANNEL = udB.get_key("LOG_CHANNEL") mod.udB = udB mod.asst = asst @@ -61,21 +82,7 @@ def load_addons(plugin_name): mod.sudo_cmd = sudo_cmd mod.HELP = HELP.get("Addons", {}) mod.CMD_HELP = HELP.get("Addons", {}) - modules["ub"] = xxx - modules["var"] = xxx - modules["support"] = xxx - modules["userbot"] = xxx - modules["telebot"] = xxx - modules["fridaybot"] = xxx - modules["uniborg.util"] = xxx - modules["telebot.utils"] = xxx - modules["userbot.utils"] = xxx - modules["userbot.events"] = xxx - modules["userbot.config"] = xxx - modules["fridaybot.utils"] = xxx - modules["fridaybot.Config"] = xxx - modules["userbot.uniborgConfig"] = xxx - modules["pyUltroid.functions"] = fns + spec.loader.exec_module(mod) modules[name] = mod doc = modules[name].__doc__.format(i=HNDLR) if modules[name].__doc__ else "" diff --git a/pyUltroid/version.py b/pyUltroid/version.py index 17ee6c6c55f822b7ed0c9a6f2865a789d50f4c8b..8c7b646d7733f90eaf46d959c67df1b9e9cdaf7c 100644 --- a/pyUltroid/version.py +++ b/pyUltroid/version.py @@ -1,2 +1,2 @@ -__version__ = "2022.12.18" -ultroid_version = "0.7.2" +__version__ = "2023.02.20" +ultroid_version = "0.8" diff --git a/requirements.txt b/requirements.txt index a7d7d9aa4d3f331f808d3ce96321306de0649981..9ca5b3894feeeae53924e5c72578573ad47b8086 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Important Requirements here. -https://github.com/New-dev0/Telethon/archive/diamond.zip +https://github.com/New-dev0/Telethon/archive/platy.zip python-decouple python-dotenv diff --git a/resources/session/ssgen.py b/resources/session/ssgen.py index 794260e96f31638c4ddbabf26deded7094c3f74d..8c9f1ba9c7bc887253f89df23026aff37bcb1af2 100644 --- a/resources/session/ssgen.py +++ b/resources/session/ssgen.py @@ -131,14 +131,18 @@ def pyro_session(): # generate a session API_ID, API_HASH = get_api_id_and_hash() print("Enter phone number when asked.\n\n") - with Client(name="ultroid", api_id=API_ID, api_hash=API_HASH, in_memory=True) as pyro: - ss = pyro.export_session_string() - pyro.send_message( - "me", - f"`{ss}`\n\nAbove is your Pyrogram Session String for @TheUltroid. **DO NOT SHARE it.**", - ) - print("Session has been sent to your saved messages!") - exit(0) + try: + with Client(name="ultroid", api_id=API_ID, api_hash=API_HASH, in_memory=True) as pyro: + ss = pyro.export_session_string() + pyro.send_message( + "me", + f"`{ss}`\n\nAbove is your Pyrogram Session String for @TheUltroid. **DO NOT SHARE it.**", + ) + print("Session has been sent to your saved messages!") + exit(0) + except Exception as er: + print("Unexpected error occurred while creating session, make sure to validate your inputs.") + print(er) def main(): diff --git a/resources/startup/_termux.py b/resources/startup/_termux.py index acaba8e1d4cedd7a252ef399611f4514f2c897d7..6efe89cc6584d2f1c71a39e7ad7a50702bf572f2 100644 --- a/resources/startup/_termux.py +++ b/resources/startup/_termux.py @@ -6,10 +6,12 @@ # Please read the GNU Affero General Public License in # . -from os import system, path -from time import sleep from datetime import datetime -from colorama import Style, Fore, Back +from os import path, system +from time import sleep + +from colorama import Back, Fore, Style + # clear screen def clear(): @@ -18,10 +20,11 @@ def clear(): MANDATORY_REQS = [ "https://github.com/New-dev0/Telethon/archive/Cartoon.zip", - "py-Ultroid==2022.6.6", "gitpython", - "enhancer==0.3.4", + "enhancer", "telegraph", + "requests", + "python-decouple", "aiohttp", ] @@ -33,7 +36,7 @@ OPT_PACKAGES = { "psutil": "Used for .usage command.", "lottie": "Used for animated sticker related conversion.", "apscheduler": "Used in autopic/nightmode (scheduling tasks.)", - #"git+https://github.com/1danish-00/google_trans_new.git": "Used for translation purposes.", + # "git+https://github.com/1danish-00/google_trans_new.git": "Used for translation purposes.", } APT_PACKAGES = ["ffmpeg", "neofetch", "mediainfo"] diff --git a/resources/startup/locals.py b/resources/startup/locals.py index d0f0e13c8004c77bdf0d0d6f4e41ca85af3cc4a2..2a89268ac9cfc02c4be073e2a9d1463457ce06c4 100644 --- a/resources/startup/locals.py +++ b/resources/startup/locals.py @@ -76,10 +76,14 @@ def start(): print("\nCongrats. All done!\nTime to start the bot!") print("\nInstalling requirements... This might take a while...") os.system("pip3 install --no-cache-dir -r requirements.txt") - ask = input("Enter 'yes/y' to Install other requirements, required for local deployment.") - if ask.lower().startswith("y") : + ask = input( + "Enter 'yes/y' to Install other requirements, required for local deployment." + ) + if ask.lower().startswith("y"): print("Started Installing...") - os.system("pip3 install --no-cache-dir -r resources/startup/optional-requirements.txt") + os.system( + "pip3 install --no-cache-dir -r resources/startup/optional-requirements.txt" + ) else: print("Skipped!") clear_screen() diff --git a/resources/startup/optional-requirements.txt b/resources/startup/optional-requirements.txt index 28a8e43c1e1d0ad1354fcb95bab87872548040fc..a52145449533b96a06167b1bcbbdb10231b3ad7a 100644 --- a/resources/startup/optional-requirements.txt +++ b/resources/startup/optional-requirements.txt @@ -13,6 +13,7 @@ gitpython google-api-python-client htmlwebshot lottie +lxml numpy>=1.21.2 oauth2client opencv-python-headless diff --git a/strings/README.md b/strings/README.md index 5133377dbd425b0d6bca37410f1795e142d7b579..0a19fba7f3167c120ca9b8dc80d6668eb58c053e 100644 --- a/strings/README.md +++ b/strings/README.md @@ -12,14 +12,14 @@ | fa | Persian [Farsi] | 491 | 3 | | fr | French [Français] | 490 | 4 | | gu | Gujarati [ગુજરાતી] | 490 | 4 | -| hi | Hindi [हिंदी] | 490 | 4 | +| hi | Hindi [हिंदी] | 489 | 5 | | id | Indonesia [Indonesia] | 490 | 4 | | it | Italian [italiano] | 490 | 4 | | jp | Japanese [日本] | 490 | 4 | | ka | Kannada [ಕನ್ನಡ] | 490 | 4 | | ml | Malayalam [മലയാളം] | 490 | 4 | | mr | Marathi [मराठी] | 491 | 3 | -| my | Malay [Bahasa Melayu] | 490 | 4 | +| ms | Malay [Bahasa Melayu] | 494 | NULL | | or | Odia [ଓଡିଆ] | 490 | 4 | | pt-br | Português [Português] | 490 | 4 | | ru | Russian [Русский] | 490 | 4 | diff --git a/strings/__init__.py b/strings/__init__.py index cdf135417f414a582a95e6360048fb388b73cdf1..30e79706b4719699a8169b6c7f4d49c27249a5c4 100644 --- a/strings/__init__.py +++ b/strings/__init__.py @@ -1,9 +1,11 @@ -import sys import os -from typing import Any, Dict, List, Union +import sys from glob import glob +from typing import Any, Dict, List, Union + from pyUltroid import * from pyUltroid.fns.tools import translate + try: from yaml import safe_load except ModuleNotFoundError: @@ -12,17 +14,25 @@ except ModuleNotFoundError: ULTConfig.lang = udB.get_key("language") or os.getenv("LANGUAGE", "en") languages = {} +PATH = "strings/strings/{}.yml" + + +def load(file): + if not file.endswith(".yml"): + return + elif not os.path.exists(file): + file = PATH.format("en") + code = file.split("/")[-1].split("\\")[-1][:-4] + try: + languages[code] = safe_load( + open(file, encoding="UTF-8"), + ) + except Exception as er: + LOGS.info(f"Error in {file[:-4]} language file") + LOGS.exception(er) -for file in glob("strings/strings/*yml"): - if file.endswith(".yml"): - code = file.split("/")[-1].split("\\")[-1][:-4] - try: - languages[code] = safe_load( - open(file, encoding="UTF-8"), - ) - except Exception as er: - LOGS.info(f"Error in {file[:-4]} language file") - LOGS.exception(er) + +load(PATH.format(ULTConfig.lang)) def get_string(key: str, _res: bool = True) -> Any: @@ -52,12 +62,16 @@ def get_string(key: str, _res: bool = True) -> Any: return None return languages["en"].get(key) or f"Failed to load language string '{key}'" + def get_help(key): doc = get_string(f"help_{key}", _res=False) if doc: return get_string("cmda") + doc + def get_languages() -> Dict[str, Union[str, List[str]]]: + for file in glob("strings/strings/*yml"): + load(file) return { code: { "name": languages[code]["name"], diff --git a/strings/strings/en.yml b/strings/strings/en.yml index 2e7e31c5196cb0ce4da32270760ed02993aa98ec..85dd02758f0b98439702565b174d1ff320b4eb38 100644 --- a/strings/strings/en.yml +++ b/strings/strings/en.yml @@ -588,7 +588,7 @@ help_afk: " -\n\n• `{i}afk `\n AFK means away from keyboar help_antiflood: " -\n\n• `{i}setflood `\n Set flood limit in a chat.\n\n• `{i}remflood`\n Remove flood limit from a chat.\n\n• `{i}getflood`\n Get flood limit of a chat.\n" help_asstcmd: " -\n\n•`{i}addcmd `\n It will set new cmd for your assistant bot with that reply message.\n\n•`{i}remcmd `\n It will remove your cmd.\n\n•`{i}listcmd`\n To Get list of all your custom cmd.\n" help_audiotools: "✘ Commands Available - \n`.makevoice `\n creates a voice note from Audio.\n\n`.atrim - `\n trim audio as per given time.\n time must be in seconds. `.atrim 50-70`\n\n`.extractaudio `\n To extract the audio from it.\n\n" -help_autoban: "\n\n• `{i}autokick `\n on - To enable.\n off - To disable.\n Automatically kick new joined users from the group.\n\n• `{i}cban`\n Enable/Disable autobanning send as channel in used chat.\n\n• `{i}addwl `\n Add Channel to channelban whitelist.\n\n• `{i}remwl `\n Remove Channel from channelban whitelist.\n\n• `{i}listwl` : List all whitelist channels.\n" +help_autoban: "\n\n• `{i}autokick `\n on - To enable.\n off - To disable.\n Automatically kick new joined users from the group.\n" help_beautify: " -\n\n• `{i}carbon `\n Carbonise the text with default settings.\n\n• `{i}rcarbon `\n Carbonise the text, with random bg colours.\n\n• `{i}ccarbon `\n Carbonise the text, with custom bg colours.\n\n• `{i}rayso /`\n `{i}rayso list` - `Get list of themes.`\n" help_blacklist: " -\n\n• `{i}blacklist `\n blacklist the choosen word in that chat.\n\n• `{i}remblacklist `\n Remove the word from blacklist..\n\n• `{i}listblacklist`\n list all blacklisted words.\n\n 'if a person uses blacklist Word his/her msg will be deleted'\n 'And u Must be Admin in that Chat'\n" help_bot: "\n\n• `{i}alive` | `{i}alive inline`\n Check if your bot is working.\n\n• `{i}ping`\n Check Ultroid's response time.\n\n• `{i}update`\n See changelogs if any update is available.\n\n• `{i}cmds`\n View all plugin names.\n\n• `{i}restart`\n To restart your bot.\n\n• `{i}logs (sys)`\n Get the full terminal logs.\n• `{i}logs carbon`\n Get the carbonized sys logs.\n• `{i}logs heroku`\n Get the latest 100 lines of heroku logs.\n\n• `{i}shutdown`\n Turn off your bot.\n" diff --git a/strings/strings/ms.yml b/strings/strings/ms.yml new file mode 100644 index 0000000000000000000000000000000000000000..04ec596d1ac19d1f9dc26ba71903aa97445d47a7 --- /dev/null +++ b/strings/strings/ms.yml @@ -0,0 +1,647 @@ +name: Malay +natively: Bahasa Melayu + +authors: + - yuno74 + - DarkBeamerYT + +# pyUltroid +py_c1: "Sesi string yang salah. Salin tampal dengan betul!" +py_c2: "Tiada sesi string yang dijumpai. Berhenti..." +py_c3: "VC_SESSION anda telah tamat tempoh. Membuang VC_SESSION daripada redis...\nMemperbaharuikan/Ubahkan nya untuk mengguna Perbualan Suara/Video daripada akaun VC..." +py_d1: "`Anda tidak dapat mengguna perintah ini buat masa kini. Hubungi pemilik bot ini!`" +py_d2: "`Sudo User Penuh Diperlukan...`" +py_d3: "`Gunakan ini di dalam group/channel.`" +py_d4: "**⚠️ Terhad kepada Developer sahaja!**\nJika anda tahu perkara ini lakukan, dan ingin meneruskan, gunakan\n`{}setdb I_DEV True`.\n\nIni mungkin berbahaya." +py_d5: "`Saya bukanlah admin.`" +py_d6: "Perintah ini tidak dapat digunakan oleh bot!" +py_d7: "Perbualan sudah dihidupkan, sila tunggu kemudian dan cuba lagi." +py_d8: "`Menghantar media atau pelekat tidak dibenarkan dalam group ini.`" + +# commons +com_1: "`Memproses...`" +com_2: "`Mencari...`" +com_3: "`Input tidak sah`" +com_4: "`Media tidak disokong..`" +com_5: "Sedang muat turun..." +com_6: "Sedang muat naik..." +com_7: "`Ada sesuatu yang tidak kena.`" + +#chatactions +can_1: "#GBanned_User telah menyertai.\n\n**Pengguna** : {}\n**Sebab**: {}\n\n`Pengguna telah diban.`" +can_2: "∆ #UsernameUpdate\n\n@{} telah menukar usernamenya kepada @{}" +can_3: "∆ #UsernameUpdate\n\n{} telah membuang usernamenya. (@{})" +can_4: "∆ Username #UsernameUpdate\n\n{} yang baharu --> @{}" + +# help +help_1: "`{}` bukan plugin yang sah!" +help_2: "Bot tidak bertindak balas terhadap pertanyaan sebaris.\nDicadangkan untuk menggunakan `{}restart`" +help_3: "`Sila hidupkan mod sebaris untuk bot anda dari` @BotFather." +help_4: "• Plugins" +help_5: "Tambahan •" +help_6: "••Voice Chat" +help_7: "Tambahan Inline••" +help_8: "⚙️ Alatan Pemilik" +help_9: "Tetapan ⚙️" +help_10: "••ᴛᴜᴛᴜᴘ••" +help_11: "Nama Plugin-{}\n✘ Perintah Tersedia -\n\n" +help_12: "Voice Chat Bot tidak aktif! Gunakan .setdb VCBOT True untuk mengaktifkan!" +help_13: "Gunakan '{}setdb ADDONS True' untuk memuatkan tambahan yang sah" + +# userlogs +userlogs_1: "Chat Id yang anda telah letak di dalam Tag Logger salah , Tolong memperbetulkannya." +userlogs_2: "Tambah saya ke dalam chat Tag Logger anda untuk menlog tags" +userlogs_3: "Tinggalkan Chat" +userlogs_4: "Bot Pembantu Anda Tidak Dapat Menghantar Mesej di dalam chat tag log.\nTambahkannya untuk mendapat Tag Logs anda.." +userlogs_5: "Tinggalkan `{}`" + +# admintools +adm_1: "`Saya tidak dapat teka siapakah dia!`" +adm_2: "`Hmm.. Nampaknya saya tiada hak di sini!`" +adm_3: "`Berikan lah masa juga..`" +pro_1: "`Balas kepada pengguna untuk mempromosikannya!`" +pro_2: "{} `sekarang lah admin {} dengan tajuk {}.`" +de_1: "`Balas kepada pengguna untuk menurunkan pangkatnya!`" +de_2: "{} `bukan lagi admin di dalam {}`" +ban_1: "`Balas kepada pengguna atau berikan username untuk melarangnya!`" +ban_2: " `Maaf, tapi saya tidak boleh melarang developer saya 😂`" +ban_3: "`Saya tidak mempunyai hak untuk melarang orang.`" +ban_4: "{} **telah dilarang oleh** {} **di dalam** `{}`" +ban_5: "\n**Sebab**: `{}`" +tban_1: "`Balas kepada seseorang atau memberi ID nya...`" +tban_2: "`Berjaya melarang` {} `di dalam {} kerana {}`" +unban_1: "`Balas kepada pengguna atau berikan username untuk unban nya!`" +unban_2: "`Saya tidak mempunyai hak untuk unban orang.`" +unban_3: "{} **telah diban oleh** {} **di dalam** `{}`" +kick_1: "`Saya tidak mempunyai hak untuk mengeluarkan pengguna.`" +kick_2: " `Maaf, tapi saya tidak boleh mengeluarkan developer saya`😂" +kick_3: "`Saya tidak boleh mengeluarkannya...`" +kick_4: "{} **telah dikeluarkan oleh** {} **di dalam** `{}`" +pin_1: "`Balas mesej untuk menyematkannya!`" +pinned_1: "Tiada mesej yang disemat dijumpa!" +pinned_2: "Mesej yang disemat di dalam chat semasa adalah di [sini]({})." +unpin_1: "Sama ada membalas mesej, atau gunakan `{}unpin all`" +listpin_1: "Tiada mesej yang disematkan dalam group ini!" +purge_1: "`Balas kepada mesej sebagai permulaan purge.`" +purgeall_1: "`Balas kepada mesej seseorang untuk dipadamkan.`" +purgeall_2: "Berjaya purge semua mesej daripada {}" + +# akinator +aki_1: "Permainan telah ditamatkan...." +aki_2: "Mulakan Permainan" +aki_3: "Masa tamat !" + +# antiflood +antiflood_1: "`Tetapan Antiflood telah disable`" +antiflood_2: "`Tiada had flood di dalam chat ini.`" +antiflood_3: "`Anda telah dimute.`" +antiflood_4: "`Berjaya mengemas kini tetapan antiflood kepada {} dalam sembang ini.`" +antiflood_5: "`Had flood di dalam chat ini adalah {}.`" + +# ascii +ascii_1: "`Balas kepada imej.`" +ascii_2: "`Sedang menukar kepada html...`" + +# audiotools +audiotools_1: "Balas kepada audio atau video.." +audiotools_2: "Berjaya muat turun, sekarang menukar kepada voice" +audiotools_3: "`Beri masa dalam format untuk trim`" +audiotools_4: "`Data yang salah`" +audiotools_5: "`Mencuba untuk muat turun...`" +audiotools_6: "`Masa trim yang salah`" +audiotools_7: "Audio telah ditrim daripada `{}` kepada `{}`" +audiotools_8: "`Balas kepada fail video..`" +audiotools_9: "`Audio tidak dijumpai...`" +audiotools_10: "`Audio yang telah diekstrak daripada Video...`" + +# asstcmd +asstcmd_1: "`Gunakan perintah ini dengan Balas dan perkataan untuk menggunakan perintah.`" +asstcmd_2: "`Beri saya perintah yang anda mahu buang.`" +asstcmd_3: "Berjaya Perintah: `/{}` Dibuang." +asstcmd_4: "Berjaya Perintah : `/{}` disimpan." +asstcmd_5: "Tiada perintah dijumpa" +asstcmd_6: "**SEMUA PERINTAH PEMBANTU**\n\n" + +# autocorrect +act_1: "Ciri AUTOCORRECT Hidup" +act_2: "Ciri AUTOCORRECT Tutup" + +# autopic +autopic_1: "`Berikan sesuatu untuk dicari...`" +autopic_2: "Tiada keputusan ditemui untuk `{}`" +autopic_3: "Mempunyai koleksi `{}` berkaitan dengan carian anda !\nMemulakan Autopic !" +autopic_4: "AUTOPIC tidak digunakan !!" +autopic_5: "AUTOPIC Berhenti!" + +# inline +inline_1: "[ʙᴀɴᴛᴜᴀɴ ᴜʟᴛʀᴏɪᴅ](t.me/UltroidSupportChat)\n\n**ᴍᴇɴᴜ ʙᴀɴᴛᴜᴀɴ ᴅᴀʀɪᴘᴀᴅᴀ {}.\n\nPʟᴜɢɪɴs ~ {}**" +inline_2: "[ʙᴀɴᴛᴜᴀɴ ᴜʟᴛʀᴏɪᴅ](t.me/UltroidSupportChat)\n\n**ᴍᴇɴᴜ ʙᴀɴᴛᴜᴀɴ ᴅᴀʀɪᴘᴀᴅᴀ {}.\n\nAᴅᴅᴏɴs ~ {}**" +inline_3: "[ʙᴀɴᴛᴜᴀɴ ᴜʟᴛʀᴏɪᴅ](t.me/UltroidSupportChat)\n\n**ᴍᴇɴᴜ ʙᴀɴᴛᴜᴀɴ ᴅᴀʀɪᴘᴀᴅᴀ {}.\n\nAᴅᴅᴏɴs ~ {}\n\nBuat **`.setdb ADDONS True`** ᴅᴀɴ ʀᴇsᴛᴀʀᴛ ᴜɴᴛᴜᴋ ᴍᴇɴᴅᴀᴘᴀᴛ ᴀᴅᴅᴏɴs..**" +inline_4: "** Bᴏᴛ {}\n\nᴍᴇɴᴜ ᴜᴛᴀᴍᴀ\n\nPʟᴜɢɪɴs ~ {}\nAᴅᴅᴏɴs ~ {}\nᴊᴜᴍʟᴀʜ ᴘᴇʀɪɴᴛᴀʜ ~ {}**" +inline_5: "**Mᴇɴᴜ ᴛᴇʟᴀʜ ᴅɪᴛᴜᴛᴜᴘ**" +inline_6: "**Menu Bantuan Voice Chat untuk {}**\n**Perintah yang ada:** `{}`\n\n@TeamUltroid" +inline_7: "Taip .help {} untuk mendapatkan senarai perintah." +inline_8: "Klik butang di bawah untuk mengemaskini!" +inline_9: "Anda Sudah Pada Versi Terkini" + +# tagnotif +tagnot_1: "{} telah tag anda di dalam {}\n\n```{}```\n\n[📨 Mesej 📨]({})" +tagnot_2: "{} telah tag anda di dalam {}\n\n [📨 Mesej 📨]({})" + +# whisper +wspr_1: "@{} mesej rahsia untuk anda.\nPadamkan mesej anda selepas membaca.\nAtau mesej seterusnya tidak akan dikemas kini." +wspr_2: "Mesej dipadam" +wspr_3: "Tambah beberapa id atau username juga" +wspr_4: "User {} Tidak Dijumpai\nCari Lagi" +wspr_5: "Anda tidak boleh melakukan ini" + +# afk +afk_1: "`Tidak lagi Afk\n\nTidak ada untuk ~ {}`" +afk_2: "#AFK\nSet mod AFK kepada **tidak aktif**\n +Tidak ada untuk `{}`" +afk_3: "`Saya sedang AFK.\nTerakhir dilihat {} lepas.`\n\n**Sebab:** `{}`" +afk_4: "`Saya sedang AFK.\n\nTerakhir dilihat {} lepas.`" +afk_5: "`Saya akan pergi AFK.`\n\n**Sebab:** `{}`" +afk_6: "Saya akan pergi AFK." + +# bot +bot_1: "Hi, saya hidup." +bot_2: "Statistik" +bot_3: "Repo" +bot_4: "Bantuan" +bot_5: "• `Sedang restart...`" +alive_1: "**Userbot Ultroid...**\n\n**{}**\n\n✵ **Pemilik** - `{}`\n✵ **Ultroid** - `{}`\n✵ **Py-Ultroid** - `{}`\n✵ **Masa Beroperasi** - `{}`\n✵ **Python** - `{}`\n✵ **Telethon** - `{}`\n✵ **Branch** - `{}`" +log: "**Heroku** Log Ultroid.\nDitampal [disini]({}) juga!" +ping: "**Pong !!** `{}ms`\n**Masa beroperasi** - `{}`" +usage: "**⚙️ Dyno Usage ⚙️**:\n\n-> **Pengunaan dyno untuk** `{}`:\n • **{}h** **{}m |** `[{}%]`\n-> **Baki kuota jam dyno bulan ini**:\n • **{}h** **{}m |** `[{}%]`\n\n**Jumlah Ruang Cakera**: `{}`\n**Telah diguna**: `{}`\n**Yang tertinggal**: `{}`\n\n**📊 Pengunaan Data 📊**\n**Muat naik**: `{}`\n**Muat turun**: `{}`\n\n**CPU**: `{}%`\n**RAM**: `{}%`\n**DISK**: `{}%`" +usage_simple: "**Total Disk Space**: `{}`\n**Used**: `{}`\n**Free**: `{}`\n\n**📊 Data Usage 📊**\n**Upload**: `{}`\n**Down**: `{}`\n\n**CPU**: `{}%`\n**RAM**: `{}%`\n**DISK**: `{}%`" +shutdown: "Bye {}.\n`Sedang menutup...`" + +# blacklist +blk_1: "`Beri kata untuk disenarai hitamkan..`" +blk_2: "Berjaya : `{}` Disenarai hitam di sini." +blk_3: "`Beri kata untuk dibuang dari senarai hitam..`" +blk_4: "Berjaya : `{}` Dibuang dari senarai hitam." +blk_5: "Senarai hitam yang telah dijumpa dalam perbualan ini ialah :\n\n" +blk_6: "Tiada perkataan yang disenarai hitamkan di sini" + +# broadcast +bd_1: "`Menambah ke dalam db...`" +bd_2: "`Cuba menambah semua saluran admin ke db...`" +bd_3: "**Berjaya.**\nPerbualan yang telah ada di dalam database: {}\nBaru ditambah: {}" +bd_4: "Saluran ditambah!" +bd_5: "`Ditambah ke dalam database!`" +bd_6: "`Saluran ini sudah ada di dalam database!`" +bd_7: "Dibuang daripada database" +bd_8: "`Membuang...`" +bd_9: "Saluran ini sudah dibuang daripada database. " + +# calculator +calc_1: "• Kalkulator Inline Ultroid •" +calc_2: "Buka Kalkulator Lagi" + +# channel hacks +cha_1: "Saluran yang tidak sah diberi" +cha_2: "Sumber ditambah dengan jayanya" +cha_3: "Saluran sumber sudah ditambah" +cha_4: "Database sumber dibersihkan." +cha_5: "Sumber telah dibuang dari database" +cha_6: "Saluran sumber sudah dibuang dari database." +cha_7: "Saluran destinasi dalam database:" +cha_8: "Saluran sumber dalam database:" + +# carbon +carbon_1: "Dikarbonkan oleh [{}](tg://user?id={})" +carbon_2: "`Balas kepada mesej atau fail yang boleh dibaca..`" +carbon_3: "`Bagi warna khas untuk membuat karbon...`" + +# chat_bot +chab_1: "Reply to a user or give me his id/username to add an AI ChatBot!" +chab_2: "`No user has AI added.`" +chab_3: "**Total List Of AI Enabled Users In This Chat :**\n\n" + +# chats +chats_1: "`Cant delete this chat.`" +chats_2: "`I m not an admin`" +chats_3: "#Deleted\nDeleted {}" +chats_4: "Your [{}]({}) Group Made Boss!" +chats_5: "Join @TeamUltroid" +chats_6: "Your {} Group/Channel Has been made Boss!" + +# clean action +clan_1: "Added Clean Action Setting For this Chat" +clan_2: "Removed Clean Action Setting For this Chat" +clan_3: "`Invalid ID`" +clan_4: "`No Chat Added`" +clan_5: "Clean Actions are already enabled in this Chat." + +# converter +cvt_1: "`Reply to any media/Document.`" +cvt_2: "Give The name and extension of file" +cvt_3: "`Reply to media..`" +cvt_4: "`Reply to img or file with thumbnail.`" +cvt_5: "Replied file has no thumbnail.`" +cvt_6: "Added [This]({}) As Your Custom Thumbnail" +cvt_7: "`Reply to a readable file`" +cvt_8: "`Not A Readable File.`" + +# eventsofday +eod_1: "🎊 **Events of the Day**\n\n" +eod_2: "• **Events for {}/2022**\n\n" + +# core +core_1: "Module Found" +core_2: "{}.py use .paste to paste in neko and raw.." +core_3: "Search Again..?" +core_4: "Module {} Found" +core_5: "{}.py use .paste to paste in neko and raw.." +core_6: "Module {}.py Not Found" +core_7: "No Such Module" +core_8: "No Module Named {}.py" +core_9: "`Give name of plugin which u want to unload`" +core_10: "**Uɴʟᴏᴀᴅᴇᴅ** `{}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**" +core_11: "**Yᴏᴜ Cᴀɴ'ᴛ Uɴʟᴏᴀᴅ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**" +core_12: "**Nᴏ Pʟᴜɢɪɴ Nᴀᴍᴇᴅ** `{}`" +core_13: "`Give name of plugin which u want to uninstall`" +core_14: "**Uɴɪɴsᴛᴀʟʟᴇᴅ** `{}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**" +core_15: "**Yᴏᴜ Cᴀɴ'ᴛ Uɴɪɴsᴛᴀʟʟ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**" +core_16: "`Give name of plugin which u want to load`" +core_17: "**Sᴜᴄᴄᴇssғᴜʟʟʏ Lᴏᴀᴅᴇᴅ** `{}`" +core_18: "**Could not load** `{}` **because of the following error.**\n`{}`" + +# devtools +devs_1: "`No cmd given`" +devs_2: "`Give some python cmd`" +devs_3: "`Give Some C++ Code..`" + +# dm +dm_1: "`Give Chat username or id where to send.`" +dm_2: "`Give text to send or reply to msg`" +dm_3: "⚜️ Message Delivered! ⚜️" +dm_4: "Error : {}\nRead Usage : `{}help other`" +dm_5: "`Check in Private.`" +dm_6: "`No message found to deliver :(`" + +# echo +echo_1: "**Activated Echo For Users:**\n\n" + +# fake action +fka_1: "Starting Fake Action For {} sec." + +# fedutils +sf_1: "Starting a Mass-FedBan..." +sf_2: "`No user designated!`" +sf_3: "You can't ban my dev you noob!!" +sf_4: "`Seems like rose isn't responding, or, the plugin is misbehaving`" +sf_5: "You can only use fed commands once every 5 minutes" +sf_6: "Try again after 5 mins." +sf_7: "Unable to collect FedAdminList. Retrying ({}/3)..." +sf_8: "Error" +sf_9: "Unable to collect FedAdminList." +sf_10: "FBaning in {} feds." +sf_11: "Specified FBan Group ID is incorrect." +sf_12: "{} Excluded." +sf_13: "Error in removing FedAdmin file.\n{}" +sf_14: "SuperFBan Completed.\nTotal Feds - {}.\nExcluded - {}.\n Affected {} feds.\n#TB" +sf_15: "Starting a Mass-UnFedBan..." +sf_16: "SuperUnFBan Completed.\nTotal Feds - {}.\nExcluded - {}.\n Affected {} feds.\n#TB" +sf_17: "`Give me someones id, or reply to somones message to check his/her fedstat.`" +sf_18: "List of feds {} has been banned in.\n\nCollected using Ultroid." +sf_19: "**Error**\n `Unblock` @MissRose_Bot `and try again!" +sf_20: "`Extracting information...`" +sf_21: "\n\nFedInfo Extracted by Ultroid" +sf_22: "No user was designated." +sf_23: "**Error**\n `Unblock` @MissRose_Bot `and try again!" + +# filter +flr_1: "`Use this command word to set as filter and reply...`" +flr_2: "Filters Found In This Chats Are\n\n" +flr_3: "`Give the filter to remove..`" +flr_4: "Done : Filter `{}` Saved." +flr_5: "Done : Filter `{}` Removed." +flr_6: "No Filters Found Here" + +# fontgen +fgn_1: "**Available Fonts**\n\n" + +# force subscribe +fsub_1: "Give Channel where you want User to Join !" +fsub_2: "Give Correct Channel Username or id" +fsub_3: "ForceSub was not Active in this Chat !" +fsub_4: "Join Channel" +fsub_5: "Unmute Me" +fsub_6: "Please Join That Channel !\nThen Click This Button !" +fsub_7: "This Message is Not for You" +fsub_8: "Thanks For Joining ! " + +# extra +ex_1: "`Reply to message..`" + +# gdrive +gdrive_1: "`You have already authorised with Google Drive`" +gdrive_2: "Go [here](https://console.developers.google.com/flows/enableapi?apiid=drive) and get your `GDRIVE_CLIENT_ID` and `GDRIVE_CLIENT_SECRET`\n\nSend your GDRIVE_CLIENT_ID and GDRIVE_CLIENT_SECRET as this.\n`GDRIVE_CLIENT_ID GDRIVE_CLIENT_SECRET` separated by space." +gdrive_3: "`Wrong Client Id`" +gdrive_4: "`Something went wrong! Authorise again.\nIf the same happens, contact `@TeamUltroid" +gdrive_5: "`Success!\nYou are all set to use Google Drive with Ultroid Userbot.`" +gdrive_6: "`Go `[here](t.me/{}?start=set)` and setup G-Drive`" +gdrive_7: "Successfully uploaded [{}]({}) on G-Drive" + +# get addons +gas_1: "Please provide a raw link!" + +# greetings +grt_1: "`Welcome note saved`" +grt_2: "Please use this in a group and not PMs!" +grt_3: "`Reply to message which u want to set as welcome`" +grt_4: "`No welcome was set!`" +grt_5: "`Welcome Note Deleted`" +grt_6: "`No goodbye was set!`" +grt_7: "`Reply to message which u want to set as goodbye`" + +# glitch +glitch_1: "`Glitching...`" + +# mediainfo +mdi_1: "More Explained Info" + +# nightmode +nightm_1: "Give Time in correct format" +nightm_2: "Setted time successfully" +nightm_3: "Done, Added Current Chat To Night Mode" +nightm_4: "Done, Removed Current Chat from Night Mode" +nightm_5: "Something Went Wrong" + +# pmpermit +pmperm_1: "Please wait for me to respond or you will be blocked and reported as spam!!" +pmperm_2: "Eyy, I told you not to spam!\nYou've been blocked and reported, for now." +pmperm_3: "Reply to someone's message or try this command in private." + +# schedule_msg +schdl_1: "`Scheduled msg Succesfully`" +schdl_2: "`Incorrect Format`" + +# searches +srch_1: "`Search for whom? Give me a user name!!`" +srch_2: "`No such user found...`" +srch_3: "`Song not found...`" + +# snip +snip_1: "Give word to set as snip and reply to a message." +snip_2: "Give the word to remove..." +snip_3: "No Snips Found Here." + +# specialtools +spcltool_1: "Reply To Audio or video." +spcltool_2: "`Done.. Now reply to video In which u want to add this Audio`" +spcltool_3: "Reply To video" +spcltool_4: "`First reply an audio with .raw`" +spcltool_5: "Downloaded Successfully, Now Adding Your Audio to video" +spcltool_6: "`Put input in dd/mm/yyyy format`" +spcltool_7: "`Happy Birthday To U🎉🎊`" +spcltool_8: "Give something to search.." +spcltool_9: "Found Nothing" + +# sudo +sudo_1: "`Reply to a msg or add it's id/username.`" +sudo_2: "You cant add yourself as Sudo User..." +sudo_3: "`No SUDO User was assigned ...`" +sudo_4: "`Bots can't be added as Sudo Users.`" + +# unsplash +unspl_1: "No Results Found !" + +# updater +upd_1: "`Checking for updates...`" +upd_2: "`Oops.. Updater cannot continue due to some problems.`\n\n**LOGTRACE:**\n" +upd_3: "**New UPDATE available for [[{}]]({}/tree/{}):\n\nCHANGELOG**\n\n{}" +upd_4: "`Changelog is too big, view the file to see it.`" +upd_5: "Click the below button to update." +upd_6: "\n`Your BOT is` **up-to-date** `with` **[[{}]]({}/tree/{})**\n" +upd_7: "`Fast Soft Updating...`" + +# upload download +udl_1: "`Reply to the file/media you want to download...`" +udl_2: "Download Successful..\nTo\n`{}`\nin `{}`" +udl_3: "`Give a specific path to file`" +udl_4: "`Trying to download...`" +udl_5: "`You forgot to give link :(`" +udl_6: "`This Directory is Empty.`" +udl_7: "`You can't do that!`" + +# vctools +vct_1: "`Voice Chat Started...`" +vct_2: "**Successfully Changed VC Title to** `{}`" +vct_3: "`Inviting Members to Voice Chat...`" +vct_4: "`Voice Chat Stopped...`" +vct_5: "`Invited {} users`" +vct_6: "No input Found!" + +# words +wrd_1: "• **Word :** `{}`\n• **Meaning :** __{}__\n\n• **Example :** __{}__" +wrd_2: "**Word** - `{}`\n\n**Synonyms** - \n" +wrd_3: "**Word** - `{}`\n\n**Antonyms** - \n" +wrd_4: "`Give a Word to Find Its Meaning..`" +wrd_5: "Synonyms" +wrd_6: "Antonyms" +wrd_7: "No synonym found!!\n\n`{}`" +wrd_8: "No Antonyms found!!\n\n`{}`" + +# profanitY +prof_1: "`Added This Chat for Profanity Filtering!`" +prof_2: "`Removed This Chat from Profanity Filtering!`" + +# notes +notes_1: "`Use this Command with Reply and word to use a note.`" +notes_2: "Done Note : `#{}` saved." +notes_3: "`Give me the note handler which you want to remove.`" +notes_4: "Notes Found In This Chats Are\n\n" +notes_5: "No Notes Found Here" + +# stickertools +sts_1: "`You haven't written any article, Waifu is going away.`" +sts_2: "`Reply to an Animated Sticker...`" +sts_3: "**Please select from {} **" +sts_4: "`Reply to Non Animated Sticker.`" +sts_5: "**Pack Kanged Successfully**.\n**Kanged Pack:** [link]({})" +sts_6: "`Reply to message/media...`" +sts_7: "`Sticker added in a Different Pack !\nThis Pack is Newly created!\nYour pack can be found` [here](t.me/addstickers/{})" +sts_8: "`Failed to add sticker, use` @Stickers `bot to add the sticker manually.`" +sts_9: "`Ooo Animated Sticker 👀...`" +sts_10: "`Reply to any media...`" +sts_11: "Kanging this Sticker..." +sts_12: "`Kanged!`\n`Emoji-` {}\n`Sticker Pack` [here](t.me/addstickers/{})" +sts_13: "`Switching to Pack {} due to insufficient space`" + +# whichsong +whs_1: "<• Reply to Audio File •>" +whs_2: "`Trying to identify the song....`" +whs_3: "Failed to Identify song :(" +whs_4: "**Song Recognised!**\nName: __{}__" + +# webupload +wbl_1: "`Provide a File Name pls..`" + +# writer +writer_1: "`Give Some Text Too`" + +# webshot +wbs_1: "`Give a URL please!`" +wbs_2: "Invalid URL!" +wbs_3: "**WebShot Generated**\n**URL**: {}" + +# youtube +youtube_1: "Give me a (youtube) URL to download audio from!" +youtube_2: "`Give A Direct Audio Link To Download`" +youtube_3: "Give me a (youtube) URL to download video from!" +youtube_4: "`Give A Direct Video Link To Download`" +youtube_5: "Give me a (youtube) search query to download audio from!" +youtube_6: "`Downloading audio song...`" +youtube_7: "Give me a (youtube) search query to download video from!" +youtube_8: "`Downloading video song...`" + +# ziptools +zip_1: "Reply to any media/Document." +zip_2: "First add All Files Via `{}addzip` then doZip to zip all files at one." +zip_3: "`Reply to zip file only`" + +# file share +fsh_1: "**List of files stored.:**" +fsh_2: "**File has been stored!**\n\n**Shareable link:** {}" +fsh_3: "`Reply to a message to make a shareable link!`" +fsh_4: "**No files stored!**" + +# getmsgs +gms_1: "Provide a valid message link!" +ls1: "`File doesn't exist or path is incorrect!`" +th_1: "`Please reply to a file to download its thumbnail!`" +th_2: "`Replied file has no thumbnail.`" + +# ------------------------- assistant --------------------------# + +ast_1: "Choose which API you want to set." +ast_2: "**remove.bg API**\nEnter your API key from remove.bg.\n\nUse /cancel to terminate the operation." +ast_3: "Hey {}. Please browse through the options" +ast_4: "List Of Available Languages." + +# inlinestuff +instu_1: "App search. Enter app name!" +instu_2: "Recent Searches.." +instu_3: "Enter Query to Search" +instu_4: "Success" + +# games +games_1: "Choose The Game 🎮" +games_2: "Choose Category!" +games_3: "Choose Difficulty Level" +games_4: "Choose Number of Questions.." +games_5: "Choose Time Interval..." +games_6: "**• Starting Quiz in 5 secs.** \n**• Level :** {}\n**• Qs :** {}" + +# callbackstuffs +clst_1: "`Userbot dyno build in progress, please wait for it to complete.`" +clst_2: "`Successfully Updated!\nRestarting, please wait...`" +clst_3: "■ Generating Changelogs..." +clst_4: "Something went wrong..." +clst_5: "Done!" + +# pmbot +pmbot_1: "**You need to join below chat(s) in order to chat with my master!\n\n**" +pmbot_2: "Please reply to someone to ban him." +pmbot_3: "User is already banned!" +pmbot_4: "`GoodBye! You have been banned.`\n**Further messages you send will not be forwarded.**" +pmbot_5: "Please reply to someone to Unban him." +pmbot_6: "User was never banned!" +pmbot_7: "`Congrats! You have been unbanned.`" + +# -------------------------- VcBot ------------------------------- # + +vcbot_1: "`Left the voice chat.`" +vcbot_2: "**ERROR:**\n{}" +vcbot_3: "• Volume Changed to `{}%` •" +vcbot_4: "`Please specify a volume from 1 to 200!`" +vcbot_5: "`Re-joining this voice chat.`" +vcbot_6: "You haven't connected to a voice chat!" +vcbot_7: "`Keep patience... It'll take some time.`" +vcbot_8: "Give only youtube playlist" +vcbot_9: "Are You Kidding Me?\nWhat to Play?" +vcbot_10: "Removed Chat from Vc AUTH Groups!" +vcbot_11: "`Getting Voice Chat Bot Users List...`" +vcbot_12: "`Muted playback in this chat.`" +vcbot_13: "`Resumed playback in this chat.`" +vcbot_14: "`Paused playback in this chat.`" +vcbot_15: "Please specify a song name or reply to a video file !" +vcbot_16: "Chat is Not in Vc Auth list..." +vcbot_17: "`Reply to user's msg or add it's id/username...`" +vcbot_18: "• Vc Auth List is Empty.." +vcbot_19: "Already Authed This Chat!" +vcbot_20: "`Downloading and converting...`" +vcbot_21: "• Nothing in queue!" +vcbot_22: "`Cleaned All Queues In Chat`" + +# Help Menus + +cmda: "✘ Commands Available" +help_admintools: "-\n\n• `.promote `\n• `.demote`\n Promote/Demote the user in the chat.\n\n• `.ban `\n• `.unban`\n Ban/Unban the user from the chat.\n\n• `.kick `\n Kick the user from the chat.\n\n• `.pin `\n Pin the message in the chat\n• `.tpin