├── resources ├── font.ttf ├── userge.png ├── sticker.webp ├── tutorial.jpg ├── docker-compose.yml └── radmeDocker.md ├── .travis.yml ├── .deepsource.toml ├── .github └── pull.yml ├── .pep8speaks.yml ├── tests ├── __init__.py └── __main__.py ├── genStr ├── .gitpod.yml ├── userge ├── plugins │ ├── admin │ │ ├── __init__.py │ │ └── purge.py │ ├── fun │ │ ├── __init__.py │ │ ├── quote.py │ │ ├── whois.py │ │ └── autopic.py │ ├── misc │ │ └── __init__.py │ ├── tools │ │ ├── __init__.py │ │ ├── json.py │ │ ├── sd.py │ │ ├── all.py │ │ ├── ping.py │ │ ├── repo.py │ │ ├── search.py │ │ ├── cancel.py │ │ ├── delete.py │ │ ├── ids.py │ │ ├── logs.py │ │ ├── updater.py │ │ └── timeout.py │ ├── utils │ │ ├── __init__.py │ │ ├── ud.py │ │ ├── header.py │ │ ├── wikipedia.py │ │ ├── google.py │ │ ├── speedtest.py │ │ ├── hash.py │ │ ├── admins.py │ │ ├── removebg.py │ │ ├── currency.py │ │ ├── covid.py │ │ ├── webss.py │ │ ├── translate.py │ │ ├── ocr.py │ │ ├── thumbnail.py │ │ ├── telegraph.py │ │ ├── dic.py │ │ └── weather.py │ └── __init__.py ├── core │ ├── types │ │ ├── __init__.py │ │ ├── bound │ │ │ └── __init__.py │ │ ├── raw │ │ │ ├── __init__.py │ │ │ └── plugin.py │ │ └── new │ │ │ └── __init__.py │ ├── ext │ │ ├── __init__.py │ │ ├── pool.py │ │ └── raw_client.py │ ├── methods │ │ ├── users │ │ │ ├── __init__.py │ │ │ └── get_user_dict.py │ │ ├── chats │ │ │ ├── __init__.py │ │ │ ├── conversation.py │ │ │ └── send_read_acknowledge.py │ │ ├── messages │ │ │ ├── __init__.py │ │ │ ├── send_as_file.py │ │ │ ├── edit_message_text.py │ │ │ └── send_message.py │ │ ├── utils │ │ │ ├── __init__.py │ │ │ ├── get_logger.py │ │ │ ├── get_channel_logger.py │ │ │ ├── terminate.py │ │ │ └── restart.py │ │ ├── __init__.py │ │ └── decorators │ │ │ ├── add_task.py │ │ │ ├── __init__.py │ │ │ ├── on_new_member.py │ │ │ ├── on_left_member.py │ │ │ └── on_filters.py │ ├── __init__.py │ └── database.py ├── __init__.py ├── utils │ ├── exceptions.py │ ├── __init__.py │ ├── sys_tools.py │ └── progress.py ├── versions.py ├── __main__.py ├── logger.py ├── logbot.py └── config.py ├── init ├── logbot │ ├── core │ │ ├── types │ │ │ ├── types.sh │ │ │ ├── message.sh │ │ │ └── messageClass.sh │ │ ├── methods │ │ │ ├── methods.sh │ │ │ ├── rawMethods.sh │ │ │ └── apiMethods.sh │ │ ├── core.sh │ │ ├── utils.sh │ │ └── api.sh │ ├── logbot.sh │ └── methods │ │ ├── methods.sh │ │ ├── basic.sh │ │ └── polling.sh ├── proc.sh ├── init.sh ├── utils.sh └── checks.sh ├── .gitpod.Dockerfile ├── run ├── requirements.txt ├── tools └── genStrSession.py ├── Dockerfile ├── .gitignore ├── README.md └── config.env.sample /resources/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmuhammadali/Userge/HEAD/resources/font.ttf -------------------------------------------------------------------------------- /resources/userge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmuhammadali/Userge/HEAD/resources/userge.png -------------------------------------------------------------------------------- /resources/sticker.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmuhammadali/Userge/HEAD/resources/sticker.webp -------------------------------------------------------------------------------- /resources/tutorial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmuhammadali/Userge/HEAD/resources/tutorial.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.8" 4 | - "3.9" 5 | install: 6 | - pip install -r requirements.txt 7 | before_script: 8 | - mkdir -p logs 9 | script: 10 | - python -m tests 11 | -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "python" 5 | enabled = true 6 | dependency_file_paths = ["requirements.txt"] 7 | 8 | [analyzers.meta] 9 | runtime_version = "3.x.x" 10 | max_line_length = 100 11 | -------------------------------------------------------------------------------- /.github/pull.yml: -------------------------------------------------------------------------------- 1 | version: "1" 2 | rules: 3 | - base: alpha 4 | upstream: UsergeTeam:alpha 5 | mergeMethod: rebase 6 | mergeUnstable: false 7 | - base: beta 8 | upstream: UsergeTeam:beta 9 | mergeMethod: rebase 10 | - base: master 11 | upstream: UsergeTeam:master 12 | mergeMethod: rebase 13 | -------------------------------------------------------------------------------- /.pep8speaks.yml: -------------------------------------------------------------------------------- 1 | # File : .pep8speaks.yml 2 | 3 | scanner: 4 | linter: flake8 5 | 6 | flake8: 7 | max-line-length: 100 8 | ignore: 9 | - W503 # line break before binary operator 10 | 11 | message: 12 | opened: 13 | header: "@{name}, Thanks for opening this PR." 14 | updated: 15 | header: "@{name}, Thanks for updating this PR." 16 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. -------------------------------------------------------------------------------- /genStr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | exec python3 tools/genStrSession.py 12 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | # Install dependencies first. 6 | - init: pip install -r ./requirements.txt 7 | # Then run if there's config.env, otherwise prompt to configure. 8 | command: > 9 | if [[ -f config.env ]]; then 10 | bash run 11 | else 12 | echo "Please copy the config.env.sample file and edit it to continue." 13 | fi 14 | -------------------------------------------------------------------------------- /userge/plugins/admin/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | -------------------------------------------------------------------------------- /userge/plugins/fun/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | -------------------------------------------------------------------------------- /userge/plugins/misc/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | -------------------------------------------------------------------------------- /userge/plugins/tools/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | -------------------------------------------------------------------------------- /userge/plugins/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | -------------------------------------------------------------------------------- /init/logbot/core/types/types.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/core/types/message.sh 12 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full-vnc 2 | 3 | RUN sudo apt-get update 4 | RUN sudo apt-get install -y \ 5 | libasound2-dev \ 6 | libgtk-3-dev \ 7 | libnss3-dev \ 8 | curl \ 9 | git \ 10 | gnupg2 \ 11 | unzip \ 12 | wget \ 13 | neofetch \ 14 | ffmpeg \ 15 | jq 16 | 17 | RUN curl -sO https://cli-assets.heroku.com/install.sh && bash install.sh && rm install.sh 18 | 19 | RUN sudo rm -rf /var/lib/apt/lists/* -------------------------------------------------------------------------------- /init/logbot/logbot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/core/core.sh 12 | . init/logbot/methods/methods.sh 13 | -------------------------------------------------------------------------------- /init/logbot/methods/methods.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/methods/basic.sh 12 | . init/logbot/methods/polling.sh 13 | -------------------------------------------------------------------------------- /userge/core/types/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from . import raw, bound, new # noqa 12 | -------------------------------------------------------------------------------- /userge/core/types/bound/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from .message import Message # noqa 12 | -------------------------------------------------------------------------------- /init/logbot/core/methods/methods.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/core/methods/apiMethods.sh 12 | . init/logbot/core/methods/rawMethods.sh 13 | -------------------------------------------------------------------------------- /init/logbot/core/types/message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | Message() { 12 | . <(sed "s/_Message/$1/g" init/logbot/core/types/messageClass.sh) 13 | } 14 | -------------------------------------------------------------------------------- /init/logbot/core/core.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/core/api.sh 12 | . init/logbot/core/types/types.sh 13 | . init/logbot/core/methods/methods.sh 14 | -------------------------------------------------------------------------------- /userge/core/types/raw/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from .filter import Filter, clear_db # noqa 12 | from .command import Command # noqa 13 | from .plugin import Plugin # noqa 14 | -------------------------------------------------------------------------------- /userge/core/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from pyrogram.types import Message as RawMessage # noqa 12 | 13 | from . import pool # noqa 14 | from .raw_client import RawClient # noqa 15 | -------------------------------------------------------------------------------- /init/logbot/core/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | urlEncode() { 12 | echo "$(echo "${1#\~}" | sed -E 's/(\\t)|(\\n)/ /g' | 13 | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-)" 14 | } 15 | -------------------------------------------------------------------------------- /userge/core/methods/users/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Users'] 12 | 13 | from .get_user_dict import GetUserDict 14 | 15 | 16 | class Users(GetUserDict): 17 | """ methods.users """ 18 | -------------------------------------------------------------------------------- /userge/core/types/new/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from .channel_logger import ChannelLogger # noqa 12 | from .conversation import Conversation # noqa 13 | from .manager import Manager # noqa 14 | -------------------------------------------------------------------------------- /resources/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | userge: 5 | build: 6 | context: https://github.com/UsergeTeam/Userge.git#master 7 | depends_on: 8 | - mongo 9 | restart: on-failure 10 | environment: 11 | DATABASE_URL: mongodb://root:example@mongo 12 | env_file: 13 | - config.env 14 | 15 | mongo: 16 | image: mongo 17 | volumes: 18 | - mongo_userge:/data/db 19 | environment: 20 | MONGO_INITDB_ROOT_USERNAME: root 21 | MONGO_INITDB_ROOT_PASSWORD: example 22 | 23 | volumes: 24 | mongo_userge: 25 | -------------------------------------------------------------------------------- /userge/core/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from pyrogram import filters # noqa 12 | 13 | from .database import get_collection # noqa 14 | from .ext import pool # noqa 15 | from .types.bound import Message # noqa 16 | from .client import Userge # noqa 17 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/proc.sh 12 | 13 | declare -ir usr1=138 14 | declare -r cmd='. init/init.sh; runUserge "$@"' 15 | 16 | run() { 17 | reInitProc 18 | bash -c "$cmd" $0 "$@" & 19 | setProc $! 20 | waitProc 21 | test $? -eq $usr1 && run "$@" 22 | } 23 | 24 | run "$@" 25 | -------------------------------------------------------------------------------- /userge/core/methods/chats/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Chats'] 12 | 13 | from .conversation import Conversation 14 | from .send_read_acknowledge import SendReadAcknowledge 15 | 16 | 17 | class Chats(Conversation, SendReadAcknowledge): 18 | """ methods.chats """ 19 | -------------------------------------------------------------------------------- /userge/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from userge.logger import logging # noqa 12 | from userge.config import Config, get_version # noqa 13 | from userge.core import ( # noqa 14 | Userge, filters, Message, get_collection, pool) 15 | 16 | userge = Userge() # userge is the client name 17 | -------------------------------------------------------------------------------- /userge/core/methods/messages/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Messages'] 12 | 13 | from .send_message import SendMessage 14 | from .edit_message_text import EditMessageText 15 | from .send_as_file import SendAsFile 16 | 17 | 18 | class Messages(SendMessage, EditMessageText, SendAsFile): 19 | """ methods.messages """ 20 | -------------------------------------------------------------------------------- /userge/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | 12 | class StopConversation(Exception): 13 | """ raise if conversation has terminated """ 14 | 15 | 16 | class ProcessCanceled(Exception): 17 | """ raise if thread has terminated """ 18 | 19 | 20 | class UsergeBotNotFound(Exception): 21 | """ raise if userge bot not found """ 22 | -------------------------------------------------------------------------------- /userge/core/methods/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Utils'] 12 | 13 | from .get_logger import GetLogger 14 | from .get_channel_logger import GetCLogger 15 | from .restart import Restart 16 | from .terminate import Terminate 17 | 18 | 19 | class Utils(GetLogger, GetCLogger, Restart, Terminate): 20 | """ methods.utils """ 21 | -------------------------------------------------------------------------------- /userge/core/methods/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Methods'] 12 | 13 | from .chats import Chats 14 | from .decorators import Decorators 15 | from .messages import Messages 16 | from .users import Users 17 | from .utils import Utils 18 | 19 | 20 | class Methods(Chats, Decorators, Messages, Users, Utils): 21 | """ userge.methods """ 22 | -------------------------------------------------------------------------------- /userge/plugins/tools/json.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("json", about={ 13 | 'header': "message object to json", 14 | 'usage': "reply {tr}json to any message"}) 15 | async def jsonify(message: Message): 16 | msg = str(message.reply_to_message) if message.reply_to_message else str(message) 17 | await message.edit_or_send_as_file(text=msg, filename="json.txt", caption="Too Large") 18 | -------------------------------------------------------------------------------- /userge/core/methods/decorators/add_task.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['AddTask'] 12 | 13 | from typing import Callable, Any 14 | 15 | from . import RawDecorator 16 | 17 | 18 | class AddTask(RawDecorator): # pylint: disable=missing-class-docstring 19 | def add_task(self, func: Callable[[], Any]) -> Callable[[], Any]: 20 | """ add tasks """ 21 | self._tasks.append(func) 22 | return func 23 | -------------------------------------------------------------------------------- /userge/plugins/tools/sd.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("sd (?:(\\d+)?\\s?(.+))", about={ 13 | 'header': "make self-destructable messages", 14 | 'usage': "{tr}sd [test]\n{tr}sd [timeout in seconds] [text]"}) 15 | async def selfdestruct(message: Message): 16 | seconds = int(message.matches[0].group(1) or 0) 17 | text = str(message.matches[0].group(2)) 18 | await message.edit(text=text, del_in=seconds) 19 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles 2 | aiohttp 3 | bs4 4 | covid 5 | cowpy 6 | dnspython 7 | emoji==0.6.0 8 | fake-headers 9 | feedparser 10 | ffmpeg-python 11 | gitpython 12 | google-api-python-client 13 | google-auth-httplib2 14 | google-auth-oauthlib 15 | googletrans==4.0.0rc1 16 | hachoir 17 | heroku3 18 | html-telegraph-poster 19 | motor 20 | oauth2client 21 | Pillow==9.0.0 22 | psutil 23 | pybase64 24 | pyrogram>=1.3.6 25 | pySmartDL 26 | pysocks 27 | py-tgcalls==0.8.5 28 | python-dotenv 29 | pytz 30 | rarfile 31 | removebg 32 | requests 33 | search-engine-parser 34 | selenium==3.141.0 35 | setuptools>=40.3.0 36 | spamwatch 37 | speedtest-cli 38 | stagger 39 | telegraph 40 | tgcrypto 41 | urbandict==0.5 42 | UsergeAntiSpamApi==0.1.8 43 | wget 44 | wikipedia 45 | youtube_dl>=2021.1.8 46 | youtube-search-python==1.4.9 47 | -------------------------------------------------------------------------------- /userge/versions.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from sys import version_info 12 | 13 | from pyrogram import __version__ as __pyro_version__ # noqa 14 | 15 | __major__ = 0 16 | __minor__ = 7 17 | __micro__ = 0 18 | 19 | __python_version__ = f"{version_info[0]}.{version_info[1]}.{version_info[2]}" 20 | __license__ = "[GNU GPL v3.0](https://github.com/UsergeTeam/Userge/blob/master/LICENSE)" 21 | __copyright__ = "[UsergeTeam](https://github.com/UsergeTeam)" 22 | -------------------------------------------------------------------------------- /userge/core/methods/decorators/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Decorators'] 12 | 13 | from .raw_decorator import RawDecorator # noqa 14 | from .add_task import AddTask 15 | from .on_cmd import OnCmd 16 | from .on_filters import OnFilters 17 | from .on_left_member import OnLeftMember 18 | from .on_new_member import OnNewMember 19 | 20 | 21 | class Decorators(AddTask, OnCmd, OnFilters, OnLeftMember, OnNewMember): 22 | """ methods.decorators """ 23 | -------------------------------------------------------------------------------- /userge/plugins/tools/all.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | from .. import get_all_plugins 11 | 12 | 13 | @userge.on_cmd("all", about={'header': "list all plugins in plugins/ path"}) 14 | async def getplugins(message: Message): 15 | raw_ = get_all_plugins() 16 | out_str = f"**--({len(raw_)}) Plugins Available!--**\n\n" 17 | for plugin in ('/'.join(i.split('.')) for i in raw_): 18 | out_str += f" `{plugin}.py`\n" 19 | await message.edit(text=out_str, del_in=0) 20 | -------------------------------------------------------------------------------- /tests/__main__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | import os 12 | 13 | from userge import userge 14 | 15 | 16 | async def _worker() -> None: 17 | chat_id = int(os.environ.get("CHAT_ID") or 0) 18 | type_ = 'unofficial' if os.path.exists("../userge/plugins/unofficial") else 'main' 19 | await userge.send_message(chat_id, f'`{type_} build completed !`') 20 | 21 | if __name__ == "__main__": 22 | userge.begin(_worker()) 23 | print('userge test has been finished!') 24 | -------------------------------------------------------------------------------- /init/logbot/core/methods/rawMethods.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | raw.getMessageCount() { 12 | return ${#_allMessages[@]} 13 | } 14 | 15 | raw.getAllMessages() { 16 | echo ${_allMessages[@]} 17 | } 18 | 19 | raw.getLastMessage() { 20 | if test ${#_allMessages[@]} -gt 0; then 21 | ${_allMessages[-1]}.$1 "$2" 22 | elif [[ -n $BOT_TOKEN && -n $LOG_CHANNEL_ID ]]; then 23 | log "first sendMessage ! (caused by \"core.methods.$FUNCNAME\")\n"$2"" 24 | else 25 | log "$2" 26 | fi 27 | } 28 | -------------------------------------------------------------------------------- /userge/plugins/tools/ping.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from datetime import datetime 10 | 11 | from pyrogram.raw.functions import Ping 12 | 13 | from userge import userge, Message 14 | 15 | 16 | @userge.on_cmd("ping", about={ 17 | 'header': "check how long it takes to ping your userbot"}, group=-1) 18 | async def pingme(message: Message): 19 | start = datetime.now() 20 | await message.client.send(Ping(ping_id=0)) 21 | end = datetime.now() 22 | m_s = (end - start).microseconds / 1000 23 | await message.edit(f"**Pong!**\n`{m_s} ms`") 24 | -------------------------------------------------------------------------------- /userge/__main__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from pyrogram import StopPropagation 12 | from pyrogram.raw.base import Message 13 | from pyrogram.raw.types import MessageService, MessageActionContactSignUp 14 | 15 | from userge import userge 16 | 17 | 18 | @userge.on_raw_update(-5) 19 | async def _on_raw(_, m: Message, *__) -> None: 20 | if isinstance(m, MessageService) and isinstance(m.action, MessageActionContactSignUp): 21 | raise StopPropagation 22 | 23 | 24 | if __name__ == "__main__": 25 | userge.begin() 26 | -------------------------------------------------------------------------------- /init/proc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | declare -i bgProc 12 | 13 | _addHandler() { 14 | trap killProc HUP TERM INT 15 | } 16 | 17 | _removeHandler() { 18 | trap - HUP TERM INT 19 | } 20 | 21 | setProc() { 22 | bgProc=$1 23 | } 24 | 25 | _waitProc() { 26 | test $bgProc && wait $bgProc 27 | } 28 | 29 | waitProc() { 30 | _waitProc 31 | _removeHandler 32 | _waitProc 33 | } 34 | 35 | killProc() { 36 | test $bgProc && kill -TERM $bgProc &> /dev/null 37 | } 38 | 39 | reInitProc() { 40 | killProc 41 | waitProc 42 | _addHandler 43 | } 44 | -------------------------------------------------------------------------------- /userge/plugins/tools/repo.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message, Config, versions, get_version 10 | 11 | 12 | @userge.on_cmd("repo", about={'header': "get repo link and details"}) 13 | async def see_repo(message: Message): 14 | """see repo""" 15 | output = f""" 16 | **Hey**, __I am using__ 🔥 **Userge** 🔥 17 | 18 | __Durable as a Serge__ 19 | 20 | • **userge version** : `{get_version()}` 21 | • **license** : {versions.__license__} 22 | • **copyright** : {versions.__copyright__} 23 | • **repo** : [Userge]({Config.UPSTREAM_REPO}) 24 | """ 25 | await message.edit(output) 26 | -------------------------------------------------------------------------------- /userge/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['ROOT', 'get_all_plugins'] 12 | 13 | import sys 14 | from os.path import dirname 15 | from typing import List 16 | 17 | from userge import logging 18 | from userge.utils import get_import_path 19 | 20 | _LOG = logging.getLogger(__name__) 21 | ROOT = dirname(__file__) 22 | 23 | 24 | def get_all_plugins() -> List[str]: 25 | """ list all plugins """ 26 | plugins = get_import_path( 27 | ROOT, "/dev/" if len(sys.argv) == 2 and sys.argv[1] == 'dev' else "/**/") 28 | _LOG.debug("All Available Plugins: %s", plugins) 29 | return list(plugins) 30 | -------------------------------------------------------------------------------- /init/logbot/methods/basic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | sendMessage() { 12 | test -z "$1" || api.sendMessage $LOG_CHANNEL_ID "$1" 13 | } 14 | 15 | replyLastMessage() { 16 | test -z "$1" || raw.getLastMessage reply "$1" 17 | } 18 | 19 | editLastMessage() { 20 | test -z "$1" || raw.getLastMessage edit "$1" 21 | } 22 | 23 | deleteLastMessage() { 24 | raw.getLastMessage delete 25 | } 26 | 27 | deleteMessages() { 28 | raw.getMessageCount 29 | local count=$(($?)) 30 | for ((i=0; i<$count; i++)); do 31 | deleteLastMessage 32 | done 33 | } 34 | 35 | printMessages() { 36 | for msg in $(raw.getAllMessages); do 37 | printf "{%s: %s}\n" $msg "$($msg.print)" 38 | done 39 | } 40 | -------------------------------------------------------------------------------- /userge/core/methods/utils/get_logger.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['GetLogger'] 12 | 13 | import inspect 14 | 15 | from userge import logging 16 | 17 | _LOG = logging.getLogger(__name__) 18 | _LOG_STR = "<<>>" 19 | 20 | 21 | class GetLogger: # pylint: disable=missing-class-docstring 22 | @staticmethod 23 | def getLogger(name: str = '') -> logging.Logger: # pylint: disable=invalid-name 24 | """ This returns new logger object """ 25 | if not name: 26 | name = inspect.currentframe().f_back.f_globals['__name__'] 27 | _LOG.debug(_LOG_STR, f"Creating Logger => {name}") 28 | return logging.getLogger(name) 29 | -------------------------------------------------------------------------------- /userge/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from .progress import progress # noqa 12 | from .sys_tools import SafeDict, get_import_path, terminate, secure_text # noqa 13 | from .tools import (sort_file_name_key, # noqa 14 | import_ytdl, 15 | is_url, 16 | demojify, 17 | get_file_id_of_media, 18 | humanbytes, 19 | time_formatter, 20 | post_to_telegraph, 21 | runcmd, 22 | take_screen_shot, 23 | parse_buttons, 24 | is_command, 25 | extract_entities) 26 | -------------------------------------------------------------------------------- /userge/plugins/tools/search.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("s", about={ 13 | 'header': "search commands in USERGE", 14 | 'examples': "{tr}s wel"}, allow_channels=False) 15 | async def search(message: Message): 16 | cmd = message.input_str 17 | if not cmd: 18 | await message.err("Enter any keyword to search in commands") 19 | return 20 | found = [i for i in sorted(list(userge.manager.enabled_commands)) if cmd in i] 21 | out_str = ' '.join(found) 22 | if found: 23 | out = f"**--I found ({len(found)}) commands for-- : `{cmd}`**\n\n`{out_str}`" 24 | else: 25 | out = f"__command not found for__ : `{cmd}`" 26 | await message.edit(text=out, del_in=0) 27 | -------------------------------------------------------------------------------- /userge/core/methods/utils/get_channel_logger.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['GetCLogger'] 12 | 13 | import inspect 14 | 15 | from userge import logging 16 | from ...ext import RawClient 17 | from ... import types 18 | 19 | _LOG = logging.getLogger(__name__) 20 | _LOG_STR = "<<>>" 21 | 22 | 23 | class GetCLogger(RawClient): # pylint: disable=missing-class-docstring 24 | # pylint: disable=invalid-name 25 | def getCLogger(self, name: str = '') -> 'types.new.ChannelLogger': 26 | """ This returns new channel logger object """ 27 | if not name: 28 | name = inspect.currentframe().f_back.f_globals['__name__'] 29 | _LOG.debug(_LOG_STR, f"Creating CLogger => {name}") 30 | return types.new.ChannelLogger(self, name) 31 | -------------------------------------------------------------------------------- /userge/core/methods/utils/terminate.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Terminate'] 12 | 13 | import asyncio 14 | 15 | from ...ext import RawClient 16 | 17 | 18 | class Terminate(RawClient): # pylint: disable=missing-class-docstring 19 | async def terminate(self) -> None: 20 | """ terminate userge """ 21 | if not self.no_updates: 22 | for _ in range(self.workers): 23 | self.dispatcher.updates_queue.put_nowait(None) 24 | for task in self.dispatcher.handler_worker_tasks: 25 | try: 26 | await asyncio.wait_for(task, timeout=0.3) 27 | except asyncio.TimeoutError: 28 | task.cancel() 29 | self.dispatcher.handler_worker_tasks.clear() 30 | await super().terminate() 31 | -------------------------------------------------------------------------------- /userge/plugins/tools/cancel.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("cancel", about={ 13 | 'header': "Reply this to message you want to cancel", 14 | 'flags': {'-a': "cancel all tasks"}}) 15 | async def cancel_(message: Message): 16 | if '-a' in message.flags: 17 | ret = Message._call_all_cancel_callbacks() # pylint: disable=protected-access 18 | if ret == 0: 19 | await message.err("nothing found to cancel", show_help=False) 20 | return 21 | replied = message.reply_to_message # type: Message 22 | if replied: 23 | if not replied._call_cancel_callbacks(): # pylint: disable=protected-access 24 | await message.err("nothing found to cancel", show_help=False) 25 | else: 26 | await message.err("source not provided !", show_help=False) 27 | -------------------------------------------------------------------------------- /init/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/logbot.sh 12 | . init/proc.sh 13 | . init/utils.sh 14 | . init/checks.sh 15 | 16 | trap 'handleSig SIGHUP' HUP 17 | trap 'handleSig SIGTERM' TERM 18 | trap 'handleSig SIGINT' INT 19 | trap '' USR1 20 | 21 | handleSig() { 22 | log "Exiting With $1 ..." 23 | killProc 24 | } 25 | 26 | initUserge() { 27 | printLogo 28 | assertPrerequisites 29 | sendMessage "Initializing Userge ..." 30 | assertEnvironment 31 | editLastMessage "Starting Userge ..." 32 | printLine 33 | } 34 | 35 | startUserge() { 36 | startLogBotPolling 37 | runPythonModule userge "$@" 38 | } 39 | 40 | stopUserge() { 41 | sendMessage "Exiting Userge ..." 42 | endLogBotPolling 43 | } 44 | 45 | runUserge() { 46 | initUserge 47 | startUserge "$@" 48 | local code=$? 49 | stopUserge 50 | return $code 51 | } 52 | -------------------------------------------------------------------------------- /init/logbot/core/methods/apiMethods.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | . init/logbot/core/utils.sh 12 | 13 | api.getUpdates() { 14 | local params=($*) 15 | _getResponse $FUNCNAME ${params[*]} 16 | } 17 | 18 | api.sendMessage() { 19 | local params=( 20 | chat_id=$1 21 | text=$(urlEncode "$2") 22 | parse_mode=HTML 23 | ) 24 | test -n $3 && params+=(reply_to_message_id=$3) 25 | log "$2" 26 | _getResponse $FUNCNAME ${params[*]} 27 | } 28 | 29 | api.editMessageText() { 30 | local params=( 31 | chat_id=$1 32 | message_id=$2 33 | text=$(urlEncode "$3") 34 | parse_mode=HTML 35 | ) 36 | log "$3" 37 | _getResponse $FUNCNAME ${params[*]} 38 | } 39 | 40 | api.deleteMessage() { 41 | local params=( 42 | chat_id=$1 43 | message_id=$2 44 | ) 45 | unset _allMessages[$3] 46 | _getResponse $FUNCNAME ${params[*]} 47 | } 48 | -------------------------------------------------------------------------------- /userge/logger.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['logging'] 12 | 13 | import logging 14 | from logging.handlers import RotatingFileHandler 15 | 16 | logging.basicConfig(level=logging.INFO, 17 | format='[%(asctime)s - %(levelname)s] - %(name)s - %(message)s', 18 | datefmt='%d-%b-%y %H:%M:%S', 19 | handlers=[ 20 | RotatingFileHandler( 21 | "logs/userge.log", maxBytes=20480, backupCount=10), 22 | logging.StreamHandler() 23 | ]) 24 | 25 | logging.getLogger("pyrogram").setLevel(logging.WARNING) 26 | logging.getLogger("pytgcalls").setLevel(logging.WARNING) 27 | logging.getLogger("pyrogram.parser.html").setLevel(logging.ERROR) 28 | logging.getLogger("pyrogram.session.session").setLevel(logging.ERROR) 29 | logging.getLogger('googleapiclient.discovery').setLevel(logging.WARNING) 30 | -------------------------------------------------------------------------------- /userge/core/methods/users/get_user_dict.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['GetUserDict'] 12 | 13 | from typing import Dict, Union 14 | 15 | from ...ext import RawClient 16 | 17 | 18 | class GetUserDict(RawClient): # pylint: disable=missing-class-docstring 19 | async def get_user_dict(self, user_id: Union[int, str]) -> Dict[str, str]: 20 | """This will return user `Dict` which contains 21 | `id`(chat id), `fname`(first name), `lname`(last name), 22 | `flname`(full name), `uname`(username) and `mention`. 23 | """ 24 | user_obj = await self.get_users(user_id) 25 | fname = (user_obj.first_name or '').strip() 26 | lname = (user_obj.last_name or '').strip() 27 | username = (user_obj.username or '').strip() 28 | if fname and lname: 29 | full_name = fname + ' ' + lname 30 | elif fname or lname: 31 | full_name = fname or lname 32 | else: 33 | full_name = "user" 34 | mention = f"[{username or full_name}](tg://user?id={user_id})" 35 | return {'id': user_obj.id, 'fname': fname, 'lname': lname, 36 | 'flname': full_name, 'uname': username, 'mention': mention} 37 | -------------------------------------------------------------------------------- /userge/core/ext/pool.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['submit_thread', 'run_in_thread'] 12 | 13 | import asyncio 14 | import atexit 15 | from concurrent.futures import ThreadPoolExecutor, Future 16 | from functools import wraps, partial 17 | from typing import Any, Callable 18 | 19 | from userge import logging, Config 20 | 21 | _LOG = logging.getLogger(__name__) 22 | _LOG_STR = "<<>>" 23 | _EXECUTOR = ThreadPoolExecutor(Config.WORKERS) 24 | # pylint: disable=protected-access 25 | _MAX = _EXECUTOR._max_workers 26 | 27 | 28 | def submit_thread(func: Callable[..., Any], *args: Any, **kwargs: Any) -> Future: 29 | """ submit thread to thread pool """ 30 | return _EXECUTOR.submit(func, *args, **kwargs) 31 | 32 | 33 | def run_in_thread(func: Callable[..., Any]) -> Callable[..., Any]: 34 | """ run in a thread """ 35 | @wraps(func) 36 | async def wrapper(*args: Any, **kwargs: Any) -> Any: 37 | loop = asyncio.get_running_loop() 38 | return await loop.run_in_executor(_EXECUTOR, partial(func, *args, **kwargs)) 39 | return wrapper 40 | 41 | 42 | def _stop(): 43 | _EXECUTOR.shutdown() 44 | _LOG.info(_LOG_STR, f"Stopped Pool : {_MAX} Workers") 45 | 46 | 47 | atexit.register(_stop) 48 | _LOG.info(_LOG_STR, f"Started Pool : {_MAX} Workers") 49 | -------------------------------------------------------------------------------- /tools/genStrSession.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name, missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | import asyncio 12 | import os 13 | 14 | from dotenv import load_dotenv 15 | from pyrogram import Client 16 | from pyrogram.errors import UserIsBot 17 | 18 | if os.path.isfile("config.env"): 19 | load_dotenv("config.env") 20 | 21 | # clean-up before gen. new Str 22 | if os.path.exists("tools/Userge.session"): 23 | os.remove("tools/Userge.session") 24 | 25 | 26 | async def genStrSession() -> None: # pylint: disable=missing-function-docstring 27 | async with Client( 28 | "Userge", 29 | api_id=int(os.environ.get("API_ID") or input("Enter Telegram APP ID: ")), 30 | api_hash=os.environ.get("API_HASH") or input("Enter Telegram API HASH: "), 31 | ) as userge: 32 | print("\nprocessing...") 33 | doneStr = "sent to saved messages!" 34 | try: 35 | await userge.send_message( 36 | "me", f"#USERGE #HU_STRING_SESSION\n\n`{await userge.export_session_string()}`" 37 | ) 38 | except UserIsBot: 39 | doneStr = "successfully printed!" 40 | print(await userge.export_session_string()) 41 | print(f"Done !, session string has been {doneStr}") 42 | 43 | 44 | if __name__ == "__main__": 45 | asyncio.get_event_loop().run_until_complete(genStrSession()) 46 | -------------------------------------------------------------------------------- /userge/logbot.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ["send_msg", "reply_last_msg", "edit_last_msg", "del_last_msg", "end"] 12 | 13 | 14 | def _log(func): 15 | def wrapper(text, log=None, tmp=None): 16 | if log and callable(log): 17 | if tmp: 18 | log(tmp, text) 19 | else: 20 | log(text) 21 | func(text) 22 | return wrapper 23 | 24 | 25 | def _send_data(*args) -> None: 26 | with open("logs/logbot.stdin", 'a') as l_b: 27 | l_b.write(f"{' '.join(args)}\n") 28 | 29 | 30 | @_log 31 | def send_msg(text: str, log=None, tmp=None) -> None: # pylint: disable=unused-argument 32 | """ send message """ 33 | _send_data("sendMessage", text) 34 | 35 | 36 | @_log 37 | def reply_last_msg(text: str, log=None, tmp=None) -> None: # pylint: disable=unused-argument 38 | """ reply to last message """ 39 | _send_data("replyLastMessage", text) 40 | 41 | 42 | @_log 43 | def edit_last_msg(text: str, log=None, tmp=None) -> None: # pylint: disable=unused-argument 44 | """ edit last message """ 45 | _send_data("editLastMessage", text) 46 | 47 | 48 | def del_last_msg() -> None: 49 | """ delete last message """ 50 | _send_data("deleteLastMessage") 51 | 52 | 53 | def end() -> None: 54 | """ end bot session """ 55 | _send_data("quit") 56 | -------------------------------------------------------------------------------- /userge/plugins/utils/ud.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from urllib.error import HTTPError 10 | 11 | import urbandict 12 | 13 | from userge import userge, Message 14 | 15 | 16 | @userge.on_cmd("ud", about={ 17 | 'header': "Searches Urban Dictionary for the query", 18 | 'flags': {'-l': "limit : defaults to 1"}, 19 | 'usage': "{tr}ud [flag] [query]", 20 | 'examples': ["{tr}ud userge", "{tr}ud -l3 userge"]}) 21 | async def urban_dict(message: Message): 22 | await message.edit("Processing...") 23 | query = message.filtered_input_str 24 | if not query: 25 | await message.err("No found any query!") 26 | return 27 | try: 28 | mean = urbandict.define(query) 29 | except HTTPError: 30 | await message.edit(f"Sorry, couldn't find any results for: `{query}`", del_in=5) 31 | return 32 | output = '' 33 | limit = int(message.flags.get('-l', 1)) 34 | for i, mean_ in enumerate(mean, start=1): 35 | output += f"{i}. **{mean_['def']}**\n" + \ 36 | f" Examples:\n * `{mean_['example'] or 'not found'}`\n\n" 37 | if limit <= i: 38 | break 39 | if not output: 40 | await message.edit(f"No result found for **{query}**", del_in=5) 41 | return 42 | output = f"**Query:** `{query}`\n**Limit:** `{limit}`\n\n{output}" 43 | await message.edit_or_send_as_file(text=output, caption=query) 44 | -------------------------------------------------------------------------------- /userge/plugins/utils/header.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import requests 10 | 11 | from userge import userge, Message 12 | 13 | 14 | @userge.on_cmd("head", about={ 15 | 'header': "View headers in URL", 16 | 'flags': { 17 | '-r': "allow redirects", 18 | '-s': "allow streams", 19 | '-t': "request timeout"}, 20 | 'usage': "{tr}head [flags] [url]", 21 | 'examples': "{tr}head -r -s -t5 https://www.google.com"}) 22 | async def req_head(message: Message): 23 | await message.edit("Processing ...") 24 | link = message.filtered_input_str 25 | flags = message.flags 26 | red = '-r' in flags 27 | stm = '-s' in flags 28 | tout = int(flags.get('-t', 3)) 29 | if not link: 30 | await message.err("Please give me a link link!") 31 | return 32 | try: 33 | cd = requests.head(url=link, 34 | stream=stm, 35 | allow_redirects=red, 36 | timeout=tout) 37 | except Exception as i_e: 38 | await message.err(i_e) 39 | return 40 | output = f"**URL**: `{link}`\n\n**STATUS CODE**: __{cd.status_code}__\n\n**HEADERS**:\n\n" 41 | for k, v in cd.headers.items(): 42 | output += f" 🏷 __{k.lower()}__ : `{v}`\n\n" 43 | await message.edit_or_send_as_file(text=output, caption=link, 44 | disable_web_page_preview=True) 45 | -------------------------------------------------------------------------------- /init/logbot/methods/polling.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | declare -i _to=1 12 | declare -r _input=logs/logbot.stdin 13 | 14 | startLogBotPolling() { 15 | test -z $BOT_TOKEN || _polling & 16 | } 17 | 18 | endLogBotPolling() { 19 | test -z $BOT_TOKEN || echo quit >> $_input 20 | wait 21 | } 22 | 23 | _polling() { 24 | local cmd func args 25 | _resetConnection 26 | log "LogBot Polling Started !" 27 | while true; do 28 | cmd="$(head -n 1 $_input 2> /dev/null && sed -i '1d' $_input)" 29 | test -z "$cmd" && _pollsleep && continue 30 | test $_to -gt 3 && let _to-=3 31 | case $cmd in 32 | quit) 33 | break;; 34 | deleteLastMessage|printMessages|deleteMessages) 35 | $cmd;; 36 | sendMessage*|replyLastMessage*|editLastMessage*) 37 | func=$(echo $cmd | cut -d' ' -f1) 38 | args=$(echo $cmd | cut -d' ' -f2-) 39 | $func "~$args";; 40 | *) 41 | log "unknown : < $cmd >" 42 | test -z $cmd && break;; 43 | esac 44 | sleep 1 45 | done 46 | log "LogBot Polling Ended !" 47 | _resetConnection 48 | exit 0 49 | } 50 | 51 | _resetConnection() { 52 | rm -f $_input 53 | } 54 | 55 | _pollsleep() { 56 | let _to+=1 57 | log "sleeping (${_to}s) (caused by \"LogBot.polling\")" 58 | sleep $_to 59 | } -------------------------------------------------------------------------------- /userge/plugins/utils/wikipedia.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import wikipedia 10 | 11 | from userge import userge, Message 12 | 13 | 14 | @userge.on_cmd("wiki", about={ 15 | 'header': "do a Wikipedia search", 16 | 'flags': {'-l': "limit the number of returned results (defaults to 5)"}, 17 | 'usage': "{tr}wiki [flags] [query | reply to msg]", 18 | 'examples': "{tr}wiki -l5 userge"}) 19 | async def wiki_pedia(message: Message): 20 | await message.edit("Processing ...") 21 | query = message.filtered_input_str 22 | flags = message.flags 23 | limit = int(flags.get('-l', 5)) 24 | if message.reply_to_message: 25 | query = message.reply_to_message.text 26 | if not query: 27 | await message.err(text="Give a query or reply to a message to wikipedia!") 28 | return 29 | try: 30 | wikipedia.set_lang("en") 31 | results = wikipedia.search(query) 32 | except Exception as e: 33 | await message.err(e) 34 | return 35 | output = "" 36 | for i, s in enumerate(results, start=1): 37 | page = wikipedia.page(s) 38 | url = page.url 39 | output += f"🌏 [{s}]({url})\n" 40 | if i == limit: 41 | break 42 | output = f"**Wikipedia Search:**\n`{query}`\n\n**Results:**\n{output}" 43 | await message.edit_or_send_as_file(text=output, caption=query, 44 | disable_web_page_preview=True) 45 | -------------------------------------------------------------------------------- /userge/core/database.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['get_collection'] 12 | 13 | import asyncio 14 | from typing import List 15 | 16 | from motor.motor_asyncio import AsyncIOMotorClient 17 | from motor.core import AgnosticClient, AgnosticDatabase, AgnosticCollection 18 | 19 | from userge import logging, Config, logbot 20 | 21 | _LOG = logging.getLogger(__name__) 22 | _LOG_STR = "$$$>>> %s <<<$$$" 23 | 24 | logbot.edit_last_msg("Connecting to Database ...", _LOG.info, _LOG_STR) 25 | 26 | _MGCLIENT: AgnosticClient = AsyncIOMotorClient(Config.DB_URI) 27 | _RUN = asyncio.get_event_loop().run_until_complete 28 | 29 | if "Userge" in _RUN(_MGCLIENT.list_database_names()): 30 | _LOG.info(_LOG_STR, "Userge Database Found :) => Now Logging to it...") 31 | else: 32 | _LOG.info(_LOG_STR, "Userge Database Not Found :( => Creating New Database...") 33 | 34 | _DATABASE: AgnosticDatabase = _MGCLIENT["Userge"] 35 | _COL_LIST: List[str] = _RUN(_DATABASE.list_collection_names()) 36 | 37 | 38 | def get_collection(name: str) -> AgnosticCollection: 39 | """ Create or Get Collection from your database """ 40 | if name in _COL_LIST: 41 | _LOG.debug(_LOG_STR, f"{name} Collection Found :) => Now Logging to it...") 42 | else: 43 | _LOG.debug(_LOG_STR, f"{name} Collection Not Found :( => Creating New Collection...") 44 | return _DATABASE[name] 45 | 46 | 47 | logbot.del_last_msg() 48 | -------------------------------------------------------------------------------- /userge/plugins/tools/delete.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from pyrogram.errors import MessageDeleteForbidden 10 | 11 | from userge import userge, Message 12 | 13 | 14 | @userge.on_cmd("del", about={'header': "delete replied message"}) 15 | async def del_msg(message: Message): 16 | if userge.dual_mode: 17 | u_msg_ids = [] 18 | b_msg_ids = [] 19 | o_msg_ids = [] 20 | for m in filter(lambda _: _, (message, message.reply_to_message)): 21 | if m.from_user and m.from_user.id == userge.id: 22 | u_msg_ids.append(m.message_id) 23 | elif m.from_user and m.from_user.id == userge.bot.id: 24 | b_msg_ids.append(m.message_id) 25 | else: 26 | o_msg_ids.append(m.message_id) 27 | if u_msg_ids: 28 | await userge.delete_messages(message.chat.id, u_msg_ids) 29 | if b_msg_ids: 30 | await userge.bot.delete_messages(message.chat.id, b_msg_ids) 31 | for o_msg_id in o_msg_ids: 32 | try: 33 | await userge.delete_messages(message.chat.id, o_msg_id) 34 | except MessageDeleteForbidden: 35 | try: 36 | await userge.bot.delete_messages(message.chat.id, o_msg_id) 37 | except MessageDeleteForbidden: 38 | pass 39 | else: 40 | await message.delete() 41 | replied = message.reply_to_message 42 | if replied: 43 | await replied.delete() 44 | -------------------------------------------------------------------------------- /userge/core/methods/utils/restart.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Restart'] 12 | 13 | import os 14 | import sys 15 | import signal 16 | 17 | import psutil 18 | 19 | from userge import logging 20 | from ...ext import RawClient 21 | 22 | _LOG = logging.getLogger(__name__) 23 | _LOG_STR = "<<>>" 24 | 25 | 26 | class Restart(RawClient): # pylint: disable=missing-class-docstring 27 | async def restart(self, update_req: bool = False, # pylint: disable=arguments-differ 28 | hard: bool = False) -> None: 29 | """ Restart the AbstractUserge """ 30 | _LOG.info(_LOG_STR, "Restarting Userge") 31 | await self.stop() 32 | if update_req: 33 | _LOG.info(_LOG_STR, "Installing Requirements...") 34 | os.system( # nosec 35 | "pip3 install -U pip && pip3 install -r requirements.txt") 36 | _LOG.info(_LOG_STR, "Requirements Installed !") 37 | if hard: 38 | os.kill(os.getpid(), signal.SIGUSR1) 39 | else: 40 | try: 41 | c_p = psutil.Process(os.getpid()) 42 | for handler in c_p.open_files() + c_p.connections(): 43 | os.close(handler.fd) 44 | except Exception as c_e: # pylint: disable=broad-except 45 | print(_LOG_STR % c_e) 46 | os.execl(sys.executable, sys.executable, '-m', 'userge') # nosec 47 | sys.exit() 48 | -------------------------------------------------------------------------------- /userge/plugins/fun/quote.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import asyncio 10 | 11 | from pyrogram.errors.exceptions.bad_request_400 import YouBlockedUser 12 | 13 | from userge import userge, Message 14 | 15 | 16 | @userge.on_cmd("quote", about={ 17 | 'header': "Quote a message", 18 | 'usage': "{tr}quote [text or reply to msg]"}, allow_via_bot=False) 19 | async def quotecmd(message: Message): 20 | """quotecmd""" 21 | asyncio.get_event_loop().create_task(message.delete()) 22 | args = message.input_str 23 | replied = message.reply_to_message 24 | async with userge.conversation('QuotLyBot') as conv: 25 | try: 26 | if replied and not args: 27 | await conv.forward_message(replied) 28 | else: 29 | if not args: 30 | await message.err('input not found!') 31 | return 32 | await conv.send_message(args) 33 | except YouBlockedUser: 34 | await message.edit('first **unblock** @QuotLyBot') 35 | return 36 | quote = await conv.get_response(mark_read=True) 37 | if not quote.sticker: 38 | await message.edit('something went wrong!, see here: @QuotlyBot') 39 | else: 40 | message_id = replied.message_id if replied else None 41 | await userge.send_sticker(chat_id=message.chat.id, 42 | sticker=quote.sticker.file_id, 43 | reply_to_message_id=message_id) 44 | -------------------------------------------------------------------------------- /userge/core/methods/chats/conversation.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Conversation'] 12 | 13 | from typing import Union 14 | 15 | from ... import types 16 | 17 | 18 | class Conversation: # pylint: disable=missing-class-docstring 19 | def conversation(self, 20 | chat_id: Union[str, int], 21 | *, user_id: Union[str, int] = 0, 22 | timeout: Union[int, float] = 10, 23 | limit: int = 10) -> 'types.new.Conversation': 24 | """\nThis returns new conversation object. 25 | 26 | Parameters: 27 | chat_id (``int`` | ``str``): 28 | Unique identifier (int) or username (str) of the target chat. 29 | For your personal cloud (Saved Messages) 30 | you can simply use "me" or "self". 31 | For a contact that exists in your Telegram address book 32 | you can use his phone number (str). 33 | 34 | user_id (``int`` | ``str`` | , *optional*): 35 | define a specific user in this chat. 36 | 37 | timeout (``int`` | ``float`` | , *optional*): 38 | set conversation timeout. 39 | defaults to 10. 40 | 41 | limit (``int`` | , *optional*): 42 | set conversation message limit. 43 | defaults to 10. 44 | """ 45 | return types.new.Conversation(self, chat_id, user_id, timeout, limit) 46 | -------------------------------------------------------------------------------- /resources/radmeDocker.md: -------------------------------------------------------------------------------- 1 | # Docker Guide For Userge 🐳 # 2 | 3 | ## Install docker ## 4 | - Follow the official docker [installation guide](https://docs.docker.com/engine/install/ubuntu/) 5 | 6 | ## Install Docker-compose ## 7 | - Easiest way to install docker-compose is
8 | ```sudo pip install docker-compose``` 9 | - Also you can check other official methods of installing docker-compose [here](https://docs.docker.com/compose/install/) 10 | 11 | ## Run Userge ## 12 | - We dont need to clone the repo (yeah Docker-compose does that for us) 13 | - Setup configs 14 | - Download the sample config file
15 | - ```mkdir userge && cd userge``` 16 | - ```wget https://raw.githubusercontent.com/UsergeTeam/Userge/alpha/config.env.sample -O config.env``` 17 | - ```vim config.env``` 18 | - Download the yml file for docker-compose 19 | - ```wget https://raw.githubusercontent.com/UsergeTeam/Userge/alpha/resources/docker-compose.yml``` 20 | - Finally start the bot
21 | ```docker-compose up -d``` 22 | - The bot should be running now
23 | Check logs with ```docker-compose logs -f``` 24 | 25 | ## How to stop the bot ## 26 | - Stop Command 27 | ```docker-compose stop``` 28 | - This will just stop the containers. Built images won't be removed. So next time you can start with ``docker-compose start`` command
29 | And it won't take time for building from scratch
30 | 31 | - Down command 32 | ```docker-compose down``` 33 | - You will stop and delete the built images also. So next time you have to do ``docker-compose up -d`` to start the bot
34 | 35 | ### Q&A ### 36 | - How to see logs
37 | `docker-compose logs -f` 38 | - How to update
39 | `docker-compose up -d`
40 | Changes will be fetched from git repo. You can change repo url from _docker-compose.yml_ file -------------------------------------------------------------------------------- /init/logbot/core/types/messageClass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | declare -a _Message_properties=() 12 | 13 | id=0 14 | chat_id=1 15 | message_id=2 16 | text=3 17 | 18 | _Message.property() { 19 | test "$2" = "=" && _Message_properties[$1]="$3" || echo "${_Message_properties[$1]}" 20 | } 21 | 22 | _Message.id() { 23 | test "$1" = "=" && _Message.property id = $2 || _Message.property id 24 | } 25 | 26 | _Message.chat_id() { 27 | test "$1" = "=" && _Message.property chat_id = $2 || _Message.property chat_id 28 | } 29 | 30 | _Message.message_id() { 31 | test "$1" = "=" && _Message.property message_id = $2 || _Message.property message_id 32 | } 33 | 34 | _Message.text() { 35 | test "$1" = "=" && _Message.property text = "$2" || _Message.property text 36 | } 37 | 38 | _Message.parse() { 39 | _Message.id = $1 40 | _Message.chat_id = $(echo $2 | jq .result.chat.id) 41 | _Message.message_id = $(echo $2 | jq .result.message_id) 42 | _Message.text = "$(echo $2 | jq -r .result.text)" 43 | } 44 | 45 | _Message.print() { 46 | printf "{id: %s, chat_id: %s, message_id: %s, text: %s}\n" \ 47 | $(_Message.id) $(_Message.chat_id) $(_Message.message_id) "$(_Message.text)" 48 | } 49 | 50 | _Message.edit() { 51 | api.editMessageText $(_Message.chat_id) $(_Message.message_id) "$1" 52 | _Message.text = "$1" 53 | } 54 | 55 | _Message.reply() { 56 | api.sendMessage $(_Message.chat_id) "$1" $(_Message.message_id) 57 | } 58 | 59 | _Message.delete() { 60 | api.deleteMessage $(_Message.chat_id) $(_Message.message_id) $(_Message.id) 61 | } 62 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # set base image (host OS) 2 | FROM python:3.9 3 | 4 | # set the working directory in the container 5 | WORKDIR /app/ 6 | 7 | RUN apt -qq update 8 | RUN apt -qq install -y --no-install-recommends \ 9 | curl \ 10 | git \ 11 | gnupg2 \ 12 | unzip \ 13 | wget \ 14 | ffmpeg \ 15 | jq 16 | 17 | # install chrome 18 | RUN mkdir -p /tmp/ && \ 19 | cd /tmp/ && \ 20 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \ 21 | # -f ==> is required to --fix-missing-dependancies 22 | dpkg -i ./google-chrome-stable_current_amd64.deb; apt -fqqy install && \ 23 | # clean up the container "layer", after we are done 24 | rm ./google-chrome-stable_current_amd64.deb 25 | 26 | # install chromedriver 27 | RUN mkdir -p /tmp/ && \ 28 | cd /tmp/ && \ 29 | wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/$(curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE)/chromedriver_linux64.zip && \ 30 | unzip /tmp/chromedriver.zip chromedriver -d /usr/bin/ && \ 31 | # clean up the container "layer", after we are done 32 | rm /tmp/chromedriver.zip 33 | 34 | ENV GOOGLE_CHROME_DRIVER /usr/bin/chromedriver 35 | ENV GOOGLE_CHROME_BIN /usr/bin/google-chrome-stable 36 | 37 | # install node-js 38 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && \ 39 | apt-get install -y nodejs && \ 40 | npm i -g npm 41 | 42 | # install rar 43 | RUN mkdir -p /tmp/ && \ 44 | cd /tmp/ && \ 45 | wget -O /tmp/rarlinux.tar.gz http://www.rarlab.com/rar/rarlinux-x64-6.0.0.tar.gz && \ 46 | tar -xzvf rarlinux.tar.gz && \ 47 | cd rar && \ 48 | cp -v rar unrar /usr/bin/ && \ 49 | # clean up 50 | rm -rf /tmp/rar* 51 | 52 | # copy the content of the local src directory to the working directory 53 | COPY . . 54 | 55 | # install dependencies 56 | RUN pip install -r requirements.txt 57 | 58 | # command to run on container start 59 | CMD [ "bash", "./run" ] 60 | -------------------------------------------------------------------------------- /userge/plugins/tools/ids.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("ids", about={ 13 | 'header': "display ids", 14 | 'usage': "reply {tr}ids any message, file or just send this command"}) 15 | async def getids(message: Message): 16 | msg = message.reply_to_message or message 17 | out_str = f"👥 **Chat ID** : `{(msg.forward_from_chat or msg.chat).id}`\n" 18 | out_str += f"💬 **Message ID** : `{msg.forward_from_message_id or msg.message_id}`\n" 19 | if msg.from_user: 20 | out_str += f"🙋‍♂️ **From User ID** : `{msg.from_user.id}`\n" 21 | if msg.sender_chat: 22 | out_str += f"👥 **Channel ID** : `{msg.sender_chat.id}`\n" 23 | file_id = None 24 | if msg.audio: 25 | type_ = "audio" 26 | file_id = msg.audio.file_id 27 | elif msg.animation: 28 | type_ = "animation" 29 | file_id = msg.animation.file_id 30 | elif msg.document: 31 | type_ = "document" 32 | file_id = msg.document.file_id 33 | elif msg.photo: 34 | type_ = "photo" 35 | file_id = msg.photo.file_id 36 | elif msg.sticker: 37 | type_ = "sticker" 38 | file_id = msg.sticker.file_id 39 | elif msg.voice: 40 | type_ = "voice" 41 | file_id = msg.voice.file_id 42 | elif msg.video_note: 43 | type_ = "video_note" 44 | file_id = msg.video_note.file_id 45 | elif msg.video: 46 | type_ = "video" 47 | file_id = msg.video.file_id 48 | if file_id is not None: 49 | out_str += f"📄 **Media Type:** `{type_}`\n" 50 | out_str += f"📄 **File ID:** `{file_id}`" 51 | await message.edit(out_str) 52 | -------------------------------------------------------------------------------- /userge/core/methods/decorators/on_new_member.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['OnNewMember'] 12 | 13 | from pyrogram import filters 14 | from pyrogram.filters import Filter as RawFilter 15 | 16 | from . import RawDecorator 17 | 18 | 19 | class OnNewMember(RawDecorator): # pylint: disable=missing-class-docstring 20 | def on_new_member(self, 21 | welcome_chats: RawFilter, 22 | group: int = -2, 23 | allow_via_bot: bool = True, 24 | check_client: bool = True, 25 | check_downpath: bool = False) -> RawDecorator._PYRORETTYPE: 26 | """\nDecorator for handling new members 27 | 28 | Parameters: 29 | welcome_chats (:obj:`~pyrogram.filters.chat`): 30 | Pass filters.chat to allow only a subset of 31 | messages to be passed in your function. 32 | 33 | group (``int``, *optional*): 34 | The group identifier, defaults to 0. 35 | 36 | allow_via_bot (``bool``, *optional*): 37 | If ``True``, allow this via your bot, defaults to True. 38 | 39 | check_client (``bool``, *optional*): 40 | If ``True``, check client is bot or not before execute, defaults to True. 41 | 42 | check_downpath (``bool``, *optional*): 43 | If ``True``, check downpath and make if not exist, defaults to False. 44 | """ 45 | return self.on_filters( 46 | filters=filters.group & filters.new_chat_members & welcome_chats, 47 | group=group, allow_via_bot=allow_via_bot, check_client=check_client, 48 | check_downpath=check_downpath) 49 | -------------------------------------------------------------------------------- /userge/core/methods/decorators/on_left_member.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['OnLeftMember'] 12 | 13 | from pyrogram import filters 14 | from pyrogram.filters import Filter as RawFilter 15 | 16 | from . import RawDecorator 17 | 18 | 19 | class OnLeftMember(RawDecorator): # pylint: disable=missing-class-docstring 20 | def on_left_member(self, 21 | leaving_chats: RawFilter, 22 | group: int = -2, 23 | allow_via_bot: bool = True, 24 | check_client: bool = True, 25 | check_downpath: bool = False) -> RawDecorator._PYRORETTYPE: 26 | """\nDecorator for handling left members 27 | 28 | Parameters: 29 | leaving_chats (:obj:`~pyrogram.filters.chat`): 30 | Pass filters.chat to allow only a subset of 31 | messages to be passed in your function. 32 | 33 | group (``int``, *optional*): 34 | The group identifier, defaults to 0. 35 | 36 | allow_via_bot (``bool``, *optional*): 37 | If ``True``, allow this via your bot, defaults to True. 38 | 39 | check_client (``bool``, *optional*): 40 | If ``True``, check client is bot or not before execute, defaults to True. 41 | 42 | check_downpath (``bool``, *optional*): 43 | If ``True``, check downpath and make if not exist, defaults to False. 44 | """ 45 | return self.on_filters( 46 | filters=filters.group & filters.left_chat_member & leaving_chats, 47 | group=group, allow_via_bot=allow_via_bot, check_client=check_client, 48 | check_downpath=check_downpath) 49 | -------------------------------------------------------------------------------- /init/logbot/core/api.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | declare -r _api_url="https://api.telegram.org/bot" 12 | declare -i _mid=0 _isChecked=0 13 | declare -a _allMessages=() 14 | 15 | _getResponse() { 16 | if [[ -n $BOT_TOKEN && -n $LOG_CHANNEL_ID ]]; then 17 | local reqType=${1#api.} parse=false; shift 18 | test ${reqType::4} = "send" && parse=true 19 | local params=$(sed 's/ /\&/g' <<< $*) 20 | test -n $params && params="?$params" 21 | local rawUpdate=$(curl -s ${_api_url}${BOT_TOKEN}/${reqType}${params}) 22 | local ok=$(echo $rawUpdate | jq .ok) 23 | test -z $ok && return 1 24 | if test $ok = true; then 25 | if test $_isChecked -eq 0; then 26 | local chatType=$(echo $rawUpdate | jq .result.chat.type) 27 | [[ $chatType == \"supergroup\" || $chatType == \"channel\" ]] || \ 28 | quit "invalid log chat type ! [$chatType]" 29 | local chatUsername=$(echo $rawUpdate | jq .result.chat.username) 30 | test $chatUsername != null && quit "log chat should be private !" 31 | _isChecked=1 32 | fi 33 | if test $parse = true; then 34 | local msg="msg$_mid" 35 | Message $msg 36 | $msg.parse $_mid "$rawUpdate" 37 | _allMessages[$_mid]=$msg 38 | let _mid+=1 39 | fi 40 | else 41 | local errcode=$(echo $rawUpdate | jq .error_code) 42 | local desc=$(echo $rawUpdate | jq .description) 43 | quit "invalid request ! (caused by core.api.$FUNCNAME) 44 | \terror_code : [$errcode] 45 | \tdescription : $desc" 46 | fi 47 | sleep 0.7 48 | fi 49 | } 50 | -------------------------------------------------------------------------------- /userge/plugins/utils/google.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from search_engine_parser import GoogleSearch 10 | 11 | from userge import userge, Message 12 | 13 | 14 | @userge.on_cmd("google", about={ 15 | 'header': "do a Google search", 16 | 'flags': { 17 | '-p': "page of results to return (default to 1)", 18 | '-l': "limit the number of returned results (defaults to 5)(max 10)"}, 19 | 'usage': "{tr}google [flags] [query | reply to msg]", 20 | 'examples': "{tr}google -p4 -l10 github-userge"}) 21 | async def gsearch(message: Message): 22 | query = message.filtered_input_str 23 | await message.edit(f"**Googling** for `{query}` ...") 24 | flags = message.flags 25 | page = int(flags.get('-p', 1)) 26 | limit = int(flags.get('-l', 5)) 27 | if message.reply_to_message: 28 | query = message.reply_to_message.text 29 | if not query: 30 | await message.err("Give a query or reply to a message to google!") 31 | return 32 | try: 33 | g_search = GoogleSearch() 34 | gresults = await g_search.async_search(query, page) 35 | except Exception as e: 36 | await message.err(e) 37 | return 38 | output = "" 39 | for i in range(limit): 40 | try: 41 | title = gresults["titles"][i].replace("\n", " ") 42 | link = gresults["links"][i] 43 | desc = gresults["descriptions"][i] 44 | output += f"[{title}]({link})\n" 45 | output += f"`{desc}`\n\n" 46 | except (IndexError, KeyError): 47 | break 48 | output = f"**Google Search:**\n`{query}`\n\n**Results:**\n{output}" 49 | await message.edit_or_send_as_file(text=output, caption=query, 50 | disable_web_page_preview=True) 51 | -------------------------------------------------------------------------------- /userge/plugins/utils/speedtest.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import os 10 | 11 | import speedtest 12 | import wget 13 | 14 | from userge import userge, Message, pool 15 | from userge.utils import humanbytes 16 | 17 | CHANNEL = userge.getCLogger(__name__) 18 | 19 | 20 | @userge.on_cmd("speedtest", about={'header': "test your server speed"}) 21 | async def speedtst(message: Message): 22 | await message.edit("`Running speed test . . .`") 23 | try: 24 | test = speedtest.Speedtest() 25 | test.get_best_server() 26 | await message.try_to_edit("`Performing download test . . .`") 27 | test.download() 28 | await message.try_to_edit("`Performing upload test . . .`") 29 | test.upload() 30 | test.results.share() 31 | result = test.results.dict() 32 | except Exception as e: 33 | await message.err(e) 34 | return 35 | path = await pool.run_in_thread(wget.download)(result['share']) 36 | output = f"""**--Started at {result['timestamp']}-- 37 | 38 | Client: 39 | 40 | ISP: `{result['client']['isp']}` 41 | Country: `{result['client']['country']}` 42 | 43 | Server: 44 | 45 | Name: `{result['server']['name']}` 46 | Country: `{result['server']['country']}, {result['server']['cc']}` 47 | Sponsor: `{result['server']['sponsor']}` 48 | Latency: `{result['server']['latency']}` 49 | 50 | Ping: `{result['ping']}` 51 | Sent: `{humanbytes(result['bytes_sent'])}` 52 | Received: `{humanbytes(result['bytes_received'])}` 53 | Download: `{humanbytes(result['download'] / 8)}/s` 54 | Upload: `{humanbytes(result['upload'] / 8)}/s`**""" 55 | msg = await message.client.send_photo(chat_id=message.chat.id, 56 | photo=path, 57 | caption=output) 58 | await CHANNEL.fwd_msg(msg) 59 | os.remove(path) 60 | await message.delete() 61 | -------------------------------------------------------------------------------- /userge/utils/sys_tools.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from glob import glob 12 | from signal import SIGTERM 13 | from os import environ, getpid, kill 14 | from os.path import isfile, relpath 15 | from typing import Dict, List, Union 16 | 17 | _SECURE = [ 18 | # critical 19 | 'API_ID', 'API_HASH', 'BOT_TOKEN', 'HU_STRING_SESSION', 'DATABASE_URL', 'HEROKU_API_KEY', 20 | 'CUSTOM_PLUGINS_REPO', 21 | # others 22 | 'USERGE_ANTISPAM_API', 'SPAM_WATCH_API', 'CURRENCY_API', 'OCR_SPACE_API_KEY', 23 | 'REMOVE_BG_API_KEY', 'G_DRIVE_CLIENT_ID', 'G_DRIVE_CLIENT_SECRET', 24 | # unofficial 25 | 'ARL_TOKEN', 'GCS_API_KEY', 'GCS_IMAGE_E_ID', 'G_PHOTOS_CLIENT_ID', 26 | 'G_PHOTOS_CLIENT_SECRET', 'CH_LYDIA_API'] 27 | 28 | 29 | class SafeDict(Dict[str, str]): 30 | """ modded dict """ 31 | def __missing__(self, key: str) -> str: 32 | return '{' + key + '}' 33 | 34 | 35 | def get_import_path(root: str, path: str) -> Union[str, List[str]]: 36 | """ return import path """ 37 | seperator = '\\' if '\\' in root else '/' 38 | if isfile(path): 39 | return '.'.join(relpath(path, root).split(seperator))[:-3] 40 | all_paths = glob(root + path.rstrip(seperator) + f"{seperator}*.py", recursive=True) 41 | return sorted( 42 | [ 43 | '.'.join(relpath(f, root).split(seperator))[:-3] for f in all_paths 44 | if not f.endswith("__init__.py") 45 | ] 46 | ) 47 | 48 | 49 | def terminate() -> None: 50 | """ terminate programme """ 51 | kill(getpid(), SIGTERM) 52 | 53 | 54 | def secure_text(text: str) -> str: 55 | """ secure given text """ 56 | if not text: 57 | return '' 58 | for var in _SECURE: 59 | tvar = environ.get(var) 60 | if tvar and tvar in text: 61 | text = text.replace(tvar, "[SECURED!]") 62 | return text 63 | -------------------------------------------------------------------------------- /userge/plugins/utils/hash.py: -------------------------------------------------------------------------------- 1 | """ hash , encode and decode """ 2 | 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | import pybase64 12 | 13 | from userge import userge, Message 14 | from userge.utils import runcmd 15 | 16 | 17 | @userge.on_cmd("hash", about={ 18 | 'header': "find hash of text", 19 | 'description': "Find the md5, sha1, sha256, sha512 of the string when written into a txt file", 20 | 'usage': "{tr}hash [text or reply to msg]"}) 21 | async def gethash(message: Message): 22 | """ find hash of text """ 23 | input_ = message.input_or_reply_str 24 | if not input_: 25 | await message.err("input not found!") 26 | return 27 | with open("hash.txt", "w+") as hashtxt: 28 | hashtxt.write(input_) 29 | md5 = (await runcmd("md5sum hash.txt"))[0].split()[0] 30 | sha1 = (await runcmd("sha1sum hash.txt"))[0].split()[0] 31 | sha256 = (await runcmd("sha256sum hash.txt"))[0].split()[0] 32 | sha512 = (await runcmd("sha512sum hash.txt"))[0].split()[0] 33 | await runcmd("rm hash.txt") 34 | ans = (f"**Text** : `{input_}`\n**MD5** : `{md5}`\n**SHA1** : `{sha1}`\n" 35 | f"**SHA256** : `{sha256}`\n**SHA512** : `{sha512}`") 36 | await message.edit_or_send_as_file(ans, filename="hash.txt", caption="hash.txt") 37 | 38 | 39 | @userge.on_cmd("base64", about={ 40 | 'header': "Find the base64 encoding of the given string", 41 | 'usage': "{tr}base64 [text or reply to msg] : encode\n" 42 | "{tr}base64 -d [text or reply to msg] : decode"}, del_pre=True) 43 | async def endecrypt(message: Message): 44 | """ encode or decode """ 45 | if message.reply_to_message: 46 | input_ = message.reply_to_message.text 47 | else: 48 | input_ = message.filtered_input_str 49 | if not input_: 50 | await message.err("input not found!") 51 | return 52 | if 'd' in message.flags: 53 | out = str(pybase64.b64decode(bytes(input_, "utf-8"), validate=True))[2:-1] 54 | await message.edit(f"**Decoded** : `{out}`") 55 | else: 56 | out = str(pybase64.b64encode(bytes(input_, "utf-8")))[2:-1] 57 | await message.edit(f"**Encoded** : `{out}`") 58 | -------------------------------------------------------------------------------- /userge/plugins/utils/admins.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message 10 | 11 | 12 | @userge.on_cmd("admins", about={ 13 | 'header': "View or mention admins in chat", 14 | 'flags': { 15 | '-m': "mention all admins", 16 | '-mc': "only mention creator", 17 | '-id': "show ids"}, 18 | 'usage': "{tr}admins [any flag] [chatid]"}, allow_channels=False) 19 | async def mentionadmins(message: Message): 20 | mentions = "🛡 **Admin List** 🛡\n" 21 | chat_id = message.filtered_input_str 22 | flags = message.flags 23 | men_admins = '-m' in flags 24 | men_creator = '-mc' in flags 25 | show_id = '-id' in flags 26 | if not chat_id: 27 | chat_id = message.chat.id 28 | try: 29 | async for x in message.client.iter_chat_members(chat_id=chat_id, filter="administrators"): 30 | status = x.status 31 | u_id = x.user.id 32 | username = x.user.username or None 33 | full_name = (await message.client.get_user_dict(u_id))['flname'] 34 | if status == "creator": 35 | if men_admins or men_creator: 36 | mentions += f"\n 👑 [{full_name}](tg://user?id={u_id})" 37 | elif username: 38 | mentions += f"\n 👑 [{full_name}](https://t.me/{username})" 39 | else: 40 | mentions += f"\n 👑 {full_name}" 41 | if show_id: 42 | mentions += f" `{u_id}`" 43 | elif status == "administrator": 44 | if men_admins: 45 | mentions += f"\n ⚜ [{full_name}](tg://user?id={u_id})" 46 | elif username: 47 | mentions += f"\n ⚜ [{full_name}](https://t.me/{username})" 48 | else: 49 | mentions += f"\n ⚜ {full_name}" 50 | if show_id: 51 | mentions += f" `{u_id}`" 52 | except Exception as e: 53 | mentions += " " + str(e) + "\n" 54 | await message.delete() 55 | await message.client.send_message( 56 | chat_id=message.chat.id, text=mentions, disable_web_page_preview=True) 57 | -------------------------------------------------------------------------------- /userge/plugins/tools/logs.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from userge import userge, Message, logging, Config, pool 10 | 11 | _LEVELS = { 12 | 'debug': logging.DEBUG, 13 | 'info': logging.INFO, 14 | 'warning': logging.WARNING, 15 | 'error': logging.ERROR, 16 | 'critical': logging.CRITICAL 17 | } 18 | 19 | 20 | @userge.on_cmd("logs", about={ 21 | 'header': "check userge logs", 22 | 'flags': { 23 | '-h': "get heroku logs", 24 | '-l': "heroku logs lines limit : default 100"}}, allow_channels=False) 25 | async def check_logs(message: Message): 26 | """ check logs """ 27 | await message.edit("`checking logs ...`") 28 | if '-h' in message.flags and Config.HEROKU_APP: 29 | limit = int(message.flags.get('-l', 100)) 30 | logs = await pool.run_in_thread(Config.HEROKU_APP.get_log)(lines=limit) 31 | await message.client.send_as_file(chat_id=message.chat.id, 32 | text=logs, 33 | filename='userge-heroku.log', 34 | caption=f'userge-heroku.log [ {limit} lines ]') 35 | else: 36 | await message.client.send_document(chat_id=message.chat.id, 37 | document="logs/userge.log", 38 | caption='userge.log') 39 | await message.delete() 40 | 41 | 42 | @userge.on_cmd("setlvl", about={ 43 | 'header': "set logger level, default to info", 44 | 'types': ['debug', 'info', 'warning', 'error', 'critical'], 45 | 'usage': "{tr}setlvl [level]", 46 | 'examples': ["{tr}setlvl info", "{tr}setlvl debug"]}) 47 | async def set_level(message: Message): 48 | """ set logger level """ 49 | await message.edit("`setting logger level ...`") 50 | level = message.input_str.lower() 51 | if level not in _LEVELS: 52 | await message.err("unknown level !") 53 | return 54 | for logger in (logging.getLogger(name) for name in logging.root.manager.loggerDict): 55 | logger.setLevel(_LEVELS[level]) 56 | await message.edit(f"`successfully set logger level as` : **{level.upper()}**", del_in=3) 57 | -------------------------------------------------------------------------------- /userge/plugins/utils/removebg.py: -------------------------------------------------------------------------------- 1 | # Userge Plugin for removing background from Images 2 | # Author: Sumanjay (https://github.com/cyberboysumanjay) (@cyberboysumanjay) 3 | # All rights reserved. 4 | 5 | import os 6 | from datetime import datetime 7 | 8 | from removebg import RemoveBg 9 | 10 | from userge import userge, Config, Message 11 | from userge.utils import progress 12 | 13 | IMG_PATH = Config.DOWN_PATH + "dl_image.jpg" 14 | 15 | 16 | @userge.on_cmd('removebg', about={ 17 | 'header': "Removes Background from Image (50 Calls per Month in the free API)", 18 | 'usage': "{tr}removebg [reply to any photo | direct link of photo]"}) 19 | async def remove_background(message: Message): 20 | if not Config.REMOVE_BG_API_KEY: 21 | await message.edit( 22 | "Get the API from HERE " 23 | " & add it to Heroku Config Vars REMOVE_BG_API_KEY", 24 | disable_web_page_preview=True, parse_mode="html") 25 | return 26 | await message.edit("Analysing...") 27 | replied = message.reply_to_message 28 | if (replied and replied.media 29 | and (replied.photo 30 | or (replied.document and "image" in replied.document.mime_type))): 31 | start_t = datetime.now() 32 | if os.path.exists(IMG_PATH): 33 | os.remove(IMG_PATH) 34 | await message.client.download_media(message=replied, 35 | file_name=IMG_PATH, 36 | progress=progress, 37 | progress_args=(message, "Downloading Image")) 38 | end_t = datetime.now() 39 | m_s = (end_t - start_t).seconds 40 | await message.edit(f"Image saved in {m_s} seconds.\nRemoving Background Now...") 41 | # Cooking Image 42 | try: 43 | rmbg = RemoveBg(Config.REMOVE_BG_API_KEY, "removebg_error.log") 44 | rmbg.remove_background_from_img_file(IMG_PATH) 45 | rbg_img_path = IMG_PATH + "_no_bg.png" 46 | await message.client.send_document( 47 | chat_id=message.chat.id, 48 | document=rbg_img_path, 49 | disable_notification=True, 50 | progress=progress, 51 | progress_args=(message, "Uploading", rbg_img_path)) 52 | await message.delete() 53 | except Exception: # pylint: disable=broad-except 54 | await message.edit("Something went wrong!\nCheck your usage quota!") 55 | return 56 | else: 57 | await message.edit("Reply to a photo to remove background!", del_in=5) 58 | -------------------------------------------------------------------------------- /userge/plugins/utils/currency.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import json 10 | 11 | import aiohttp 12 | from emoji import get_emoji_regexp 13 | 14 | from userge import userge, Message, Config 15 | 16 | CHANNEL = userge.getCLogger(__name__) 17 | LOG = userge.getLogger(__name__) 18 | 19 | 20 | @userge.on_cmd("cr", about={ 21 | 'header': "use this to convert currency & get exchange rate", 22 | 'description': "Convert currency & get exchange rates.", 23 | 'examples': "{tr}cr 1 BTC USD"}) 24 | async def cur_conv(message: Message): 25 | """ 26 | this function can get exchange rate results 27 | """ 28 | if Config.CURRENCY_API is None: 29 | await message.edit( 30 | "Oops!!get the API from " 31 | "HERE " 32 | "& add it to Heroku config vars (CURRENCY_API)", 33 | disable_web_page_preview=True, 34 | parse_mode="html", del_in=0) 35 | return 36 | 37 | filterinput = get_emoji_regexp().sub(u'', message.input_str) 38 | curcon = filterinput.upper().split() 39 | 40 | if len(curcon) == 3: 41 | amount, currency_to, currency_from = curcon 42 | else: 43 | await message.err("you entered invalid data") 44 | return 45 | 46 | if amount.isdigit(): 47 | url = ("https://free.currconv.com/api/v7/convert?" 48 | f"apiKey={Config.CURRENCY_API}&q=" 49 | f"{currency_from}_{currency_to}&compact=ultra") 50 | async with aiohttp.ClientSession() as ses, ses.get(url) as res: 51 | data = json.loads(await res.text()) 52 | try: 53 | result = data[f'{currency_from}_{currency_to}'] 54 | except KeyError: 55 | LOG.info(data) 56 | await message.edit("`invalid response from api !`", del_in=5) 57 | return 58 | result = float(amount) / float(result) 59 | result = round(result, 5) 60 | await message.edit( 61 | "**CURRENCY EXCHANGE RATE RESULT:**\n\n" 62 | f"`{amount}` **{currency_to}** = `{result}` **{currency_from}**") 63 | await CHANNEL.log("`cr` command executed sucessfully") 64 | 65 | else: 66 | await message.edit( 67 | r"`This seems to be some alien currency, which I can't convert right now.. (⊙_⊙;)`", 68 | del_in=0) 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | env/ 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | 132 | # config files 133 | .apt/ 134 | .heroku/ 135 | .profile.d/ 136 | vendor/ 137 | config.env 138 | .vscode/ 139 | .idea/ 140 | *.session 141 | unknown_errors.txt 142 | logs/ 143 | bin/ 144 | resources/base_profile_pic.jpg 145 | resources/mdfy_profile_pic.jpg 146 | resources/MutantAcademyBB.ttf 147 | userge/plugins/dev/ -------------------------------------------------------------------------------- /userge/utils/progress.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | import time 12 | from math import floor 13 | from typing import Dict, Tuple 14 | 15 | from pyrogram.errors.exceptions import FloodWait 16 | 17 | import userge 18 | from .tools import humanbytes, time_formatter 19 | 20 | _TASKS: Dict[str, Tuple[float, float]] = {} 21 | 22 | 23 | async def progress(current: int, 24 | total: int, 25 | message: 'userge.Message', 26 | ud_type: str, 27 | file_name: str = '', 28 | delay: int = userge.Config.EDIT_SLEEP_TIMEOUT) -> None: 29 | """ progress function """ 30 | if message.process_is_canceled: 31 | await message.client.stop_transmission() 32 | task_id = f"{message.chat.id}.{message.message_id}" 33 | if current == total: 34 | if task_id not in _TASKS: 35 | return 36 | del _TASKS[task_id] 37 | try: 38 | await message.edit("`finalizing process ...`") 39 | except FloodWait as f_e: 40 | time.sleep(f_e.x) 41 | return 42 | now = time.time() 43 | if task_id not in _TASKS: 44 | _TASKS[task_id] = (now, now) 45 | start, last = _TASKS[task_id] 46 | elapsed_time = now - start 47 | if (now - last) >= delay: 48 | _TASKS[task_id] = (start, now) 49 | percentage = current * 100 / total 50 | speed = current / elapsed_time 51 | time_to_completion = time_formatter(int((total - current) / speed)) 52 | progress_str = \ 53 | "__{}__ : `{}`\n" + \ 54 | "```[{}{}]```\n" + \ 55 | "**Progress** : `{}%`\n" + \ 56 | "**Completed** : `{}`\n" + \ 57 | "**Total** : `{}`\n" + \ 58 | "**Speed** : `{}/s`\n" + \ 59 | "**ETA** : `{}`" 60 | progress_str = progress_str.format( 61 | ud_type, 62 | file_name, 63 | ''.join((userge.Config.FINISHED_PROGRESS_STR 64 | for _ in range(floor(percentage / 5)))), 65 | ''.join((userge.Config.UNFINISHED_PROGRESS_STR 66 | for _ in range(20 - floor(percentage / 5)))), 67 | round(percentage, 2), 68 | humanbytes(current), 69 | humanbytes(total), 70 | humanbytes(speed), 71 | time_to_completion if time_to_completion else "0 s") 72 | try: 73 | await message.edit(progress_str) 74 | except FloodWait as f_e: 75 | time.sleep(f_e.x) 76 | -------------------------------------------------------------------------------- /userge/plugins/utils/covid.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 3 | # and is released under the "GNU v3.0 License Agreement". 4 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 5 | 6 | # Userge Plugin for getting detailed stats of Covid Patients 7 | # Author: Sumanjay (https://github.com/cyberboysumanjay) (@cyberboysumanjay) 8 | # All rights reserved. 9 | 10 | from covid import Covid 11 | 12 | from userge import userge, Message, pool 13 | 14 | 15 | @userge.on_cmd("covid", about={ 16 | 'header': "see covid details", 17 | 'description': "The current real time situation of the COVID-19 patients reported in worldwide", 18 | 'flags': {'-l': "list countries"}, 19 | 'usage': "{tr}covid [flag | country]", 20 | 'examples': ["{tr}covid -l", "{tr}covid", "{tr}covid india"]}) 21 | async def covid(message: Message): 22 | await message.edit("`fetching covid ...`") 23 | covid_ = await pool.run_in_thread(Covid)("worldometers") 24 | country = message.input_str 25 | result = "" 26 | if '-l' in message.flags: 27 | result += "Covid Supported Countries\n\n`" 28 | result += '` , `'.join(sorted(filter(lambda x: x, covid_.list_countries()))) 29 | result += "`" 30 | elif country: 31 | try: 32 | data = covid_.get_status_by_country_name(country) 33 | except ValueError: 34 | await message.err(f"invalid country name <{country}>!") 35 | return 36 | result += f"Covid Status for {data['country']}\n\n" 37 | result += f"**new cases** : `{data['new_cases']}`\n" 38 | result += f"**new deaths** : `{data['new_deaths']}`\n\n" 39 | result += f"**critical** : `{data['critical']}`\n" 40 | result += f"**active** : `{data['active']}`\n" 41 | result += f"**confirmed** : `{data['confirmed']}`\n" 42 | result += f"**deaths** : `{data['deaths']}`\n" 43 | result += f"**recovered** : `{data['recovered']}`\n\n" 44 | result += f"**total tests** : `{data['total_tests']}`\n" 45 | result += f"**total tests per million** : `{data['total_tests_per_million']}`\n" 46 | result += f"**total cases per million** : `{data['total_cases_per_million']}`\n" 47 | result += f"**total deaths per million** : `{data['total_deaths_per_million']}`\n" 48 | result += f"**population** : `{data['population']}`\n" 49 | else: 50 | result += "Covid Status in the world\n\n" 51 | result += f"**total active cases** : `{covid_.get_total_active_cases()}`\n" 52 | result += f"**total confirmed cases** : `{covid_.get_total_confirmed_cases()}`\n" 53 | result += f"**total deaths** : `{covid_.get_total_deaths()}`\n" 54 | result += f"**total recovered** : `{covid_.get_total_recovered()}`\n" 55 | await message.edit_or_send_as_file(result) 56 | -------------------------------------------------------------------------------- /userge/core/methods/chats/send_read_acknowledge.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['SendReadAcknowledge'] 12 | 13 | from typing import List, Optional, Union 14 | 15 | from pyrogram.raw import functions 16 | 17 | from ...ext import RawClient, RawMessage 18 | 19 | 20 | class SendReadAcknowledge(RawClient): # pylint: disable=missing-class-docstring 21 | async def send_read_acknowledge(self, 22 | chat_id: Union[int, str], 23 | message: Union[List[RawMessage], 24 | Optional[RawMessage]] = None, 25 | *, max_id: Optional[int] = None, 26 | clear_mentions: bool = False) -> bool: 27 | """\nMarks messages as read and optionally clears mentions. 28 | 29 | Parameters: 30 | chat_id (``int`` | ``str``): 31 | Unique identifier (int) or username (str) of the target chat. 32 | For your personal cloud (Saved Messages) 33 | you can simply use "me" or "self". 34 | For a contact that exists in your Telegram address book 35 | you can use his phone number (str). 36 | 37 | message (``list`` | :obj: `Message`, *optional*): 38 | Either a list of messages or a single message. 39 | 40 | max_id (``int``, *optional*): 41 | Until which message should the read acknowledge be sent for. 42 | This has priority over the ``message`` parameter. 43 | 44 | clear_mentions (``bool``, *optional*): 45 | Whether the mention badge should be cleared (so that 46 | there are no more mentions) or not for the given entity. 47 | If no message is provided, this will be the only action 48 | taken. 49 | defaults to False. 50 | 51 | Returns: 52 | On success, True is returned. 53 | """ 54 | if max_id is None: 55 | if message: 56 | if isinstance(message, list): 57 | max_id = max(msg.message_id for msg in message) 58 | else: 59 | max_id = message.message_id 60 | else: 61 | max_id = 0 62 | if clear_mentions: 63 | await self.send( 64 | functions.messages.ReadMentions( 65 | peer=await self.resolve_peer(chat_id))) 66 | if max_id is None: 67 | return True 68 | if max_id is not None: 69 | return bool(await self.read_history(chat_id=chat_id, max_id=max_id)) 70 | return False 71 | -------------------------------------------------------------------------------- /init/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | declare -r minPVer=8 12 | declare -r maxPVer=9 13 | 14 | getPythonVersion() { 15 | local -i count=$minPVer 16 | local found 17 | while true; do 18 | found=$(python3.$count -c "print('hi')" 2> /dev/null) 19 | test "$found" && break 20 | count+=1 21 | [[ $count -gt $maxPVer ]] && break 22 | done 23 | local ptn='s/Python (3\.[0-9]{1,2}\.[0-9]{1,2}).*/\1/g' 24 | declare -gr pVer=$(sed -E "$ptn" <<< "$(python3.$count -V 2> /dev/null)") 25 | } 26 | 27 | log() { 28 | local text="$*" 29 | test ${#text} -gt 0 && test ${text::1} != '~' \ 30 | && echo -e "[$(date +'%d-%b-%y %H:%M:%S') - INFO] - init - ${text#\~}" 31 | } 32 | 33 | quit() { 34 | local err="\t:: ERROR :: $1\nExiting With SIGTERM (143) ..." 35 | if (( getMessageCount )); then 36 | replyLastMessage "$err" 37 | else 38 | log "$err" 39 | fi 40 | exit 143 41 | } 42 | 43 | runPythonCode() { 44 | python${pVer%.*} -c "$1" 45 | } 46 | 47 | runPythonModule() { 48 | python${pVer%.*} -m "$@" & 49 | setProc $! 50 | waitProc 51 | } 52 | 53 | gitInit() { 54 | git init &> /dev/null 55 | } 56 | 57 | gitClone() { 58 | git clone "$@" &> /dev/null 59 | } 60 | 61 | remoteIsExist() { 62 | grep -q $1 < <(git remote) 63 | } 64 | 65 | addHeroku() { 66 | git remote add heroku $HEROKU_GIT_URL 67 | } 68 | 69 | addUpstream() { 70 | git remote add $UPSTREAM_REMOTE ${UPSTREAM_REPO%.git}.git 71 | } 72 | 73 | updateUpstream() { 74 | git remote rm $UPSTREAM_REMOTE && addUpstream 75 | } 76 | 77 | fetchUpstream() { 78 | git fetch $UPSTREAM_REMOTE &> /dev/null 79 | } 80 | 81 | fetchBranches() { 82 | local r_bs l_bs 83 | r_bs=$(grep -oP '(?<=refs/heads/)\w+' < <(git ls-remote --heads $UPSTREAM_REMOTE)) 84 | l_bs=$(grep -oP '\w+' < <(git branch)) 85 | for r_b in $r_bs; do 86 | [[ $l_bs =~ $r_b ]] || git branch $r_b $UPSTREAM_REMOTE/$r_b &> /dev/null 87 | done 88 | } 89 | 90 | updateBuffer() { 91 | git config http.postBuffer 524288000 92 | } 93 | 94 | upgradePip() { 95 | pip3 install -U pip &> /dev/null 96 | } 97 | 98 | installReq() { 99 | pip3 install -r $1/requirements.txt &> /dev/null 100 | } 101 | 102 | installCustomReq() { 103 | pip3 install $(tr ' ' '\n' <<< "$1") &> /dev/null 104 | } 105 | 106 | printLine() { 107 | echo '->- ->- ->- ->- ->- ->- ->- --- -<- -<- -<- -<- -<- -<- -<-' 108 | } 109 | 110 | printLogo() { 111 | printLine 112 | echo ' 113 | ________ __ __ ______ 114 | /_ __/ /_ ___ / / / /_______ _____/ ____/__ 115 | / / / __ \/ _ \ / / / / ___/ _ \/ ___/ / __/ _ \ 116 | / / / / / / __/ / /_/ (__ ) __/ / / /_/ / __/ 117 | /_/ /_/ /_/\___/ \____/____/\___/_/ \____/\___/ 118 | 119 | ' 120 | printLine 121 | } 122 | -------------------------------------------------------------------------------- /userge/plugins/admin/purge.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | from datetime import datetime 10 | 11 | from userge import userge, Message 12 | 13 | 14 | @userge.on_cmd("purge", about={ 15 | 'header': "purge messages from user", 16 | 'flags': { 17 | '-u': "get user_id from replied message", 18 | '-l': "message limit : max 100"}, 19 | 'usage': "reply {tr}purge to the start message to purge.\n" 20 | "use {tr}purge [user_id | user_name] to purge messages from that user or use flags", 21 | 'examples': ['{tr}purge', '{tr}purge -u', '{tr}purge [user_id | user_name]']}, 22 | allow_bots=False, del_pre=True) 23 | async def purge_(message: Message): 24 | await message.edit("`purging ...`") 25 | from_user_id = None 26 | if message.filtered_input_str: 27 | from_user_id = (await message.client.get_users(message.filtered_input_str)).id 28 | start_message = 0 29 | if 'l' in message.flags: 30 | limit = min(100, int(message.flags['l'])) 31 | start_message = message.message_id - limit 32 | if message.reply_to_message: 33 | start_message = message.reply_to_message.message_id 34 | if 'u' in message.flags: 35 | from_user_id = message.reply_to_message.from_user.id 36 | if not start_message: 37 | await message.err("invalid start message!") 38 | return 39 | list_of_messages = [] 40 | purged_messages_count = 0 41 | 42 | async def handle_msg(_msg): 43 | nonlocal list_of_messages, purged_messages_count 44 | if (from_user_id and _msg and _msg.from_user 45 | and _msg.from_user.id == from_user_id): 46 | list_of_messages.append(_msg.message_id) 47 | if not from_user_id: 48 | list_of_messages.append(_msg.message_id) 49 | if len(list_of_messages) >= 100: 50 | await message.client.delete_messages( 51 | chat_id=message.chat.id, 52 | message_ids=list_of_messages 53 | ) 54 | purged_messages_count += len(list_of_messages) 55 | list_of_messages = [] 56 | 57 | start_t = datetime.now() 58 | if message.client.is_bot: 59 | for msg in await message.client.get_messages( 60 | chat_id=message.chat.id, replies=0, 61 | message_ids=range(start_message, message.message_id)): 62 | await handle_msg(msg) 63 | else: 64 | async for msg in message.client.iter_history( 65 | chat_id=message.chat.id, offset_id=start_message, reverse=True): 66 | await handle_msg(msg) 67 | if list_of_messages: 68 | await message.client.delete_messages(chat_id=message.chat.id, 69 | message_ids=list_of_messages) 70 | purged_messages_count += len(list_of_messages) 71 | end_t = datetime.now() 72 | time_taken_s = (end_t - start_t).seconds 73 | out = f"purged {purged_messages_count} messages in {time_taken_s} seconds." 74 | await message.edit(out, del_in=3) 75 | -------------------------------------------------------------------------------- /userge/plugins/utils/webss.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import os 10 | import asyncio 11 | from re import match 12 | 13 | import aiofiles 14 | from selenium import webdriver 15 | from fake_headers import Headers 16 | from userge import userge, Message, Config 17 | 18 | 19 | @userge.on_cmd("webss", about={'header': "Get snapshot of a website"}) 20 | async def webss(message: Message): 21 | if Config.GOOGLE_CHROME_BIN is None: 22 | await message.edit("`need to install Google Chrome. Module Stopping`", del_in=5) 23 | return 24 | link_match = match(r'\bhttps?://.*\.\S+', message.input_str) 25 | if not link_match: 26 | await message.err("I need a valid link to take screenshots from.") 27 | return 28 | link = link_match.group() 29 | await message.edit("`Processing ...`") 30 | chrome_options = webdriver.ChromeOptions() 31 | header = Headers(headers=False).generate() 32 | chrome_options.binary_location = Config.GOOGLE_CHROME_BIN 33 | chrome_options.add_argument('--ignore-certificate-errors') 34 | chrome_options.add_argument("--test-type") 35 | chrome_options.add_argument("--headless") 36 | chrome_options.add_argument('--no-sandbox') 37 | chrome_options.add_argument('--disable-dev-shm-usage') 38 | chrome_options.add_argument("--no-sandbox") 39 | chrome_options.add_argument('--disable-gpu') 40 | chrome_options.add_argument(f"user-agent={header['User-Agent']}") 41 | driver = webdriver.Chrome(chrome_options=chrome_options) 42 | driver.get(link) 43 | height = driver.execute_script( 44 | "return Math.max(document.body.scrollHeight, document.body.offsetHeight, " 45 | "document.documentElement.clientHeight, document.documentElement.scrollHeight, " 46 | "document.documentElement.offsetHeight);") 47 | width = driver.execute_script( 48 | "return Math.max(document.body.scrollWidth, document.body.offsetWidth, " 49 | "document.documentElement.clientWidth, document.documentElement.scrollWidth, " 50 | "document.documentElement.offsetWidth);") 51 | driver.set_window_size(width + 125, height + 125) 52 | wait_for = height / 1000 53 | await message.edit(f"`Generating screenshot of the page...`" 54 | f"\n`Height of page = {height}px`" 55 | f"\n`Width of page = {width}px`" 56 | f"\n`Waiting ({int(wait_for)}s) for the page to load.`") 57 | await asyncio.sleep(int(wait_for)) 58 | im_png = driver.get_screenshot_as_png() 59 | driver.close() 60 | message_id = message.message_id 61 | if message.reply_to_message: 62 | message_id = message.reply_to_message.message_id 63 | file_path = os.path.join(Config.DOWN_PATH, "webss.png") 64 | async with aiofiles.open(file_path, 'wb') as out_file: 65 | await out_file.write(im_png) 66 | await asyncio.gather( 67 | message.delete(), 68 | message.client.send_document(chat_id=message.chat.id, 69 | document=file_path, 70 | caption=link, 71 | reply_to_message_id=message_id) 72 | ) 73 | os.remove(file_path) 74 | driver.quit() 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Userge 4 | 5 |
6 | Pluggable Telegram UserBot 7 |
8 | Inspiration 9 |  •  10 | Documentation 11 |  •  12 | Deployment 13 |  •  14 | Project Credits 15 |  •  16 | Copyright & License 17 |

18 | 19 | # Userge 🔥 20 | 21 | [![Build Status](https://travis-ci.com/UsergeTeam/Userge.svg?branch=alpha)](https://travis-ci.com/UsergeTeam/Userge) 22 | ![Python Version](https://img.shields.io/badge/python-3.8/3.9-lightgrey) 23 | ![Release](https://img.shields.io/github/v/release/UsergeTeam/Userge) 24 | ![Stars](https://img.shields.io/github/stars/UsergeTeam/Userge) 25 | ![Forks](https://img.shields.io/github/forks/UsergeTeam/Userge) 26 | ![Issues Open](https://img.shields.io/github/issues/UsergeTeam/Userge) 27 | ![Issues Closed](https://img.shields.io/github/issues-closed/UsergeTeam/Userge) 28 | ![PRs Open](https://img.shields.io/github/issues-pr/UsergeTeam/Userge) 29 | ![PRs Closed](https://img.shields.io/github/issues-pr-closed/UsergeTeam/Userge) 30 | ![Contributors](https://img.shields.io/github/contributors/UsergeTeam/Userge) 31 | ![Repo Size](https://img.shields.io/github/repo-size/UsergeTeam/Userge) 32 | ![License](https://img.shields.io/github/license/UsergeTeam/Userge) 33 | ![Commit Activity](https://img.shields.io/github/commit-activity/m/UsergeTeam/Userge) 34 | [![Plugins Repo!](https://img.shields.io/badge/Plugins%20Repo-!-orange)](https://github.com/UsergeTeam/Userge-Plugins) 35 | [![Join Channel!](https://img.shields.io/badge/Join%20Channel-!-red)](https://t.me/theUserge) 36 | [![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/UsergeTeam/Userge/?ref=repository-badge) 37 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/UsergeTeam/Userge) 38 | 39 | > **Userge** is a Powerful , _Pluggable_ Telegram UserBot written in _Python_ using [Pyrogram](https://github.com/pyrogram/pyrogram). 40 | 41 | ## Inspiration 😇 42 | 43 | > This project is inspired by the following projects :) 44 | 45 | * [tg_userbot](https://github.com/watzon/tg_userbot) ( heavily ) 🤗 46 | * [PyroGramBot](https://github.com/SpEcHiDe/PyroGramBot) 47 | * [Telegram-Paperplane](https://github.com/RaphielGang/Telegram-Paperplane) 48 | * [UniBorg](https://github.com/SpEcHiDe/UniBorg) 49 | 50 | > Special Thanks to all of you !!!. 51 | 52 | ## [Documentation](http://theuserge.tech) 📘 53 | 54 | ## [Deployment](http://theuserge.tech/deployment) 👷 55 | 56 | ## [Plugins](https://github.com/UsergeTeam/Userge-Plugins) 🔌 57 | 58 | ### Support & Discussions 👥 59 | 60 | > Head over to the [Discussion Group](https://t.me/usergeot) and [Update Channel](https://t.me/theUserge) 61 | 62 | ### Project Credits 💆‍♂️ 63 | 64 | * [Specially to these projects](https://github.com/UsergeTeam/Userge#inspiration-) 🥰 65 | * [Contributors](https://github.com/UsergeTeam/Userge/graphs/contributors) 👥 66 | 67 | ### Copyright & License 👮 68 | 69 | * Copyright (C) 2020 - 2022 by [UsergeTeam](https://github.com/UsergeTeam) ❤️️ 70 | * Licensed under the terms of the [GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007](https://github.com/UsergeTeam/Userge/blob/master/LICENSE) 71 | -------------------------------------------------------------------------------- /userge/plugins/utils/translate.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import time 10 | import asyncio 11 | from json import dumps 12 | 13 | from emoji import get_emoji_regexp 14 | from googletrans import Translator, LANGUAGES 15 | 16 | from userge import userge, Message, Config, pool 17 | 18 | 19 | @userge.on_cmd("tr", about={ 20 | 'header': "Translate the given text using Google Translate", 21 | 'supported languages': dumps(LANGUAGES, indent=4, sort_keys=True), 22 | 'usage': "from english to sinhala\n" 23 | "{tr}tr -en -si i am userge\n\n" 24 | "from auto detected language to sinhala\n" 25 | "{tr}tr -si i am userge\n\n" 26 | "from auto detected language to preferred\n" 27 | "{tr}tr i am userge\n\n" 28 | "reply to message you want to translate from english to sinhala\n" 29 | "{tr}tr -en -si\n\n" 30 | "reply to message you want to translate from auto detected language to sinhala\n" 31 | "{tr}tr -si\n\n" 32 | "reply to message you want to translate from auto detected language to preferred\n" 33 | "{tr}tr"}, del_pre=True) 34 | async def translateme(message: Message): 35 | text = message.filtered_input_str 36 | flags = message.flags 37 | replied = message.reply_to_message 38 | is_poll = False 39 | 40 | if replied: 41 | if replied.poll: 42 | is_poll = True 43 | text = f'{replied.poll.question}' 44 | for option in replied.poll.options: 45 | text += f'\n\n\n{option.text}' 46 | else: 47 | text = replied.text or replied.caption 48 | if not text: 49 | return await message.err("Give a text or reply to a message to translate!") 50 | 51 | if len(flags) == 2: 52 | src, dest = list(flags) 53 | elif len(flags) == 1: 54 | src, dest = 'auto', list(flags)[0] 55 | else: 56 | src, dest = 'auto', Config.LANG 57 | text = get_emoji_regexp().sub(u'', text) 58 | await message.edit("`Translating ...`") 59 | try: 60 | reply_text = await _translate_this(text, dest, src) 61 | except ValueError: 62 | return await message.err("Invalid destination language.") 63 | 64 | if is_poll: 65 | options = reply_text.text.split('\n\n\n') 66 | if len(options) > 1: 67 | question = options.pop(0) 68 | await asyncio.gather( 69 | message.delete(), 70 | message.client.send_poll( 71 | chat_id=message.chat.id, 72 | question=question, 73 | options=options, 74 | is_anonymous=replied.poll.is_anonymous 75 | ) 76 | ) 77 | return 78 | source_lan = LANGUAGES[f'{reply_text.src.lower()}'] 79 | transl_lan = LANGUAGES[f'{reply_text.dest.lower()}'] 80 | output = f"**Source ({source_lan.title()}):**`\n{text}`\n\n\ 81 | **Translation ({transl_lan.title()}):**\n`{reply_text.text}`" 82 | await message.edit_or_send_as_file(text=output, caption="translated") 83 | 84 | 85 | @pool.run_in_thread 86 | def _translate_this(text: str, dest: str, src: str) -> str: 87 | for i in range(10): 88 | try: 89 | return Translator().translate(text, dest=dest, src=src) 90 | except AttributeError: 91 | if i == 9: 92 | raise 93 | time.sleep(0.3) 94 | -------------------------------------------------------------------------------- /userge/plugins/utils/ocr.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import os 10 | 11 | import requests 12 | 13 | from userge import userge, Message, Config, pool 14 | 15 | CHANNEL = userge.getCLogger(__name__) 16 | 17 | 18 | @pool.run_in_thread 19 | def ocr_space_file(filename, 20 | language='eng', 21 | overlay=False, 22 | api_key=Config.OCR_SPACE_API_KEY): 23 | """ 24 | OCR.space API request with local file. 25 | Python3.5 - not tested on 2.7 26 | :param filename: Your file path & name. 27 | :param overlay: Is OCR.space overlay required in your response. 28 | Defaults to False. 29 | :param api_key: OCR.space API key. 30 | Defaults to 'helloworld'. 31 | :param language: Language code to be used in OCR. 32 | List of available language codes can be found on https://ocr.space/OCRAPI 33 | Defaults to 'en'. 34 | :return: Result in JSON format. 35 | """ 36 | payload = { 37 | 'isOverlayRequired': overlay, 38 | 'apikey': api_key, 39 | 'language': language, 40 | } 41 | with open(filename, 'rb') as f: 42 | r = requests.post( 43 | 'https://api.ocr.space/parse/image', 44 | files={filename: f}, 45 | data=payload, 46 | ) 47 | return r.json() 48 | 49 | 50 | @userge.on_cmd("ocr", about={ 51 | 'header': "use this to run ocr reader", 52 | 'description': "get ocr result for images (file size limit = 1MB)", 53 | 'examples': [ 54 | "{tr}ocr [reply to image]", 55 | "{tr}ocr eng [reply to image] (get lang codes from 'https://ocr.space/ocrapi')"]}) 56 | async def ocr_gen(message: Message): 57 | """ 58 | this function can generate ocr output for a image file 59 | """ 60 | if Config.OCR_SPACE_API_KEY is None: 61 | await message.edit( 62 | "Oops!!get the OCR API from " 63 | "HERE " 64 | "& add it to Heroku config vars (OCR_SPACE_API_KEY)", 65 | disable_web_page_preview=True, 66 | parse_mode="html", del_in=0) 67 | return 68 | 69 | if message.reply_to_message: 70 | 71 | if message.input_str: 72 | lang_code = message.input_str 73 | else: 74 | lang_code = "eng" 75 | 76 | await message.edit(r"`Trying to Read.. 📖") 77 | downloaded_file_name = await message.client.download_media(message.reply_to_message) 78 | test_file = await ocr_space_file(downloaded_file_name, lang_code) 79 | try: 80 | ParsedText = test_file["ParsedResults"][0]["ParsedText"] 81 | except Exception as e_f: 82 | await message.edit( 83 | r"`Couldn't read it.. (╯‵□′)╯︵┻━┻`" 84 | "\n`I guess I need new glasses.. 👓`" 85 | f"\n\n**ERROR**: `{e_f}`", del_in=0) 86 | os.remove(downloaded_file_name) 87 | return 88 | else: 89 | await message.edit( 90 | "**Here's what I could read from it:**" 91 | f"\n\n`{ParsedText}`") 92 | os.remove(downloaded_file_name) 93 | await CHANNEL.log("`ocr` command succefully executed") 94 | return 95 | 96 | else: 97 | await message.err(r"i can't read nothing (°ー°〃)") 98 | return 99 | -------------------------------------------------------------------------------- /userge/core/methods/messages/send_as_file.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['SendAsFile'] 12 | 13 | import inspect 14 | import io 15 | from typing import Union, Optional 16 | 17 | from pyrogram.parser import Parser 18 | 19 | from userge import logging, Config 20 | from userge.utils import secure_text 21 | from ... import types 22 | from ...ext import RawClient 23 | 24 | _LOG = logging.getLogger(__name__) 25 | _LOG_STR = "<<>>" 26 | 27 | 28 | class SendAsFile(RawClient): # pylint: disable=missing-class-docstring 29 | async def send_as_file(self, 30 | chat_id: Union[int, str], 31 | text: str, 32 | as_raw: bool = False, 33 | filename: str = "output.txt", 34 | caption: str = '', 35 | log: Union[bool, str] = False, 36 | reply_to_message_id: Optional[int] = None) -> 'types.bound.Message': 37 | """\nYou can send large outputs as file 38 | 39 | Example: 40 | @userge.send_as_file(chat_id=12345, text="hello") 41 | 42 | Parameters: 43 | chat_id (``int`` | ``str``): 44 | Unique identifier (int) or username (str) of the target chat. 45 | For your personal cloud (Saved Messages) 46 | you can simply use "me" or "self". 47 | For a contact that exists in your Telegram address book 48 | you can use his phone number (str). 49 | 50 | text (``str``): 51 | Text of the message to be sent. 52 | 53 | as_raw (``bool``, *optional*): 54 | If ``False``, the message will be escaped with current parse mode. 55 | default to ``False``. 56 | 57 | filename (``str``, *optional*): 58 | file_name for output file. 59 | 60 | caption (``str``, *optional*): 61 | caption for output file. 62 | 63 | log (``bool`` | ``str``, *optional*): 64 | If ``True``, the message will be forwarded 65 | to the log channel. 66 | If ``str``, the logger name will be updated. 67 | 68 | reply_to_message_id (``int``, *optional*): 69 | If the message is a reply, ID of the original message. 70 | 71 | Returns: 72 | On success, the sent Message is returned. 73 | """ 74 | if text and chat_id not in Config.AUTH_CHATS: 75 | text = secure_text(str(text)) 76 | if not as_raw: 77 | text = (await Parser(self).parse(text)).get("message") 78 | doc = io.BytesIO(text.encode()) 79 | doc.name = filename 80 | _LOG.debug(_LOG_STR, f"Uploading {filename} To Telegram") 81 | msg = await self.send_document(chat_id=chat_id, 82 | document=doc, 83 | caption=caption[:1024], 84 | disable_notification=True, 85 | reply_to_message_id=reply_to_message_id) 86 | module = inspect.currentframe().f_back.f_globals['__name__'] 87 | if log: 88 | await self._channel.fwd_msg(msg, module if isinstance(log, bool) else log) 89 | return types.bound.Message.parse(self, msg, module=module) 90 | -------------------------------------------------------------------------------- /userge/plugins/utils/thumbnail.py: -------------------------------------------------------------------------------- 1 | """ custom thumbnail """ 2 | 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | import os 12 | import base64 13 | from datetime import datetime 14 | 15 | import aiofiles 16 | 17 | from userge import userge, Config, Message, get_collection 18 | from userge.utils import progress 19 | 20 | SAVED_SETTINGS = get_collection("CONFIGS") 21 | CHANNEL = userge.getCLogger(__name__) 22 | 23 | 24 | async def _init() -> None: 25 | data = await SAVED_SETTINGS.find_one({'_id': 'CUSTOM_THUMB'}) 26 | if data and not os.path.exists(Config.THUMB_PATH): 27 | with open(Config.THUMB_PATH, "wb") as thumb_file: 28 | thumb_file.write(base64.b64decode(data['data'])) 29 | 30 | 31 | @userge.on_cmd('sthumb', about={ 32 | 'header': "Save thumbnail", 33 | 'usage': "{tr}sthumb [reply to any photo]"}) 34 | async def save_thumb_nail(message: Message): 35 | """ setup thumbnail """ 36 | await message.edit("processing ...") 37 | replied = message.reply_to_message 38 | if (replied and replied.media 39 | and (replied.photo 40 | or (replied.document and "image" in replied.document.mime_type))): 41 | start_t = datetime.now() 42 | if os.path.exists(Config.THUMB_PATH): 43 | os.remove(Config.THUMB_PATH) 44 | await message.client.download_media(message=replied, 45 | file_name=Config.THUMB_PATH, 46 | progress=progress, 47 | progress_args=(message, "trying to download")) 48 | async with aiofiles.open(Config.THUMB_PATH, "rb") as thumb_file: 49 | media = base64.b64encode(await thumb_file.read()) 50 | await SAVED_SETTINGS.update_one({'_id': 'CUSTOM_THUMB'}, 51 | {"$set": {'data': media}}, upsert=True) 52 | end_t = datetime.now() 53 | m_s = (end_t - start_t).seconds 54 | await message.edit(f"thumbnail saved in {m_s} seconds.", del_in=3) 55 | else: 56 | await message.edit("Reply to a photo to save custom thumbnail", del_in=3) 57 | 58 | 59 | @userge.on_cmd('dthumb', about={'header': "Delete thumbnail"}, allow_channels=False) 60 | async def clear_thumb_nail(message: Message): 61 | """ delete thumbnail """ 62 | await message.edit("`processing ...`") 63 | if os.path.exists(Config.THUMB_PATH): 64 | os.remove(Config.THUMB_PATH) 65 | await SAVED_SETTINGS.find_one_and_delete({'_id': 'CUSTOM_THUMB'}) 66 | await message.edit("✅ Custom thumbnail deleted succesfully.", del_in=3) 67 | elif os.path.exists('resources/userge.png'): 68 | os.remove('resources/userge.png') 69 | await message.edit("✅ Default thumbnail deleted succesfully.", del_in=3) 70 | else: 71 | await message.delete() 72 | 73 | 74 | @userge.on_cmd('vthumb', about={'header': "View thumbnail"}, allow_channels=False) 75 | async def get_thumb_nail(message: Message): 76 | """ view current thumbnail """ 77 | await message.edit("processing ...") 78 | if os.path.exists(Config.THUMB_PATH): 79 | msg = await message.client.send_document(chat_id=message.chat.id, 80 | document=Config.THUMB_PATH, 81 | disable_notification=True, 82 | reply_to_message_id=message.message_id) 83 | await CHANNEL.fwd_msg(msg) 84 | await message.delete() 85 | else: 86 | await message.edit("`Custom Thumbnail Not Found!`", del_in=5) 87 | -------------------------------------------------------------------------------- /userge/plugins/tools/updater.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import asyncio 10 | 11 | from git import Repo 12 | from git.exc import GitCommandError 13 | 14 | from userge import userge, Message, Config 15 | 16 | LOG = userge.getLogger(__name__) 17 | CHANNEL = userge.getCLogger(__name__) 18 | 19 | 20 | @userge.on_cmd("update", about={ 21 | 'header': "Check Updates or Update Userge", 22 | 'flags': { 23 | '-pull': "pull updates", 24 | '-master': "select master branch", 25 | '-beta': "select beta branch"}, 26 | 'usage': "{tr}update : check updates from master branch\n" 27 | "{tr}update -[branch_name] : check updates from any branch\n" 28 | "add -pull if you want to pull updates", 29 | 'examples': "{tr}update -beta -pull"}, del_pre=True, allow_channels=False) 30 | async def check_update(message: Message): 31 | """ check or do updates """ 32 | await message.edit("`Checking for updates, please wait....`") 33 | flags = list(message.flags) 34 | pull_from_repo = False 35 | branch = "master" 36 | if "pull" in flags: 37 | pull_from_repo = True 38 | flags.remove("pull") 39 | if len(flags) == 1: 40 | branch = flags[0] 41 | dev_branch = "alpha" 42 | if branch == dev_branch: 43 | await message.err('Can\'t update to unstable [alpha] branch. ' 44 | 'Please use other branches instead !') 45 | return 46 | repo = Repo() 47 | if branch not in repo.branches: 48 | await message.err(f'invalid branch name : {branch}') 49 | return 50 | try: 51 | out = _get_updates(repo, branch) 52 | except GitCommandError as g_e: 53 | await message.err(g_e, del_in=5) 54 | return 55 | if pull_from_repo: 56 | if out: 57 | await message.edit(f'`New update found for [{branch}], Now pulling...`') 58 | await _pull_from_repo(repo, branch) 59 | await CHANNEL.log(f"**PULLED update from [{branch}]:\n\n📄 CHANGELOG 📄**\n\n{out}") 60 | await message.edit('**Userge Successfully Updated!**\n' 61 | '`Now restarting... Wait for a while!`', del_in=3) 62 | asyncio.get_event_loop().create_task(userge.restart(True)) 63 | else: 64 | active = repo.active_branch.name 65 | if active == branch: 66 | await message.err(f"already in [{branch}]!") 67 | return 68 | await message.edit( 69 | f'`Moving HEAD from [{active}] >>> [{branch}] ...`', parse_mode='md') 70 | await _pull_from_repo(repo, branch) 71 | await CHANNEL.log(f"`Moved HEAD from [{active}] >>> [{branch}] !`") 72 | await message.edit('`Now restarting... Wait for a while!`', del_in=3) 73 | asyncio.get_event_loop().create_task(userge.restart()) 74 | elif out: 75 | change_log = f'**New UPDATE available for [{branch}]:\n\n📄 CHANGELOG 📄**\n\n' 76 | await message.edit_or_send_as_file(change_log + out, disable_web_page_preview=True) 77 | else: 78 | await message.edit(f'**Userge is up-to-date with [{branch}]**', del_in=5) 79 | 80 | 81 | def _get_updates(repo: Repo, branch: str) -> str: 82 | repo.remote(Config.UPSTREAM_REMOTE).fetch(branch) 83 | upst = Config.UPSTREAM_REPO.rstrip('/') 84 | return ''.join( 85 | f"🔨 **#{i.count()}** : [{i.summary}]({upst}/commit/{i}) 👷 __{i.author}__\n\n" 86 | for i in repo.iter_commits(f'HEAD..{Config.UPSTREAM_REMOTE}/{branch}') 87 | ) 88 | 89 | 90 | async def _pull_from_repo(repo: Repo, branch: str) -> None: 91 | repo.git.checkout(branch, force=True) 92 | repo.git.reset('--hard', branch) 93 | repo.remote(Config.UPSTREAM_REMOTE).pull(branch, force=True) 94 | await asyncio.sleep(1) 95 | -------------------------------------------------------------------------------- /userge/plugins/fun/whois.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import os 10 | 11 | from pyrogram.errors.exceptions.bad_request_400 import BotMethodInvalid 12 | 13 | from userge import userge, Message 14 | 15 | 16 | @userge.on_cmd("whois", about={ 17 | 'header': "use this to get any user details", 18 | 'usage': "just reply to any user message or add user_id or username", 19 | 'examples': "{tr}whois [user_id | username]"}, allow_channels=False) 20 | async def who_is(message: Message): 21 | await message.edit("`Collecting Whois Info.. Hang on!`") 22 | user_id = message.input_str 23 | if user_id: 24 | try: 25 | from_user = await message.client.get_users(user_id) 26 | from_chat = await message.client.get_chat(user_id) 27 | except Exception: # pylint: disable=broad-except 28 | await message.err("no valid user_id or message specified") 29 | return 30 | elif message.reply_to_message and message.reply_to_message.from_user: 31 | from_user = await message.client.get_users(message.reply_to_message.from_user.id) 32 | from_chat = await message.client.get_chat(message.reply_to_message.from_user.id) 33 | else: 34 | await message.err("no valid user_id or message specified") 35 | return 36 | if from_user or from_chat is not None: 37 | pp_c = await message.client.get_profile_photos_count(from_user.id) 38 | message_out_str = "USER INFO:\n\n" 39 | message_out_str += f"🗣 First Name: {from_user.first_name}\n" 40 | message_out_str += f"🗣 Last Name: {from_user.last_name}\n" 41 | message_out_str += f"👤 Username: @{from_user.username}\n" 42 | message_out_str += f"🏢 DC ID: {from_user.dc_id}\n" 43 | message_out_str += f"🤖 Is Bot: {from_user.is_bot}\n" 44 | message_out_str += f"🚫 Is Restricted: {from_user.is_scam}\n" 45 | message_out_str += "✅ Is Verified by Telegram: " 46 | message_out_str += f"{from_user.is_verified}\n" 47 | message_out_str += f"🕵️‍♂️ User ID: {from_user.id}\n" 48 | message_out_str += f"🖼 Profile Photos: {pp_c}\n" 49 | try: 50 | cc_no = len(await message.client.get_common_chats(from_user.id)) 51 | except BotMethodInvalid: 52 | pass 53 | else: 54 | message_out_str += f"👥 Common Chats: {cc_no}\n" 55 | message_out_str += f"📝 Bio: {from_chat.bio}\n\n" 56 | message_out_str += f"👁 Last Seen: {from_user.status}\n" 57 | message_out_str += "🔗 Permanent Link To Profile: " 58 | message_out_str += f"{from_user.first_name}" 59 | 60 | s_perm = True 61 | if message.chat.permissions: 62 | s_perm = bool(message.chat.permissions.can_send_media_messages) 63 | if from_user.photo and s_perm: 64 | local_user_photo = await message.client.download_media( 65 | message=from_user.photo.big_file_id) 66 | await message.client.send_photo(chat_id=message.chat.id, 67 | photo=local_user_photo, 68 | caption=message_out_str, 69 | parse_mode="html", 70 | disable_notification=True) 71 | os.remove(local_user_photo) 72 | await message.delete() 73 | else: 74 | cuz = "Chat Send Media Forbidden" if not s_perm else "NO DP Found" 75 | message_out_str = "📷 " + cuz + " 📷\n\n" + message_out_str 76 | await message.edit(message_out_str) 77 | -------------------------------------------------------------------------------- /userge/plugins/utils/telegraph.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import aiofiles 10 | from aiofiles import os 11 | from PIL import Image 12 | from telegraph import upload_file 13 | from userge import userge, Message, Config, pool 14 | from userge.utils import post_to_telegraph, progress 15 | 16 | _T_LIMIT = 5242880 17 | 18 | 19 | @userge.on_cmd("telegraph", about={ 20 | 'header': "Upload file to Telegra.ph's servers", 21 | 'types': ['.jpg', '.jpeg', '.png', '.gif', '.mp4', '.webp', '.html', '.txt', '.py'], 22 | 'usage': "reply {tr}telegraph to media or text : limit 5MB for media", 23 | 'examples': "reply {tr}telegraph to `header|content`\n(You can use html code)"}) 24 | async def telegraph_(message: Message): 25 | replied = message.reply_to_message 26 | if not replied: 27 | await message.err("reply to media or text") 28 | return 29 | if not ((replied.photo and replied.photo.file_size <= _T_LIMIT) 30 | or (replied.animation and replied.animation.file_size <= _T_LIMIT) 31 | or (replied.video and replied.video.file_name.endswith('.mp4') 32 | and replied.video.file_size <= _T_LIMIT) 33 | or (replied.sticker and replied.sticker.file_name.endswith('.webp')) 34 | or replied.text 35 | or (replied.document 36 | and replied.document.file_name.endswith( 37 | ('.jpg', '.jpeg', '.png', '.gif', '.mp4', '.html', '.txt', '.py')) 38 | and replied.document.file_size <= _T_LIMIT)): 39 | await message.err("not supported!") 40 | return 41 | await message.edit("`processing...`") 42 | if (replied.text 43 | or (replied.document 44 | and replied.document.file_name.endswith( 45 | ('.html', '.txt', '.py')))): 46 | if replied.document: 47 | dl_loc = await message.client.download_media( 48 | message=message.reply_to_message, 49 | file_name=Config.DOWN_PATH, 50 | progress=progress, 51 | progress_args=(message, "trying to download") 52 | ) 53 | async with aiofiles.open(dl_loc, "r") as jv: 54 | text = await jv.read() 55 | header = message.input_str 56 | if not header: 57 | header = "Pasted content by @theuserge" 58 | await os.remove(dl_loc) 59 | else: 60 | content = message.reply_to_message.text.html 61 | if "|" in content and not content.startswith("<"): 62 | content = content.split("|", maxsplit=1) 63 | header = content[0] 64 | text = content[1] 65 | else: 66 | text = content 67 | header = "Pasted content by @theuserge" 68 | t_url = await pool.run_in_thread(post_to_telegraph)(header, text.replace("\n", "
")) 69 | jv_text = f"**[Here Your Telegra.ph Link!]({t_url})**" 70 | await message.edit(text=jv_text, disable_web_page_preview=True) 71 | return 72 | dl_loc = await message.client.download_media( 73 | message=message.reply_to_message, 74 | file_name=Config.DOWN_PATH, 75 | progress=progress, 76 | progress_args=(message, "trying to download") 77 | ) 78 | if replied.sticker: 79 | img = Image.open(dl_loc).convert('RGB') 80 | img.save(f'{Config.DOWN_PATH}/userge.png', 'png') 81 | await os.remove(dl_loc) 82 | dl_loc = f'{Config.DOWN_PATH}/userge.png' 83 | await message.edit("`uploading to telegraph...`") 84 | try: 85 | response = await pool.run_in_thread(upload_file)(dl_loc) 86 | except Exception as t_e: 87 | await message.err(str(t_e)) 88 | else: 89 | await message.edit(f"**[Here Your Telegra.ph Link!](https://telegra.ph{response[0]})**") 90 | finally: 91 | await os.remove(dl_loc) 92 | -------------------------------------------------------------------------------- /config.env.sample: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | 12 | # Remove this line first before doing anything else 13 | _____REMOVE_____THIS_____LINE_____=true 14 | 15 | # if you fill it correctly, but still having problem 16 | # Remove the quotes foo="bar" to foo=bar 17 | 18 | # ----------- REQUIRED ----------- # 19 | 20 | 21 | # Get them from https://my.telegram.org/ 22 | API_ID="" 23 | API_HASH="" 24 | 25 | 26 | # Mongodb url from https://cloud.mongodb.com/ 27 | # comment below line if you are going to use docker ! 28 | DATABASE_URL="" 29 | 30 | 31 | # Telegram Log Channel ID 32 | LOG_CHANNEL_ID="" 33 | 34 | 35 | # one of USERGE MODE 36 | # you can use userge as [ USER or BOT or DUAL ] MODE 37 | # see below for more info 38 | 39 | 40 | # ----------- OPTIONAL ----------- # 41 | 42 | 43 | # Set true if your like to use unofficial plugins 44 | LOAD_UNOFFICIAL_PLUGINS=false 45 | 46 | 47 | # assert running single Userge instance to prevent from AUTH_KEY_DUPLICATED error. 48 | ASSERT_SINGLE_INSTANCE=false 49 | 50 | 51 | # Custom pip packages which are seperated by spaces to install while starting the bot. 52 | CUSTOM_PIP_PACKAGES="" 53 | 54 | 55 | # This is best if you wanna add your own plugins 56 | # Set this to fork of https://github.com/UsergeTeam/Custom-Plugins and add your plugins 57 | CUSTOM_PLUGINS_REPO="" 58 | 59 | # Userbot Workers Count : Default = cpu_count + 4 60 | WORKERS="" 61 | 62 | # Telegram Chat id For Updates of Rss Feed 63 | RSS_CHAT_ID="" 64 | 65 | # Telegram Chat id to Fban User 66 | # add your federation bots to chat and copy chat_id of that chat 67 | FBAN_CHAT_ID="" 68 | 69 | # Googel Drive API Keys from https://console.developers.google.com/ 70 | G_DRIVE_CLIENT_ID="" 71 | G_DRIVE_CLIENT_SECRET="" 72 | 73 | # Set true if it is TeamDrive 74 | G_DRIVE_IS_TD=false 75 | 76 | # Index link for gdrive 77 | G_DRIVE_INDEX_LINK="" 78 | 79 | # Set name to your working directory 80 | DOWN_PATH="downloads/" 81 | 82 | # Your Languge ( ex: if english => 'en' ) 83 | PREFERRED_LANGUAGE="en" 84 | 85 | # get API Key from 'https://free.currencyconverterapi.com/' 86 | CURRENCY_API="" 87 | 88 | # get API key for OCR module 'http://eepurl.com/bOLOcf' 89 | OCR_SPACE_API_KEY="" 90 | 91 | # add default city for weather 92 | WEATHER_DEFCITY="" 93 | 94 | # Userge AntiSpam API get it from @UsergeAntiSpamBot in Telegram 95 | USERGE_ANTISPAM_API="" 96 | 97 | # SpamWatch API get it from @SpamWatch in Telegram 98 | SPAM_WATCH_API="" 99 | 100 | # Weather API get it from 'https://openweathermap.org/' 101 | OPEN_WEATHER_MAP="" 102 | 103 | # RemoveBg API Key get it from 'https://www.remove.bg/api' 104 | REMOVE_BG_API_KEY="" 105 | 106 | # GDrive Folder ID 107 | G_DRIVE_PARENT_ID="" 108 | 109 | # set command prefix 110 | CMD_TRIGGER="." 111 | 112 | # set command prefix for SUDO users 113 | SUDO_TRIGGER="!" 114 | 115 | # set this to your USERGE fork on GitHub 116 | UPSTREAM_REPO="" 117 | 118 | # single character for finished progress 119 | FINISHED_PROGRESS_STR='█' 120 | 121 | # single character for unfinished progress 122 | UNFINISHED_PROGRESS_STR='░' 123 | 124 | # custom name for your sticker pack 125 | CUSTOM_PACK_NAME="" 126 | 127 | # custom audio max duration for voice chat plugin 128 | MAX_DURATION=900 129 | 130 | # set your own custom media for .alive or 131 | # disable it by putting value 'nothing' 132 | # accepted formats: 133 | # a link to message: https://t.me/theuserge/8 134 | # chat and message id separated by |: -1005545442|84565 135 | ALIVE_MEDIA="" 136 | 137 | # ----------- Only If Using Heroku ----------- # 138 | 139 | 140 | # get a Heroku API key from http://dashboard.heroku.com/account 141 | HEROKU_API_KEY="" 142 | 143 | 144 | # given app name to the heroku app 145 | HEROKU_APP_NAME="" 146 | 147 | # ----------- USERGE MODES ----------- # 148 | 149 | # >>> USER MODE <<< # 150 | # use userge as user 151 | # get this using [ '@genStr_Bot' or `bash genStr` ] 152 | HU_STRING_SESSION="" 153 | 154 | # >>> BOT MODE <<< # 155 | # use userge as bot 156 | # get this from https://t.me/botfather if you like to use userge as a bot 157 | # And your user id 158 | BOT_TOKEN="" 159 | OWNER_ID="" 160 | 161 | # >>> DUAL MODE <<< # 162 | # use userge as both user and bot 163 | # fill all USER MODE and BOT MODE 164 | 165 | # >>> optional variable for utube.py <<< # 166 | YOUTUBE_DL_PATH=youtube_dl 167 | 168 | -------------------------------------------------------------------------------- /userge/plugins/utils/dic.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import aiohttp 10 | 11 | from userge import userge, Message 12 | 13 | LOG = userge.getLogger(__name__) # logger object 14 | CHANNEL = userge.getCLogger(__name__) # channel logger object 15 | 16 | 17 | @userge.on_cmd("dic", about={ 18 | 'header': "English Dictionary-telegram", 19 | 'usage': "{tr}dic [word]", 20 | 'examples': 'word : Search for any word'}) 21 | async def dictionary(message: Message): 22 | """this is a dictionary""" 23 | LOG.info("starting dic command...") 24 | input_ = message.input_str 25 | 26 | await message.edit("`processing...⚙️🛠`") 27 | 28 | def combine(s_word, name): 29 | w_word = f"🛑--**__{name.title()}__**--\n" 30 | for i in s_word: 31 | if "definition" in i: 32 | if "example" in i: 33 | w_word += ("\n👩‍🏫 **Definition** 👨‍🏫\n
" + i["definition"] +
 34 |                                "
\n\t\t❓Example❔\n
" + i["example"] + "
") 35 | else: 36 | w_word += "\n👩‍🏫 **Definition** 👨‍🏫\n" + "
" + i["definition"] + "
" 37 | w_word += "\n\n" 38 | return w_word 39 | 40 | def out_print(word1): 41 | out = "" 42 | if "meaning" in list(word1): 43 | meaning = word1["meaning"] 44 | if "noun" in list(meaning): 45 | noun = meaning["noun"] 46 | out += combine(noun, "noun") 47 | # print(noun) 48 | if "verb" in list(meaning): 49 | verb = meaning["verb"] 50 | out += combine(verb, "verb") 51 | # print(verb) 52 | if "preposition" in list(meaning): 53 | preposition = meaning["preposition"] 54 | out += combine(preposition, "preposition") 55 | # print(preposition) 56 | if "adverb" in list(meaning): 57 | adverb = meaning["adverb"] 58 | out += combine(adverb, "adverb") 59 | # print(adverb) 60 | if "adjective" in list(meaning): 61 | adjec = meaning["adjective"] 62 | out += combine(adjec, "adjective") 63 | # print(adjec) 64 | if "abbreviation" in list(meaning): 65 | abbr = meaning["abbreviation"] 66 | out += combine(abbr, "abbreviation") 67 | # print(abbr) 68 | if "exclamation" in list(meaning): 69 | exclamation = meaning["exclamation"] 70 | out += combine(exclamation, "exclamation") 71 | # print(exclamation) 72 | if "transitive verb" in list(meaning): 73 | transitive_verb = meaning["transitive verb"] 74 | out += combine(transitive_verb, "transitive verb") 75 | # print(tt) 76 | if "determiner" in list(meaning): 77 | determiner = meaning["determiner"] 78 | out += combine(determiner, "determiner") 79 | # print(determiner) 80 | if "crossReference" in list(meaning): 81 | crosref = meaning["crossReference"] 82 | out += combine(crosref, "crossReference") 83 | # print(crosref) 84 | if "title" in list(word1): 85 | out += ("🔖--**__Error Note__**--\n\n▪️`" + word1["title"] + 86 | "🥺\n\n▪️" + word1["message"] + "😬\n\n▪️" + word1["resolution"] + 87 | "🤓`") 88 | return out 89 | 90 | if not input_: 91 | await message.err("❌Please enter word to search‼️") 92 | else: 93 | word = input_ 94 | url = f"https://api.dictionaryapi.dev/api/v1/entries/en/{word}" 95 | async with aiohttp.ClientSession() as ses, ses.get(url) as res: 96 | r_dec = await res.json() 97 | v_word = input_ 98 | if isinstance(r_dec, list): 99 | r_dec = r_dec[0] 100 | v_word = r_dec['word'] 101 | last_output = out_print(r_dec) 102 | if last_output: 103 | await message.edit("`📌Search result for `" + f"👉 {v_word}\n\n" + last_output) 104 | await CHANNEL.log(f"Got dictionary results for 👉 {v_word}") 105 | else: 106 | await message.edit('`No result found in the database.😔`', del_in=5) 107 | await CHANNEL.log("Got dictionary result empty") 108 | -------------------------------------------------------------------------------- /userge/core/methods/messages/edit_message_text.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['EditMessageText'] 12 | 13 | import inspect 14 | import asyncio 15 | from typing import Optional, Union, List 16 | 17 | from pyrogram.types import InlineKeyboardMarkup, MessageEntity 18 | 19 | from userge import Config 20 | from userge.utils import secure_text 21 | from ...ext import RawClient 22 | from ... import types 23 | 24 | 25 | class EditMessageText(RawClient): # pylint: disable=missing-class-docstring 26 | async def edit_message_text(self, # pylint: disable=arguments-differ 27 | chat_id: Union[int, str], 28 | message_id: int, 29 | text: str, 30 | del_in: int = -1, 31 | log: Union[bool, str] = False, 32 | parse_mode: Union[str, object] = object, 33 | entities: List[MessageEntity] = None, 34 | disable_web_page_preview: Optional[bool] = None, 35 | reply_markup: InlineKeyboardMarkup = None 36 | ) -> Union['types.bound.Message', bool]: 37 | """\nExample: 38 | message.edit_text("hello") 39 | 40 | Parameters: 41 | chat_id (``int`` | ``str``): 42 | Unique identifier (int) or username (str) of the target chat. 43 | For your personal cloud (Saved Messages) 44 | you can simply use "me" or "self". 45 | For a contact that exists in your Telegram address book 46 | you can use his phone number (str). 47 | 48 | message_id (``int``): 49 | Message identifier in the chat specified in chat_id. 50 | 51 | text (``str``): 52 | New text of the message. 53 | 54 | del_in (``int``): 55 | Time in Seconds for delete that message. 56 | 57 | log (``bool`` | ``str``, *optional*): 58 | If ``True``, the message will be forwarded 59 | to the log channel. 60 | If ``str``, the logger name will be updated. 61 | 62 | parse_mode (``str``, *optional*): 63 | By default, texts are parsed using 64 | both Markdown and HTML styles. 65 | You can combine both syntaxes together. 66 | Pass "markdown" or "md" to enable 67 | Markdown-style parsing only. 68 | Pass "html" to enable HTML-style parsing only. 69 | Pass None to completely disable style parsing. 70 | 71 | entities (List of :obj:`~pyrogram.types.MessageEntity`): 72 | List of special entities that appear in message text, 73 | which can be specified instead of *parse_mode*. 74 | 75 | disable_web_page_preview (``bool``, *optional*): 76 | Disables link previews for links in this message. 77 | 78 | reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): 79 | An InlineKeyboardMarkup object. 80 | 81 | Returns: 82 | On success, the edited 83 | :obj:`Message` or True is returned. 84 | 85 | Raises: 86 | RPCError: In case of a Telegram RPC error. 87 | """ 88 | if text and chat_id not in Config.AUTH_CHATS: 89 | text = secure_text(str(text)) 90 | msg = await super().edit_message_text(chat_id=chat_id, 91 | message_id=message_id, 92 | text=text, 93 | parse_mode=parse_mode, 94 | entities=entities, 95 | disable_web_page_preview=disable_web_page_preview, 96 | reply_markup=reply_markup) 97 | module = inspect.currentframe().f_back.f_globals['__name__'] 98 | if log: 99 | await self._channel.fwd_msg(msg, module if isinstance(log, bool) else log) 100 | del_in = del_in or Config.MSG_DELETE_TIMEOUT 101 | if del_in > 0: 102 | await asyncio.sleep(del_in) 103 | return bool(await msg.delete()) 104 | return types.bound.Message.parse(self, msg, module=module) 105 | -------------------------------------------------------------------------------- /userge/config.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Config', 'get_version'] 12 | 13 | import os 14 | from typing import Set 15 | 16 | import heroku3 17 | from git import Repo 18 | from pyrogram import filters 19 | 20 | from userge import logging, logbot 21 | from . import versions 22 | 23 | _LOG = logging.getLogger(__name__) 24 | logbot.reply_last_msg("Setting Configs ...") 25 | 26 | 27 | class Config: 28 | """ Configs to setup Userge """ 29 | API_ID = int(os.environ.get("API_ID")) 30 | API_HASH = os.environ.get("API_HASH") 31 | WORKERS = int(os.environ.get("WORKERS")) or os.cpu_count() + 4 32 | BOT_TOKEN = os.environ.get("BOT_TOKEN") 33 | HU_STRING_SESSION = os.environ.get("HU_STRING_SESSION") 34 | OWNER_ID = tuple(filter(lambda x: x, map(int, os.environ.get("OWNER_ID", "0").split()))) 35 | LOG_CHANNEL_ID = int(os.environ.get("LOG_CHANNEL_ID")) 36 | AUTH_CHATS = (OWNER_ID[0], LOG_CHANNEL_ID) if OWNER_ID else (LOG_CHANNEL_ID,) 37 | DB_URI = os.environ.get("DATABASE_URL") 38 | LANG = os.environ.get("PREFERRED_LANGUAGE") 39 | DOWN_PATH = os.environ.get("DOWN_PATH") 40 | CMD_TRIGGER = os.environ.get("CMD_TRIGGER") 41 | SUDO_TRIGGER = os.environ.get("SUDO_TRIGGER") 42 | PUBLIC_TRIGGER = '/' 43 | FINISHED_PROGRESS_STR = os.environ.get("FINISHED_PROGRESS_STR") 44 | UNFINISHED_PROGRESS_STR = os.environ.get("UNFINISHED_PROGRESS_STR") 45 | ALIVE_MEDIA = os.environ.get("ALIVE_MEDIA") 46 | CUSTOM_PACK_NAME = os.environ.get("CUSTOM_PACK_NAME") 47 | UPSTREAM_REPO = os.environ.get("UPSTREAM_REPO") 48 | UPSTREAM_REMOTE = os.environ.get("UPSTREAM_REMOTE") 49 | USERGE_ANTISPAM_API = os.environ.get("USERGE_ANTISPAM_API") 50 | SPAM_WATCH_API = os.environ.get("SPAM_WATCH_API") 51 | CURRENCY_API = os.environ.get("CURRENCY_API") 52 | OCR_SPACE_API_KEY = os.environ.get("OCR_SPACE_API_KEY") 53 | OPEN_WEATHER_MAP = os.environ.get("OPEN_WEATHER_MAP") 54 | REMOVE_BG_API_KEY = os.environ.get("REMOVE_BG_API_KEY") 55 | WEATHER_DEFCITY = os.environ.get("WEATHER_DEFCITY") 56 | TZ_NUMBER = os.environ.get("TZ_NUMBER", 1) 57 | MAX_DURATION = int(os.environ.get("MAX_DURATION", 900)) 58 | G_DRIVE_CLIENT_ID = os.environ.get("G_DRIVE_CLIENT_ID") 59 | G_DRIVE_CLIENT_SECRET = os.environ.get("G_DRIVE_CLIENT_SECRET") 60 | G_DRIVE_PARENT_ID = os.environ.get("G_DRIVE_PARENT_ID") 61 | G_DRIVE_INDEX_LINK = os.environ.get("G_DRIVE_INDEX_LINK") 62 | GOOGLE_CHROME_DRIVER = os.environ.get("GOOGLE_CHROME_DRIVER") 63 | GOOGLE_CHROME_BIN = os.environ.get("GOOGLE_CHROME_BIN") 64 | HEROKU_ENV = bool(int(os.environ.get("HEROKU_ENV", "0"))) 65 | HEROKU_API_KEY = os.environ.get("HEROKU_API_KEY") 66 | HEROKU_APP_NAME = os.environ.get("HEROKU_APP_NAME") 67 | G_DRIVE_IS_TD = os.environ.get("G_DRIVE_IS_TD") == "true" 68 | LOAD_UNOFFICIAL_PLUGINS = os.environ.get("LOAD_UNOFFICIAL_PLUGINS") == "true" 69 | ASSERT_SINGLE_INSTANCE = os.environ.get("ASSERT_SINGLE_INSTANCE") == "true" 70 | THUMB_PATH = DOWN_PATH + "thumb_image.jpg" 71 | TMP_PATH = "userge/plugins/temp/" 72 | MAX_MESSAGE_LENGTH = 4096 73 | MSG_DELETE_TIMEOUT = 120 74 | WELCOME_DELETE_TIMEOUT = 120 75 | EDIT_SLEEP_TIMEOUT = 0.2 76 | AUTOPIC_TIMEOUT = 300 77 | ALLOWED_CHATS = filters.chat([]) 78 | ALLOW_ALL_PMS = True 79 | USE_USER_FOR_CLIENT_CHECKS = False 80 | SUDO_ENABLED = False 81 | SUDO_USERS: Set[int] = set() 82 | DISABLED_ALL = False 83 | DISABLED_CHATS: Set[int] = set() 84 | ALLOWED_COMMANDS: Set[str] = set() 85 | IGNORE_VERIFIED_CHATS = True 86 | ANTISPAM_SENTRY = False 87 | FBAN_CHAT_ID = int(os.environ.get("FBAN_CHAT_ID") or 0) 88 | RUN_DYNO_SAVER = False 89 | HEROKU_APP = heroku3.from_key(HEROKU_API_KEY).apps()[HEROKU_APP_NAME] \ 90 | if HEROKU_ENV and HEROKU_API_KEY and HEROKU_APP_NAME else None 91 | STATUS = None 92 | 93 | 94 | def get_version() -> str: 95 | """ get userge version """ 96 | repo = Repo() 97 | repo.remote(Config.UPSTREAM_REMOTE).fetch() 98 | ver = f"{versions.__major__}.{versions.__minor__}.{versions.__micro__}" 99 | if "/usergeteam/userge" in Config.UPSTREAM_REPO.lower(): 100 | diff = list(repo.iter_commits(f'v{ver}..HEAD')) 101 | if diff: 102 | ver = f"{ver}-patch.{len(diff)}" 103 | else: 104 | diff = list(repo.iter_commits( 105 | f'{Config.UPSTREAM_REMOTE}/master..HEAD')) 106 | if diff: 107 | ver = f"{ver}-custom.{len(diff)}" 108 | return ver + '@' + repo.active_branch.name 109 | -------------------------------------------------------------------------------- /userge/plugins/utils/weather.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import json 10 | from datetime import datetime 11 | 12 | import aiohttp 13 | from pytz import country_timezones as c_tz, timezone as tz, country_names as c_n 14 | 15 | from userge import userge, Message, Config 16 | 17 | CHANNEL = userge.getCLogger(__name__) 18 | 19 | 20 | async def get_tz(con): 21 | """Get time zone of the given country 22 | Credits: @aragon12 and @zakaryan2004 23 | """ 24 | for c_code in c_n: 25 | if con == c_n[c_code]: 26 | return tz(c_tz[c_code][0]) 27 | try: 28 | if c_n[con]: 29 | return tz(c_tz[con][0]) 30 | except KeyError: 31 | return 32 | 33 | 34 | @userge.on_cmd("weather", about={ 35 | 'header': "use this to get weather details", 36 | 'description': "get weather info for any city", 37 | 'examples': [ 38 | "{tr}weather (default city)", 39 | "{tr}weather colombo (city name)"]}) 40 | async def weather_get(message: Message): 41 | """ 42 | this function can get weather info 43 | """ 44 | OWM_API = Config.OPEN_WEATHER_MAP 45 | if not OWM_API: 46 | await message.edit( 47 | "Oops!!get the API from " 48 | "HERE " 49 | "& add it to Heroku config vars (OPEN_WEATHER_MAP)", 50 | disable_web_page_preview=True, 51 | parse_mode="html", del_in=0) 52 | return 53 | 54 | APPID = OWM_API 55 | 56 | if not message.input_str: 57 | CITY = Config.WEATHER_DEFCITY 58 | if not CITY: 59 | await message.edit("`Please specify a city or set one as default!`", del_in=0) 60 | return 61 | else: 62 | CITY = message.input_str 63 | 64 | timezone_countries = { 65 | timezone: country 66 | for country, timezones in c_tz.items() for timezone in timezones 67 | } 68 | 69 | if "," in CITY: 70 | newcity = CITY.split(",") 71 | if len(newcity[1]) == 2: 72 | CITY = newcity[0].strip() + "," + newcity[1].strip() 73 | else: 74 | country = await get_tz((newcity[1].strip()).title()) 75 | try: 76 | countrycode = timezone_countries[f'{country}'] 77 | except KeyError: 78 | await message.edit("`Invalid country.`", del_in=0) 79 | return 80 | CITY = newcity[0].strip() + "," + countrycode.strip() 81 | 82 | url = f'https://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={APPID}' 83 | async with aiohttp.ClientSession() as ses, ses.get(url) as res: 84 | req_status = res.status 85 | res_text = await res.text() 86 | result = json.loads(res_text) 87 | 88 | if req_status != 200: 89 | await message.edit(r"`Invalid country.. ¯\_(ツ)_/¯`", del_in=0) 90 | return 91 | 92 | cityname = result['name'] 93 | curtemp = result['main']['temp'] 94 | humidity = result['main']['humidity'] 95 | min_temp = result['main']['temp_min'] 96 | max_temp = result['main']['temp_max'] 97 | desc = result['weather'][0] 98 | desc = desc['main'] 99 | country = result['sys']['country'] 100 | sunrise = result['sys']['sunrise'] 101 | sunset = result['sys']['sunset'] 102 | wind = result['wind']['speed'] 103 | winddir = result['wind']['deg'] 104 | 105 | ctimezone = tz(c_tz[country][0]) 106 | time = datetime.now(ctimezone).strftime("%A, %I:%M %p") 107 | fullc_n = c_n[f"{country}"] 108 | # dirs = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", 109 | # "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"] 110 | dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] 111 | 112 | div = (360 / len(dirs)) 113 | funmath = int((winddir + (div / 2)) / div) 114 | findir = dirs[funmath % len(dirs)] 115 | kmph = str(wind * 3.6).split(".") 116 | mph = str(wind * 2.237).split(".") 117 | 118 | def fahrenheit(f): 119 | temp = str(((f - 273.15) * 9 / 5 + 32)).split(".") 120 | return temp[0] 121 | 122 | def celsius(c): 123 | temp = str((c - 273.15)).split(".") 124 | return temp[0] 125 | 126 | def sun(unix): 127 | xx = datetime.fromtimestamp(unix, tz=ctimezone).strftime("%I:%M %p") 128 | return xx 129 | 130 | await message.edit( 131 | f"**Temperature:** `{celsius(curtemp)}°C | {fahrenheit(curtemp)}°F`\n" 132 | + 133 | f"**Min. Temp.:** `{celsius(min_temp)}°C | {fahrenheit(min_temp)}°F`\n" 134 | + 135 | f"**Max. Temp.:** `{celsius(max_temp)}°C | {fahrenheit(max_temp)}°F`\n" 136 | + f"**Humidity:** `{humidity}%`\n" + 137 | f"**Wind:** `{kmph[0]} kmh | {mph[0]} mph, {findir}`\n" + 138 | f"**Sunrise:** `{sun(sunrise)}`\n" + 139 | f"**Sunset:** `{sun(sunset)}`\n\n\n" + f"**{desc}**\n" + 140 | f"`{cityname}, {fullc_n}`\n" + f"`{time}`") 141 | await CHANNEL.log(f"check `{CITY}` weather results") 142 | -------------------------------------------------------------------------------- /userge/core/ext/raw_client.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['RawClient'] 12 | 13 | import asyncio 14 | from math import floor 15 | from typing import Optional, Dict, List 16 | from time import time, perf_counter, sleep 17 | 18 | import pyrogram.raw.functions as funcs 19 | import pyrogram.raw.types as types 20 | from pyrogram import Client 21 | from pyrogram.session import Session 22 | from pyrogram.raw.core import TLObject 23 | 24 | import userge # pylint: disable=unused-import 25 | 26 | _LOG = userge.logging.getLogger(__name__) 27 | _LOG_STR = "<<>>" 28 | 29 | 30 | class RawClient(Client): 31 | """ userge raw client """ 32 | DUAL_MODE = False 33 | USER_ID = 0 34 | BOT_ID = 0 35 | LAST_OUTGOING_TIME = time() 36 | REQ_LOGS: Dict[int, 'ChatReq'] = {} 37 | REQ_LOCK = asyncio.Lock() 38 | 39 | def __init__(self, bot: Optional['userge.core.client.UsergeBot'] = None, **kwargs) -> None: 40 | self._bot = bot 41 | super().__init__(**kwargs) 42 | self._channel = userge.core.types.new.ChannelLogger(self, "CORE") 43 | userge.core.types.new.Conversation.init(self) 44 | 45 | async def send(self, data: TLObject, retries: int = Session.MAX_RETRIES, 46 | timeout: float = Session.WAIT_TIMEOUT, sleep_threshold: float = None): 47 | key = 0 48 | if isinstance(data, (funcs.messages.SendMessage, 49 | funcs.messages.SendMedia, 50 | funcs.messages.SendMultiMedia, 51 | funcs.messages.EditMessage, 52 | funcs.messages.ForwardMessages)): 53 | if isinstance(data, funcs.messages.ForwardMessages): 54 | tmp = data.to_peer 55 | else: 56 | tmp = data.peer 57 | if isinstance(data, funcs.messages.SendMedia) and isinstance( 58 | data.media, (types.InputMediaUploadedDocument, 59 | types.InputMediaUploadedPhoto)): 60 | tmp = None 61 | if tmp: 62 | if isinstance(tmp, (types.InputPeerChannel, types.InputPeerChannelFromMessage)): 63 | key = int(tmp.channel_id) 64 | elif isinstance(tmp, types.InputPeerChat): 65 | key = int(tmp.chat_id) 66 | elif isinstance(tmp, (types.InputPeerUser, types.InputPeerUserFromMessage)): 67 | key = int(tmp.user_id) 68 | elif isinstance(data, funcs.channels.DeleteMessages) and isinstance( 69 | data.channel, (types.InputChannel, types.InputChannelFromMessage)): 70 | key = int(data.channel.channel_id) 71 | if key: 72 | async with self.REQ_LOCK: 73 | try: 74 | req = self.REQ_LOGS[key] 75 | except KeyError: 76 | req = self.REQ_LOGS[key] = ChatReq() 77 | async with req.lock: 78 | now = perf_counter() 79 | req.update(now - 60) 80 | if req.has: 81 | to_sl = 0.0 82 | diff = now - req.last 83 | if 0 < diff < 1: 84 | to_sl = 1 - diff 85 | diff = now - req.first 86 | if req.count > 18: 87 | to_sl = max(to_sl, 60 - diff) 88 | if to_sl > 0: 89 | if to_sl > 1: 90 | _LOG.info(_LOG_STR, to_sl, key) 91 | else: 92 | _LOG.debug(_LOG_STR, to_sl, key) 93 | await asyncio.sleep(to_sl) 94 | now += to_sl 95 | count = 0 96 | counter = floor(now - 1) 97 | for r in self.REQ_LOGS.values(): 98 | if r.has and r.last > counter: 99 | count += 1 100 | if count > 25: 101 | _LOG.info(_LOG_STR, 1, key) 102 | sleep(1) 103 | now += 1 104 | req.add(now) 105 | return await super().send(data, retries, timeout, sleep_threshold) 106 | 107 | 108 | class ChatReq: 109 | def __init__(self) -> None: 110 | self._lock = asyncio.Lock() 111 | self._logs: List[float] = [] 112 | 113 | @property 114 | def lock(self): 115 | return self._lock 116 | 117 | @property 118 | def has(self) -> bool: 119 | return len(self._logs) != 0 120 | 121 | @property 122 | def first(self) -> float: 123 | return self._logs[0] 124 | 125 | @property 126 | def last(self) -> Optional[float]: 127 | return self._logs[-1] 128 | 129 | @property 130 | def count(self) -> int: 131 | return len(self._logs) 132 | 133 | def add(self, log: float) -> None: 134 | self._logs.append(log) 135 | 136 | def update(self, t: float) -> None: 137 | self._logs = [i for i in self._logs if i > t] 138 | -------------------------------------------------------------------------------- /userge/plugins/fun/autopic.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 2 | # 3 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 4 | # and is released under the "GNU v3.0 License Agreement". 5 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 6 | # 7 | # All rights reserved. 8 | 9 | import os 10 | import base64 11 | import asyncio 12 | import datetime 13 | import textwrap 14 | from shutil import copyfile 15 | 16 | import aiofiles 17 | from PIL import Image, ImageFont, ImageDraw 18 | 19 | from userge import userge, Message, Config, get_collection 20 | 21 | SAVED_SETTINGS = get_collection("CONFIGS") 22 | UPDATE_PIC = False 23 | BASE_PIC = "resources/base_profile_pic.jpg" 24 | MDFY_PIC = "resources/mdfy_profile_pic.jpg" 25 | LOG = userge.getLogger(__name__) 26 | 27 | 28 | async def _init() -> None: 29 | global UPDATE_PIC # pylint: disable=global-statement 30 | data = await SAVED_SETTINGS.find_one({'_id': 'UPDATE_PIC'}) 31 | if data: 32 | UPDATE_PIC = data['on'] 33 | if not os.path.exists(BASE_PIC): 34 | with open(BASE_PIC, "wb") as media_file_: 35 | media_file_.write(base64.b64decode(data['media'])) 36 | 37 | 38 | @userge.on_cmd( 39 | "autopic", about={ 40 | 'header': "set profile picture", 41 | 'usage': "{tr}autopic\n{tr}autopic [image path]\nset timeout using {tr}sapicto"}, 42 | allow_channels=False, allow_via_bot=False) 43 | async def autopic(message: Message): 44 | global UPDATE_PIC # pylint: disable=global-statement 45 | await message.edit('`processing...`') 46 | if UPDATE_PIC: 47 | if isinstance(UPDATE_PIC, asyncio.Task): 48 | UPDATE_PIC.cancel() 49 | UPDATE_PIC = False 50 | await SAVED_SETTINGS.update_one({'_id': 'UPDATE_PIC'}, 51 | {"$set": {'on': False}}, upsert=True) 52 | await asyncio.sleep(1) 53 | await message.edit('`setting old photo...`') 54 | await userge.set_profile_photo(photo=BASE_PIC) 55 | await message.edit('auto profile picture updation has been **stopped**', 56 | del_in=5, log=__name__) 57 | return 58 | image_path = message.input_str 59 | store = False 60 | if os.path.exists(BASE_PIC) and not image_path: 61 | pass 62 | elif not image_path: 63 | profile_photo = await userge.get_profile_photos("me", limit=1) 64 | if not profile_photo: 65 | await message.err("sorry, couldn't find any picture!") 66 | return 67 | await userge.download_media(profile_photo[0], file_name=BASE_PIC) 68 | store = True 69 | else: 70 | if not os.path.exists(image_path): 71 | await message.err("input path not found!") 72 | return 73 | if os.path.exists(BASE_PIC): 74 | os.remove(BASE_PIC) 75 | copyfile(image_path, BASE_PIC) 76 | store = True 77 | data_dict = {'on': True} 78 | if store: 79 | async with aiofiles.open(BASE_PIC, "rb") as media_file: 80 | media = base64.b64encode(await media_file.read()) 81 | data_dict['media'] = media 82 | await SAVED_SETTINGS.update_one({'_id': 'UPDATE_PIC'}, 83 | {"$set": data_dict}, upsert=True) 84 | await message.edit( 85 | 'auto profile picture updation has been **started**', del_in=3, log=__name__) 86 | UPDATE_PIC = asyncio.get_event_loop().create_task(apic_worker()) 87 | 88 | 89 | @userge.add_task 90 | async def apic_worker(): 91 | user_dict = await userge.get_user_dict('me') 92 | user = '@' + user_dict['uname'] if user_dict['uname'] else user_dict['flname'] 93 | count = 0 94 | while UPDATE_PIC: 95 | if not count % Config.AUTOPIC_TIMEOUT: 96 | img = Image.open(BASE_PIC) 97 | i_width, i_height = img.size 98 | s_font = ImageFont.truetype("resources/font.ttf", int((35 / 640)*i_width)) 99 | l_font = ImageFont.truetype("resources/font.ttf", int((50 / 640)*i_width)) 100 | draw = ImageDraw.Draw(img) 101 | current_h, pad = 10, 0 102 | for user in textwrap.wrap(user, width=20): 103 | u_width, u_height = draw.textsize(user, font=l_font) 104 | draw.text(xy=((i_width - u_width) / 2, int((current_h / 640)*i_width)), 105 | text=user, font=l_font, fill=(255, 255, 255)) 106 | current_h += u_height + pad 107 | tim = datetime.datetime.now( 108 | tz=datetime.timezone(datetime.timedelta(minutes=30, hours=5))) 109 | date_time = (f"DATE: {tim.day}.{tim.month}.{tim.year}\n" 110 | f"TIME: {tim.hour}:{tim.minute}:{tim.second}\n" 111 | "UTC+5:30") 112 | d_width, d_height = draw.textsize(date_time, font=s_font) 113 | draw.multiline_text( 114 | xy=((i_width - d_width) / 2, i_height - d_height - int((20 / 640)*i_width)), 115 | text=date_time, fill=(255, 255, 255), font=s_font, align="center") 116 | img.convert('RGB').save(MDFY_PIC) 117 | await userge.set_profile_photo(photo=MDFY_PIC) 118 | os.remove(MDFY_PIC) 119 | LOG.info("profile photo has been updated!") 120 | await asyncio.sleep(1) 121 | count += 1 122 | if count: 123 | LOG.info("profile picture updation has been stopped!") 124 | -------------------------------------------------------------------------------- /userge/core/types/raw/plugin.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['Plugin'] 12 | 13 | import asyncio 14 | from typing import Union, List, Optional 15 | 16 | from userge import logging 17 | from . import command, filter as _filter # pylint: disable=unused-import 18 | from ... import client as _client # pylint: disable=unused-import 19 | 20 | _LOG = logging.getLogger(__name__) 21 | _LOG_STR = "<<>>" 22 | 23 | 24 | class Plugin: 25 | """ plugin class """ 26 | def __init__(self, client: '_client.Userge', name: str, parent: str) -> None: 27 | self._client = client 28 | self.name = name 29 | self.parent = parent 30 | self.doc: Optional[str] = None 31 | self.commands: List['command.Command'] = [] 32 | self.filters: List['_filter.Filter'] = [] 33 | _LOG.debug(_LOG_STR, f"created plugin -> {self.name}") 34 | 35 | def __repr__(self) -> str: 36 | return f"" 37 | 38 | @property 39 | def is_enabled(self) -> bool: 40 | """ returns enable status """ 41 | return any((flt.is_enabled for flt in self.commands + self.filters)) 42 | 43 | @property 44 | def is_disabled(self) -> bool: 45 | """ returns disable status """ 46 | return all((flt.is_disabled for flt in self.commands + self.filters)) 47 | 48 | @property 49 | def is_loaded(self) -> bool: 50 | """ returns load status """ 51 | return any((flt.is_loaded for flt in self.commands + self.filters)) 52 | 53 | @property 54 | def enabled_commands(self) -> List['command.Command']: 55 | """ returns all enabled commands """ 56 | return [cmd for cmd in self.commands if cmd.is_enabled] 57 | 58 | @property 59 | def disabled_commands(self) -> List['command.Command']: 60 | """ returns all disabled commands """ 61 | return [cmd for cmd in self.commands if cmd.is_disabled] 62 | 63 | @property 64 | def loaded_commands(self) -> List['command.Command']: 65 | """ returns all loaded commands """ 66 | return [cmd for cmd in self.commands if cmd.is_loaded] 67 | 68 | @property 69 | def unloaded_commands(self) -> List['command.Command']: 70 | """ returns all unloaded commands """ 71 | return [cmd for cmd in self.commands if not cmd.is_loaded] 72 | 73 | @property 74 | def enabled_filters(self) -> List['_filter.Filter']: 75 | """ returns all enabled filters """ 76 | return [flt for flt in self.filters if flt.is_enabled] 77 | 78 | @property 79 | def disabled_filters(self) -> List['_filter.Filter']: 80 | """ returns all disabled filters """ 81 | return [flt for flt in self.filters if flt.is_disabled] 82 | 83 | @property 84 | def loaded_filters(self) -> List['_filter.Filter']: 85 | """ returns all loaded filters """ 86 | return [flt for flt in self.filters if flt.is_loaded] 87 | 88 | @property 89 | def unloaded_filters(self) -> List['_filter.Filter']: 90 | """ returns all unloaded filters """ 91 | return [flt for flt in self.filters if not flt.is_loaded] 92 | 93 | async def init(self) -> None: 94 | """ initialize the plugin """ 95 | await asyncio.gather(*[flt.init() for flt in self.commands + self.filters]) 96 | 97 | def add(self, obj: Union['command.Command', '_filter.Filter']) -> None: 98 | """ add command or filter to plugin """ 99 | obj.plugin_name = self.name 100 | if isinstance(obj, command.Command): 101 | type_ = self.commands 102 | else: 103 | type_ = self.filters 104 | for flt in type_: 105 | if flt.name == obj.name: 106 | type_.remove(flt) 107 | break 108 | type_.append(obj) 109 | _LOG.debug(_LOG_STR, f"add filter to plugin -> {self.name}") 110 | 111 | def get_commands(self) -> List[str]: 112 | """ returns all sorted command names in the plugin """ 113 | return sorted((cmd.name for cmd in self.enabled_commands)) 114 | 115 | async def enable(self) -> List[str]: 116 | """ enable all commands in the plugin """ 117 | if self.is_enabled: 118 | return [] 119 | return await _do_it(self, 'enable') 120 | 121 | async def disable(self) -> List[str]: 122 | """ disable all commands in the plugin """ 123 | if not self.is_enabled: 124 | return [] 125 | return await _do_it(self, 'disable') 126 | 127 | async def load(self) -> List[str]: 128 | """ load all commands in the plugin """ 129 | if self.is_loaded: 130 | return [] 131 | return await _do_it(self, 'load') 132 | 133 | async def unload(self) -> List[str]: 134 | """ unload all commands in the plugin """ 135 | if not self.is_loaded: 136 | return [] 137 | return await _do_it(self, 'unload') 138 | 139 | 140 | async def _do_it(plg: Plugin, work_type: str) -> List[str]: 141 | done: List[str] = [] 142 | for flt in plg.commands + plg.filters: 143 | tmp = await getattr(flt, work_type)() 144 | if tmp: 145 | done.append(tmp) 146 | if done: 147 | _LOG.info(_LOG_STR, f"{work_type.rstrip('e')}ed {plg}") 148 | return done 149 | -------------------------------------------------------------------------------- /userge/plugins/tools/timeout.py: -------------------------------------------------------------------------------- 1 | """ set or view your timeouts """ 2 | 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | from userge import userge, Message, Config, get_collection 12 | 13 | SAVED_SETTINGS = get_collection("CONFIGS") 14 | 15 | 16 | async def _init() -> None: 17 | msg_t = await SAVED_SETTINGS.find_one({'_id': 'MSG_DELETE_TIMEOUT'}) 18 | if msg_t: 19 | Config.MSG_DELETE_TIMEOUT = msg_t['data'] 20 | wel_t = await SAVED_SETTINGS.find_one({'_id': 'WELCOME_DELETE_TIMEOUT'}) 21 | if wel_t: 22 | Config.WELCOME_DELETE_TIMEOUT = wel_t['data'] 23 | pp_t = await SAVED_SETTINGS.find_one({'_id': 'AUTOPIC_TIMEOUT'}) 24 | if pp_t: 25 | Config.AUTOPIC_TIMEOUT = pp_t['data'] 26 | es_t = await SAVED_SETTINGS.find_one({'_id': 'EDIT_SLEEP_TIMEOUT'}) 27 | if es_t: 28 | Config.EDIT_SLEEP_TIMEOUT = es_t['data'] 29 | 30 | 31 | @userge.on_cmd("sdelto (\\d+)", about={ 32 | 'header': "Set auto message delete timeout", 33 | 'usage': "{tr}sdelto [timeout in seconds]", 34 | 'examples': "{tr}sdelto 15\n{tr}sdelto 0 : for disable deletion"}) 35 | async def set_delete_timeout(message: Message): 36 | """ set delete timeout """ 37 | await message.edit("`Setting auto message delete timeout...`") 38 | t_o = int(message.matches[0].group(1)) 39 | Config.MSG_DELETE_TIMEOUT = t_o 40 | await SAVED_SETTINGS.update_one( 41 | {'_id': 'MSG_DELETE_TIMEOUT'}, {"$set": {'data': t_o}}, upsert=True) 42 | if t_o: 43 | await message.edit( 44 | f"`Set auto message delete timeout as {t_o} seconds!`", del_in=3) 45 | else: 46 | await message.edit("`Auto message deletion disabled!`", del_in=3) 47 | 48 | 49 | @userge.on_cmd("vdelto", about={'header': "View auto message delete timeout"}) 50 | async def view_delete_timeout(message: Message): 51 | """ view delete timeout """ 52 | if Config.MSG_DELETE_TIMEOUT: 53 | await message.edit( 54 | f"`Messages will be deleted after {Config.MSG_DELETE_TIMEOUT} seconds!`", 55 | del_in=5) 56 | else: 57 | await message.edit("`Auto message deletion disabled!`", del_in=3) 58 | 59 | 60 | @userge.on_cmd("swelto (\\d+)", about={ 61 | 'header': "Set auto welcome/left message delete timeout", 62 | 'usage': "{tr}swelto [timeout in seconds]", 63 | 'examples': "{tr}swelto 15\n{tr}swelto 0 : for disable deletion"}) 64 | async def set_welcome_timeout(message: Message): 65 | """ set welcome/left timeout """ 66 | await message.edit("`Setting auto welcome/left message delete timeout...`") 67 | t_o = int(message.matches[0].group(1)) 68 | Config.WELCOME_DELETE_TIMEOUT = t_o 69 | await SAVED_SETTINGS.update_one( 70 | {'_id': 'WELCOME_DELETE_TIMEOUT'}, {"$set": {'data': t_o}}, upsert=True) 71 | if t_o: 72 | await message.edit( 73 | f"`Set auto welcome/left message delete timeout as {t_o} seconds!`", del_in=3) 74 | else: 75 | await message.edit("`Auto welcome/left message deletion disabled!`", del_in=3) 76 | 77 | 78 | @userge.on_cmd("vwelto", about={'header': "View auto welcome/left message delete timeout"}) 79 | async def view_welcome_timeout(message: Message): 80 | """ view welcome/left timeout """ 81 | if Config.WELCOME_DELETE_TIMEOUT: 82 | await message.edit( 83 | "`Welcome/Left messages will be deleted after " 84 | f"{Config.WELCOME_DELETE_TIMEOUT} seconds!`", 85 | del_in=5) 86 | else: 87 | await message.edit("`Auto welcome/left message deletion disabled!`", del_in=3) 88 | 89 | 90 | @userge.on_cmd("sapicto (\\d+)", about={ 91 | 'header': "Set auto profile picture timeout", 92 | 'usage': "{tr}sapicto [timeout in seconds]", 93 | 'examples': "{tr}sapicto 60"}) 94 | async def set_app_timeout(message: Message): 95 | """ set auto profile picture timeout """ 96 | t_o = int(message.matches[0].group(1)) 97 | if t_o < 15: 98 | await message.err("too short! (min = 15sec)") 99 | return 100 | await message.edit("`Setting auto profile picture timeout...`") 101 | Config.AUTOPIC_TIMEOUT = t_o 102 | await SAVED_SETTINGS.update_one( 103 | {'_id': 'AUTOPIC_TIMEOUT'}, {"$set": {'data': t_o}}, upsert=True) 104 | await message.edit( 105 | f"`Set auto profile picture timeout as {t_o} seconds!`", del_in=3) 106 | 107 | 108 | @userge.on_cmd("vapicto", about={'header': "View auto profile picture timeout"}) 109 | async def view_app_timeout(message: Message): 110 | """ view profile picture timeout """ 111 | await message.edit( 112 | f"`Profile picture will be updated after {Config.AUTOPIC_TIMEOUT} seconds!`", 113 | del_in=5) 114 | 115 | 116 | @userge.on_cmd("sesto (\\d+)", about={ 117 | 'header': "Set edit sleep timeout", 118 | 'usage': "{tr}sesto [timeout in seconds]", 119 | 'examples': "{tr}sesto 10"}) 120 | async def set_es_timeout(message: Message): 121 | """ set edit sleep timeout """ 122 | t_o = int(message.matches[0].group(1)) 123 | if t_o < 5: 124 | await message.err("too short! (min = 5sec)") 125 | return 126 | await message.edit("`Setting edit sleep timeout...`") 127 | Config.EDIT_SLEEP_TIMEOUT = t_o 128 | await SAVED_SETTINGS.update_one( 129 | {'_id': 'EDIT_SLEEP_TIMEOUT'}, {"$set": {'data': t_o}}, upsert=True) 130 | await message.edit( 131 | f"`Set edit sleep timeout as {t_o} seconds!`", del_in=3) 132 | 133 | 134 | @userge.on_cmd("vesto", about={'header': "View edit sleep timeout"}) 135 | async def view_es_timeout(message: Message): 136 | """ view edit sleep timeout """ 137 | await message.edit( 138 | f"`Current edit sleep timeout = {Config.EDIT_SLEEP_TIMEOUT} seconds!`", 139 | del_in=5) 140 | -------------------------------------------------------------------------------- /userge/core/methods/messages/send_message.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['SendMessage'] 12 | 13 | import asyncio 14 | import inspect 15 | from typing import Optional, Union, List 16 | 17 | from pyrogram.types import ( 18 | InlineKeyboardMarkup, ReplyKeyboardMarkup, 19 | ReplyKeyboardRemove, ForceReply, MessageEntity) 20 | 21 | from userge import Config 22 | from userge.utils import secure_text 23 | from ... import types 24 | from ...ext import RawClient 25 | 26 | 27 | class SendMessage(RawClient): # pylint: disable=missing-class-docstring 28 | async def send_message(self, # pylint: disable=arguments-differ 29 | chat_id: Union[int, str], 30 | text: str, 31 | del_in: int = -1, 32 | log: Union[bool, str] = False, 33 | parse_mode: Union[str, object] = object, 34 | entities: List[MessageEntity] = None, 35 | disable_web_page_preview: Optional[bool] = None, 36 | disable_notification: Optional[bool] = None, 37 | reply_to_message_id: Optional[int] = None, 38 | schedule_date: Optional[int] = None, 39 | protect_content: bool = None, 40 | reply_markup: Union[InlineKeyboardMarkup, 41 | ReplyKeyboardMarkup, 42 | ReplyKeyboardRemove, 43 | ForceReply] = None 44 | ) -> Union['types.bound.Message', bool]: 45 | """\nSend text messages. 46 | 47 | Example: 48 | @userge.send_message(chat_id=12345, text='test') 49 | 50 | Parameters: 51 | chat_id (``int`` | ``str``): 52 | Unique identifier (int) or username (str) of the target chat. 53 | For your personal cloud (Saved Messages) 54 | you can simply use "me" or "self". 55 | For a contact that exists in your Telegram address book 56 | you can use his phone number (str). 57 | 58 | text (``str``): 59 | Text of the message to be sent. 60 | 61 | del_in (``int``): 62 | Time in Seconds for delete that message. 63 | 64 | log (``bool`` | ``str``, *optional*): 65 | If ``True``, the message will be forwarded to the log channel. 66 | If ``str``, the logger name will be updated. 67 | 68 | parse_mode (``str``, *optional*): 69 | By default, texts are parsed using both Markdown and HTML styles. 70 | You can combine both syntaxes together. 71 | Pass "markdown" or "md" to enable Markdown-style parsing only. 72 | Pass "html" to enable HTML-style parsing only. 73 | Pass None to completely disable style parsing. 74 | 75 | entities (List of :obj:`~pyrogram.types.MessageEntity`): 76 | List of special entities that appear in message text, 77 | which can be specified instead of *parse_mode*. 78 | 79 | disable_web_page_preview (``bool``, *optional*): 80 | Disables link previews for links in this message. 81 | 82 | disable_notification (``bool``, *optional*): 83 | Sends the message silently. 84 | Users will receive a notification with no sound. 85 | 86 | reply_to_message_id (``int``, *optional*): 87 | If the message is a reply, ID of the original message. 88 | 89 | schedule_date (``int``, *optional*): 90 | Date when the message will be automatically sent. Unix time. 91 | 92 | protect_content (``bool``, *optional*): 93 | Protects the contents of the sent message from forwarding and saving. 94 | 95 | reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` 96 | | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): 97 | Additional interface options. An object for an inline keyboard, 98 | custom reply keyboard, instructions to remove 99 | reply keyboard or to force a reply from the user. 100 | 101 | Returns: 102 | :obj:`Message`: On success, the sent text message or True is returned. 103 | """ 104 | if text and chat_id not in Config.AUTH_CHATS: 105 | text = secure_text(str(text)) 106 | msg = await super().send_message(chat_id=chat_id, 107 | text=text, 108 | parse_mode=parse_mode, 109 | entities=entities, 110 | disable_web_page_preview=disable_web_page_preview, 111 | disable_notification=disable_notification, 112 | reply_to_message_id=reply_to_message_id, 113 | schedule_date=schedule_date, 114 | protect_content=protect_content, 115 | reply_markup=reply_markup) 116 | module = inspect.currentframe().f_back.f_globals['__name__'] 117 | if log: 118 | await self._channel.fwd_msg(msg, module if isinstance(log, bool) else log) 119 | del_in = del_in or Config.MSG_DELETE_TIMEOUT 120 | if del_in > 0: 121 | await asyncio.sleep(del_in) 122 | return bool(await msg.delete()) 123 | return types.bound.Message.parse(self, msg, module=module) 124 | -------------------------------------------------------------------------------- /userge/core/methods/decorators/on_filters.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | __all__ = ['OnFilters'] 12 | 13 | from pyrogram.filters import Filter as RawFilter 14 | 15 | from ... import types 16 | from . import RawDecorator 17 | 18 | 19 | class OnFilters(RawDecorator): # pylint: disable=missing-class-docstring 20 | def on_filters(self, # pylint: disable=arguments-differ 21 | filters: RawFilter, 22 | group: int = 0, 23 | allow_private: bool = True, 24 | allow_bots: bool = True, 25 | allow_groups: bool = True, 26 | allow_channels: bool = True, 27 | only_admins: bool = False, 28 | allow_via_bot: bool = True, 29 | check_client: bool = True, 30 | check_downpath: bool = False, 31 | stop_propagation: bool = False, 32 | continue_propagation: bool = False, 33 | check_change_info_perm: bool = False, 34 | check_edit_perm: bool = False, 35 | check_delete_perm: bool = False, 36 | check_restrict_perm: bool = False, 37 | check_promote_perm: bool = False, 38 | check_invite_perm: bool = False, 39 | check_pin_perm: bool = False) -> RawDecorator._PYRORETTYPE: 40 | """\nDecorator for handling filters 41 | 42 | Parameters: 43 | filters (:obj:`~pyrogram.filters`): 44 | Pass one or more filters to allow only a subset of 45 | messages to be passed in your function. 46 | 47 | group (``int``, *optional*): 48 | The group identifier, defaults to 0. 49 | 50 | allow_private (``bool``, *optional*): 51 | If ``False``, prohibit private chats, defaults to True. 52 | 53 | allow_bots (``bool``, *optional*): 54 | If ``False``, prohibit bot chats, defaults to True. 55 | 56 | allow_groups (``bool``, *optional*): 57 | If ``False``, prohibit group chats, defaults to True. 58 | 59 | allow_channels (``bool``, *optional*): 60 | If ``False``, prohibit channel chats, defaults to True. 61 | 62 | only_admins (``bool``, *optional*): 63 | If ``True``, client should be an admin, defaults to False. 64 | 65 | allow_via_bot (``bool``, *optional*): 66 | If ``True``, allow this via your bot, defaults to True. 67 | 68 | check_client (``bool``, *optional*): 69 | If ``True``, check client is bot or not before execute, defaults to True. 70 | 71 | check_downpath (``bool``, *optional*): 72 | If ``True``, check downpath and make if not exist, defaults to False. 73 | 74 | stop_propagation (``bool``, *optional*): 75 | If ``True``, stop propagation to other groups, defaults to False. 76 | 77 | continue_propagation (``bool``, *optional*): 78 | If ``True``, continue propagation in this group, defaults to False. 79 | 80 | check_change_info_perm (``bool``, *optional*): 81 | If ``True``, check user has change_info permission before execute, 82 | defaults to False. 83 | 84 | check_edit_perm (``bool``, *optional*): 85 | If ``True``, check user has edit permission before execute, 86 | defaults to False. 87 | 88 | check_delete_perm (``bool``, *optional*): 89 | If ``True``, check user has delete permission before execute, 90 | defaults to False. 91 | 92 | check_restrict_perm (``bool``, *optional*): 93 | If ``True``, check user has restrict permission before execute, 94 | defaults to False. 95 | 96 | check_promote_perm (``bool``, *optional*): 97 | If ``True``, check user has promote permission before execute, 98 | defaults to False. 99 | 100 | check_invite_perm (``bool``, *optional*): 101 | If ``True``, check user has invite permission before execute, 102 | defaults to False. 103 | 104 | check_pin_perm (``bool``, *optional*): 105 | If ``True``, check user has pin permission before execute, 106 | defaults to False. 107 | """ 108 | return self._build_decorator( 109 | types.raw.Filter.parse(client=self, 110 | filters=filters, 111 | group=group, 112 | allow_private=allow_private, 113 | allow_bots=allow_bots, 114 | allow_groups=allow_groups, 115 | allow_channels=allow_channels, 116 | only_admins=only_admins, 117 | allow_via_bot=allow_via_bot, 118 | check_client=check_client, 119 | check_downpath=check_downpath, 120 | stop_propagation=stop_propagation, 121 | continue_propagation=continue_propagation, 122 | check_change_info_perm=check_change_info_perm, 123 | check_edit_perm=check_edit_perm, 124 | check_delete_perm=check_delete_perm, 125 | check_restrict_perm=check_restrict_perm, 126 | check_promote_perm=check_promote_perm, 127 | check_invite_perm=check_invite_perm, 128 | check_pin_perm=check_pin_perm)) 129 | -------------------------------------------------------------------------------- /init/checks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2020-2022 by UsergeTeam@Github, < https://github.com/UsergeTeam >. 4 | # 5 | # This file is part of < https://github.com/UsergeTeam/Userge > project, 6 | # and is released under the "GNU v3.0 License Agreement". 7 | # Please see < https://github.com/UsergeTeam/Userge/blob/master/LICENSE > 8 | # 9 | # All rights reserved. 10 | 11 | _checkBashReq() { 12 | log "Checking Bash Commands ..." 13 | command -v jq &> /dev/null || quit "Required command : jq : could not be found !" 14 | } 15 | 16 | _checkPythonVersion() { 17 | log "Checking Python Version ..." 18 | getPythonVersion 19 | ( test -z $pVer || test $(sed 's/\.//g' <<< $pVer) -lt 3${minPVer}0 ) \ 20 | && quit "You MUST have a python version of at least 3.$minPVer.0 !" 21 | log "\tFound PYTHON - v$pVer ..." 22 | } 23 | 24 | _checkConfigFile() { 25 | log "Checking Config File ..." 26 | configPath="config.env" 27 | if test -f $configPath; then 28 | log "\tConfig file found : $configPath, Exporting ..." 29 | set -a 30 | . $configPath 31 | set +a 32 | test ${_____REMOVE_____THIS_____LINE_____:-fasle} = true \ 33 | && quit "Please remove the line mentioned in the first hashtag from the config.env file" 34 | fi 35 | } 36 | 37 | _checkRequiredVars() { 38 | log "Checking Required ENV Vars ..." 39 | for var in API_ID API_HASH LOG_CHANNEL_ID DATABASE_URL; do 40 | test -z ${!var} && quit "Required $var var !" 41 | done 42 | [[ -z $HU_STRING_SESSION && -z $BOT_TOKEN ]] && quit "Required HU_STRING_SESSION or BOT_TOKEN var !" 43 | [[ -n $BOT_TOKEN && -z $OWNER_ID ]] && quit "Required OWNER_ID var !" 44 | test -z $BOT_TOKEN && log "\t[HINT] >>> BOT_TOKEN not found ! (Disabling Advanced Loggings)" 45 | } 46 | 47 | _checkDefaultVars() { 48 | replyLastMessage "Checking Default ENV Vars ..." 49 | declare -rA def_vals=( 50 | [WORKERS]=0 51 | [PREFERRED_LANGUAGE]="en" 52 | [DOWN_PATH]="downloads" 53 | [UPSTREAM_REMOTE]="upstream" 54 | [UPSTREAM_REPO]="https://github.com/UsergeTeam/Userge" 55 | [LOAD_UNOFFICIAL_PLUGINS]=false 56 | [ASSERT_SINGLE_INSTANCE]=false 57 | [CUSTOM_PIP_PACKAGES]="" 58 | [CUSTOM_PLUGINS_REPO]="" 59 | [G_DRIVE_IS_TD]=true 60 | [CMD_TRIGGER]="." 61 | [SUDO_TRIGGER]="!" 62 | [FINISHED_PROGRESS_STR]="█" 63 | [UNFINISHED_PROGRESS_STR]="░" 64 | ) 65 | for key in ${!def_vals[@]}; do 66 | set -a 67 | test -z ${!key} && eval $key=${def_vals[$key]} 68 | set +a 69 | done 70 | if test $WORKERS -le 0; then 71 | WORKERS=$(($(nproc)+4)) 72 | elif test $WORKERS -gt 32; then 73 | WORKERS=32 74 | fi 75 | export MOTOR_MAX_WORKERS=$WORKERS 76 | export HEROKU_ENV=$(test $DYNO && echo 1 || echo 0) 77 | DOWN_PATH=${DOWN_PATH%/}/ 78 | if [[ $HEROKU_ENV == 1 && -n $HEROKU_API_KEY && -n $HEROKU_APP_NAME ]]; then 79 | local herokuErr=$(runPythonCode ' 80 | import heroku3 81 | try: 82 | if "'$HEROKU_APP_NAME'" not in heroku3.from_key("'$HEROKU_API_KEY'").apps(): 83 | raise Exception("Invalid HEROKU_APP_NAME \"'$HEROKU_APP_NAME'\"") 84 | except Exception as e: 85 | print(e)') 86 | [[ $herokuErr ]] && quit "heroku response > $herokuErr" 87 | fi 88 | for var in G_DRIVE_IS_TD LOAD_UNOFFICIAL_PLUGINS ASSERT_SINGLE_INSTANCE; do 89 | eval $var=$(tr "[:upper:]" "[:lower:]" <<< ${!var}) 90 | done 91 | local uNameAndPass=$(grep -oP "(?<=\/\/)(.+)(?=\@cluster)" <<< $DATABASE_URL) 92 | local parsedUNameAndPass=$(runPythonCode ' 93 | from urllib.parse import quote_plus 94 | print(quote_plus("'$uNameAndPass'"))') 95 | DATABASE_URL=$(sed 's/$uNameAndPass/$parsedUNameAndPass/' <<< $DATABASE_URL) 96 | } 97 | 98 | _checkDatabase() { 99 | editLastMessage "Checking DATABASE_URL ..." 100 | local mongoErr=$(runPythonCode ' 101 | import pymongo 102 | try: 103 | pymongo.MongoClient("'$DATABASE_URL'").list_database_names() 104 | except Exception as e: 105 | print(e)') 106 | [[ $mongoErr ]] && quit "pymongo response > $mongoErr" || log "\tpymongo response > {status : 200}" 107 | } 108 | 109 | _checkTriggers() { 110 | editLastMessage "Checking TRIGGERS ..." 111 | test $CMD_TRIGGER = $SUDO_TRIGGER \ 112 | && quit "Invalid SUDO_TRIGGER!, You can't use $CMD_TRIGGER as SUDO_TRIGGER" 113 | } 114 | 115 | _checkPaths() { 116 | editLastMessage "Checking Paths ..." 117 | for path in $DOWN_PATH logs bin; do 118 | test ! -d $path && { 119 | log "\tCreating Path : ${path%/} ..." 120 | mkdir -p $path 121 | } 122 | done 123 | } 124 | 125 | _checkBins() { 126 | editLastMessage "Checking BINS ..." 127 | declare -rA bins=( 128 | [bin/megadown]="https://raw.githubusercontent.com/yshalsager/megadown/master/megadown" 129 | [bin/cmrudl]="https://raw.githubusercontent.com/yshalsager/cmrudl.py/master/cmrudl.py" 130 | ) 131 | for bin in ${!bins[@]}; do 132 | test ! -f $bin && { 133 | log "\tDownloading $bin ..." 134 | curl -so $bin ${bins[$bin]} 135 | } 136 | done 137 | } 138 | 139 | _checkUpstreamRepo() { 140 | remoteIsExist $UPSTREAM_REMOTE || addUpstream 141 | editLastMessage "Fetching Data From UPSTREAM_REPO ..." 142 | fetchUpstream || updateUpstream && fetchUpstream || quit "Invalid UPSTREAM_REPO var !" 143 | fetchBranches 144 | updateBuffer 145 | } 146 | 147 | _setupPlugins() { 148 | local link path tmp 149 | if test $(grep -P '^'$2'$' <<< $3); then 150 | editLastMessage "Cloning $1 Plugins ..." 151 | link=$(test $4 && echo $4 || echo $3) 152 | tmp=Temp-Plugins 153 | gitClone --depth=1 $link $tmp 154 | replyLastMessage "\tInstalling Requirements ..." 155 | upgradePip 156 | installReq $tmp 157 | path=$(tr "[:upper:]" "[:lower:]" <<< $1) 158 | rm -rf userge/plugins/$path/ 159 | mv $tmp/plugins/ userge/plugins/$path/ 160 | cp -r $tmp/resources/. resources/ 161 | rm -rf $tmp/ 162 | deleteLastMessage 163 | else 164 | editLastMessage "$1 Plugins Disabled !" 165 | fi 166 | } 167 | 168 | _checkUnoffPlugins() { 169 | _setupPlugins UnOfficial true $LOAD_UNOFFICIAL_PLUGINS https://github.com/UsergeTeam/Userge-Plugins.git 170 | } 171 | 172 | _checkCustomPlugins() { 173 | _setupPlugins Custom "https://(ghp_[0-9A-z]{36}@)?github.com/.+/.+" $CUSTOM_PLUGINS_REPO 174 | } 175 | 176 | _checkPipPackages() { 177 | editLastMessage "Checking Custom Pip Packages ..." 178 | if [[ $CUSTOM_PIP_PACKAGES ]]; then 179 | log "\tFound and Installing ..." 180 | upgradePip 181 | installCustomReq "$CUSTOM_PIP_PACKAGES" 182 | fi 183 | } 184 | 185 | _flushMessages() { 186 | deleteLastMessage 187 | } 188 | 189 | assertPrerequisites() { 190 | _checkBashReq 191 | _checkPythonVersion 192 | _checkConfigFile 193 | _checkRequiredVars 194 | } 195 | 196 | assertEnvironment() { 197 | _checkDefaultVars 198 | _checkDatabase 199 | _checkTriggers 200 | _checkPaths 201 | _checkBins 202 | _checkUpstreamRepo 203 | _checkUnoffPlugins 204 | _checkCustomPlugins 205 | _checkPipPackages 206 | _flushMessages 207 | } 208 | --------------------------------------------------------------------------------