├── 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 |
4 |
5 |
6 | Pluggable Telegram UserBot
7 |
8 | Inspiration
9 |  • 
10 | Documentation
11 |  • 
12 | Deployment
13 |  • 
14 | Project Credits
15 |  • 
16 | Copyright & License
17 |
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", "" + 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"