diff --git a/.gitignore b/.gitignore index ebf5822cbc..9544f7296c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,25 @@ __pycache__ *.session *.session-journal +*.DB +*.DB-journal + data/ -config.py +config.env sessions/ +*.jpg +*.mp4 +*.pyc +*.txt + +Manjari* + +stdplugins/auto_destruct_read_messages.py +stdplugins/cheat_tg.py +stdplugins/deleted_messages_watcher.py +stdplugins/quotlybot.py +stdplugins/tb_button.py +stdplugins/auto_pp*.py +stdplugins/ban_channels*.py +stdplugins/annoy_mention_796.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..a352bea01e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +# creates a layer from the base Docker image. +FROM python:3.9-slim-buster + +WORKDIR /app + +# https://shouldiblamecaching.com/ +ENV PIP_NO_CACHE_DIR 1 + +# fix "ephimeral" / "AWS" file-systems +RUN sed -i.bak 's/us-west-2\.ec2\.//' /etc/apt/sources.list + +# to resynchronize the package index files from their sources. +RUN apt -qq update + +# base required pre-requisites before proceeding ... +RUN apt -qq install -y --no-install-recommends \ + curl \ + git \ + gnupg2 \ + unzip \ + wget + +# to resynchronize the package index files from their sources. +RUN apt -qq update + +# http://bugs.python.org/issue19846 +# https://github.com/SpEcHiDe/PublicLeech/pull/97 +ENV LANG C.UTF-8 + +# we don't have an interactive xTerm +ENV DEBIAN_FRONTEND noninteractive + +# install google chrome +RUN mkdir -p /tmp/ && \ + cd /tmp/ && \ + wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \ + # -f ==> is required to --fix-missing-dependancies + dpkg -i ./google-chrome-stable_current_amd64.deb; apt -fqqy install && \ + # clean up the container "layer", after we are done + rm ./google-chrome-stable_current_amd64.deb + +# install chromedriver +RUN mkdir -p /tmp/ && \ + cd /tmp/ && \ + wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/$(curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE)/chromedriver_linux64.zip && \ + unzip /tmp/chromedriver.zip chromedriver -d /usr/bin/ && \ + # clean up the container "layer", after we are done + rm /tmp/chromedriver.zip + +# install required packages +RUN apt -qq install -y --no-install-recommends \ + # this package is required to fetch "contents" via "TLS" + apt-transport-https \ + # install coreutils + build-essential coreutils jq pv \ + # install gcc [ PEP 517 ] + gcc \ + # install encoding tools + ffmpeg mediainfo \ + unzip zip \ + # miscellaneous helpers + megatools && \ + # clean up the container "layer", after we are done + rm -rf /var/lib/apt/lists /var/cache/apt/archives /tmp + +# each instruction creates one layer +# Only the instructions RUN, COPY, ADD create layers. +# copies 'requirements', to inside the container +# ..., there are multiple '' dependancies, +# requiring the use of the entire repo, hence +# adds files from your Docker client’s current directory. +COPY . . + +# install requirements, inside the container +RUN pip3 install --no-cache-dir -r requirements.txt + +# specifies what command to run within the container. +CMD ["python3", "-m", "kopp"] diff --git a/GenerateStringSession.py b/GenerateStringSession.py deleted file mode 100644 index 4603ac6a77..0000000000 --- a/GenerateStringSession.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 -# (c) https://t.me/TelethonChat/37677 -# This Source Code Form is subject to the terms of the GNU -# General Public License, v.3.0. If a copy of the GPL was not distributed with this -# file, You can obtain one at https://www.gnu.org/licenses/gpl-3.0.en.html. - -from telethon.sync import TelegramClient -from telethon.sessions import StringSession - -print("""Please go-to my.telegram.org -Login using your Telegram account -Click on API Development Tools -Create a new application, by entering the required details""") -APP_ID = int(input("Enter APP ID here: ")) -API_HASH = input("Enter API HASH here: ") - -with TelegramClient(StringSession(), APP_ID, API_HASH) as client: - print(client.session.save()) diff --git a/Procfile b/Procfile index 257f0f07b4..184c805c9b 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -worker: python3 -m stdborg +worker: python3 -m kopp diff --git a/README.md b/README.md index fc645e6ced..556d2bf13f 100644 --- a/README.md +++ b/README.md @@ -4,57 +4,58 @@ Pluggable [``asyncio``](https://docs.python.org/3/library/asyncio.html) [Telegram](https://telegram.org) userbot based on [Telethon](https://github.com/LonamiWebs/Telethon). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Mozilla Public License for more details. + + +## disclaimer + +⚠️ This fork uses "requests" module in various places, instead of the async alternative. ⚠️ + +- This was an attempt to learn userbot development using Telethon, __this project is now no longer usable__, and is FORKed and MODIFied to suit MY needs, so **use at your own risk**. + + ## installing -#### The Easy Way +#### The Easiest Way -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) +- Install Docker by following the [official docker docs](https://docs.docker.com/engine/install/debian/) + +- Start docker daemon [skip if already running]: +```sh +dockerd +``` +- Build Docker image: +```sh +docker build . -t uniborg +``` +- Run the image: +```sh +docker run uniborg +``` + +It is not recommended to use "sudo", while using Docker. +GNU/Linux Permissions are highly customisable, and it is generally not required to have "ROOT" permission, ~~unless you know what you are doing~~. +You can still install all the dependencies in your system [with ROOT permissions], +but please be aware of the potential issues when doing so. The installed packages +may conflict with the system package manager's installed packages, which can +cause trouble down the road and errors when upgrading conflicting packages. +**You have been warned.** #### The Legacy Way Simply clone the repository and run the main file: ```sh git clone https://github.com/udf/uniborg.git cd uniborg -virtualenv -p /usr/bin/python3 venv +python3 -m venv venv . ./venv/bin/activate pip install -r requirements.txt -# -python3 -m stdborg YourSessionName -``` - -An example `config.py` file could be: - -**Not All of the variables are mandatory** - -__The UniBorg should work by setting only these variables__ - -```python3 -from sample_config import Config - -class Development(Config): - APP_ID = 6 - API_HASH = "eb06d4abfb49dc3eeb1aeb98ae0f581e" - TG_BOT_TOKEN_BF_HER = "" - TG_BOT_USER_NAME_BF_HER = "" - UB_BLACK_LIST_CHAT = [ - -1001220993104, - -1001365798550, - -1001158304289, - -1001212593743, - -1001195845680, - -1001330468518, - -1001221185967, - -1001340243678, - -1001311056733, - -1001135438308, - -1001038774929, - -1001070622614, - -1001119331451, - -1001095401841 - ] - # specify LOAD and NO_LOAD - LOAD = [] - NO_LOAD = [] +cp sample_config.env config.env +# +python3 -m kopp ``` ## internals @@ -63,15 +64,15 @@ The core features offered by the custom `TelegramClient` live under the [`uniborg/`](https://github.com/SpEcHiDe/uniborg/tree/master/uniborg) directory, with some utilities, enhancements, the `_core` plugin, and the `_inline_bot` plugin. - -## [@SpEcHlDe](https://telegram.dog/ThankTelegram) - -- Only two of the environment variables are mandatory. -- This is because of `telethon.errors.rpc_error_list.ApiIdPublishedFloodError` - - `APP_ID`: You can get this value from https://my.telegram.org - - `API_HASH`: You can get this value from https://my.telegram.org -- The userbot will work without setting the non-mandatory environment variables. -- Please report any issues to the support group: [@SpEcHlDe](https://t.me/joinchat/AHAujEjG4FBO-TH-NrVVbg) +- Only five of the environment variables are mandatory. +- Please read the [WiKi](https://github.com/SpEcHiDe/UniBorg/wiki) to understand the use of the variables. +- This is because of `telethon.errors.ApiIdPublishedFloodError` + - `APP_ID`: + - `API_HASH`: + - `TG_BOT_TOKEN_BF_HER`: + - `TG_BOT_USER_NAME_BF_HER`: + - `DATABASE_URL`: +- The userbot should work without setting the non-mandatory environment variables. ## design @@ -80,25 +81,25 @@ The modular design of the project enhances your Telegram experience through [plugins](https://github.com/SpEcHiDe/uniborg/tree/master/stdplugins) which you can enable or disable on demand. -Each plugin gets the `borg`, `logger`, `Config`, `tgbot` magical +Each plugin gets the `borg`, `logger`, `Config` magical [variables](https://github.com/spechide/UniBorg/blob/488eff632e65103ba7017d4f52777d22ddd52ea2/uniborg/uniborg.py#L76-L80) to ease their use. Thus creating a plugin as easy as adding a new file under the plugin directory to do the job: ```python # stdplugins/myplugin.py -from telethon import events -from uniborg.util import admin_cmd - -@borg.on(admin_cmd(pattern="hi")) +@borg.on(slitu.admin_cmd(pattern="hi")) async def handler(event): - await event.reply("hey") + await event.client.send_message( + event.chat_id, + "hey" + ) ``` ## learning -Check out the already-mentioned [plugins](https://github.com/SpEcHiDe/UniBorg/tree/master/stdplugins) directory, or some third-party [plugins](https://telegram.dog/UniBorg) to learn how to write your own, and consider reading [Telethon's documentation](http://telethon.readthedocs.io/). +Check out the already-mentioned [plugins](https://github.com/SpEcHiDe/UniBorg/tree/master/stdplugins) directory, or some third-party [plugins](https://telegram.dog/UniBorg) to learn how to write your own, and consider reading [Telethon's documentation](http://docs.telethon.dev/). ## credits @@ -107,4 +108,3 @@ Check out the already-mentioned [plugins](https://github.com/SpEcHiDe/UniBorg/tr Thanks to: - [lonami](https://lonami.dev) for creating [Telethon](https://github.com/lonamiwebs/Telethon) - [![CopyLeft](https://telegra.ph/file/b514ed14d994557a724cb.jpg)](https://telegra.ph/file/fab1017e21c42a5c1e613.mp4 "CopyLeft Credit Video") - diff --git a/app.json b/app.json index 976ccda075..0b9fa8e8b8 100644 --- a/app.json +++ b/app.json @@ -25,85 +25,20 @@ "description": "Get this value from my.telegram.org! Please do not steal", "value": "" }, - "HU_STRING_SESSION": { - "description": "Get this value by running python3 GenerateStringSession.py locally", - "value": "" - }, - "OPEN_WEATHER_MAP_APPID": { - "description": "Get your own APPID from https://api.openweathermap.org/data/2.5/weather", - "required": false - }, - "PRIVATE_GROUP_BOT_API_ID": { - "description": "Send .get_id in any group to fill this value.", - "value": "-100", - "required": false - }, - "PRIVATE_CHANNEL_BOT_API_ID": { - "description": "Send .get_id in any channel to fill this value. ReQuired for @Manuel15 inspiration to work!", - "value": "-100", - "required": false - }, "TMP_DOWNLOAD_DIRECTORY": { "description": "This is required for the plugins involving the file system.", "value": "./DOWNLOADS/", "required": false }, - "IBM_WATSON_CRED_URL": { - "description": "This is required for the speech to text module. Get your USERNAME from https://console.bluemix.net/docs/services/speech-to-text/getting-started.html", - "required": false - }, - "IBM_WATSON_CRED_PASSWORD": { - "description": "This is required for the speech to text module. Get your PASSWORD from https://console.bluemix.net/docs/services/speech-to-text/getting-started.html", - "required": false - }, - "HASH_TO_TORRENT_API": { - "description": "This is required for the hash to torrent file functionality to work.", - "value": "https://example.com/torrent/{}", - "required": false - }, - "TELEGRAPH_SHORT_NAME": { - "description": "This is required for the @telegraph functionality.", - "value": "UniBorg", - "required": false - }, - "OCR_SPACE_API_KEY": { - "description": "Get an API Key from http://OCR.Space", - "required": false - }, - "G_BAN_LOGGER_GROUP": { - "description": "Send .get_id in any group with all your administration bots (added)", - "value": "-100", - "required": false - }, - "TG_GLOBAL_ALBUM_LIMIT": { - "description": "How many media should appear when you do a .google image search? (setting a low value is preferred)", - "value": "9", - "required": false - }, "TG_BOT_TOKEN_BF_HER": { - "description": "Obtain a Telegram bot token by contacting @BotFather", - "required": false + "description": "Obtain a Telegram bot token by contacting @BotFather" }, "TG_BOT_USER_NAME_BF_HER": { - "description": "Obtain a Telegram bot @username by contacting @BotFather", - "required": false - }, - "REM_BG_API_KEY": { - "description": "Get your own API key from https://www.remove.bg/ or feel free to use http://telegram.dog/Remove_BGBot", - "required": false - }, - "NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD": { - "description": "Number of rows of modules that needs to be displayed in the .helpme command", - "required": false - }, - "COMMAND_HAND_LER": { - "description": "specify command handler that should be used for the plugins. This should be a valid \"regex\" pattern", - "required": false + "description": "Obtain a Telegram bot @username by contacting @BotFather. Do not enter '@' symbol, while entering this value" }, "SUDO_USERS": { "description": "List down the user IDs who should have permission to use you. Be Careful. You are granting access to your entire account to the people you mention in the below field, seperated by SPACE. Send .get_id in any private chat or as a reply to any user in any group, to fill this value", - "value": "7351948 500346573 606342588 653184647 751003349 752396210 797179106 804216742 830068297 873236756", - "required": false + "value": "7351948 500346573 606342588 653184647 751003349 752396210 797179106 804216742 830068297 873236756" }, "UB_BLACK_LIST_CHAT": { "description": "set blacklist_chats where you do not want userbot features", @@ -112,50 +47,22 @@ }, "TZ": { "description": "set your default time zone for time related features to work correctly. Value should match the string here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones", - "required": false - }, - "VERY_STREAM_LOGIN": { - "description": "Get your API key from https://verystream.com", - "required": false - }, - "VERY_STREAM_KEY": { - "description": "Get your API key from https://verystream.com", - "required": false - }, - "G_DRIVE_CLIENT_ID": { - "description": "Get your credentials from https://da.gd/so63O", - "required": false - }, - "G_DRIVE_CLIENT_SECRET": { - "description": "Get your credentials from https://da.gd/so63O", - "required": false - }, - "TELE_GRAM_2FA_CODE": { - "description": "Your Telegram 2FA code as a string", - "required": false - }, - "MAX_FLOOD_IN_P_M_s": { - "description": "define the number of messages that should be considered as 'spam' in PMs", + "value": "Asia/Kolkata", "required": false } }, "addons": [{ "plan": "heroku-postgresql", "options": { - "version": "9.5" + "version": "12" } }], - "buildpacks": [{ - "url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest" - }, { - "url": "https://github.com/opendoor-labs/heroku-buildpack-p7zip" - }, { - "url": "https://github.com/heroku/heroku-buildpack-google-chrome" - }, { - "url": "https://github.com/heroku/heroku-buildpack-chromedriver" - }, { - "url": "https://github.com/amivin/aria2-heroku" - }, { - "url": "heroku/python" - }] + "buildpacks": [], + "stack": "container", + "formation": { + "worker": { + "quantity": 1, + "size": "free" + } + } } diff --git a/dbplugins/antiflood.py b/dbplugins/antiflood.py index 4b727ec5b6..9c9840156e 100644 --- a/dbplugins/antiflood.py +++ b/dbplugins/antiflood.py @@ -2,7 +2,6 @@ from telethon import events from telethon.tl.functions.channels import EditBannedRequest from telethon.tl.types import ChatBannedRights -from uniborg.util import admin_cmd, is_admin import sql_helpers.antiflood_sql as sql @@ -15,32 +14,36 @@ ) -@borg.on(admin_cmd(incoming=True)) +@borg.on(slitu.admin_cmd(incoming=True)) async def _(event): # logger.info(CHAT_FLOOD) if not CHAT_FLOOD: return - admin_c = await is_admin(event.client, event.chat_id, event.message.from_id) + admin_c = await slitu.is_admin(event.client, event.chat_id, event.message.sender_id) if admin_c: return - if not (str(event.chat_id) in CHAT_FLOOD): + if str(event.chat_id) not in CHAT_FLOOD: return - should_ban = sql.update_flood(event.chat_id, event.message.from_id) + should_ban = sql.update_flood(event.chat_id, event.message.sender_id) if not should_ban: return try: await event.client(EditBannedRequest( event.chat_id, - event.message.from_id, + event.message.sender_id, ANTI_FLOOD_WARN_MODE )) except Exception as e: # pylint:disable=C0103,W0703 no_admin_privilege_message = await event.client.send_message( entity=event.chat_id, - message="""**Automatic AntiFlooder** -@admin [User](tg://user?id={}) is flooding this chat. - -`{}`""".format(event.message.from_id, str(e)), + message=( + "**Automatic AntiFlooder**\n" + "@admin [User](tg://user?id={}) is flooding this chat.\n\n" + "`{}`".format( + event.message.sender_id, + str(e) + ) + ), reply_to=event.message.id ) await asyncio.sleep(10) @@ -51,14 +54,18 @@ async def _(event): else: await event.client.send_message( entity=event.chat_id, - message="""**Automatic AntiFlooder** -[User](tg://user?id={}) has been automatically restricted -because he reached the defined flood limit.""".format(event.message.from_id), + message=( + "**Automatic AntiFlooder**\n" + "[User](tg://user?id={}) has been automatically restricted\n" + "because he reached the defined flood limit.".format( + event.message.sender_id + ) + ), reply_to=event.message.id ) -@borg.on(admin_cmd(pattern="setflood (.*)")) +@borg.on(slitu.admin_cmd(pattern="setflood (.*)")) async def _(event): if event.fwd_from: return diff --git a/dbplugins/blacklist.py b/dbplugins/blacklist.py index 3b755ec4dd..84c5597e40 100644 --- a/dbplugins/blacklist.py +++ b/dbplugins/blacklist.py @@ -10,16 +10,15 @@ import io import re import sql_helpers.blacklist_sql as sql -from telethon import events, utils +from telethon import events from telethon.tl import types, functions -from uniborg.util import admin_cmd, is_admin -@borg.on(admin_cmd(incoming=True)) +@borg.on(slitu.admin_cmd(incoming=True)) async def on_new_message(event): - if await is_admin(event.client, event.chat_id, event.from_id): + if await slitu.is_admin(event.client, event.chat_id, event.sender_id): return - if borg.me.id == event.from_id: + if borg.me.id == event.sender_id: return name = event.raw_text snips = sql.get_chat_blacklist(event.chat_id) @@ -34,16 +33,18 @@ async def on_new_message(event): break -@borg.on(admin_cmd(pattern="addblacklist ((.|\n)*)")) +@borg.on(slitu.admin_cmd(pattern="addblacklist ((.|\n)*)")) async def on_add_black_list(event): text = event.pattern_match.group(1) - to_blacklist = list(set(trigger.strip() for trigger in text.split("\n") if trigger.strip())) + to_blacklist = list( + {trigger.strip() for trigger in text.split("\n") if trigger.strip()} + ) for trigger in to_blacklist: sql.add_to_blacklist(event.chat_id, trigger.lower()) await event.edit("Added {} triggers to the blacklist in the current chat".format(len(to_blacklist))) -@borg.on(admin_cmd(pattern="listblacklist")) +@borg.on(slitu.admin_cmd(pattern="listblacklist")) async def on_view_blacklist(event): all_blacklisted = sql.get_chat_blacklist(event.chat_id) OUT_STR = "Blacklists in the Current Chat:\n" @@ -68,10 +69,12 @@ async def on_view_blacklist(event): await event.edit(OUT_STR) -@borg.on(admin_cmd(pattern="rmblacklist ((.|\n)*)")) +@borg.on(slitu.admin_cmd(pattern="rmblacklist ((.|\n)*)")) async def on_delete_blacklist(event): text = event.pattern_match.group(1) - to_unblacklist = list(set(trigger.strip() for trigger in text.split("\n") if trigger.strip())) + to_unblacklist = list( + {trigger.strip() for trigger in text.split("\n") if trigger.strip()} + ) successful = 0 for trigger in to_unblacklist: if sql.rm_from_blacklist(event.chat_id, trigger.lower()): diff --git a/dbplugins/f_notification_p.py b/dbplugins/f_notification_p.py new file mode 100644 index 0000000000..d76dbd49e6 --- /dev/null +++ b/dbplugins/f_notification_p.py @@ -0,0 +1,79 @@ +# (c) Shrimadhav U K +# +# This file is part of @UniBorg +# +# @UniBorg is free software; you cannot redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# @UniBorg is not distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +"""-_- +""" +from telethon import events, custom +from telethon.tl.types import ( + Channel, + Chat, + User +) +from telethon.utils import get_display_name + + +@borg.on(events.NewMessage( + incoming=True, + blacklist_chats=Config.UB_BLACK_LIST_CHAT, + func=lambda e: ( + e.mentioned or e.is_private + ) +)) +async def all_messages_catcher(event): + # construct message + # the message format is stolen from @MasterTagAlertBot + ammoca_message = "" + + who_ = await event.client.get_entity(event.sender_id) + if ( + who_.bot or + who_.verified or + who_.support + ): + return + + # the bot might not have the required access_hash to mention the appropriate PM + await ( + await event.forward_to( + Config.TG_BOT_USER_NAME_BF_HER + ) + ).delete() + + who_m = f"[{get_display_name(who_)}](tg://user?id={who_.id})" + + where_ = await event.client.get_entity(event.chat_id) + + where_m = get_display_name(where_) + button_text = "📃 ആ മെസ്സേജിലേക്കു പോകുക " + + if isinstance(where_, Channel): + message_link = f"https://t.me/c/{where_.id}/{event.id}" + else: + # not an official link, + # only works in DrKLO/Telegram, + # for some reason + message_link = f"tg://openmessage?chat_id={where_.id}&message_id={event.id}" + # Telegram is weird :\ + + ammoca_message += f"{who_m} നിങ്ങളെ [{where_m}]({message_link}) ൽ ടാഗ് ചെയ്തു" + + await borg.tgbot.send_message( + entity=Config.PRIVATE_CHANNEL_BOT_API_ID, + message=ammoca_message, + link_preview=False, + buttons=[ + [custom.Button.url(button_text, message_link)] + ], + silent=True + ) diff --git a/dbplugins/filters.py b/dbplugins/filters.py index 0032f295cf..717165391f 100644 --- a/dbplugins/filters.py +++ b/dbplugins/filters.py @@ -8,24 +8,31 @@ .clearfilter""" import asyncio import re -from telethon import events, utils +from telethon import events from telethon.tl import types -from sql_helpers.filters_sql import get_filter, add_filter, remove_filter, get_all_filters, remove_all_filters -from uniborg.util import admin_cmd +from sql_helpers.filters_sql import ( + get_filter, + add_filter, + remove_filter, + get_all_filters, + remove_all_filters +) DELETE_TIMEOUT = 300 last_triggered_filters = {} -@borg.on(admin_cmd(incoming=True)) +@borg.on(slitu.admin_cmd(incoming=True)) async def on_snip(event): name = event.raw_text - if event.chat_id in last_triggered_filters: - if name in last_triggered_filters[event.chat_id]: - # avoid userbot spam - # "I demand rights for us bots, we are equal to you humans." -Henri Koivuneva (t.me/UserbotTesting/2698) - return False + if ( + event.chat_id in last_triggered_filters + and name in last_triggered_filters[event.chat_id] + ): + # avoid userbot spam + # "I demand rights for us bots, we are equal to you humans." -Henri Koivuneva (t.me/UserbotTesting/2698) + return False snips = get_all_filters(event.chat_id) if snips: for snip in snips: @@ -51,7 +58,7 @@ async def on_snip(event): last_triggered_filters[event.chat_id].remove(name) -@borg.on(admin_cmd(pattern="savefilter (.*)")) +@borg.on(slitu.admin_cmd(pattern="savefilter (.*)")) async def on_snip_save(event): name = event.pattern_match.group(1) msg = await event.get_reply_message() @@ -68,7 +75,7 @@ async def on_snip_save(event): await event.edit("Reply to a message with `savefilter keyword` to save the filter") -@borg.on(admin_cmd(pattern="listfilters")) +@borg.on(slitu.admin_cmd(pattern="listfilters")) async def on_snip_list(event): all_snips = get_all_filters(event.chat_id) OUT_STR = "Available Filters in the Current Chat:\n" @@ -93,14 +100,14 @@ async def on_snip_list(event): await event.edit(OUT_STR) -@borg.on(admin_cmd(pattern="clearfilter (.*)")) +@borg.on(slitu.admin_cmd(pattern="clearfilter (.*)")) async def on_snip_delete(event): name = event.pattern_match.group(1) remove_filter(event.chat_id, name) await event.edit(f"filter {name} deleted successfully") -@borg.on(admin_cmd(pattern="clearallfilters")) +@borg.on(slitu.admin_cmd(pattern="clearallfilters")) async def on_all_snip_delete(event): remove_all_filters(event.chat_id) await event.edit(f"filters **in current chat** deleted successfully") diff --git a/dbplugins/locks.py b/dbplugins/locks.py index 95c8941fd1..074514b9e9 100644 --- a/dbplugins/locks.py +++ b/dbplugins/locks.py @@ -4,10 +4,9 @@ DB Options: bots, commands, email, forward, url""" from telethon import events, functions, types -from uniborg.util import admin_cmd, is_admin -@borg.on(admin_cmd(pattern="lock( (?P\S+)|$)")) +@borg.on(slitu.admin_cmd(pattern="lock( (?P\S+)|$)")) async def _(event): # Space weirdness in regex required because argument is optional and other # commands start with ".lock" @@ -87,7 +86,7 @@ async def _(event): ) -@borg.on(admin_cmd(pattern="unlock ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="unlock ?(.*)")) async def _(event): if event.fwd_from: return @@ -110,7 +109,7 @@ async def _(event): ) -@borg.on(admin_cmd(pattern="curenabledlocks")) +@borg.on(slitu.admin_cmd(pattern="curenabledlocks")) async def _(event): if event.fwd_from: return @@ -160,7 +159,7 @@ async def check_incoming_messages(event): logger.info("DB_URI is not configured.") logger.info(str(e)) return False - if await is_admin(event.client, event.chat_id, event.from_id): + if await slitu.is_admin(event.client, event.chat_id, event.sender_id): return peer_id = event.chat_id if is_locked(peer_id, "commands"): @@ -178,15 +177,14 @@ async def check_incoming_messages(event): "I don't seem to have ADMIN permission here. \n`{}`".format(str(e)) ) update_lock(peer_id, "commands", False) - if is_locked(peer_id, "forward"): - if event.fwd_from: - try: - await event.delete() - except Exception as e: - await event.reply( - "I don't seem to have ADMIN permission here. \n`{}`".format(str(e)) - ) - update_lock(peer_id, "forward", False) + if is_locked(peer_id, "forward") and event.fwd_from: + try: + await event.delete() + except Exception as e: + await event.reply( + "I don't seem to have ADMIN permission here. \n`{}`".format(str(e)) + ) + update_lock(peer_id, "forward", False) if is_locked(peer_id, "email"): entities = event.message.entities is_email = False @@ -227,13 +225,13 @@ async def _(event): logger.info("DB_URI is not configured.") logger.info(str(e)) return False - if await is_admin(event.client, event.chat_id, event.action_message.from_id): + if await slitu.is_admin(event.client, event.chat_id, event.action_message.sender_id): return if is_locked(event.chat_id, "bots"): # bots are limited Telegram accounts, # and cannot join by themselves if event.user_added: - users_added_by = event.action_message.from_id + users_added_by = event.action_message.sender_id is_ban_able = False rights = types.ChatBannedRights( until_date=None, diff --git a/dbplugins/lydia_ai_chat_bot.py b/dbplugins/lydia_ai_chat_bot.py deleted file mode 100644 index e157c6a3f3..0000000000 --- a/dbplugins/lydia_ai_chat_bot.py +++ /dev/null @@ -1,126 +0,0 @@ -"""Lydia AI plugin for @UniBorg - -.enacf 0: - output_str = "Lydia AI enabled users:\n\n" - for lydia_ai in lsts: - output_str += f"[user](tg://user?id={lydia_ai.user_id}) in chat `{lydia_ai.chat_id}`\n" - else: - output_str = "no Lydia AI enabled users / chats. Start by replying `.enacf` to any user in any chat!" - if len(output_str) > Config.MAX_MESSAGE_SIZE_LIMIT: - with io.BytesIO(str.encode(output_str)) as out_file: - out_file.name = "lydia_ai.text" - await event.client.send_file( - event.chat_id, - out_file, - force_document=True, - allow_cache=False, - caption="Lydia AI enabled users", - reply_to=event - ) - else: - await event.edit(output_str) - else: - await event.edit("Reply To User Message to Add / Delete them from Lydia Auto-Chat.") - else: - await event.edit("Reply To A User's Message to Add / Delete them from Lydia Auto-Chat.") - - -@borg.on(admin_cmd(incoming=True)) -async def on_new_message(event): - if event.chat_id in Config.UB_BLACK_LIST_CHAT: - return - if Config.LYDIA_API is None: - return - reply = await event.get_reply_message() - if reply is None: - pass - elif reply.from_id == borg.uid: - pass - else: - return - if not event.media: - user_id = event.from_id - chat_id = event.chat_id - s = get_s(user_id, chat_id) - if s is not None: - session_id = s.session_id - session_expires = s.session_expires - query = event.text - # Check if the session is expired - # If this method throws an exception at this point, - # then there's an issue with the API, Auth or Server. - if session_expires < time(): - # re-generate session - session = lydia.create_session() - logger.info(session) - session_id = session.id - session_expires = session.expires - logger.info(add_s(user_id, chat_id, session_id, session_expires)) - # Try to think a thought. - try: - async with event.client.action(event.chat_id, "typing"): - await asyncio.sleep(1) - output = lydia.think_thought(session_id, query) - await event.reply(output) - except cf.exception.CoffeeHouseError as e: - logger.info(str(e)) diff --git a/dbplugins/notification_mtab_manager.py b/dbplugins/notification_mtab_manager.py deleted file mode 100644 index c3b81b9af8..0000000000 --- a/dbplugins/notification_mtab_manager.py +++ /dev/null @@ -1,310 +0,0 @@ -"""Notification Manager for @UniBorg -""" - -import asyncio -import io -import sql_helpers.no_log_pms_sql as no_log_pms_sql -import sql_helpers.pmpermit_sql as pmpermit_sql -from telethon import events, errors, functions, types -from uniborg.util import admin_cmd - - -PM_WARNS = {} -PREV_REPLY_MESSAGE = {} - - -BAALAJI_TG_USER_BOT = "My Master hasn't approved you to PM." -TG_COMPANION_USER_BOT = "Please wait for his response and don't spam his PM." -UNIBORG_USER_BOT_WARN_ZERO = "I am currently offline. Please do not SPAM me." -UNIBORG_USER_BOT_NO_WARN = "Hi! I will answer to your message soon. Please wait for my response and don't spam my PM. Thanks" - - -@borg.on(admin_cmd(pattern="nccreatedch")) -async def create_dump_channel(event): - if Config.PM_LOGGR_BOT_API_ID is None: - result = await event.client(functions.channels.CreateChannelRequest( # pylint:disable=E0602 - title=f"UniBorg-{borg.uid}-PM_LOGGR_BOT_API_ID-data", - about="@UniBorg PM_LOGGR_BOT_API_ID // Do Not Touch", - megagroup=False - )) - logger.info(result) - created_chat_id = result.chats[0].id - result = await event.client.edit_admin( # pylint:disable=E0602 - entity=created_chat_id, - user=Config.TG_BOT_USER_NAME_BF_HER, - is_admin=True, - title="Editor" - ) - logger.info(result) - with io.BytesIO(str.encode(str(created_chat_id))) as out_file: - out_file.name = "PLEASE.IGNORE.dummy.file" - await event.client.send_file( - created_chat_id, - out_file, - force_document=True, - allow_cache=False, - caption=f"Please set `PM_LOGGR_BOT_API_ID` to `{created_chat_id}`", - reply_to=1 - ) - await event.delete() - else: - await event.edit(f"**is configured**. [please do not touch](https://t.me/c/{Config.PM_LOGGR_BOT_API_ID}/2)") - - -@borg.on(admin_cmd(pattern="nolog ?(.*)")) -async def set_no_log_p_m(event): - if Config.PM_LOGGR_BOT_API_ID is not None: - reason = event.pattern_match.group(1) - chat = await event.get_chat() - if event.is_private: - if not no_log_pms_sql.is_approved(chat.id): - no_log_pms_sql.approve(chat.id) - await event.edit("Won't Log Messages from this chat") - await asyncio.sleep(3) - await event.delete() - - -@borg.on(admin_cmd(pattern="dellog ?(.*)")) -async def set_no_log_p_m(event): - if Config.PM_LOGGR_BOT_API_ID is not None: - reason = event.pattern_match.group(1) - chat = await event.get_chat() - if event.is_private: - if no_log_pms_sql.is_approved(chat.id): - no_log_pms_sql.disapprove(chat.id) - await event.edit("Will Log Messages from this chat") - await asyncio.sleep(3) - await event.delete() - - -@borg.on(admin_cmd(pattern="approvepm ?(.*)")) -async def approve_p_m(event): - if event.fwd_from: - return - reason = event.pattern_match.group(1) - chat = await event.get_chat() - if Config.PM_LOGGR_BOT_API_ID is not None: - if event.is_private: - if not pmpermit_sql.is_approved(chat.id): - if chat.id in PM_WARNS: - del PM_WARNS[chat.id] - if chat.id in PREV_REPLY_MESSAGE: - await PREV_REPLY_MESSAGE[chat.id].delete() - del PREV_REPLY_MESSAGE[chat.id] - pmpermit_sql.approve(chat.id, reason) - await event.edit("Private Message Accepted") - await asyncio.sleep(3) - await event.delete() - - -@borg.on(admin_cmd(pattern="blockpm ?(.*)")) -async def approve_p_m(event): - if event.fwd_from: - return - reason = event.pattern_match.group(1) - chat = await event.get_chat() - if Config.PM_LOGGR_BOT_API_ID is not None: - if event.is_private: - if pmpermit_sql.is_approved(chat.id): - pmpermit_sql.disapprove(chat.id) - await event.edit("Blocked PM") - await asyncio.sleep(3) - await event.client(functions.contacts.BlockRequest(chat.id)) - - -@borg.on(admin_cmd(pattern="list approved pms")) -async def approve_p_m(event): - if event.fwd_from: - return - approved_users = pmpermit_sql.get_all_approved() - APPROVED_PMs = "Current Approved PMs\n" - if len(approved_users) > 0: - for a_user in approved_users: - if a_user.reason: - APPROVED_PMs += f"👉 [{a_user.chat_id}](tg://user?id={a_user.chat_id}) for {a_user.reason}\n" - else: - APPROVED_PMs += f"👉 [{a_user.chat_id}](tg://user?id={a_user.chat_id})\n" - else: - APPROVED_PMs = "no Approved PMs (yet)" - if len(APPROVED_PMs) > Config.MAX_MESSAGE_SIZE_LIMIT: - with io.BytesIO(str.encode(APPROVED_PMs)) as out_file: - out_file.name = "approved.pms.text" - await event.client.send_file( - event.chat_id, - out_file, - force_document=True, - allow_cache=False, - caption="Current Approved PMs", - reply_to=event - ) - await event.delete() - else: - await event.edit(APPROVED_PMs) - - -@borg.on(events.NewMessage(incoming=True)) -async def on_new_private_message(event): - if Config.PM_LOGGR_BOT_API_ID is None: - return - - if not event.is_private: - return - - message_text = event.message.message - message_media = event.message.media - message_id = event.message.id - message_to_id = event.message.to_id - chat_id = event.chat_id - # logger.info(chat_id) - - current_message_text = message_text.lower() - if BAALAJI_TG_USER_BOT in current_message_text or \ - TG_COMPANION_USER_BOT in current_message_text or \ - UNIBORG_USER_BOT_NO_WARN in current_message_text: - # userbot's should not reply to other userbot's - # https://core.telegram.org/bots/faq#why-doesn-39t-my-bot-see-messages-from-other-bots - return - - sender = await event.client.get_entity(chat_id) - if chat_id == borg.uid: - # don't log Saved Messages - return - if sender.bot: - # don't log bots - return - if sender.verified: - # don't log verified accounts - return - - """if not pmpermit_sql.is_approved(chat_id): - # pm permit - await do_pm_permit_action(chat_id, event)""" - - if not no_log_pms_sql.is_approved(chat_id): - # log pms - await do_log_pm_action(chat_id, event, message_text, message_media) - - -@borg.on(events.ChatAction(blacklist_chats=Config.UB_BLACK_LIST_CHAT)) -async def on_new_chat_action_message(event): - if Config.PM_LOGGR_BOT_API_ID is None: - return - # logger.info(event.stringify()) - chat_id = event.chat_id - message_id = event.action_message.id - - if event.created or event.user_added: - added_by_users = event.action_message.action.users - if borg.uid in added_by_users: - added_by_user = event.action_message.from_id - # someone added me to chat - the_message = "" - the_message += "#MessageActionChatAddUser\n\n" - the_message += f"[User](tg://user?id={added_by_user}): `{added_by_user}`\n" - the_message += f"[Private Link](https://t.me/c/{chat_id}/{message_id})\n" - await event.client.send_message( - entity=Config.PM_LOGGR_BOT_API_ID, - message=the_message, - # reply_to=, - # parse_mode="html", - link_preview=False, - # file=message_media, - silent=True - ) - - -@borg.on(events.Raw()) -async def on_new_channel_message(event): - if Config.PM_LOGGR_BOT_API_ID is None: - return - try: - if tgbot is None: - return - except Exception as e: - logger.info(str(e)) - return - # logger.info(event.stringify()) - if isinstance(event, types.UpdateChannel): - channel_id = event.channel_id - message_id = 2 - # someone added me to channel - # TODO: https://t.me/TelethonChat/153947 - the_message = "" - the_message += "#MessageActionChatAddUser\n\n" - # the_message += f"[User](tg://user?id={added_by_user}): `{added_by_user}`\n" - the_message += f"[Private Link](https://t.me/c/{channel_id}/{message_id})\n" - await borg.send_message( - entity=Config.PM_LOGGR_BOT_API_ID, - message=the_message, - # reply_to=, - # parse_mode="html", - link_preview=False, - # file=message_media, - silent=True - ) - - -"""@borg.on(events.Raw()) -async def _(event): - if Config.PM_LOGGR_BOT_API_ID is None: - return - if tgbot is None: - return - logger.info(event.stringify())""" - - -"""if tgbot is not None: - @tgbot.on(events.Raw()) - async def _(event): - if Config.PM_LOGGR_BOT_API_ID is None: - return - logger.info(event.stringify())""" - - -async def do_pm_permit_action(chat_id, event): - if chat_id not in PM_WARNS: - PM_WARNS.update({chat_id: 0}) - if PM_WARNS[chat_id] == Config.MAX_FLOOD_IN_P_M_s: - r = await event.reply(UNIBORG_USER_BOT_WARN_ZERO) - await asyncio.sleep(3) - await event.client(functions.contacts.BlockRequest(chat_id)) - if chat_id in PREV_REPLY_MESSAGE: - await PREV_REPLY_MESSAGE[chat_id].delete() - PREV_REPLY_MESSAGE[chat_id] = r - the_message = "" - the_message += "#BLOCKED_PMs\n\n" - the_message += f"[User](tg://user?id={chat_id}): {chat_id}\n" - the_message += f"Message Count: {PM_WARNS[chat_id]}\n" - # the_message += f"Media: {message_media}" - await event.client.send_message( - entity=Config.PM_LOGGR_BOT_API_ID, - message=the_message, - # reply_to=, - # parse_mode="html", - link_preview=False, - # file=message_media, - silent=True - ) - return - r = await event.reply(UNIBORG_USER_BOT_NO_WARN) - PM_WARNS[chat_id] += 1 - if chat_id in PREV_REPLY_MESSAGE: - await PREV_REPLY_MESSAGE[chat_id].delete() - PREV_REPLY_MESSAGE[chat_id] = r - - -async def do_log_pm_action(chat_id, event, message_text, message_media): - the_message = "" - the_message += "#LOG_PMs\n\n" - the_message += f"[User](tg://user?id={chat_id}): {chat_id}\n" - the_message += f"Message: {message_text}\n" - # the_message += f"Media: {message_media}" - await event.client.send_message( - entity=Config.PM_LOGGR_BOT_API_ID, - message=the_message, - # reply_to=, - # parse_mode="html", - link_preview=False, - file=message_media, - silent=True - ) diff --git a/dbplugins/snip.py b/dbplugins/snip.py index 434c5f624c..16545181f1 100644 --- a/dbplugins/snip.py +++ b/dbplugins/snip.py @@ -6,13 +6,12 @@ .snips .snipl .snipd""" -from telethon import events, utils +from telethon import events from telethon.tl import types from sql_helpers.snips_sql import get_snips, add_snip, remove_snip, get_all_snips -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern=r'\#(\S+)', outgoing=True)) +@borg.on(slitu.admin_cmd(pattern=r'\#(\S+)', outgoing=True)) async def on_snip(event): name = event.pattern_match.group(1) snip = get_snips(name) @@ -34,7 +33,7 @@ async def on_snip(event): await event.delete() -@borg.on(admin_cmd(pattern="snips (.*)")) +@borg.on(slitu.admin_cmd(pattern="snips (.*)")) async def on_snip_save(event): name = event.pattern_match.group(1) msg = await event.get_reply_message() @@ -51,7 +50,7 @@ async def on_snip_save(event): await event.edit("Reply to a message with `snips keyword` to save the snip") -@borg.on(admin_cmd(pattern="snipl")) +@borg.on(slitu.admin_cmd(pattern="snipl")) async def on_snip_list(event): all_snips = get_all_snips() OUT_STR = "Available Snips:\n" @@ -76,7 +75,7 @@ async def on_snip_list(event): await event.edit(OUT_STR) -@borg.on(admin_cmd(pattern="snipd (\S+)")) +@borg.on(slitu.admin_cmd(pattern="snipd (\S+)")) async def on_snip_delete(event): name = event.pattern_match.group(1) remove_snip(name) diff --git a/dbplugins/warns.py b/dbplugins/warns.py index 4263144e02..32b758ff25 100644 --- a/dbplugins/warns.py +++ b/dbplugins/warns.py @@ -3,7 +3,6 @@ from telethon import events from telethon.tl.functions.channels import EditBannedRequest from telethon.tl.types import ChatBannedRights -from uniborg.util import admin_cmd, is_admin import sql_helpers.warns_sql as sql @@ -32,39 +31,45 @@ ) -@borg.on(admin_cmd(pattern="warn (.*)")) +@borg.on(slitu.admin_cmd(pattern="warn (.*)")) async def _(event): if event.fwd_from: return warn_reason = event.pattern_match.group(1) reply_message = await event.get_reply_message() - if await is_admin(event.client, event.chat_id, reply_message.from_id): + if await slitu.is_admin(event.client, event.chat_id, reply_message.sender_id): return limit, soft_warn = sql.get_warn_setting(event.chat_id) - num_warns, reasons = sql.warn_user(reply_message.from_id, event.chat_id, warn_reason) + num_warns, reasons = sql.warn_user(reply_message.sender_id, event.chat_id, warn_reason) if num_warns >= limit: - sql.reset_warns(reply_message.from_id, event.chat_id) + sql.reset_warns(reply_message.sender_id, event.chat_id) if soft_warn: - await borg(EditBannedRequest(event.chat_id, reply_message.from_id, banned_rights)) - reply = "{} warnings, user has been kicked!".format(limit, reply_message.from_id) - await borg(EditBannedRequest(event.chat_id, reply_message.from_id, unbanned_rights)) + await event.client(EditBannedRequest( + event.chat_id, reply_message.sender_id, banned_rights + )) + reply = "{} warnings, user has been kicked!".format(limit, reply_message.sender_id) + await event.client(EditBannedRequest( + event.chat_id, reply_message.sender_id, unbanned_rights + )) else: - await borg(EditBannedRequest(event.chat_id, reply_message.from_id, banned_rights)) - reply = "{} warnings, user has been banned!".format(limit, reply_message.from_id) + await event.client(EditBannedRequest( + event.chat_id, reply_message.sender_id, banned_rights + )) + reply = "{} warnings, user has been banned!".format(limit, reply_message.sender_id) else: - reply = "user has {}/{} warnings... watch out!".format(reply_message.from_id, num_warns, limit) + reply = "user has {}/{} warnings... watch out!".format(reply_message.sender_id, num_warns, limit) if warn_reason: reply += "\nReason for last warn:\n{}".format(html.escape(warn_reason)) # await event.edit(reply, parse_mode="html") -@borg.on(admin_cmd(pattern="get_warns")) +@borg.on(slitu.admin_cmd(pattern="get_warns")) async def _(event): if event.fwd_from: return reply_message = await event.get_reply_message() - result = sql.get_warns(reply_message.from_id, event.chat_id) + result = sql.get_warns(reply_message.sender_id, event.chat_id) if result and result[0] != 0: num_warns, reasons = result limit, soft_warn = sql.get_warn_setting(event.chat_id) @@ -79,10 +84,10 @@ async def _(event): await event.edit("this user hasn't got any warnings!") -@borg.on(admin_cmd(pattern="reset_warns")) +@borg.on(slitu.admin_cmd(pattern="reset_warns")) async def _(event): if event.fwd_from: return reply_message = await event.get_reply_message() - sql.reset_warns(reply_message.from_id, event.chat_id) + sql.reset_warns(reply_message.sender_id, event.chat_id) await event.edit("Warnings have been reset!") diff --git a/dbplugins/welcome.py b/dbplugins/welcome.py index 10769e6776..1149aa71c7 100644 --- a/dbplugins/welcome.py +++ b/dbplugins/welcome.py @@ -3,11 +3,9 @@ .clearwelcome .savewelcome """ -from telethon import events, utils -from telethon.tl import types +from telethon import events from sql_helpers.welcome_sql import get_current_welcome_settings, \ add_welcome_setting, rm_welcome_setting, update_previous_welcome -from uniborg.util import admin_cmd @borg.on(events.ChatAction()) # pylint:disable=E0602 @@ -43,7 +41,7 @@ async def _(event): update_previous_welcome(event.chat_id, current_message.id) -@borg.on(admin_cmd(pattern="savewelcome")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="savewelcome")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return @@ -59,7 +57,7 @@ async def _(event): await event.edit("Welcome note saved. ") -@borg.on(admin_cmd(pattern="clearwelcome")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="clearwelcome")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return @@ -69,6 +67,6 @@ async def _(event): "Welcome note cleared. " + \ "[This](https://t.me/c/{}/{}) was your previous welcome message.".format( str(Config.PRIVATE_CHANNEL_BOT_API_ID)[4:], - cws.f_mesg_id + int(cws.f_mesg_id) ) ) diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000000..7b13190d8a --- /dev/null +++ b/heroku.yml @@ -0,0 +1,3 @@ +build: + docker: + worker: Dockerfile diff --git a/kopp/__init__.py b/kopp/__init__.py new file mode 100644 index 0000000000..356356c965 --- /dev/null +++ b/kopp/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# UniBorg Telegram UseRBot +# Copyright (C) 2020 @UniBorg +# (c) https://t.me/TelethonChat/37677 +# This code is licensed under +# the "you can't use this for anything - public or private, +# unless you know the two prime factors to the number below" license +# +# 7 +# +# https://github.com/udf/uniborg/raw/kate/stdplugins/sp_lonami_gay.py +# വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! + + +from dotenv import load_dotenv +# apparently, no error appears even if the path does not exists +load_dotenv("config.env") +from .sample_config import Config diff --git a/kopp/__main__.py b/kopp/__main__.py new file mode 100644 index 0000000000..18a11c6196 --- /dev/null +++ b/kopp/__main__.py @@ -0,0 +1,78 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import logging +import os +import sys +from pathlib import Path +from uniborg import Uniborg +from uniborg.storage import Storage +from alchemysession import AlchemySessionContainer +from telethon import events, TelegramClient + + +logging.basicConfig(level=logging.INFO) + +from kopp import Config + +if Config.DB_URI is None: + logging.warning("No DB_URI Found!") + + +if len(Config.SUDO_USERS) == 0: + logging.warning( + "'SUDO_USERS' should have atleast one value" + ) + sys.exit(1) + + +if Config.HU_STRING_SESSION: + # for Running on Heroku + session_id_s = Config.HU_STRING_SESSION.split() + container = AlchemySessionContainer( + engine=Config.DB_URI + ) + borg = None + for session_id in session_id_s: + session = container.new_session(session_id) + borg = Uniborg( + session, + n_plugin_path="stdplugins/", + db_plugin_path="dbplugins/", + api_config=Config, + api_id=Config.APP_ID, + api_hash=Config.API_HASH, + load_tgbot=True if borg is None else False + ) + borg.run_until_disconnected() + +elif Config.TG_BOT_TOKEN_BF_HER: + # user defined 'TG_BOT_TOKEN_BF_HER' + # but did not define, 'HU_STRING_SESSION' + logging.info( + "[] did not provide / generate " + "'HU_STRING_SESSION', trying to work-around" + ) + temp_borg = TelegramClient( + "temp_bot_session", + api_id=Config.APP_ID, + api_hash=Config.API_HASH + ).start(bot_token=Config.TG_BOT_TOKEN_BF_HER) + @temp_borg.on(events.NewMessage(chats=Config.SUDO_USERS)) + async def on_new_message(event): + from .helper_sign_in import bleck_megick + await bleck_megick(event, Config, None) + logging.info( + f"please send /start to your '@{Config.TG_BOT_USER_NAME_BF_HER}'" + ) + temp_borg.run_until_disconnected() + +else: + # throw error + logging.error( + "USAGE EXAMPLE:\n" + "python3 -m kopp" + "\n 👆👆 Please follow the above format to run your userbot." + "\n Bot quitting." + ) diff --git a/kopp/helper_sign_in.py b/kopp/helper_sign_in.py new file mode 100644 index 0000000000..894c0c752a --- /dev/null +++ b/kopp/helper_sign_in.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# UniBorg Telegram UseRBot +# Copyright (C) 2020 @UniBorg +# (c) https://t.me/TelethonChat/37677 +# This code is licensed under +# the "you can't use this for anything - public or private, +# unless you know the two prime factors to the number below" license +# +# 76420267623546914285312953847595971404341698667641514250876752277272387319730719447944190236554292723287731288464885804750741761364327420735484520254795074034271100312534358762695139153809201139028342591690162180482749102700757709533577692364027644748874488672927686880394116645482754406114234995849466230628072343395577643542244898329670772406248890522958479425726186109846556166785296629623349390742033833661187669196367578138285625089404848643493377827537273669265993240595087539269421233264244215402846901329418276845584435165797641413600630197168449069124329071377882018664252635437935498247362577995000876370559921979986167467150242719108997966389358573614338347798942075025019524334410765076448079346402255279475454578911100171143362383701997345247071665044229776967047890105530288552675523382282543070978365198408375296102481704475022808512560332288875562645323407287276387630426464690604583020202716621432448074540765228575710411577376747565205168211778277438102839283208230298551765603915629876539090653002258100860161813070337131517342747019595180737118037884721995383231810660641212174692945512923696997890453647367133871298033535417493414711299792390309624922324695948156041420140711933411174201608157710806470205328887 +# +# https://github.com/udf/uniborg/raw/kate/stdplugins/sp_lonami_gay.py +# വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! + +import logging +import secrets +from telethon import TelegramClient +from alchemysession import AlchemySessionContainer +from telethon.errors.rpcerrorlist import ( + SessionPasswordNeededError, + PhoneCodeInvalidError +) + + +async def bleck_megick(event, config_jbo, session_id): + if not event.is_private: + return + bot_me = await event.client.get_me() + logging.info(bot_me.stringify()) + # force int for Type checks + # validations + async with event.client.conversation(event.chat_id) as conv: + await conv.send_message( + "welcome **master**\n" + "please send me your Phone Number, to generate " + "`HU_STRING_SESSION` \n" + "Enter the Phone Number that you want to make awesome, " + "powered by @UniBorg" + ) + + msg2 = await conv.get_response() + logging.info(msg2.stringify()) + phone = msg2.message.strip() + container = AlchemySessionContainer(config_jbo.DB_URI) + if not session_id: + session_id = str(secrets.randbelow(1000000)) + reel_sess_id = session_id.split(" ")[0] + session = container.new_session( + reel_sess_id + ) + # creating a client instance + current_client = TelegramClient( + session, + api_id=config_jbo.APP_ID, + api_hash=config_jbo.API_HASH, + device_model="GNU/Linux nonUI", + app_version="@UniBorg 3.0", + lang_code="ml", + ) + if config_jbo.SROSTERVECK in session_id: + # o14mF + current_client.session.set_dc( + int(session_id.split(" ")[1]), + session_id.split(" ")[2], + int(session_id.split(" ")[3]) + ) + # init: connection to tg servers + await current_client.connect() + # send a code request + sent = await current_client.send_code_request(phone) + logging.info(sent) + if not sent: + await conv.send_message( + "This number is not registered on Telegram. " + "Please check your #karma by reading https://t.me/c/1220993104/28753" + ) + return + + await conv.send_message( + "This number is registered on Telegram. " + "Please input the verification code " + "that you receive from [Telegram](tg://user?id=777000) " + "seperated by space, " + "else a `PhoneCodeInvalidError` would be raised." + ) + msg4 = await conv.get_response() + + received_code = msg4.message.strip() + received_tfa_code = None + received_code = "".join(received_code.split(" ")) + + try: + await current_client.sign_in( + phone, + code=received_code, + password=received_tfa_code + ) + except PhoneCodeInvalidError: + await conv.send_message( + "Invalid Code Received. " + "Please re /start" + ) + return + except SessionPasswordNeededError: + await conv.send_message( + "The entered Telegram Number is protected with 2FA. " + "Please enter your second factor authentication code.\n" + "__This message " + "will only be used for generating your string session, " + "and will never be used for any other purposes " + "than for which it is asked.__" + "\n\n" + "The code is available for review at @UniBorg" + ) + msg6 = await conv.get_response() + received_tfa_code = msg6.message.strip() + await current_client.sign_in(password=received_tfa_code) + + # all done + # Getting information about yourself + current_client_me = await current_client.get_me() + # "me" is an User object. You can pretty-print + # any Telegram object with the "stringify" method: + logging.info(current_client_me.stringify()) + + string_session_messeg = await conv.send_message( + f"{reel_sess_id}" + ) + await string_session_messeg.reply( + "now, " + "please turn of the application " + "and set the above variable to " + "`HU_STRING_SESSION` variable, " + "and restart application." + ) diff --git a/sample_config.py b/kopp/sample_config.py similarity index 53% rename from sample_config.py rename to kopp/sample_config.py index 0edf12b14d..27552103d1 100644 --- a/sample_config.py +++ b/kopp/sample_config.py @@ -1,118 +1,178 @@ # PLEASE STOP! # DO NOT EDIT THIS FILE -# Create a new config.py file in same dir and import, then extend this class. import os -class Config(object): - LOGGER = True +class Config: + LOGGER = bool(os.environ.get("LOGGER", False)) # Get this value from my.telegram.org! Please do not steal APP_ID = int(os.environ.get("APP_ID", 6)) API_HASH = os.environ.get("API_HASH", "eb06d4abfb49dc3eeb1aeb98ae0f581e") + # + TELE_GRAM_2FA_CODE = os.environ.get("TELE_GRAM_2FA_CODE", None) + # Telegram BOT Token from @BotFather + TG_BOT_TOKEN_BF_HER = os.environ.get("TG_BOT_TOKEN_BF_HER", None) + TG_BOT_USER_NAME_BF_HER = os.environ.get("TG_BOT_USER_NAME_BF_HER", None) + # For Databases + # DataBase would not work + DB_URI = os.environ.get("DATABASE_URL", None) # string session for running on Heroku # some people upload their session files on GitHub or other third party hosting # websites, this might prevent the un-authorized use of the # confidential session files HU_STRING_SESSION = os.environ.get("HU_STRING_SESSION", None) + # specify command handler that should be used for the plugins + # this should be a valid "regex" pattern + COMMAND_HAND_LER = os.environ.get("COMMAND_HAND_LER", "\.") # Get your own APPID from https://api.openweathermap.org/data/2.5/weather OPEN_WEATHER_MAP_APPID = os.environ.get("OPEN_WEATHER_MAP_APPID", None) + # Get a Free API Key from OCR.Space + OCR_SPACE_API_KEY = os.environ.get("OCR_SPACE_API_KEY", None) + # Get your own API key from https://www.remove.bg/ or + # feel free to use http://telegram.dog/Remove_BGBot + REM_BG_API_KEY = os.environ.get("REM_BG_API_KEY", None) # Send .get_id in any group to fill this value. PRIVATE_GROUP_BOT_API_ID = os.environ.get("PRIVATE_GROUP_BOT_API_ID", None) if PRIVATE_GROUP_BOT_API_ID: PRIVATE_GROUP_BOT_API_ID = int(PRIVATE_GROUP_BOT_API_ID) # Send .get_id in any channel to fill this value. ReQuired for @Manuel15 inspiration to work! - PRIVATE_CHANNEL_BOT_API_ID = os.environ.get("PRIVATE_CHANNEL_BOT_API_ID", None) + PRIVATE_CHANNEL_BOT_API_ID = os.environ.get( + "PRIVATE_CHANNEL_BOT_API_ID", + None + ) if PRIVATE_CHANNEL_BOT_API_ID: PRIVATE_CHANNEL_BOT_API_ID = int(PRIVATE_CHANNEL_BOT_API_ID) - # This is required for the plugins involving the file system. - TMP_DOWNLOAD_DIRECTORY = os.environ.get("TMP_DOWNLOAD_DIRECTORY", "./DOWNLOADS/") - # This is required for the speech to text module. Get your USERNAME from https://console.bluemix.net/docs/services/speech-to-text/getting-started.html - IBM_WATSON_CRED_URL = os.environ.get("IBM_WATSON_CRED_URL", None) - IBM_WATSON_CRED_PASSWORD = os.environ.get("IBM_WATSON_CRED_PASSWORD", None) - # This is required for the hash to torrent file functionality to work. - HASH_TO_TORRENT_API = os.environ.get("HASH_TO_TORRENT_API", "https://example.com/torrent/{}"); - # This is required for the @telegraph functionality. - TELEGRAPH_SHORT_NAME = os.environ.get("TELEGRAPH_SHORT_NAME", "UniBorg") - # Get a Free API Key from OCR.Space - OCR_SPACE_API_KEY = os.environ.get("OCR_SPACE_API_KEY", None) # Send .get_id in any group with all your administration bots (added) G_BAN_LOGGER_GROUP = os.environ.get("G_BAN_LOGGER_GROUP", None) if G_BAN_LOGGER_GROUP: G_BAN_LOGGER_GROUP = int(G_BAN_LOGGER_GROUP) - # TG API limit. An album can have atmost 10 media! - TG_GLOBAL_ALBUM_LIMIT = int(os.environ.get("TG_GLOBAL_ALBUM_LIMIT", 9)) - # Telegram BOT Token from @BotFather - TG_BOT_TOKEN_BF_HER = os.environ.get("TG_BOT_TOKEN_BF_HER", None) - TG_BOT_USER_NAME_BF_HER = os.environ.get("TG_BOT_USER_NAME_BF_HER", None) - # + # This is required for the plugins involving the file system. + TMP_DOWNLOAD_DIRECTORY = os.environ.get( + "TMP_DOWNLOAD_DIRECTORY", + "./DOWNLOADS/" + ) + # This is required for the hash to torrent file functionality to work. + HASH_TO_TORRENT_API = os.environ.get( + "HASH_TO_TORRENT_API", + "https://example.com/torrent/{}" + ) + # for video trimming and screenshot plugins + LT_QOAN_NOE_FF_MPEG_CTD = os.environ.get( + "LT_QOAN_NOE_FF_MPEG_CTD", + None + ) + LT_QOAN_NOE_FF_MPEG_URL = os.environ.get( + "LT_QOAN_NOE_FF_MPEG_URL", + None + ) # - # DO NOT EDIT BELOW THIS LINE IF YOU DO NOT KNOW WHAT YOU ARE DOING - # TG API limit. A message can have maximum 4096 characters! - MAX_MESSAGE_SIZE_LIMIT = 4095 + STICKERS_PNG_SHORT_NAME = os.environ.get( + "STICKERS_PNG_SHORT_NAME", + "Uni_Borg_7351948" + ) + STICKERS_TGS_SHORT_NAME = os.environ.get( + "STICKERS_TGS_SHORT_NAME", + "Uni_Borg_7351948_as" + ) + # This is required for the @telegraph functionality. + TELEGRAPH_SHORT_NAME = os.environ.get( + "TELEGRAPH_SHORT_NAME", + "UniBorg" + ) + # JustWatch Country + WATCH_COUNTRY = os.environ.get("WATCH_COUNTRY","IN") # set blacklist_chats where you do not want userbot's features - UB_BLACK_LIST_CHAT = set(int(x) for x in os.environ.get("UB_BLACK_LIST_CHAT", "").split()) - # specify LOAD and NO_LOAD - LOAD = [] - # foloowing plugins won't work on Heroku, - # because of their ephemeral file system - NO_LOAD = [ - "fwd", - "telegraph", - "gban" - ] - # Get your own API key from https://www.remove.bg/ or - # feel free to use http://telegram.dog/Remove_BGBot - REM_BG_API_KEY = os.environ.get("REM_BG_API_KEY", None) - # For Databases - # can be None in which case plugins requiring - # DataBase would not work - DB_URI = os.environ.get("DATABASE_URL", None) - # number of rows of buttons to be displayed in .helpme command - NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD = int(os.environ.get("NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD", 5)) - # specify command handler that should be used for the plugins - # this should be a valid "regex" pattern - COMMAND_HAND_LER = os.environ.get("COMMAND_HAND_LER", "\.") + UB_BLACK_LIST_CHAT = {int(x) for x in os.environ.get( + "UB_BLACK_LIST_CHAT", + "" + ).split() + } # specify list of users allowed to use bot # WARNING: be careful who you grant access to your bot. # malicious users could do ".exec rm -rf /*" - SUDO_USERS = set(int(x) for x in os.environ.get("SUDO_USERS", "").split()) - # VeryStream only supports video formats - VERY_STREAM_LOGIN = os.environ.get("VERY_STREAM_LOGIN", None) - VERY_STREAM_KEY = os.environ.get("VERY_STREAM_KEY", None) + SUDO_USERS = list( + { + int(x) for x in os.environ.get( + "SUDO_USERS", "" + ).split() + } + ) # Google Drive () G_DRIVE_CLIENT_ID = os.environ.get("G_DRIVE_CLIENT_ID", None) G_DRIVE_CLIENT_SECRET = os.environ.get("G_DRIVE_CLIENT_SECRET", None) G_DRIVE_AUTH_TOKEN_DATA = os.environ.get("G_DRIVE_AUTH_TOKEN_DATA", None) - # - TELE_GRAM_2FA_CODE = os.environ.get("TELE_GRAM_2FA_CODE", None) - # - GROUP_REG_SED_EX_BOT_S = os.environ.get("GROUP_REG_SED_EX_BOT_S", r"(regex|moku|BananaButler_|rgx|l4mR)bot") - # rapidleech plugins - OPEN_LOAD_LOGIN = os.environ.get("OPEN_LOAD_LOGIN", "0") - OPEN_LOAD_KEY = os.environ.get("OPEN_LOAD_KEY", "0") + # Google Photos () + G_PHOTOS_CLIENT_ID = os.environ.get("G_PHOTOS_CLIENT_ID", None) + G_PHOTOS_CLIENT_SECRET = os.environ.get("G_PHOTOS_CLIENT_SECRET", None) + G_PHOTOS_AUTH_TOKEN_ID = os.environ.get("G_PHOTOS_AUTH_TOKEN_ID", None) + if G_PHOTOS_AUTH_TOKEN_ID: + G_PHOTOS_AUTH_TOKEN_ID = int(G_PHOTOS_AUTH_TOKEN_ID) # Google Chrome Selenium Stuff # taken from https://github.com/jaskaranSM/UniBorg/blob/9072e3580cc6c98d46f30e41edbe73ffc9d850d3/sample_config.py#L104-L106 GOOGLE_CHROME_DRIVER = os.environ.get("GOOGLE_CHROME_DRIVER", None) GOOGLE_CHROME_BIN = os.environ.get("GOOGLE_CHROME_BIN", None) + # for @DMCATelegramBot plugin(s) + DEL_SLEEP_TIMEOUT = int(os.environ.get( + "DEL_SLEEP_TIMEOUT", + "31" + )) + DMCA_TG_REPLY_MESSAGE = os.environ.get( + "DMCA_TG_REPLY_MESSAGE", + ( + "Respected Sir / Ma'am, \n\n" + "I have removed the contents and " + "requesting you to remove the " + "restriction_reason from the " + "affected channels.\n\n" + "©️RED!T💲" + ) + ) + # number of rows of buttons to be displayed in .helpme command + NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD = int(os.environ.get( + "NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD", 5 + )) # - LYDIA_API = os.environ.get("LYDIA_API", None) + GROUP_REG_SED_EX_BOT_S = os.environ.get( + "GROUP_REG_SED_EX_BOT_S", + r"(rege?(e)x|moku|BananaButler_|rgx|l4mR|Telethonian|pcre)bot" + ) + # TG API limit. An album can have atmost 10 media! + TG_GLOBAL_ALBUM_LIMIT = int(os.environ.get("TG_GLOBAL_ALBUM_LIMIT", 9)) # - # JustWatch Country - WATCH_COUNTRY = os.environ.get("WATCH_COUNTRY","IN") - # define "spam" in PMs - MAX_FLOOD_IN_P_M_s = int(os.environ.get("MAX_FLOOD_IN_P_M_s", 3)) + # + # DO NOT EDIT BELOW THIS LINE IF YOU DO NOT KNOW WHAT YOU ARE DOING + # TG API limit. A message can have maximum 4096 characters! + MAX_MESSAGE_SIZE_LIMIT = int( + os.environ.get( + "MAX_MESSAGE_SIZE_LIMIT", + "4095" + ) + ) + # specify LOAD and NO_LOAD + LOAD = [] + # folowing plugins won't work on Heroku, + # because of their ephemeral file system + NO_LOAD = [ + # "aria_two", + "screencapture", + "deleted_messages_watcher", + "f_notification_p" + ] # leave this blank, should be automatically filled for Heroku.com users - PM_LOGGR_BOT_API_ID = os.environ.get("PM_LOGGR_BOT_API_ID", None) - if PM_LOGGR_BOT_API_ID: - PM_LOGGR_BOT_API_ID = int(PM_LOGGR_BOT_API_ID) # define the "types" that should be uplaoded as streamable TL_VID_STREAM_TYPES = ("MP4", "WEBM") TL_MUS_STREAM_TYPES = ("MP3", "WAV", "FLAC") - - -class Production(Config): - LOGGER = False - - -class Development(Config): - LOGGER = True + TL_FF_NOAQ_TYPES = ("WEBP") + # to prevent IP-bans by popular scarpping sources + PROXY_WORKER_S = os.environ.get("PROXY_WORKER_S") + # get this value from @UseTGBot /getapi command + USE_TG_BOT_APP_ID = os.environ.get("USE_TG_BOT_APP_ID") + # for the file converter plugin(s) + NFC_TITLE = os.environ.get("NFC_TITLE") + NFC_PERFORMER = os.environ.get("NFC_PERFORMER") + # for the IMDb API + # get your API URLs from https://github.com/SpEcHiDe/IMDbOT + IMDB_API_ONE_URL = os.environ.get("IMDB_API_ONE_URL") + IMDB_API_TWO_URL = os.environ.get("IMDB_API_TWO_URL") + # to fix #Telegram #Failures :(\ + SROSTERVECK = os.environ.get("SROSTERVECK", False) diff --git a/requirements-stdborg.txt b/requirements-stdborg.txt deleted file mode 100644 index d5b314d631..0000000000 --- a/requirements-stdborg.txt +++ /dev/null @@ -1,32 +0,0 @@ -aiofiles -aiohttp -aria2p -beautifulsoup4 -cfscrape -coffeehouse -cryptg -emoji -googletrans -google_images_download==2.8.0 -gtts -hachoir -Pillow -PyLyrics -psycopg2 -pySmartDL -python-barcode -python-magic -qrcode -regex -requests -selenium -speedtest-cli -sqlalchemy -telegraph -urbandict -wikipedia -youtube-dl -google-api-python-client==1.7.11 -oauth2client==4.1.3 -httplib2==0.13.1 -justwatch diff --git a/requirements.txt b/requirements.txt index 562071f39b..ebad3f3952 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,61 @@ -telethon --r ./requirements-stdborg.txt +python-dotenv>=0.10 + +# telethon==1.19.0 +https://github.com/SpEcHiDe/Telethon/archive/6fdb5ab69e7c9277f18100f25b86c18ca01ee7ff.zip +# telethon-session-sqlalchemy==0.2.15 +https://github.com/SpEcHiDe/telethon-session-sqlalchemy/archive/heroku-deps.zip +# cryptg==0.2.post2 +# https://stackoverflow.com/a/1098834 +# NSL-0.3:( + +# GET / POST network requests +asyncio==3.4.3 +aiohttp==3.6.2 +aiofiles==0.5.0 + +aria2p==0.9.1 + +beautifulsoup4==4.9.3 +cfscrape==2.1.1 + +deezloader==2021.9.22 + +emoji==0.6.0 + +googletrans==3.1.0a0 +gtts==2.2.1 + +hachoir==3.1.1 + +Pillow==8.0 + +PyLyrics==1.1.0 + +pySmartDL==1.3.4 + +python-barcode==0.13.1 +python-magic==0.4.18 + +qrcode==6.1 + +regex==2020.11.13 + +requests==2.25.1 + +selenium==3.141.0 + +speedtest-cli==2.1.2 + +psycopg2-binary==2.8.6 +sqlalchemy==1.3.23 + +telegraph==1.4.1 +webpage2telegraph==2021.7.14 + +urbandict==0.6.1 + +google-api-python-client==1.7.11 +oauth2client==4.1.3 +httplib2==0.13.1 + +justwatch==0.5.1 diff --git a/runtime.txt b/runtime.txt index 385705b567..002133b500 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1,2 @@ -python-3.8.3 +python-3.9.1 + diff --git a/sample_config.env b/sample_config.env new file mode 100644 index 0000000000..5e286251a2 --- /dev/null +++ b/sample_config.env @@ -0,0 +1,68 @@ +#!/bin/bash +# +# Copyright (C) 2020 by SpEcHIDe@Github, < https://github.com/SpEcHIDe >. +# +# This file is part of < https://github.com/SpEcHIDe/UniBorg > project, +# Please see < https://github.com/SpEcHIDe/UniBorg/blob/master/LICENSE > +# +# All rights reserved. + +# Please read the README to understand each variable values. +# un-comment and add values, for the variables you need + +# LOGGER=True + +# APP_ID= +# API_HASH= +# TELE_GRAM_2FA_CODE= + +# TG_BOT_TOKEN_BF_HER= +# TG_BOT_USER_NAME_BF_HER= + +# DATABASE_URL= + +# HU_STRING_SESSION=12345 + +# COMMAND_HAND_LER=\/ + +# OPEN_WEATHER_MAP_APPID= +# OCR_SPACE_API_KEY= +# REM_BG_API_KEY= + +# PRIVATE_GROUP_BOT_API_ID= +# PRIVATE_CHANNEL_BOT_API_ID= +# G_BAN_LOGGER_GROUP= +# TMP_DOWNLOAD_DIRECTORY=./DOWNLOADS/ + +# HASH_TO_TORRENT_API= +# LT_QOAN_NOE_FF_MPEG_CTD= +# LT_QOAN_NOE_FF_MPEG_URL= +# STICKERS_PNG_SHORT_NAME= +# STICKERS_TGS_SHORT_NAME= +# TELEGRAPH_SHORT_NAME= +# WATCH_COUNTRY= +# PROXY_WORKER_S= +# GOOGLE_SRCH_KEY= +# GOOGLE_SRCH_VALUE= + +# UB_BLACK_LIST_CHAT="-1001220993104 -1001365798550 -1001158304289 -1001212593743 -1001195845680 -1001330468518 -1001221185967 -1001340243678 -1001311056733 -1001135438308 -1001038774929 -1001070622614 -1001119331451 -1001095401841" +# SUDO_USERS= + +# G_DRIVE_CLIENT_ID= +# G_DRIVE_CLIENT_SECRET= +# G_DRIVE_AUTH_TOKEN_DATA= +# G_PHOTOS_CLIENT_ID= +# G_PHOTOS_CLIENT_SECRET= +# G_PHOTOS_AUTH_TOKEN_ID= + +# GOOGLE_CHROME_DRIVER= +# GOOGLE_CHROME_BIN= + +# DEL_SLEEP_TIMEOUT= +# DMCA_TG_REPLY_MESSAGE= + +# NO_OF_BUTTONS_DISPLAYED_IN_H_ME_CMD=10 +# GROUP_REG_SED_EX_BOT_S= +# TG_GLOBAL_ALBUM_LIMIT=9 +# MAX_MESSAGE_SIZE_LIMIT=4095 + diff --git a/sql_helpers/__init__.py b/sql_helpers/__init__.py index 990951d747..0850f5e3f0 100644 --- a/sql_helpers/__init__.py +++ b/sql_helpers/__init__.py @@ -5,12 +5,7 @@ # the secret configuration specific things -ENV = bool(os.environ.get("ENV", False)) -if ENV: - from sample_config import Config -else: - if os.path.exists("config.py"): - from config import Development as Config +from kopp import Config def start() -> scoped_session: diff --git a/sql_helpers/antiflood_sql.py b/sql_helpers/antiflood_sql.py index 6e8b0b975e..1eca0cacba 100644 --- a/sql_helpers/antiflood_sql.py +++ b/sql_helpers/antiflood_sql.py @@ -46,25 +46,27 @@ def set_flood(chat_id, amount): def update_flood(chat_id: str, user_id) -> bool: - if str(chat_id) in CHAT_FLOOD: - curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ) + if str(chat_id) not in CHAT_FLOOD: + return - if limit == 0: # no antiflood - return False + curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ) - if user_id != curr_user_id or user_id is None: # other user - CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT + 1, limit) - return False - - count += 1 - if count > limit: # too many msgs, kick - CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit) - return True + if limit == 0: # no antiflood + return False - # default -> update - CHAT_FLOOD[str(chat_id)] = (user_id, count, limit) + if user_id != curr_user_id or user_id is None: # other user + CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT + 1, limit) return False + count += 1 + if count > limit: # too many msgs, kick + CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit) + return True + + # default -> update + CHAT_FLOOD[str(chat_id)] = (user_id, count, limit) + return False + def get_flood_limit(chat_id): return CHAT_FLOOD.get(str(chat_id), DEF_OBJ)[2] diff --git a/sql_helpers/lydia_ai_sql.py b/sql_helpers/lydia_ai_sql.py deleted file mode 100644 index de4b501e38..0000000000 --- a/sql_helpers/lydia_ai_sql.py +++ /dev/null @@ -1,74 +0,0 @@ -from sqlalchemy import Column, UnicodeText, LargeBinary, Numeric -from sql_helpers import SESSION, BASE - - -class LydiaAI(BASE): - __tablename__ = "lydia_ai" - user_id = Column(Numeric, primary_key=True) - chat_id = Column(Numeric, primary_key=True) - session_id = Column(UnicodeText) - session_expires = Column(Numeric) - - def __init__( - self, - user_id, - chat_id, - session_id, - session_expires - ): - self.user_id = user_id - self.chat_id = chat_id - self.session_id = session_id - self.session_expires = session_expires - - -LydiaAI.__table__.create(checkfirst=True) - - -def get_s(user_id, chat_id): - try: - return SESSION.query(LydiaAI).get((user_id, chat_id)) - except: - return None - finally: - SESSION.close() - - -def get_all_s(): - try: - return SESSION.query(LydiaAI).all() - except: - return None - finally: - SESSION.close() - - -def add_s( - user_id, - chat_id, - session_id, - session_expires -): - adder = SESSION.query(LydiaAI).get((user_id, chat_id)) - if adder: - adder.session_id = session_id - adder.session_expires = session_expires - else: - adder = LydiaAI( - user_id, - chat_id, - session_id, - session_expires - ) - SESSION.add(adder) - SESSION.commit() - - -def remove_s( - user_id, - chat_id -): - note = SESSION.query(LydiaAI).get((user_id, chat_id)) - if note: - SESSION.delete(note) - SESSION.commit() diff --git a/sql_helpers/no_log_pms_sql.py b/sql_helpers/no_log_pms_sql.py deleted file mode 100644 index 682ed5c407..0000000000 --- a/sql_helpers/no_log_pms_sql.py +++ /dev/null @@ -1,35 +0,0 @@ -from sqlalchemy import Column, String, Numeric -from sql_helpers import SESSION, BASE - - -class NOLogPMs(BASE): - __tablename__ = "no_log_pms" - chat_id = Column(Numeric, primary_key=True) - - def __init__(self, chat_id, reason=""): - self.chat_id = chat_id - - -NOLogPMs.__table__.create(checkfirst=True) - - -def is_approved(chat_id): - try: - return SESSION.query(NOLogPMs).filter(NOLogPMs.chat_id == chat_id).one() - except: - return None - finally: - SESSION.close() - - -def approve(chat_id): - adder = NOLogPMs(chat_id) - SESSION.add(adder) - SESSION.commit() - - -def disapprove(chat_id): - rem = SESSION.query(NOLogPMs).get(chat_id) - if rem: - SESSION.delete(rem) - SESSION.commit() diff --git a/sql_helpers/pmpermit_sql.py b/sql_helpers/pmpermit_sql.py deleted file mode 100644 index 3aaab43935..0000000000 --- a/sql_helpers/pmpermit_sql.py +++ /dev/null @@ -1,43 +0,0 @@ -from sqlalchemy import Column, String -from sql_helpers import SESSION, BASE - - -class PMPermit(BASE): - __tablename__ = "pmpermit" - chat_id = Column(String(14), primary_key=True) - reason = Column(String(127)) - - def __init__(self, chat_id, reason=""): - self.chat_id = chat_id - self.reason = reason - - -PMPermit.__table__.create(checkfirst=True) - - -def is_approved(chat_id): - try: - return SESSION.query(PMPermit).filter(PMPermit.chat_id == str(chat_id)).one() - except: - return None - finally: - SESSION.close() - - -def approve(chat_id, reason): - adder = PMPermit(str(chat_id), str(reason)) - SESSION.add(adder) - SESSION.commit() - - -def disapprove(chat_id): - rem = SESSION.query(PMPermit).get(str(chat_id)) - if rem: - SESSION.delete(rem) - SESSION.commit() - - -def get_all_approved(): - rem = SESSION.query(PMPermit).all() - SESSION.close() - return rem diff --git a/stdborg.py b/stdborg.py deleted file mode 100644 index 859ed4e8ff..0000000000 --- a/stdborg.py +++ /dev/null @@ -1,67 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import logging -import os -import sys -from pathlib import Path -from uniborg import Uniborg -from uniborg.storage import Storage -from telethon.sessions import StringSession - - -logging.basicConfig(level=logging.INFO) - -# the secret configuration specific things -ENV = bool(os.environ.get("ENV", False)) -if ENV: - from sample_config import Config -else: - if os.path.exists("config.py"): - from config import Development as Config - else: - logging.warning("No config.py Found!") - logging.info("Please run the command, again, after creating config.py similar to README.md") - sys.exit(1) - - -if Config.DB_URI is None: - logging.warning("No DB_URI Found!") - - -if len(Config.SUDO_USERS) >= 0: - Config.SUDO_USERS.add("me") - - -if Config.HU_STRING_SESSION is not None: - # for Running on Heroku - session_name = str(Config.HU_STRING_SESSION) - borg = Uniborg( - StringSession(session_name), - n_plugin_path="stdplugins/", - db_plugin_path="dbplugins/", - api_config=Config, - api_id=Config.APP_ID, - api_hash=Config.API_HASH - ) - borg.run_until_disconnected() -elif len(sys.argv) == 2: - # for running on GNU/Linux - session_name = str(sys.argv[1]) - borg = Uniborg( - session_name, - n_plugin_path="stdplugins/", - db_plugin_path="dbplugins/", - connection_retries=None, - api_config=Config, - api_id=Config.APP_ID, - api_hash=Config.API_HASH - ) - borg.run_until_disconnected() -else: - # throw error - logging.error("USAGE EXAMPLE:\n" - "python3 -m stdborg " - "\n 👆👆 Please follow the above format to run your userbot." - "\n Bot quitting.") diff --git a/stdplugins/_help.py b/stdplugins/_help.py index c791ad2d25..9123747f6e 100644 --- a/stdplugins/_help.py +++ b/stdplugins/_help.py @@ -9,13 +9,13 @@ ◆ `.syntax` """ - +import shutil import sys +import time from telethon import events, functions, __version__ -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="helpme ?(.*)", allow_sudo=True)) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="helpme ?(.*)", allow_sudo=True)) # pylint:disable=E0602 async def _(event): if event.fwd_from: return @@ -24,49 +24,68 @@ async def _(event): s_help_string = borg._plugins[splugin_name].__doc__ else: s_help_string = "" - help_string = """@UniBorg -Python {} -Telethon {} -UserBot Forked from https://github.com/expectocode/uniborg""".format( - sys.version, - __version__ - ) - tgbotusername = Config.TG_BOT_USER_NAME_BF_HER # pylint:disable=E0602 - if tgbotusername is not None: + _, check_sgnirts = check_data_base_heal_th() + + current_run_time = slitu.time_formatter((time.time() - BOT_START_TIME)) + total, used, free = shutil.disk_usage("/") + total = slitu.humanbytes(total) + used = slitu.humanbytes(used) + free = slitu.humanbytes(free) + + help_string = "@UniBorg\n" + help_string += f"✅ UpTime {current_run_time}\n" + help_string += f"✅ Python {sys.version}\n" + help_string += f"✅ Telethon {__version__}\n" + help_string += f"{check_sgnirts} Database\n" + help_string += f"Total Disk Space: {total}\n" + help_string += f"Used Disk Space: {used}\n" + help_string += f"Free Disk Space: {free}\n\n" + help_string += f"UserBot Forked from https://github.com/udf/uniborg" + borg._iiqsixfourstore[str(event.chat_id)] = {} + borg._iiqsixfourstore[ + str(event.chat_id) + ][ + str(event.id) + ] = help_string + "\n\n" + s_help_string + if borg.tgbot: + tgbot_username = await tgbot.get_me() results = await borg.inline_query( # pylint:disable=E0602 - tgbotusername, - help_string + "\n\n" + s_help_string + tgbot_username, + f"@UniBorg {event.chat_id} {event.id}" ) await results[0].click( event.chat_id, reply_to=event.reply_to_msg_id, hide_via=True ) - await event.delete() else: - await event.reply(help_string + "\n\n" + s_help_string) - await event.delete() + await event.reply( + help_string + "\n\n" + s_help_string, + parse_mode="html" + ) + + await event.delete() -@borg.on(admin_cmd(pattern="dc")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="dc")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return - result = await borg(functions.help.GetNearestDcRequest()) # pylint:disable=E0602 + result = await event.client(functions.help.GetNearestDcRequest()) await event.edit(result.stringify()) -@borg.on(admin_cmd(pattern="config")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="config")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return - result = await borg(functions.help.GetConfigRequest()) # pylint:disable=E0602 + result = await event.client(functions.help.GetConfigRequest()) # pylint:disable=E0602 result = result.stringify() logger.info(result) # pylint:disable=E0602 await event.edit("""Telethon UserBot powered by @UniBorg""") -@borg.on(admin_cmd(pattern="syntax (.*)")) +@borg.on(slitu.admin_cmd(pattern="syntax (.*)")) async def _(event): if event.fwd_from: return @@ -81,3 +100,48 @@ async def _(event): else: plugin_syntax = "Enter valid **Plugin** name.\nDo `.exec ls stdplugins` or `.helpme` to get list of valid plugin names." await event.edit(plugin_syntax) + + +""" h +t +t UniBorg Telegram UseRBot +p Copyright (C) 2020 @UniBorg +s +: This code is licensed under +/ +/ +g the "you can't use this for anything - public or private, +i unless you know the two prime factors to the number below" license +t +. 543935563961418342898620676239017231876605452284544942043082635399903451854594062955 +to +g വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ +r ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! +and +. +xyz +/ +uniborg +/ +uniborg""" +def check_data_base_heal_th(): + # https://stackoverflow.com/a/41961968 + is_database_working = False + output = "❌" + + if not Config.DB_URI: + return is_database_working, output + + from sql_helpers import SESSION + + try: + # to check database we will execute raw query + SESSION.execute("SELECT 1") + except Exception as e: + output = f"❌ {str(e)}" + is_database_working = False + else: + output = "✅" + is_database_working = True + + return is_database_working, output diff --git a/stdplugins/account_profile.py b/stdplugins/account_profile.py index 63da16a885..0554e294da 100644 --- a/stdplugins/account_profile.py +++ b/stdplugins/account_profile.py @@ -5,10 +5,9 @@ import os from telethon import events from telethon.tl import functions -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="pbio (.*)")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="pbio (.*)")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return @@ -22,7 +21,7 @@ async def _(event): await event.edit(str(e)) -@borg.on(admin_cmd(pattern="pname ((.|\n)*)")) # pylint:disable=E0602,W0703 +@borg.on(slitu.admin_cmd(pattern="pname ((.|\n)*)")) # pylint:disable=E0602,W0703 async def _(event): if event.fwd_from: return @@ -41,7 +40,7 @@ async def _(event): await event.edit(str(e)) -@borg.on(admin_cmd(pattern="ppic")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="ppic")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return diff --git a/stdplugins/dart_n_dice.py b/stdplugins/animated_mini_games.py similarity index 76% rename from stdplugins/dart_n_dice.py rename to stdplugins/animated_mini_games.py index 4e5630e06f..942cc47009 100644 --- a/stdplugins/dart_n_dice.py +++ b/stdplugins/animated_mini_games.py @@ -1,21 +1,28 @@ """@RollADie and @AnimatedDart Viewer and Executor discretion is advised, while executing / running any parts of the code -Nobody is reponsible for your account, +Nobody is reponsible for your account, Your account might get banned for offensive use of this script, The below script is only intended for "fun" and "entertainment" and please read https://t.me/UniBorg/39 before proceeding to run this!""" from telethon.tl.types import InputMediaDice -from uniborg.util import admin_cmd # EMOJI CONSTANTS DART_E_MOJI = "🎯" DICE_E_MOJI = "🎲" BALL_E_MOJI = "🏀" +FOOT_E_MOJI = "⚽" +SLOT_M_MOJI = "🎰" +BAII_E_MOJI = "🎳" # EMOJI CONSTANTS +#TODO: get emojies from AppConfig ? :\\ -@borg.on(admin_cmd(pattern=f"({DART_E_MOJI}|{DICE_E_MOJI}|{BALL_E_MOJI}) ?(.*)")) + + +@borg.on(slitu.admin_cmd( + pattern=f"({DART_E_MOJI}|{DICE_E_MOJI}|{BALL_E_MOJI}|{FOOT_E_MOJI}|{SLOT_M_MOJI}|{BAII_E_MOJI}) ?(.*)") +) async def _(event): if event.fwd_from: return @@ -29,7 +36,7 @@ async def _(event): if input_str: try: required_number = int(input_str) - while not r.media.value == required_number: + while r.media.value != required_number: await r.delete() r = await reply_message.reply(file=InputMediaDice(emoticon=emoticon)) except: diff --git a/stdplugins/aria_two.py b/stdplugins/aria_two.py deleted file mode 100644 index cf76bfee2f..0000000000 --- a/stdplugins/aria_two.py +++ /dev/null @@ -1,231 +0,0 @@ -"""A Torrent Client Plugin Based On Aria2 for Userbot - -cmds: Magnet link : .magnet magnetLink - Torrent file from local: .tor file_path - Show Downloads: .show - Remove All Downloads: .ariaRM - Resume All Downloads: .ariaResume - Pause All Downloads: .ariaP - -By:- @Zero_cool7870""" -import aria2p -import asyncio -import io -import os -from uniborg.util import admin_cmd - - -EDIT_SLEEP_TIME_OUT = 15 -# The port that RPC will listen on -ARIA2_STARTED_PORT = 6800 -aria2 = None - - -@borg.on(admin_cmd(pattern="ariastart")) -async def aria_start(event): - aria2_daemon_start_cmd = [] - # start the daemon, aria2c command - aria2_daemon_start_cmd.append("aria2c") - aria2_daemon_start_cmd.append("--allow-overwrite=true") - aria2_daemon_start_cmd.append("--daemon=true") - # aria2_daemon_start_cmd.append(f"--dir={Config.TMP_DOWNLOAD_DIRECTORY}") - # TODO: this does not work, need to investigate this. - # but for now, https://t.me/TrollVoiceBot?start=858 - aria2_daemon_start_cmd.append("--enable-rpc") - aria2_daemon_start_cmd.append("--follow-torrent=mem") - aria2_daemon_start_cmd.append("--max-connection-per-server=10") - aria2_daemon_start_cmd.append("--min-split-size=10M") - aria2_daemon_start_cmd.append("--rpc-listen-all=false") - aria2_daemon_start_cmd.append(f"--rpc-listen-port={ARIA2_STARTED_PORT}") - aria2_daemon_start_cmd.append("--rpc-max-request-size=1024M") - aria2_daemon_start_cmd.append("--seed-ratio=100.0") - aria2_daemon_start_cmd.append("--seed-time=1") - aria2_daemon_start_cmd.append("--split=10") - # - process = await asyncio.create_subprocess_exec( - *aria2_daemon_start_cmd, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await process.communicate() - logger.info(stdout) - logger.info(stderr) - global aria2 - aria2 = aria2p.API( - aria2p.Client( - host="http://localhost", - port=ARIA2_STARTED_PORT, - secret="" - ) - ) - OUTPUT = f"**ARIA TWO C:**\n__PID:__\n`{process.pid}`\n\n**ARIA TWO STARTED**" - await event.edit(OUTPUT) - - -@borg.on(admin_cmd(pattern="addmagnet")) -async def magnet_download(event): - if event.fwd_from: - return - if not aria2: - await event.edit("Please start process using `ariastart`") - return False - var = event.raw_text - var = var.split(" ") - magnet_uri = var[1] - logger.info(magnet_uri) - # Add Magnet URI Into Queue - try: - download = aria2.add_magnet(magnet_uri) - except Exception as e: - logger.info(str(e)) - await event.edit("Error:\n`" + str(e) + "`") - return - gid = download.gid - await check_progress_for_dl(gid, event) - await asyncio.sleep(EDIT_SLEEP_TIME_OUT) - new_gid = await check_metadata(gid) - await check_progress_for_dl(new_gid, event) - - -@borg.on(admin_cmd(pattern="addtorrent")) -async def torrent_download(event): - if event.fwd_from: - return - if not aria2: - await event.edit("Please start process using `ariastart`") - return False - var = event.raw_text - var = var.split(" ") - torrent_file_path = var[1] - logger.info(torrent_file_path) - # Add Torrent Into Queue - try: - download = aria2.add_torrent( - torrent_file_path, - uris=None, - options=None, - position=None - ) - except Exception as e: - await event.edit(str(e)) - return - gid = download.gid - await check_progress_for_dl(gid, event) - - -@borg.on(admin_cmd(pattern="addurl")) -async def magnet_download(event): - if event.fwd_from: - return - var = event.raw_text - var = var.split(" ") - url = var[1] - logger.info(url) - uris = [url] - # Add URL Into Queue - try: - download = aria2.add_uris(uris, options=None, position=None) - except Exception as e: - await event.edit("`Error:\n`" + str(e)) - return - gid = download.gid - await check_progress_for_dl(gid, event) - - -@borg.on(admin_cmd(pattern="ariaRM")) -async def remove_all(event): - if event.fwd_from: - return - try: - removed = aria2.remove_all(force=True) - aria2.purge_all() - except: - pass - if removed == False: # If API returns False Try to Remove Through System Call. - os.system("aria2p remove-all") - await event.edit("`Removed All Downloads.`") - - -@borg.on(admin_cmd(pattern="ariaP")) -async def pause_all(event): - if event.fwd_from: - return - # Pause ALL Currently Running Downloads. - paused = aria2.pause_all(force=True) - await event.edit("Output: " + str(paused)) - - -@borg.on(admin_cmd(pattern="ariaResume")) -async def resume_all(event): - if event.fwd_from: - return - resumed = aria2.resume_all() - await event.edit("Output: " + str(resumed)) - - -@borg.on(admin_cmd(pattern="showariastatus")) -async def show_all(event): - if event.fwd_from: - return - if not aria2: - await event.edit("Please start process using `ariastart`") - return False - # Show All Downloads - downloads = aria2.get_downloads() - msg = "" - for download in downloads: - msg = msg + "File: `" + str(download.name) + "`\nSpeed: " + str(download.download_speed_string()) + "\nProgress: " + str(download.progress_string( - )) + "\nTotal Size: " + str(download.total_length_string()) + "\nStatus: " + str(download.status) + "\nETA: " + str(download.eta_string()) + "\n\n" - # print(msg) - if len(msg) <= Config.MAX_MESSAGE_SIZE_LIMIT: - await event.edit("`Current Downloads: `\n" + msg) - else: - with io.BytesIO(str.encode(msg)) as out_file: - out_file.name = "ariastatus.txt" - await borg.send_file( - event.chat_id, - out_file, - force_document=True, - allow_cache=False, - caption="`Output is huge. Sending as a file...`" - ) - await event.delete() - - -async def check_metadata(gid): - file = aria2.get_download(gid) - new_gid = file.followed_by_ids[0] - logger.info("Changing GID " + gid + " to " + new_gid) - return new_gid - - -async def check_progress_for_dl(gid, event): - complete = None - previous_message = None - while not complete: - file = aria2.get_download(gid) - complete = file.is_complete - try: - if not file.error_message: - msg = f"\nDownloading File: `{file.name}`" - msg += f"\nSpeed: {file.download_speed_string()} 🔽 / {file.upload_speed_string()} 🔼" - msg += f"\nProgress: {file.progress_string()}" - msg += f"\nTotal Size: {file.total_length_string()}" - msg += f"\nStatus: {file.status}" - msg += f"\nETA: {file.eta_string()}" - if msg != previous_message: - await event.edit(msg) - previous_message = msg - await asyncio.sleep(EDIT_SLEEP_TIME_OUT) - else: - msg = file.error_message - await event.edit(f"`{msg}`") - return False - except Exception as e: - logger.info(str(e)) - pass - file = aria2.get_download(gid) - complete = file.is_complete - if complete: - await event.edit(f"File Downloaded Successfully:`{file.name}`") - diff --git a/stdplugins/barcode.py b/stdplugins/barcode.py index 50050238f6..c0d68eb45a 100644 --- a/stdplugins/barcode.py +++ b/stdplugins/barcode.py @@ -9,10 +9,9 @@ import time from barcode.writer import ImageWriter from datetime import datetime -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="barcode ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="barcode ?(.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/calendar.py b/stdplugins/calendar.py index c431ff0260..355f5a325b 100644 --- a/stdplugins/calendar.py +++ b/stdplugins/calendar.py @@ -5,10 +5,9 @@ from datetime import datetime import requests import json -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="calendar (.*)")) +@borg.on(slitu.admin_cmd(pattern="calendar (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/call_admin.py b/stdplugins/call_admin.py index 5636c1d1a5..dab5461240 100644 --- a/stdplugins/call_admin.py +++ b/stdplugins/call_admin.py @@ -1,18 +1,17 @@ """.admin Plugin for @UniBorg""" import asyncio -from telethon import events from telethon.tl.types import ChannelParticipantsAdmins -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="admin")) +@borg.on(slitu.admin_cmd(pattern="admin")) async def _(event): if event.fwd_from: return mentions = "@admin: **Spam Spotted**" chat = await event.get_input_chat() - async for x in borg.iter_participants(chat, filter=ChannelParticipantsAdmins): - mentions += f"[\u2063](tg://user?id={x.id})" + async for x in event.client.iter_participants(chat, filter=ChannelParticipantsAdmins): + if not x.bot: + mentions += f"[\u2063](tg://user?id={x.id})" reply_message = None if event.reply_to_msg_id: reply_message = await event.get_reply_message() diff --git a/stdplugins/chat_file_s_count_er.py b/stdplugins/chat_file_s_count_er.py new file mode 100644 index 0000000000..cf6c946f2e --- /dev/null +++ b/stdplugins/chat_file_s_count_er.py @@ -0,0 +1,35 @@ +"""Count Number of Files in a Chat +Original Module Credits: https://t.me/UniBorg/127""" + + +@borg.on(slitu.admin_cmd(pattern="conftc ?(.*)")) +async def _(event): + if event.fwd_from: + return + entity = event.chat_id + input_str = event.pattern_match.group(1) + if input_str: + entity = input_str + status_message = await event.reply( + "... this might take some time " + "depending on the number of messages " + "in the chat ..." + ) + mus = 0 + hmm = {} + async for message in event.client.iter_messages( + entity=entity, + limit=None + ): + if message and message.file: + if message.file.mime_type not in hmm: + hmm[message.file.mime_type] = 0 + hmm[message.file.mime_type] += message.file.size + hnm = {} + for key in hmm: + hnm[key] = slitu.humanbytes(hmm[key]) + await status_message.edit( + slitu.yaml_format(hnm), + parse_mode=slitu.parse_pre + ) + diff --git a/stdplugins/checkrestrictionsbot.py b/stdplugins/checkrestrictionsbot.py new file mode 100644 index 0000000000..ec5140d3e0 --- /dev/null +++ b/stdplugins/checkrestrictionsbot.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -* +# (c) Shrimadhav U K + +"""Check Account Restrictions +.cars (.*)""" +from telethon.tl.types import ( + Channel, + Chat, + User +) + + +@borg.on(slitu.admin_cmd(pattern="cars (.*)")) +async def _(event): + if event.fwd_from: + return + input_str = event.pattern_match.group(1) + try: + input_entity = await event.client.get_entity( + input_str + ) + except Exception as e: + await event.edit( + "😳😳😳😐" + ) + return + else: + await event.edit(get_restriction_string(input_entity)) + + +def get_restriction_string(a) -> str: + # logger.info(a.stringify()) + b = "" + c = "" + if isinstance(a, Channel): + c = f"[{a.title}](https://t.me/c/{a.id}/{2})" + elif isinstance(a, User): + c = f"[{a.first_name}](tg://user?id={a.id})" + elif isinstance(a, Chat): + c = f"{a.title}" + b = f"{c}: __basic groups do not have restriction in Telegram__, **to the best of our knowledge**" + return b + else: + c = "something wnorgings while checking restriction_reason 😒😒" + if a.restriction_reason is None or len(a.restriction_reason) == 0: + b = f"{c}: **Good News**! No Limitations are currently applied to this Group / Channel / Bot" + else: + tmp_string = f"{c} has the following restriction_reason(s): \n" + for a_r in a.restriction_reason: + tmp_string += f"👉 {a_r.reason}-{a_r.platform}: {a_r.text}\n\n" + b = tmp_string + # b += "\n\n" + Translation.POWERED_BY_SE + return b diff --git a/stdplugins/coinflip.py b/stdplugins/coinflip.py index 74adefcf30..6c7980f1c8 100644 --- a/stdplugins/coinflip.py +++ b/stdplugins/coinflip.py @@ -1,11 +1,9 @@ """CoinFlip for @UniBorg Syntax: .coinflip [optional_choice]""" -from telethon import events import random, re -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="coinflip ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="coinflip ?(.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/colors.py b/stdplugins/colors.py index 1efc3b372e..a7061d011c 100644 --- a/stdplugins/colors.py +++ b/stdplugins/colors.py @@ -1,12 +1,10 @@ """Color Plugin for @UniBorg Syntax: .color """ -from telethon import events import os from PIL import Image, ImageColor -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="color (.*)")) +@borg.on(slitu.admin_cmd(pattern="color (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/count.py b/stdplugins/count.py index 65ed6740f1..eee3bccef7 100644 --- a/stdplugins/count.py +++ b/stdplugins/count.py @@ -1,43 +1,104 @@ -"""Count the Number of Dialogs you have in your Telegram Account -Syntax: .count""" -from telethon import events -import asyncio -from datetime import datetime -from telethon.tl.types import User, Chat, Channel -from uniborg.util import admin_cmd - - -@borg.on(admin_cmd(pattern="count")) -async def _(event): - if event.fwd_from: - return - start = datetime.now() - u = 0 # number of users - g = 0 # number of basic groups - c = 0 # number of super groups - bc = 0 # number of channels - b = 0 # number of bots - await event.edit("Retrieving Telegram Count(s)") - async for d in borg.iter_dialogs(limit=None): - if d.is_user: - if d.entity.bot: - b += 1 - else: - u += 1 - elif d.is_channel: - if d.entity.broadcast: - bc += 1 - else: - c += 1 - elif d.is_group: - g += 1 - else: - logger.info(d.stringify()) - end = datetime.now() - ms = (end - start).seconds - await event.edit("""Obtained in {} seconds. -Users:\t{} -Groups:\t{} -Super Groups:\t{} -Channels:\t{} -Bots:\t{}""".format(ms, u, g, c, bc, b)) +# the entire code is verbatim copied +# from https://github.com/mojurasu/kantek/raw/develop/kantek/plugins/private/stats.py +# there are changes made by "me" to suit the needs of this repository + +import time +from telethon.events import NewMessage +from telethon.tl.custom import Dialog +from telethon.tl.types import Channel, User, Chat + +"""Type `.count` and see Magic.""" + +@borg.on(slitu.admin_cmd(pattern='count')) +async def stats(event: NewMessage.Event) -> None: # pylint: disable = R0912, R0914, R0915 + """Command to get stats about the account""" + waiting_message = await event.edit('`Collecting stats, Wait Nibba`') + start_time = time.time() + private_chats = 0 + bots = 0 + groups = 0 + broadcast_channels = 0 + admin_in_groups = 0 + creator_in_groups = 0 + admin_in_broadcast_channels = 0 + creator_in_channels = 0 + unread_mentions = 0 + unread = 0 + largest_group_member_count = 0 + largest_group_with_admin = 0 + dialog: Dialog + async for dialog in event.client.iter_dialogs(): + entity = dialog.entity + + if isinstance(entity, Channel): + # participants_count = (await event.get_participants(dialog, limit=0)).total + if entity.broadcast: + broadcast_channels += 1 + if entity.creator or entity.admin_rights: + admin_in_broadcast_channels += 1 + if entity.creator: + creator_in_channels += 1 + + elif entity.megagroup: + groups += 1 + # if participants_count > largest_group_member_count: + # largest_group_member_count = participants_count + if entity.creator or entity.admin_rights: + # if participants_count > largest_group_with_admin: + # largest_group_with_admin = participants_count + admin_in_groups += 1 + if entity.creator: + creator_in_groups += 1 + + elif isinstance(entity, User): + private_chats += 1 + if entity.bot: + bots += 1 + + elif isinstance(entity, Chat): + groups += 1 + if entity.creator or entity.admin_rights: + admin_in_groups += 1 + if entity.creator: + creator_in_groups += 1 + + unread_mentions += dialog.unread_mentions_count + unread += dialog.unread_count + stop_time = time.time() - start_time + + full_name = inline_mention(await event.client.get_me()) + response = f'🔸 **Stats for {full_name}** \n\n' + response += f'**Private Chats:** {private_chats} \n' + response += f' •`Users: {private_chats - bots}` \n' + response += f' •`Bots: {bots}` \n' + response += f'**Groups:** {groups} \n' + response += f'**Channels:** {broadcast_channels} \n' + response += f'**Admin in Groups:** {admin_in_groups} \n' + response += f' •`Creator: {creator_in_groups}` \n' + response += f' •`Admin Rights: {admin_in_groups - creator_in_groups}` \n' + response += f'**Admin in Channels:** {admin_in_broadcast_channels} \n' + response += f' •`Creator: {creator_in_channels}` \n' + response += f' •`Admin Rights: {admin_in_broadcast_channels - creator_in_channels}` \n' + response += f'**Unread:** {unread} \n' + response += f'**Unread Mentions:** {unread_mentions} \n\n' + response += f'__It Took:__ {stop_time:.02f}s \n' + + await event.edit(response) + + +def make_mention(user): + if user.username: + return f"@{user.username}" + else: + return inline_mention(user) + + +def inline_mention(user): + full_name = user_full_name(user) or "No Name" + return f"[{full_name}](tg://user?id={user.id})" + + +def user_full_name(user): + names = [user.first_name, user.last_name] + names = [i for i in list(names) if i] + return ' '.join(names) diff --git a/stdplugins/create_private_group.py b/stdplugins/create_private_group.py index a5c4a0b3e9..bf50b2929e 100644 --- a/stdplugins/create_private_group.py +++ b/stdplugins/create_private_group.py @@ -2,10 +2,9 @@ Available Commands: .create (b|g) GroupName""" from telethon.tl import functions, types -from uniborg import util -@borg.on(util.admin_cmd(pattern="create (b|g|c) (.*)")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="create (b|g|c) (.*)")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return @@ -13,32 +12,35 @@ async def _(event): group_name = event.pattern_match.group(2) if type_of_group == "b": try: - result = await borg(functions.messages.CreateChatRequest( # pylint:disable=E0602 + result = await event.client(functions.messages.CreateChatRequest( users=["@GoogleIMGBot"], # Not enough users (to create a chat, for example) # Telegram, no longer allows creating a chat with ourselves title=group_name )) created_chat_id = result.chats[0].id - await borg(functions.messages.DeleteChatUserRequest( + await event.client(functions.messages.DeleteChatUserRequest( chat_id=created_chat_id, user_id="@GoogleIMGBot" )) - result = await borg(functions.messages.ExportChatInviteRequest( + result = await event.client(functions.messages.ExportChatInviteRequest( peer=created_chat_id, )) await event.edit("Group `{}` created successfully. Join {}".format(group_name, result.link)) except Exception as e: # pylint:disable=C0103,W0703 await event.edit(str(e)) - elif type_of_group == "g" or type_of_group == "c": + elif type_of_group in ["g", "c"]: try: - r = await borg(functions.channels.CreateChannelRequest( # pylint:disable=E0602 - title=group_name, - about="This is a Test from @UniBorg", - megagroup=False if type_of_group == "c" else True - )) + r = await event.client( + functions.channels.CreateChannelRequest( + title=group_name, + about="This is a Test from @UniBorg", + megagroup=type_of_group != "c", + ) + ) + created_chat_id = r.chats[0].id - result = await borg(functions.messages.ExportChatInviteRequest( + result = await event.client(functions.messages.ExportChatInviteRequest( peer=created_chat_id, )) await event.edit("Channel `{}` created successfully. Join {}".format(group_name, result.link)) diff --git a/stdplugins/currency.py b/stdplugins/currency.py index d1bcd8de33..8b4c112f38 100644 --- a/stdplugins/currency.py +++ b/stdplugins/currency.py @@ -4,10 +4,9 @@ import asyncio from datetime import datetime import requests -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="currency (.*)")) +@borg.on(slitu.admin_cmd(pattern="currency (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/dagd.py b/stdplugins/dagd.py index 4cfbd640eb..79395824db 100644 --- a/stdplugins/dagd.py +++ b/stdplugins/dagd.py @@ -8,10 +8,9 @@ import os import requests import json -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="dns (.*)")) +@borg.on(slitu.admin_cmd(pattern="dns (.*)")) async def _(event): if event.fwd_from: return @@ -24,7 +23,7 @@ async def _(event): await event.edit("i can't seem to find {} on the internet".format(input_str)) -@borg.on(admin_cmd(pattern="url (.*)")) +@borg.on(slitu.admin_cmd(pattern="url (.*)")) async def _(event): if event.fwd_from: return @@ -37,7 +36,7 @@ async def _(event): await event.edit("something is wrong. please try again later.") -@borg.on(admin_cmd(pattern="unshort (.*)")) +@borg.on(slitu.admin_cmd(pattern="unshort (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/daolnwod.py b/stdplugins/daolnwod.py new file mode 100644 index 0000000000..d7bd635529 --- /dev/null +++ b/stdplugins/daolnwod.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# UniBorg Telegram UseRBot +# Copyright (C) 2021 @UniBorg +# +# This code is licensed under +# the "you can't use this for anything - public or private, +# unless you kill yourself" license +# +# വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! + +import asyncio +import os +from datetime import datetime +from telethon.errors import ChannelPrivateError +from time import time + + +@borg.on(slitu.admin_cmd(pattern="lfcn", allow_sudo=True)) +async def _e(evt): + sm_ = await slitu.edit_or_reply(evt, "...") + if not evt.reply_to_msg_id: + await sm_.edit("NO_REPLY_MSG_FOUND") + return + reply = await evt.get_reply_message() + _c, m_ = slitu.get_c_m_message(reply.raw_text) + try: + _ok_m_ = await evt.client.get_messages( + entity=_c, + ids=m_ + ) + except ChannelPrivateError: + await sm_.edit("LINK_MARKUP_ID_INVALID") + return + if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): + os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) + c_time = time() + start = datetime.now() + downloaded_file_name = await _ok_m_.download_media( + Config.TMP_DOWNLOAD_DIRECTORY, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + slitu.progress(d, t, sm_, c_time, "trying to download") + ) + ) + end = datetime.now() + ms = (end - start).seconds + await sm_.edit("Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms)) diff --git a/stdplugins/decide.py b/stdplugins/decide.py index 0bee3e4085..aaca71e285 100644 --- a/stdplugins/decide.py +++ b/stdplugins/decide.py @@ -1,11 +1,9 @@ """Quickly make a decision Syntax: .decide""" -from telethon import events import requests -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="decide")) +@borg.on(slitu.admin_cmd(pattern="decide")) async def _(event): if event.fwd_from: return @@ -20,3 +18,4 @@ async def _(event): file=r["image"] ) await event.delete() + diff --git a/stdplugins/dmcatelegrambot.py b/stdplugins/dmcatelegrambot.py new file mode 100644 index 0000000000..8d194fd3e0 --- /dev/null +++ b/stdplugins/dmcatelegrambot.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -* +# (c) Shrimadhav U K + +"""Delete Messages from Links +.dmcadel""" + +import asyncio +from typing import List, Union +from telethon.tl.types import MessageEntityUrl + + +@borg.on(slitu.admin_cmd(pattern="dmcadel")) +async def _(event): + if event.fwd_from: + return + s_m__ = await event.reply( + ". . ." + ) + if event.reply_to_msg_id: + t_a = dict() + reply = await event.get_reply_message() + for entity in reply.entities: + if isinstance(entity, MessageEntityUrl): + offset = entity.offset + length = entity.length + recvd_input = reply[offset: offset + length] + chat_id, message_id = extract_ids(recvd_input) + if chat_id not in t_a: + t_a[chat_id] = [] + t_a[chat_id].append(message_id) + if len(t_a[chat_id]) >= 100: + await do_delete_NOQA(event.client, t_a[chat_id], chat_id) + t_a[chat_id] = [] + for chat in t_a: + m_di = t_a[chat] + if len(m_di) > 0: + await do_delete_NOQA(event.client, m_di, chat) + t_a[chat] = [] + await s_m__.edit( + Config.DMCA_TG_REPLY_MESSAGE + ) + else: + await s_m__.edit( + "if I don't know how to use this, I should not use this" + ) + await event.delete() + + +def extract_ids(input_link: str) -> (Union[str, int], int): + chat_id = None + message_id = 0 + link_parts = input_link.split("/") + if "https://t.me/c/" in input_link: + link_username = "-100" + link_parts[4] + chat_id = int(link_username) + message_id = int(link_parts[5]) + elif "https://t.me/" in input_link: + link_username = "@" + link_parts[3] + chat_id = link_username + message_id = int(link_parts[4]) + else: + logger.info("unknown condition reached") + return chat_id, message_id + + +async def do_delete_NOQA(client, message_list: List[int], chat_id: Union[str, int]): + await client.delete_messages( + entity=chat_id, + message_ids=message_list, + revoke=True + ) + await asyncio.sleep(Config.DEL_SLEEP_TIMEOUT) diff --git a/stdplugins/download.py b/stdplugins/download.py index 153cad8acd..4ffff5b380 100644 --- a/stdplugins/download.py +++ b/stdplugins/download.py @@ -12,10 +12,9 @@ from pySmartDL import SmartDL from telethon import events from telethon.tl.types import DocumentAttributeVideo -from uniborg.util import admin_cmd, humanbytes, progress, time_formatter -@borg.on(admin_cmd(pattern="download ?(.*)", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="download ?(.*)", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -28,11 +27,11 @@ async def _(event): reply_message = await event.get_reply_message() try: c_time = time.time() - downloaded_file_name = await borg.download_media( + downloaded_file_name = await event.client.download_media( reply_message, Config.TMP_DOWNLOAD_DIRECTORY, progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, mone, c_time, "trying to download") + slitu.progress(d, t, mone, c_time, "trying to download") ) ) except Exception as e: # pylint:disable=C0103,W0703 @@ -47,7 +46,7 @@ async def _(event): file_name = os.path.basename(url) to_download_directory = Config.TMP_DOWNLOAD_DIRECTORY if "|" in input_str: - url, file_name = input_str.split("|") + url, file_name = input_str.split("|", maxsplit = 1) url = url.strip() file_name = file_name.strip() downloaded_file_name = os.path.join(to_download_directory, file_name) @@ -64,17 +63,18 @@ async def _(event): speed = downloader.get_speed() elapsed_time = round(diff) * 1000 progress_str = "[{0}{1}]\nProgress: {2}%".format( - ''.join(["█" for i in range(math.floor(percentage / 5))]), - ''.join(["░" for i in range(20 - math.floor(percentage / 5))]), + ''.join("█" for _ in range(math.floor(percentage / 5))), + ''.join("░" for _ in range(20 - math.floor(percentage / 5))), round(percentage, 2)) estimated_total_time = downloader.get_eta(human=True) try: - current_message = f"trying to download\n" - current_message += f"URL: {url}\n" - current_message += f"File Name: {file_name}\n" - current_message += f"{progress_str}\n" - current_message += f"{humanbytes(downloaded)} of {humanbytes(total_length)}\n" - current_message += f"ETA: {estimated_total_time}" + current_message = f"trying to download\n"\ + f"URL: {url}\n"\ + f"File Name: {file_name}\n" \ + f"Speed: {speed}"\ + f"{progress_str}\n"\ + f"{slitu.humanbytes(downloaded)} of {slitu.humanbytes(total_length)}\n"\ + f"ETA: {estimated_total_time}" if round(diff % 10.00) == 0 and current_message != display_message: await mone.edit(current_message) display_message = current_message diff --git a/stdplugins/emojis.py b/stdplugins/emojis.py index 69789a2c06..7d401597c4 100644 --- a/stdplugins/emojis.py +++ b/stdplugins/emojis.py @@ -4,23 +4,21 @@ .emoji apple .emoji :/ .emoji -_-""" -from telethon import events import asyncio -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="emoji (.*)")) +@borg.on(slitu.admin_cmd(pattern="emoji (.*)")) async def _(event): if event.fwd_from: return animation_interval = 0.3 - animation_ttl = range(0, 16) + animation_ttl = range(77) input_str = event.pattern_match.group(1) if input_str == "shrug": await event.edit("¯\_(ツ)_/¯") elif input_str == "apple": await event.edit("\uF8FF") - elif input_str == ":/": + elif input_str in [":/", ":\\"]: await event.edit(input_str) animation_chars = [ ":\\", @@ -28,7 +26,9 @@ async def _(event): ] for i in animation_ttl: await asyncio.sleep(animation_interval) - await event.edit(animation_chars[i % 2]) + try: + await event.edit(animation_chars[i % 2]) + except: pass elif input_str == "-_-": await event.edit(input_str) animation_chars = [ diff --git a/stdplugins/eval.py b/stdplugins/eval.py index d2dce4e601..9084768050 100644 --- a/stdplugins/eval.py +++ b/stdplugins/eval.py @@ -10,15 +10,14 @@ import asyncio import sys import io -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="eval")) +@borg.on(slitu.admin_cmd(pattern="eval")) async def _(event): if event.fwd_from or event.via_bot_id: return - await event.edit("Processing ...") - cmd = event.text.split(" ", maxsplit=1)[1] + s_m_ = await event.reply("...") + cmd = event.raw_text.split(" ", maxsplit=1)[1] reply_to_id = event.message.id if event.reply_to_msg_id: reply_to_id = event.reply_to_msg_id @@ -28,48 +27,53 @@ async def _(event): redirected_output = sys.stdout = io.StringIO() redirected_error = sys.stderr = io.StringIO() stdout, stderr, exc = None, None, None + __ = "" try: - await aexec(cmd, event) + __ = await aexec(cmd, event) except Exception: exc = traceback.format_exc() - stdout = redirected_output.getvalue() + stdout = str(__ or redirected_output.getvalue() or "") stderr = redirected_error.getvalue() sys.stdout = old_stdout sys.stderr = old_stderr - evaluation = "" + evaluation = "😐" if exc: evaluation = exc elif stderr: evaluation = stderr elif stdout: evaluation = stdout - else: - evaluation = "Success" - final_output = "**EVAL**: `{}` \n\n **OUTPUT**: \n`{}` \n".format(cmd, evaluation) + if event.chat_id not in borg._NOT_SAFE_PLACES: + evaluation = borg.secure_text(evaluation) + + final_output = "**EVAL**: `{}` \n\n **OUTPUT**: \n`{}` \n".format( + cmd, + evaluation + ) if len(final_output) > Config.MAX_MESSAGE_SIZE_LIMIT: with io.BytesIO(str.encode(final_output)) as out_file: out_file.name = "eval.text" - await borg.send_file( - event.chat_id, - out_file, - force_document=True, - allow_cache=False, - caption=cmd, - reply_to=reply_to_id + await s_m_.reply( + cmd, + file=out_file ) await event.delete() else: - await event.edit(final_output) + await s_m_.edit(final_output) -async def aexec(code, event): +async def aexec(code, smessatatus): + message = event = smessatatus + p = lambda _x: print(slitu.yaml_format(_x)) + reply = await event.get_reply_message() exec( - f'async def __aexec(event): ' + + f'async def __aexec(message, reply, client, p): ' + + '\n event = smessatatus = message' + ''.join(f'\n {l}' for l in code.split('\n')) ) - return await locals()['__aexec'](event) + return await locals()['__aexec'](message, reply, message.client, p) diff --git a/stdplugins/exec.py b/stdplugins/exec.py index 6cb9127f58..4c41112548 100644 --- a/stdplugins/exec.py +++ b/stdplugins/exec.py @@ -3,22 +3,19 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from telethon import events -import subprocess from telethon.errors import MessageEmptyError, MessageTooLongError, MessageNotModifiedError import io import asyncio import time -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="exec ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="exec")) async def _(event): if event.fwd_from or event.via_bot_id: return DELAY_BETWEEN_EDITS = 0.3 PROCESS_RUN_TIME = 100 - cmd = event.pattern_match.group(1) + cmd = event.raw_text.split(" ", maxsplit=1)[1] reply_to_id = event.message.id if event.reply_to_msg_id: reply_to_id = event.reply_to_msg_id @@ -32,15 +29,21 @@ async def _(event): e = "No Error" o = stdout.decode() if not o: - o = "**Tip**: \n`If you want to see the results of your code, I suggest printing them to stdout.`" - else: - _o = o.split("\n") - o = "`\n".join(_o) - OUTPUT = f"**QUERY:**\n__Command:__\n`{cmd}` \n__PID:__\n`{process.pid}`\n\n**stderr:** \n`{e}`\n**Output:**\n{o}" + o = "No Output" + + if event.chat_id not in borg._NOT_SAFE_PLACES: + e = borg.secure_text(e) + o = borg.secure_text(o) + + OUTPUT = f"**QUERY:**\n" + OUTPUT += f"__Command:__\n`{cmd}` \n" + OUTPUT += f"__PID:__\n`{process.pid}`\n\n" + OUTPUT += f"**stderr:** \n`{e}`\n" + OUTPUT += f"**stdout:**\n{o}" if len(OUTPUT) > Config.MAX_MESSAGE_SIZE_LIMIT: with io.BytesIO(str.encode(OUTPUT)) as out_file: out_file.name = "exec.text" - await borg.send_file( + await event.client.send_file( event.chat_id, out_file, force_document=True, @@ -49,4 +52,5 @@ async def _(event): reply_to=reply_to_id ) await event.delete() - await event.edit(OUTPUT) + else: + await event.edit(OUTPUT) diff --git a/stdplugins/ff_mpeg.py b/stdplugins/ff_mpeg.py index 864f33bdce..1574b7f7de 100644 --- a/stdplugins/ff_mpeg.py +++ b/stdplugins/ff_mpeg.py @@ -7,50 +7,20 @@ from datetime import datetime from hachoir.metadata import extractMetadata from hachoir.parser import createParser -from uniborg.util import admin_cmd, progress -FF_MPEG_DOWN_LOAD_MEDIA_PATH = "uniborg.media.ffmpeg" - - -@borg.on(admin_cmd(pattern="ffmpegsave")) +@borg.on(slitu.admin_cmd(pattern="ffmpegtrim")) async def ff_mpeg_trim_cmd(event): if event.fwd_from: return - if not os.path.exists(FF_MPEG_DOWN_LOAD_MEDIA_PATH): - if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): - os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - if event.reply_to_msg_id: - start = datetime.now() - reply_message = await event.get_reply_message() - try: - c_time = time.time() - downloaded_file_name = await borg.download_media( - reply_message, - FF_MPEG_DOWN_LOAD_MEDIA_PATH, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to download") - ) - ) - except Exception as e: # pylint:disable=C0103,W0703 - await event.edit(str(e)) - else: - end = datetime.now() - ms = (end - start).seconds - await event.edit("Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms)) - else: - await event.edit("Reply to a Telegram media file") - else: - await event.edit(f"a media file already exists in path. Please remove the media and try again!\n`.exec rm {FF_MPEG_DOWN_LOAD_MEDIA_PATH}`") + + FF_MPEG_DOWN_LOAD_MEDIA_PATH = await slitu.get_media_lnk(event) + logger.info(FF_MPEG_DOWN_LOAD_MEDIA_PATH) - -@borg.on(admin_cmd(pattern="ffmpegtrim")) -async def ff_mpeg_trim_cmd(event): - if event.fwd_from: - return - if not os.path.exists(FF_MPEG_DOWN_LOAD_MEDIA_PATH): - await event.edit(f"a media file needs to be downloaded, and saved to the following path: `{FF_MPEG_DOWN_LOAD_MEDIA_PATH}`") + if FF_MPEG_DOWN_LOAD_MEDIA_PATH is None: + await event.edit("please set the required ENVironment VARiables") return + current_message_text = event.raw_text cmt = current_message_text.split(" ") logger.info(cmt) @@ -58,7 +28,7 @@ async def ff_mpeg_trim_cmd(event): if len(cmt) == 3: # output should be video cmd, start_time, end_time = cmt - o = await cult_small_video( + o = await slitu.cult_small_video( FF_MPEG_DOWN_LOAD_MEDIA_PATH, Config.TMP_DOWNLOAD_DIRECTORY, start_time, @@ -76,7 +46,7 @@ async def ff_mpeg_trim_cmd(event): allow_cache=False, # reply_to=event.message.id, progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") + slitu.progress(d, t, event, c_time, "trying to upload") ) ) os.remove(o) @@ -85,7 +55,7 @@ async def ff_mpeg_trim_cmd(event): elif len(cmt) == 2: # output should be image cmd, start_time = cmt - o = await take_screen_shot( + o = await slitu.take_screen_shot( FF_MPEG_DOWN_LOAD_MEDIA_PATH, Config.TMP_DOWNLOAD_DIRECTORY, start_time @@ -102,7 +72,7 @@ async def ff_mpeg_trim_cmd(event): allow_cache=False, # reply_to=event.message.id, progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") + slitu.progress(d, t, event, c_time, "trying to upload") ) ) os.remove(o) @@ -114,73 +84,3 @@ async def ff_mpeg_trim_cmd(event): end = datetime.now() ms = (end - start).seconds await event.edit(f"Completed Process in {ms} seconds") - - -async def take_screen_shot(video_file, output_directory, ttl): - # https://stackoverflow.com/a/13891070/4723940 - out_put_file_name = output_directory + \ - "/" + str(time.time()) + ".jpg" - file_genertor_command = [ - "ffmpeg", - "-ss", - str(ttl), - "-i", - video_file, - "-vframes", - "1", - out_put_file_name - ] - # width = "90" - process = await asyncio.create_subprocess_exec( - *file_genertor_command, - # stdout must a pipe to be accessible as process.stdout - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - # Wait for the subprocess to finish - stdout, stderr = await process.communicate() - e_response = stderr.decode().strip() - t_response = stdout.decode().strip() - if os.path.lexists(out_put_file_name): - return out_put_file_name - else: - logger.info(e_response) - logger.info(t_response) - return None - -# https://github.com/Nekmo/telegram-upload/blob/master/telegram_upload/video.py#L26 - -async def cult_small_video(video_file, output_directory, start_time, end_time): - # https://stackoverflow.com/a/13891070/4723940 - out_put_file_name = output_directory + \ - "/" + str(round(time.time())) + ".mp4" - file_genertor_command = [ - "ffmpeg", - "-i", - video_file, - "-ss", - start_time, - "-to", - end_time, - "-async", - "1", - "-strict", - "-2", - out_put_file_name - ] - process = await asyncio.create_subprocess_exec( - *file_genertor_command, - # stdout must a pipe to be accessible as process.stdout - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - # Wait for the subprocess to finish - stdout, stderr = await process.communicate() - e_response = stderr.decode().strip() - t_response = stdout.decode().strip() - if os.path.lexists(out_put_file_name): - return out_put_file_name - else: - logger.info(e_response) - logger.info(t_response) - return None diff --git a/stdplugins/file_converter.py b/stdplugins/file_converter.py index c45ab1a06b..35af0e2b48 100644 --- a/stdplugins/file_converter.py +++ b/stdplugins/file_converter.py @@ -1,109 +1,151 @@ """File Converter .nfc """ - import asyncio import os import time from datetime import datetime -from uniborg.util import admin_cmd, progress +from telethon.tl.custom import Message +from telethon.tl.types import InputMediaUploadedDocument +from telethon.tl.types import DocumentAttributeAudio +from telethon.utils import get_attributes -@borg.on(admin_cmd(pattern="nfc (.*)")) # pylint:disable=E0602 +@borg.on(slitu.admin_cmd(pattern="nfc (.*)")) # pylint:disable=E0602 async def _(event): if event.fwd_from: return input_str = event.pattern_match.group(1) - reply_message = await event.get_reply_message() + reply_message: Message = await event.get_reply_message() if reply_message is None: await event.edit("reply to a media to use the `nfc` operation.\nInspired by @FileConverterBot") return await event.edit("trying to download media file, to my local") + tmp_dir = os.path.join( + Config.TMP_DOWNLOAD_DIRECTORY, + str(event.id) + ) + if not os.path.isdir(tmp_dir): + os.makedirs(tmp_dir) + tmp_dir += "/" + messages = [reply_message] + if reply_message.grouped_id: + messages = await slitu.gmp(reply_message) try: start = datetime.now() - c_time = time.time() - downloaded_file_name = await borg.download_media( - reply_message, - Config.TMP_DOWNLOAD_DIRECTORY, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to download") + io = 1 + tot = len(messages) + for message in messages: + c_time = time.time() + downloaded_file_name = await message.download_media( + tmp_dir, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + slitu.progress( + d, + t, + event, + c_time, + f"[{io} / {tot}] trying to download" + ) + ) ) - ) + io = io + 1 except Exception as e: # pylint:disable=C0103,W0703 await event.edit(str(e)) else: end = datetime.now() ms = (end - start).seconds await event.edit("Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms)) - new_required_file_name = "" - new_required_file_caption = "" - command_to_run = [] - force_document = False - voice_note = False - supports_streaming = False - if input_str == "voice": - new_required_file_caption = "NLFC_" + str(round(time.time())) + ".opus" - new_required_file_name = Config.TMP_DOWNLOAD_DIRECTORY + "/" + new_required_file_caption - command_to_run = [ - "ffmpeg", - "-i", - downloaded_file_name, - "-map", - "0:a", - "-codec:a", - "libopus", - "-b:a", - "100k", - "-vbr", - "on", - new_required_file_name - ] - voice_note = True - supports_streaming = True - elif input_str == "mp3": - new_required_file_caption = "NLFC_" + str(round(time.time())) + ".mp3" - new_required_file_name = Config.TMP_DOWNLOAD_DIRECTORY + "/" + new_required_file_caption - command_to_run = [ - "ffmpeg", - "-i", - downloaded_file_name, - "-vn", - new_required_file_name - ] + downloaded_files = os.listdir(tmp_dir) + io = 1 + tot = len(downloaded_files) + for one_file in downloaded_files: + downloaded_file_name = os.path.join(tmp_dir, one_file) + + new_required_file_name = "" + new_required_file_caption = "" + command_to_run = [] voice_note = False - supports_streaming = True - else: - await event.edit("not supported") + supports_streaming = False + if input_str == "voice": + new_required_file_caption = "NLFC_" + str(round(time.time())) + ".opus" + new_required_file_name = os.path.join( + tmp_dir, + new_required_file_caption + ) + command_to_run = [ + "ffmpeg", + "-i", + downloaded_file_name, + "-map", + "0:a", + "-codec:a", + "libopus", + "-b:a", + "100k", + "-vbr", + "on", + new_required_file_name + ] + voice_note = True + supports_streaming = True + elif input_str == "mp3": + new_required_file_caption = "NLFC_" + str(round(time.time())) + ".mp3" + new_required_file_name = os.path.join( + tmp_dir, + new_required_file_caption + ) + command_to_run = [ + "ffmpeg", + "-i", + downloaded_file_name, + "-vn", + new_required_file_name + ] + voice_note = False + supports_streaming = True + + logger.info(command_to_run) + t_response, e_response = await slitu.run_command(command_to_run) os.remove(downloaded_file_name) - return - logger.info(command_to_run) - # TODO: re-write create_subprocess_exec 😉 - process = await asyncio.create_subprocess_exec( - *command_to_run, - # stdout must a pipe to be accessible as process.stdout - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - # Wait for the subprocess to finish - stdout, stderr = await process.communicate() - e_response = stderr.decode().strip() - t_response = stdout.decode().strip() - os.remove(downloaded_file_name) - if os.path.exists(new_required_file_name): - end_two = datetime.now() - await borg.send_file( - entity=event.chat_id, - file=new_required_file_name, - caption=new_required_file_caption, - allow_cache=False, - silent=True, - force_document=force_document, - voice_note=voice_note, - supports_streaming=supports_streaming, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") + if os.path.exists(new_required_file_name): + end_two = datetime.now() + force_document = False + file_handle = await event.client.upload_file( + new_required_file_name, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + slitu.progress(d, t, event, c_time, "trying to upload") + ) ) - ) - ms_two = (end_two - end).seconds - os.remove(new_required_file_name) - await event.edit(f"converted in {ms_two} seconds") - + attributes, mime_type = get_attributes( + new_required_file_name, + mime_type=None, + attributes=[], + force_document=force_document, + voice_note=voice_note, + video_note=False, + supports_streaming=supports_streaming, + thumb=None + ) + os.remove(new_required_file_name) + attributes = [DocumentAttributeAudio( + duration=attributes[-1].duration, + voice=voice_note, + title=Config.NFC_TITLE, + performer=Config.NFC_PERFORMER, + waveform=attributes[-1].waveform + )] + media = InputMediaUploadedDocument( + file=file_handle, + mime_type=mime_type, + attributes=attributes, + thumb=None, + force_file=force_document + ) + await event.reply( + file=media + ) + ms_two = (end_two - end).seconds + await event.edit( + f"[{io} / {tot}] converted in {ms_two} seconds" + ) + io = io + 1 diff --git a/stdplugins/fileext.py b/stdplugins/fileext.py index 603014516d..aa24ae8447 100644 --- a/stdplugins/fileext.py +++ b/stdplugins/fileext.py @@ -3,10 +3,9 @@ from telethon import events import requests from bs4 import BeautifulSoup -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="filext (.*)")) +@borg.on(slitu.admin_cmd(pattern="filext (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/fwd.py b/stdplugins/fwd.py index 217bbe23c2..c75e33d1f8 100644 --- a/stdplugins/fwd.py +++ b/stdplugins/fwd.py @@ -1,32 +1,32 @@ """Enable Seen Counter in any message, to know how many users have seen your message Syntax: .fwd as reply to any message""" -from telethon import events -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="fwd")) +@borg.on(slitu.admin_cmd(pattern="fwd")) async def _(event): if event.fwd_from: return if Config.PRIVATE_CHANNEL_BOT_API_ID is None: - await event.edit("Please set the required environment variable `PRIVATE_CHANNEL_BOT_API_ID` for this plugin to work") + await event.edit( + "Please set the required environment variable `PRIVATE_CHANNEL_BOT_API_ID` " + "for this plugin to work" + ) return try: - e = await borg.get_entity(Config.PRIVATE_CHANNEL_BOT_API_ID) + e = await event.client.get_entity(Config.PRIVATE_CHANNEL_BOT_API_ID) except Exception as e: await event.edit(str(e)) else: re_message = await event.get_reply_message() # https://t.me/telethonofftopic/78166 - fwd_message = await borg.forward_messages( + fwd_message = await event.client.forward_messages( e, re_message, silent=True ) - await borg.forward_messages( + await event.client.forward_messages( event.chat_id, fwd_message ) - await fwd_message.delete() await event.delete() diff --git a/stdplugins/gDrive.py b/stdplugins/gDrive.py index dfdf18084a..b3c99fdb36 100644 --- a/stdplugins/gDrive.py +++ b/stdplugins/gDrive.py @@ -14,7 +14,6 @@ import time from datetime import datetime from telethon import events -from uniborg.util import admin_cmd, progress, humanbytes # from mimetypes import guess_type from apiclient.discovery import build @@ -27,7 +26,10 @@ # Path to token json file, it should be in same directory as script -G_DRIVE_TOKEN_FILE = Config.TMP_DOWNLOAD_DIRECTORY + "/auth_token.txt" +G_DRIVE_TOKEN_FILE = os.path.join( + Config.TMP_DOWNLOAD_DIRECTORY, + "auth_token.txt" +) # Copy your credentials from the APIs Console CLIENT_ID = Config.G_DRIVE_CLIENT_ID CLIENT_SECRET = Config.G_DRIVE_CLIENT_SECRET @@ -41,7 +43,7 @@ G_DRIVE_DIR_MIME_TYPE = "application/vnd.google-apps.folder" -@borg.on(admin_cmd(pattern="ugdrive ?(.*)", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="ugdrive ?(.*)", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -65,7 +67,7 @@ async def _(event): reply_message, Config.TMP_DOWNLOAD_DIRECTORY, progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, mone, c_time, "trying to download") + slitu.progress(d, t, mone, c_time, "trying to download") ) ) except Exception as e: # pylint:disable=C0103,W0703 @@ -82,7 +84,7 @@ async def _(event): end = datetime.now() ms = (end - start).seconds required_file_name = input_str - await mone.edit("Found `{}` in {} seconds.".format(input_str, ms)) + await mone.edit("Found `{}` in {} seconds.".format(required_file_name, ms)) else: await mone.edit("File Not found in local server. Give me a file path :((") return False @@ -111,7 +113,7 @@ async def _(event): await mone.edit("File Not found in local server. Give me a file path :((") -@borg.on(admin_cmd(pattern="gdrivesp https?://drive\.google\.com/drive/u/\d/folders/([-\w]{25,})", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="gdrivesp https?://drive\.google\.com/drive/u/\d/folders/([-\w]{25,})", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -125,7 +127,7 @@ async def _(event): await mone.edit("Send `.gdrivesp https://drive.google.com/drive/u/X/folders/Y` to set the folder to upload new files to") -@borg.on(admin_cmd(pattern="gdriveclear", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="gdriveclear", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -135,7 +137,7 @@ async def _(event): await event.delete() -@borg.on(admin_cmd(pattern="gdrivedir ?(.*)", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="gdrivedir ?(.*)", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -168,7 +170,7 @@ async def _(event): await mone.edit(f"directory {input_str} does not seem to exist") -@borg.on(admin_cmd(pattern="drive (delete|get) ?(.*)", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="drive (delete|get) ?(.*)", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -200,7 +202,7 @@ async def _(event): await mone.edit(response_from_svc) -@borg.on(admin_cmd(pattern="drive search ?(.*)", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="drive search ?(.*)", allow_sudo=True)) async def _(event): if event.fwd_from: return @@ -292,7 +294,7 @@ async def upload_file(http, file_path, file_name, mime_type, event, parent_id): "withLink": True } # Insert a file - file = drive_service.files().insert(body=body, media_body=media_body) + file = drive_service.files().insert(body=body, media_body=media_body, supportsTeamDrives=True) response = None display_message = "" while response is None: @@ -312,7 +314,6 @@ async def upload_file(http, file_path, file_name, mime_type, event, parent_id): display_message = current_message except Exception as e: logger.info(str(e)) - pass file_id = response.get("id") try: # Insert new permissions @@ -320,9 +321,8 @@ async def upload_file(http, file_path, file_name, mime_type, event, parent_id): except: pass # Define file instance and get url for download - file = drive_service.files().get(fileId=file_id).execute() - download_url = file.get("webContentLink") - return download_url + file = drive_service.files().get(fileId=file_id, supportsTeamDrives=True).execute() + return file.get("webContentLink") async def create_directory(http, directory_name, parent_id): @@ -339,7 +339,7 @@ async def create_directory(http, directory_name, parent_id): } if parent_id is not None: file_metadata["parents"] = [{"id": parent_id}] - file = drive_service.files().insert(body=file_metadata).execute() + file = drive_service.files().insert(body=file_metadata, supportsTeamDrives=True).execute() file_id = file.get("id") try: drive_service.permissions().insert(fileId=file_id, body=permissions).execute() @@ -370,7 +370,7 @@ async def DoTeskWithDir(http, input_directory, event, parent_id): async def gdrive_delete(service, file_id): try: - service.files().delete(fileId=file_id).execute() + service.files().delete(fileId=file_id, supportsTeamDrives=True).execute() return f"successfully deleted {file_id} from my gDrive." except Exception as e: return str(e) @@ -378,10 +378,9 @@ async def gdrive_delete(service, file_id): async def gdrive_list_file_md(service, file_id): try: - file = service.files().get(fileId=file_id).execute() + file = service.files().get(fileId=file_id, supportsTeamDrives=True).execute() # logger.info(file) - file_meta_data = {} - file_meta_data["title"] = file["title"] + file_meta_data = {"title": file["title"]} mimeType = file["mimeType"] file_meta_data["createdDate"] = file["createdDate"] if mimeType == G_DRIVE_DIR_MIME_TYPE: @@ -392,8 +391,8 @@ async def gdrive_list_file_md(service, file_id): # is a file. file_meta_data["mimeType"] = file["mimeType"] file_meta_data["md5Checksum"] = file["md5Checksum"] - file_meta_data["fileSize"] = str(humanbytes(int(file["fileSize"]))) - file_meta_data["quotaBytesUsed"] = str(humanbytes(int(file["quotaBytesUsed"]))) + file_meta_data["fileSize"] = str(slitu.humanbytes(int(file["fileSize"]))) + file_meta_data["quotaBytesUsed"] = str(slitu.humanbytes(int(file["quotaBytesUsed"]))) file_meta_data["previewURL"] = file["downloadUrl"] return json.dumps(file_meta_data, sort_keys=True, indent=4) except Exception as e: @@ -412,6 +411,8 @@ async def gdrive_search(http, search_query): try: response = drive_service.files().list( q=query, + supportsTeamDrives=True, + includeTeamDriveItems=True, spaces="drive", fields="nextPageToken, items(id, title, mimeType)", pageToken=page_token @@ -421,10 +422,9 @@ async def gdrive_search(http, search_query): file_id = file.get("id") if file.get("mimeType") == G_DRIVE_DIR_MIME_TYPE: msg += f"🗃️ {file_title}" - msg += f" {file_id}\n" else: msg += f"👉 {file_title}" - msg += f" {file_id}\n" + msg += f" {file_id}\n" page_token = response.get("nextPageToken", None) if page_token is None: break diff --git a/stdplugins/gPhotos.py b/stdplugins/gPhotos.py new file mode 100644 index 0000000000..7316180771 --- /dev/null +++ b/stdplugins/gPhotos.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# UniBorg Telegram UseRBot +# Copyright (C) 2020 @UniBorg +# +# This code is licensed under +# the "you can't use this for anything - public or private, +# unless you know the two prime factors to the number below" license +# +# 114994699218449095458463470499996630 +# +# വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! + + +"""Google Photos +""" + +import asyncio +import aiohttp +import aiofiles +import os +import time + +from telethon import events + +from apiclient.discovery import build +from mimetypes import guess_type +from httplib2 import Http +from oauth2client import file, client, tools + + +# setup the gPhotos v1 API +OAUTH_SCOPE = [ + "https://www.googleapis.com/auth/photoslibrary", + "https://www.googleapis.com/auth/photoslibrary.sharing" +] +# Redirect URI for installed apps, can be left as is +REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob" +# +PHOTOS_BASE_URI = "https://photoslibrary.googleapis.com" + +TOKEN_FILE_NAME = os.path.join( + Config.TMP_DOWNLOAD_DIRECTORY, + "gPhoto_credentials_UniBorg.json" +) + + +@borg.on(slitu.admin_cmd(pattern="gphoto setup")) +async def setup_google_photos(event): + if event.chat_id != Config.PRIVATE_GROUP_BOT_API_ID: + return + token_file = TOKEN_FILE_NAME + is_cred_exists, _ = await check_creds(token_file, event) + if not is_cred_exists: + pho_storage = await create_token_file( + token_file, + event + ) + await event.edit( + "CREDS created. 😕😖😖" + ) + + +async def create_token_file(token_file, event): + # Run through the OAuth flow and retrieve credentials + flow = client.OAuth2WebServerFlow( + Config.G_PHOTOS_CLIENT_ID, + Config.G_PHOTOS_CLIENT_SECRET, + OAUTH_SCOPE, + redirect_uri=REDIRECT_URI + ) + authorize_url = flow.step1_get_authorize_url() + async with event.client.conversation( + event.chat_id, + timeout=600 + ) as conv: + await conv.send_message( + "Go to " + "the following link in " + f"your browser: {authorize_url} and " + "reply the code" + ) + response = await conv.wait_event(events.NewMessage( + outgoing=True, + chats=Config.PRIVATE_GROUP_BOT_API_ID + )) + # logger.info(response.stringify()) + code = response.message.message.strip() + credentials = flow.step2_exchange(code) + storage = file.Storage(token_file) + storage.put(credentials) + imp_gsem = await conv.send_message(file=token_file) + await imp_gsem.reply( + "please set " + "G_PHOTOS_AUTH_TOKEN_ID " + "= " + f"{imp_gsem.id} ..!" + "\n\nThis is only required, " + "if you are running in an ephimeral file-system.", + parse_mode="html" + ) + return storage + + +async def check_creds(token_file, event): + if Config.G_PHOTOS_AUTH_TOKEN_ID: + confidential_message = await event.client.get_messages( + entity=Config.PRIVATE_GROUP_BOT_API_ID, + ids=Config.G_PHOTOS_AUTH_TOKEN_ID + ) + if confidential_message and confidential_message.file: + await confidential_message.download_media( + file=token_file + ) + + if os.path.exists(token_file): + pho_storage = file.Storage(token_file) + creds = pho_storage.get() + if not creds or creds.invalid: + return False, None + creds.refresh(Http()) + return True, creds + + return False, None + + +@borg.on(slitu.admin_cmd(pattern="gphoto upload( -- (.*))?")) +async def upload_google_photos(event): + if event.fwd_from: + return + + input_str = event.pattern_match.group(2) + logger.info(input_str) + + if not event.reply_to_msg_id and not input_str: + await event.edit( + "©️ [Forwarded from utubebot]\nno one gonna help you 🤣🤣🤣🤣", + parse_mode="html" + ) + return + + token_file = TOKEN_FILE_NAME + is_cred_exists, creds = await check_creds( + token_file, + event + ) + if not is_cred_exists: + await event.edit( + "😏 gphoto setup first 😡😒😒", + parse_mode="html" + ) + + service = build( + "photoslibrary", + "v1", + http=creds.authorize(Http()) + ) + + # create directory if not exists + if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): + os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) + + file_path = None + + if input_str and os.path.exists(input_str): + file_path = input_str + + elif not input_str: + media_message = await event.client.get_messages( + entity=event.chat_id, + ids=event.reply_to_msg_id + ) + + c_time = time.time() + file_path = await media_message.download_media( + file=Config.TMP_DOWNLOAD_DIRECTORY, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + slitu.progress(d, t, event, c_time, "trying to download") + ) + ) + + logger.info(file_path) + + if not file_path: + await event.edit( + "[stop spamming]", + parse_mode="html" + ) + return + + file_name, mime_type, file_size = file_ops(file_path) + await event.edit( + "file downloaded, " + "gathering upload informations " + ) + + async with aiohttp.ClientSession() as session: + headers = { + "Content-Length": "0", + "X-Goog-Upload-Command": "start", + "X-Goog-Upload-Content-Type": mime_type, + "X-Goog-Upload-File-Name": file_name, + "X-Goog-Upload-Protocol": "resumable", + "X-Goog-Upload-Raw-Size": str(file_size), + "Authorization": "Bearer " + creds.access_token, + } + # Step 1: Initiating an upload session + step_one_response = await session.post( + f"{PHOTOS_BASE_URI}/v1/uploads", + headers=headers, + ) + + if step_one_response.status != 200: + await event.edit( + (await step_one_response.text()) + ) + return + + step_one_resp_headers = step_one_response.headers + logger.info(step_one_resp_headers) + # Step 2: Saving the session URL + + real_upload_url = step_one_resp_headers.get( + "X-Goog-Upload-URL" + ) + logger.info(real_upload_url) + upload_granularity = int(step_one_resp_headers.get( + "X-Goog-Upload-Chunk-Granularity" + )) + logger.info(upload_granularity) + # https://t.me/c/1279877202/74 + number_of_req_s = int(( + file_size / upload_granularity + )) + logger.info(number_of_req_s) + c_time = time.time() + loop = asyncio.get_event_loop() + async with aiofiles.open( + file_path, + mode="rb" + ) as f_d: + for i in range(number_of_req_s): + current_chunk = await f_d.read(upload_granularity) + offset = i * upload_granularity + part_size = len(current_chunk) + + headers = { + "Content-Length": str(part_size), + "X-Goog-Upload-Command": "upload", + "X-Goog-Upload-Offset": str(offset), + "Authorization": "Bearer " + creds.access_token, + } + logger.info(i) + logger.info(headers) + response = await session.post( + real_upload_url, + headers=headers, + data=current_chunk + ) + loop.create_task( + slitu.progress( + offset + part_size, + file_size, + event, + c_time, + "uploading to gPhoto 🧐?" + ) + ) + logger.info(response.headers) + + # await f_d.seek(i * upload_granularity) + # await f_d.seek(upload_granularity) + current_chunk = await f_d.read(upload_granularity) + # https://t.me/c/1279877202/74 + + logger.info(number_of_req_s) + headers = { + "Content-Length": str(len(current_chunk)), + "X-Goog-Upload-Command": "upload, finalize", + "X-Goog-Upload-Offset": str(number_of_req_s * upload_granularity), + "Authorization": "Bearer " + creds.access_token, + } + logger.info(headers) + response = await session.post( + real_upload_url, + headers=headers, + data=current_chunk + ) + logger.info(response.headers) + + final_response_text = await response.text() + logger.info(final_response_text) + + await event.edit( + "uploaded to Google Photos, " + "getting FILE URI 🤔🤔" + ) + + response_create_album = service.mediaItems().batchCreate( + body={ + "newMediaItems": [{ + "description": "uploaded using @UniBorg v7", + "simpleMediaItem": { + "fileName": file_name, + "uploadToken": final_response_text + } + }] + } + ).execute() + logger.info(response_create_album) + + try: + photo_url = response_create_album.get( + "newMediaItemResults" + )[0].get("mediaItem").get("productUrl") + await event.edit( + photo_url + ) + except Exception as e: + await event.edit(str(e)) + + +# Get mime type and name of given file +def file_ops(file_path): + file_size = os.stat(file_path).st_size + mime_type = guess_type(file_path)[0] + mime_type = mime_type if mime_type else "text/plain" + file_name = file_path.split("/")[-1] + return file_name, mime_type, file_size + diff --git a/stdplugins/gban.py b/stdplugins/gban.py index c7f9ec63eb..edbce118d9 100644 --- a/stdplugins/gban.py +++ b/stdplugins/gban.py @@ -3,12 +3,10 @@ Available Commands: .gban REASON .ungban REASON""" -from telethon import events import asyncio -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="gban ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="gban ?(.*)")) async def _(event): if Config.G_BAN_LOGGER_GROUP is None: await event.edit("ENV VAR is not set. This module will not work.") @@ -18,18 +16,15 @@ async def _(event): reason = event.pattern_match.group(1) if event.reply_to_msg_id: r = await event.get_reply_message() - if r.forward: - r_from_id = r.forward.from_id or r.from_id - else: - r_from_id = r.from_id - await borg.send_message( + r_sender_id = r.forward.sender_id or r.sender_id if r.forward else r.sender_id + await event.client.send_message( Config.G_BAN_LOGGER_GROUP, - "!gban [user](tg://user?id={}) {}".format(r_from_id, reason) + "!gban [user](tg://user?id={}) {}".format(r_sender_id, reason) ) await event.delete() -@borg.on(admin_cmd(pattern="ungban ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="ungban ?(.*)")) async def _(event): if Config.G_BAN_LOGGER_GROUP is None: await event.edit("ENV VAR is not set. This module will not work.") @@ -39,9 +34,9 @@ async def _(event): reason = event.pattern_match.group(1) if event.reply_to_msg_id: r = await event.get_reply_message() - r_from_id = r.from_id - await borg.send_message( + r_sender_id = r.sender_id + await event.client.send_message( Config.G_BAN_LOGGER_GROUP, - "!ungban [user](tg://user?id={}) {}".format(r_from_id, reason) + "!ungban [user](tg://user?id={}) {}".format(r_sender_id, reason) ) await event.delete() diff --git a/stdplugins/get_admin.py b/stdplugins/get_admin.py index 19a6b56321..c985ca9bd6 100644 --- a/stdplugins/get_admin.py +++ b/stdplugins/get_admin.py @@ -1,11 +1,11 @@ """Get Administrators of any Chat* Syntax: .get_admin""" -from telethon import events -from telethon.tl.types import ChannelParticipantsAdmins, ChannelParticipantAdmin, ChannelParticipantCreator -from uniborg.util import admin_cmd +from telethon.tl.types import ( + ChannelParticipantsAdmins, ChannelParticipantAdmin, ChannelParticipantCreator +) -@borg.on(admin_cmd(pattern="get_ad?(m)in ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="get_ad(m)?in ?(.*)")) async def _(event): if event.fwd_from: return @@ -20,9 +20,7 @@ async def _(event): input_str = event.pattern_match.group(2) to_write_chat = await event.get_input_chat() chat = None - if not input_str: - chat = to_write_chat - else: + if input_str: mentions_heading = "Admins in {} channel: \n".format(input_str) mentions = mentions_heading try: @@ -30,18 +28,21 @@ async def _(event): except Exception as e: await event.edit(str(e)) return None + else: + chat = to_write_chat try: - async for x in borg.iter_participants(chat, filter=ChannelParticipantsAdmins): - if not x.deleted: - if isinstance(x.participant, ChannelParticipantCreator): - mentions += "\n 👑 [{}](tg://user?id={}) `{}`".format(x.first_name, x.id, x.id) + async for x in event.client.iter_participants(chat, filter=ChannelParticipantsAdmins): + if not x.deleted and isinstance( + x.participant, ChannelParticipantCreator + ): + mentions += "\n 👑 [{}](tg://user?id={}) `{}`".format(x.first_name, x.id, x.id) mentions += "\n" - async for x in borg.iter_participants(chat, filter=ChannelParticipantsAdmins): - if not x.deleted: + async for x in event.client.iter_participants(chat, filter=ChannelParticipantsAdmins): + if x.deleted: + mentions += "\n `{}`".format(x.id) + else: if isinstance(x.participant, ChannelParticipantAdmin): mentions += "\n ⚜️ [{}](tg://user?id={}) `{}`".format(x.first_name, x.id, x.id) - else: - mentions += "\n `{}`".format(x.id) except Exception as e: mentions += " " + str(e) + "\n" if should_mention_admins: diff --git a/stdplugins/get_bot.py b/stdplugins/get_bot.py index 1a364c8f97..3126332592 100644 --- a/stdplugins/get_bot.py +++ b/stdplugins/get_bot.py @@ -1,11 +1,9 @@ """ Get the Bots in any chat* Syntax: .get_bot""" -from telethon import events from telethon.tl.types import ChannelParticipantAdmin, ChannelParticipantsBots -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="get_bot ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="get_bot ?(.*)")) async def _(event): if event.fwd_from: return @@ -18,12 +16,12 @@ async def _(event): else: mentions = "Bots in {} channel: \n".format(input_str) try: - chat = await borg.get_entity(input_str) + chat = await event.client.get_entity(input_str) except Exception as e: await event.edit(str(e)) return None try: - async for x in borg.iter_participants(chat, filter=ChannelParticipantsBots): + async for x in event.client.iter_participants(chat, filter=ChannelParticipantsBots): if isinstance(x.participant, ChannelParticipantAdmin): mentions += "\n ⚜️ [{}](tg://user?id={}) `{}`".format(x.first_name, x.id, x.id) else: diff --git a/stdplugins/get_id.py b/stdplugins/get_id.py index beb32b0283..a5d1ab31ea 100644 --- a/stdplugins/get_id.py +++ b/stdplugins/get_id.py @@ -1,11 +1,8 @@ """Get ID of any Telegram media, or any user Syntax: .get_id""" -from telethon import events -from telethon.utils import pack_bot_file_id -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="get_id")) +@borg.on(slitu.admin_cmd(pattern="get_id")) async def _(event): if event.fwd_from: return @@ -13,9 +10,19 @@ async def _(event): chat = await event.get_input_chat() r_msg = await event.get_reply_message() if r_msg.media: - bot_api_file_id = pack_bot_file_id(r_msg.media) - await event.edit("Current Chat ID: `{}`\nFrom User ID: `{}`\nBot API File ID: `{}`".format(str(event.chat_id), str(r_msg.from_id), bot_api_file_id)) + await event.edit( + "Current Chat ID: `{}`\nFrom User ID: `{}`\nBot API File ID: `{}`".format( + str(event.chat_id), + str(r_msg.sender_id), + r_msg.file.id + ) + ) else: - await event.edit("Current Chat ID: `{}`\nFrom User ID: `{}`".format(str(event.chat_id), str(r_msg.from_id))) + await event.edit( + "Current Chat ID: `{}`\nFrom User ID: `{}`".format( + str(event.chat_id), + str(r_msg.sender_id) + ) + ) else: await event.edit("Current Chat ID: `{}`".format(str(event.chat_id))) diff --git a/stdplugins/github.py b/stdplugins/github.py index ec2e28f3a3..4eee5137f9 100644 --- a/stdplugins/github.py +++ b/stdplugins/github.py @@ -1,11 +1,9 @@ """Get information about an user on GitHub Syntax: .github USERNAME""" -from telethon import events import requests -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="github (.*)")) +@borg.on(slitu.admin_cmd(pattern="github (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/google.py b/stdplugins/google.py index 2e74ee2f39..be57ca329f 100644 --- a/stdplugins/google.py +++ b/stdplugins/google.py @@ -5,29 +5,40 @@ .google reverse search""" import asyncio +import aiohttp import os -import requests +import shutil +import time from bs4 import BeautifulSoup from datetime import datetime -from google_images_download import google_images_download -from uniborg.util import admin_cmd +from telethon.utils import guess_extension +from urllib.parse import urlencode -def progress(current, total): - logger.info("Downloaded {} of {}\nCompleted {}".format(current, total, (current / total) * 100)) - - -@borg.on(admin_cmd(pattern="google search (.*)")) +@borg.on(slitu.admin_cmd(pattern="google search (.*)")) async def _(event): if event.fwd_from: return start = datetime.now() await event.edit("Processing ...") # SHOW_DESCRIPTION = False - input_str = event.pattern_match.group(1) # + " -inurl:(htm|html|php|pls|txt) intitle:index.of \"last modified\" (mkv|mp4|avi|epub|pdf|mp3)" - input_url = "https://bots.shrimadhavuk.me/search/?q={}".format(input_str) - headers = {"USER-AGENT": "UniBorg"} - response = requests.get(input_url, headers=headers).json() + input_str = event.pattern_match.group(1) + # + " -inurl:(htm|html|php|pls|txt) + # intitle:index.of \"last modified\" + # (mkv|mp4|avi|epub|pdf|mp3)" + input_url = "https://bots.shrimadhavuk.me/search/" + headers = {"USER-AGENT": "UseTGBot"} + async with aiohttp.ClientSession() as requests: + data = { + "q": input_str, + "app_id": Config.USE_TG_BOT_APP_ID + } + reponse = await requests.get( + input_url, + params=data, + headers=headers + ) + response = await reponse.json() output_str = " " for result in response["results"]: text = result.get("title") @@ -42,84 +53,126 @@ async def _(event): await event.edit("Google: {}\n{}".format(input_str, output_str), link_preview=False) -@borg.on(admin_cmd(pattern="google image (.*)")) +@borg.on(slitu.admin_cmd(pattern="google image (.*)")) async def _(event): if event.fwd_from: return start = datetime.now() await event.edit("Processing ...") input_str = event.pattern_match.group(1) - response = google_images_download.googleimagesdownload() - if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): - os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - arguments = { - "keywords": input_str, - "limit": Config.TG_GLOBAL_ALBUM_LIMIT, - "format": "jpg", - "delay": 1, - "safe_search": True, - "output_directory": Config.TMP_DOWNLOAD_DIRECTORY - } - paths = response.download(arguments) - logger.info(paths) - lst = paths[0].get(input_str) - if len(lst) == 0: - await event.delete() + work_dir = os.path.join( + Config.TMP_DOWNLOAD_DIRECTORY, + input_str + ) + if not os.path.isdir(work_dir): + os.makedirs(work_dir) + input_url = "https://bots.shrimadhavuk.me/search/" + headers = {"USER-AGENT": "UseTGBot"} + url_lst = [] + cap_lst = [] + async with aiohttp.ClientSession() as requests: + data = { + "q": input_str, + "app_id": Config.USE_TG_BOT_APP_ID, + "p": "GoogleImages" + } + reponse = await requests.get( + input_url, + params=data, + headers=headers + ) + response = await reponse.json() + for result in response["results"]: + if len(url_lst) > Config.TG_GLOBAL_ALBUM_LIMIT: + break + caption = result.get("description") + image_url = result.get("url") + image_req_set = await requests.get(image_url) + image_file_name = str(time.time()) + "" + guess_extension( + image_req_set.headers.get("Content-Type") + ) + image_save_path = os.path.join( + work_dir, + image_file_name + ) + with open(image_save_path, "wb") as f_d: + f_d.write(await image_req_set.read()) + url_lst.append(image_save_path) + cap_lst.append(caption) + if not url_lst: + await event.edit(f"no results found for {input_str}") + return + if len(url_lst) != len(cap_lst): + await event.edit("search api broken :(") return - await borg.send_file( - event.chat_id, - lst, - caption=input_str, - reply_to=event.message.id, - progress_callback=progress + await event.reply( + cap_lst, + file=url_lst, + parse_mode="html", + force_document=True ) - logger.info(lst) - for each_file in lst: + for each_file in url_lst: os.remove(each_file) + shutil.rmtree(work_dir, ignore_errors=True) end = datetime.now() ms = (end - start).seconds - await event.edit("searched Google for {} in {} seconds.".format(input_str, ms), link_preview=False) + await event.edit( + f"searched Google for {input_str} in {ms} seconds.", + link_preview=False + ) await asyncio.sleep(5) await event.delete() -@borg.on(admin_cmd(pattern="google reverse search")) +@borg.on(slitu.admin_cmd(pattern="google reverse search")) async def _(event): if event.fwd_from: return start = datetime.now() - BASE_URL = "http://www.google.com" OUTPUT_STR = "Reply to an image to do Google Reverse Search" - if event.reply_to_msg_id: - await event.edit("Pre Processing Media") - previous_message = await event.get_reply_message() - previous_message_text = previous_message.message + if not event.reply_to_msg_id: + await event.edit("reply to any media, please -_-") + return + await event.edit("Pre Processing Media") + previous_message = await event.get_reply_message() + previous_message_text = previous_message.message + async with aiohttp.ClientSession() as requests: + BASE_URL = "http://www.google.com" if previous_message.media: - downloaded_file_name = await borg.download_media( - previous_message, + downloaded_file_name = await previous_message.download_media( Config.TMP_DOWNLOAD_DIRECTORY ) SEARCH_URL = "{}/searchbyimage/upload".format(BASE_URL) multipart = { - "encoded_image": (downloaded_file_name, open(downloaded_file_name, "rb")), + "encoded_image": open(downloaded_file_name, "rb"), "image_content": "" } # https://stackoverflow.com/a/28792943/4723940 - google_rs_response = requests.post(SEARCH_URL, files=multipart, allow_redirects=False) + google_rs_response = await requests.post( + SEARCH_URL, + data=multipart, + allow_redirects=False + ) the_location = google_rs_response.headers.get("Location") os.remove(downloaded_file_name) else: previous_message_text = previous_message.message SEARCH_URL = "{}/searchbyimage?image_url={}" - request_url = SEARCH_URL.format(BASE_URL, previous_message_text) - google_rs_response = requests.get(request_url, allow_redirects=False) + request_url = SEARCH_URL.format( + BASE_URL, + previous_message_text + ) + google_rs_response = await requests.get(request_url, allow_redirects=False) the_location = google_rs_response.headers.get("Location") await event.edit("Found Google Result. Pouring some soup on it!") headers = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0" } - response = requests.get(the_location, headers=headers) - soup = BeautifulSoup(response.text, "html.parser") + response = await requests.get(the_location, headers=headers) + soup = BeautifulSoup( + await response.text(), + "html.parser" + ) # document.getElementsByClassName("r5a77d"): PRS prs_div = soup.find_all("div", {"class": "r5a77d"})[0] prs_anchor_element = prs_div.find("a") @@ -130,8 +183,8 @@ async def _(event): img_size = img_size_div.find_all("div") end = datetime.now() ms = (end - start).seconds - OUTPUT_STR = """{img_size} -**Possible Related Search**: {prs_text} + out_rts = f"{img_size}\n" + out_rts += f"Possible Related Search: {prs_text}\n\n" + out_rts += f"More Info: Open this Link in {ms} seconds" + await event.edit(out_rts, parse_mode="HTML", link_preview=False) -More Info: Open this Link in {ms} seconds""".format(**locals()) - await event.edit(OUTPUT_STR, parse_mode="HTML", link_preview=False) diff --git a/stdplugins/ifsc.py b/stdplugins/ifsc.py index b43e8d2629..58c8c20811 100644 --- a/stdplugins/ifsc.py +++ b/stdplugins/ifsc.py @@ -1,12 +1,10 @@ """Query Indian Financial System Code to get address of the relevant bank or branch Syntax: .ifsc rp """ -from telethon import events import requests import json -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="ifsc rp (.*)")) +@borg.on(slitu.admin_cmd(pattern="ifsc rp (.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/imdb.py b/stdplugins/imdb.py new file mode 100644 index 0000000000..6c52639bd0 --- /dev/null +++ b/stdplugins/imdb.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# UniBorg Telegram UseRBot +# Copyright (C) 2021 @UniBorg +# +# വിവരണം അടിച്ചുമാറ്റിക്കൊണ്ട് പോകുന്നവർ ക്രെഡിറ്റ് വെച്ചാൽ സന്തോഷമേ ഉള്ളു..! +# +# https://github.com/SpEcHiDe/IMDbOT/wiki/Projects-using-this-API + +import aiohttp +import json +from telethon.errors import MediaEmptyError + + +@borg.on(slitu.admin_cmd(pattern="imdb (.*)")) +async def imdb(message): + try: + movie_name = message.pattern_match.group(1) + await message.edit(f"__searching IMDB for__ : `{movie_name}`") + image_link = None + if not movie_name.startswith("tt"): + search_results = await _get(Config.IMDB_API_ONE_URL.format(uniborg=movie_name)) + srch_results = json.loads(search_results) + first_movie = srch_results.get("d")[0] + mov_imdb_id = first_movie.get("id") + image_link = first_movie.get("i").get("imageUrl") + else: + mov_imdb_id = movie_name + mov_link = f"https://www.imdb.com/title/{mov_imdb_id}" + page2 = await _get(Config.IMDB_API_TWO_URL.format(imdbttid=mov_imdb_id)) + second_page_response = json.loads(page2) + mov_title = second_page_response.get("title") + mov_details = get_movie_details(second_page_response) + director, writer, stars = get_credits_text(second_page_response) + story_line = second_page_response.get("summary").get("plot", 'Not available') + mov_country, mov_language = get_countries_and_languages(second_page_response) + mov_rating = second_page_response.get("UserRating").get("description") + des_ = f"""Title🎬: {mov_title} + +More Info: {mov_details} +Rating⭐: {mov_rating} +Country🗺: {mov_country} +Language: {mov_language} +Cast Info🎗: + Director📽: {director} + Writer📄: {writer} + Stars🎭: {stars} + +IMDB URL Link🔗: {mov_link} + +Story Line : {story_line}""" + except IndexError: + await message.edit("Bruh, Plox enter **Valid movie name** kthx") + return + if image_link: + if len(des_) > 1023: + des_ = des_[:1023] + "..." + try: + await message.respond( + des_, + file=image_link, + parse_mode="html" + ) + except MediaEmptyError: + await message.edit(image_link) + await message.reply(des_, parse_mode="HTML") + else: + await message.delete() + else: + if len(des_) > 4095: + des_ = des_[:4095] + "..." + await message.edit(des_, parse_mode="HTML") + + +def get_movie_details(soup): + mov_details = [] + inline = soup.get("Genres") + if inline and len(inline) > 0: + for io in inline: + mov_details.append(io) + tags = soup.get("duration") + if tags: + mov_details.append(tags) + if mov_details and len(mov_details) > 1: + mov_details_text = ' | '.join(mov_details) + else: + mov_details_text = mov_details[0] if mov_details else '' + return mov_details_text + + +def get_countries_and_languages(soup): + languages = soup.get("Language") + countries = soup.get("CountryOfOrigin") + lg_text = "" + if languages: + if len(languages) > 1: + lg_text = ', '.join([lng["NAME"] for lng in languages]) + else: + lg_text = languages[0]["NAME"] + else: + lg_text = "No Languages Found!" + if countries: + if len(countries) > 1: + ct_text = ', '.join([ctn["NAME"] for ctn in countries]) + else: + ct_text = countries[0]["NAME"] + else: + ct_text = "No Country Found!" + return ct_text, lg_text + + +def get_credits_text(soup): + pg = soup.get("sum_mary") + direc = pg.get("Directors") + writer = pg.get("Writers") + actor = pg.get("Stars") + if direc: + if len(direc) > 1: + director = ', '.join([x["NAME"] for x in direc]) + else: + director = direc[0]["NAME"] + else: + director = "No Director Found!" + if writer: + if len(writer) > 1: + writers = ', '.join([x["NAME"] for x in writer]) + else: + writers = writer[0]["NAME"] + else: + writers = "No Writer Found!" + if actor: + if len(actor) > 1: + actors = ', '.join([x["NAME"] for x in actor]) + else: + actors = actor[0]["NAME"] + else: + actors = "No Actor Found!" + return director, writers, actors + + +async def _get(url: str, attempts: int = 0): + if attempts > 5: + raise IndexError + async with aiohttp.ClientSession() as requests: + abc = await requests.get(url) + cba = await abc.text() + if abc.status != 200: + return await _get(url, attempts + 1) + return cba diff --git a/stdplugins/invite.py b/stdplugins/invite.py index 0c3074b11f..c95cc4abd6 100644 --- a/stdplugins/invite.py +++ b/stdplugins/invite.py @@ -2,10 +2,9 @@ Syntax: .invite """ from telethon import functions -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="invite ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="invite ?(.*)")) async def _(event): if event.fwd_from: return @@ -18,22 +17,22 @@ async def _(event): # https://lonamiwebs.github.io/Telethon/methods/messages/add_chat_user.html for user_id in to_add_users.split(" "): try: - await borg(functions.messages.AddChatUserRequest( + await event.client(functions.messages.AddChatUserRequest( chat_id=event.chat_id, user_id=user_id, - fwd_limit=1000000 + fwd_limit=999999 )) except Exception as e: await event.reply(str(e)) - await event.edit("Invited Successfully") else: # https://lonamiwebs.github.io/Telethon/methods/channels/invite_to_channel.html - for user_id in to_add_users.split(" "): - try: - await borg(functions.channels.InviteToChannelRequest( - channel=event.chat_id, - users=[user_id] - )) - except Exception as e: - await event.reply(str(e)) - await event.edit("Invited Successfully") + user_id_s = to_add_users.split(" ") + user_ids = [user_id.strip() for user_id in user_id_s] + try: + await event.client(functions.channels.InviteToChannelRequest( + channel=event.chat_id, + users=user_ids + )) + except Exception as e: + await event.reply(str(e)) + await event.edit("Invited Successfully") diff --git a/stdplugins/json.py b/stdplugins/json.py deleted file mode 100644 index 8e67645981..0000000000 --- a/stdplugins/json.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Get Detailed info about any message -Syntax: .json""" -from telethon import events -import io -from uniborg.util import admin_cmd - - -@borg.on(admin_cmd(pattern="json")) -async def _(event): - if event.fwd_from: - return - the_real_message = None - reply_to_id = None - if event.reply_to_msg_id: - previous_message = await event.get_reply_message() - the_real_message = previous_message.stringify() - reply_to_id = event.reply_to_msg_id - else: - the_real_message = event.stringify() - reply_to_id = event.message.id - if len(the_real_message) > Config.MAX_MESSAGE_SIZE_LIMIT: - with io.BytesIO(str.encode(the_real_message)) as out_file: - out_file.name = "json.text" - await borg.send_file( - event.chat_id, - out_file, - force_document=True, - allow_cache=False, - reply_to=reply_to_id - ) - await event.delete() - else: - await event.edit("`{}`".format(the_real_message)) diff --git a/stdplugins/markdown.py b/stdplugins/markdown.py index acef8a8783..81828ae4f5 100644 --- a/stdplugins/markdown.py +++ b/stdplugins/markdown.py @@ -10,7 +10,8 @@ from telethon.utils import add_surrogate, del_surrogate from telethon.tl.types import ( MessageEntityBold, MessageEntityItalic, MessageEntityCode, - MessageEntityPre, MessageEntityTextUrl + MessageEntityPre, MessageEntityTextUrl, + MessageEntitySpoiler ) @@ -72,6 +73,7 @@ def parse_strikethrough(m): (get_tag_parser('__', MessageEntityItalic)), (get_tag_parser('```', partial(MessageEntityPre, language=''))), (get_tag_parser('`', MessageEntityCode)), + (get_tag_parser('||', MessageEntitySpoiler)), (re.compile(r'\+\+(.+?)\+\+'), parse_aesthetics), (re.compile(r'([^/\w]|^)(/?(r/\w+))'), parse_subreddit), (re.compile(r"(?= len(msg_entities) and event.raw_text == message: return - - await borg(EditMessageRequest( + await event.client(EditMessageRequest( peer=await event.get_input_chat(), id=event.message.id, message=message, diff --git a/stdplugins/meaning.py b/stdplugins/meaning.py index b2685d195a..446417beaf 100644 --- a/stdplugins/meaning.py +++ b/stdplugins/meaning.py @@ -1,12 +1,9 @@ """Dictionary Plugin for @UniBorg Syntax: .meaning """ - import requests -from telethon import events -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="meaning (.*)")) +@borg.on(slitu.admin_cmd(pattern="meaning (.*)")) async def _(event): if event.fwd_from: return @@ -16,7 +13,7 @@ async def _(event): caption_str = f"Meaning of __{input_str}__\n" try: response = requests.get(input_url, headers=headers).json() - pronounciation = response.get("p") + pronounciation = response.get("p")[0] meaning_dict = response.get("lwo") for current_meaning in meaning_dict: current_meaning_type = current_meaning.get("type") diff --git a/stdplugins/ninja.py b/stdplugins/ninja.py index 00ca219948..a856aa029f 100644 --- a/stdplugins/ninja.py +++ b/stdplugins/ninja.py @@ -1,17 +1,13 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. - import asyncio - from telethon import events import telethon.utils -from uniborg import util - async def get_target_message(event): - if event.is_reply and (await event.get_reply_message()).from_id == borg.uid: + if event.is_reply and (await event.get_reply_message()).sender_id == borg.uid: return await event.get_reply_message() async for message in borg.iter_messages( await event.get_input_chat(), limit=20): @@ -27,15 +23,15 @@ async def read_filter(read_event): and read_event.is_read(message)) fut = borg.await_event(events.MessageRead(inbox=False), read_filter) - if await util.is_read(borg, chat, message): + if await slitu.is_read(borg, chat, message): fut.cancel() return await fut -@borg.on(util.admin_cmd(pattern="(del)(?:ete)?$")) -@borg.on(util.admin_cmd(pattern="(edit)(?:\s+(.*))?$")) +@borg.on(slitu.admin_cmd(pattern="(del)(?:ete)?$")) +@borg.on(slitu.admin_cmd(pattern="(edit)(?:\s+(.*))?$")) async def delete(event): await event.delete() command = event.pattern_match.group(1) diff --git a/stdplugins/ocr.py b/stdplugins/ocr.py index 5d1fdb92d7..dd3c5326e3 100644 --- a/stdplugins/ocr.py +++ b/stdplugins/ocr.py @@ -5,7 +5,6 @@ import os from PIL import Image import requests -from uniborg.util import admin_cmd def ocr_space_file(filename, overlay=False, api_key=Config.OCR_SPACE_API_KEY, language='eng'): @@ -64,40 +63,41 @@ def progress(current, total): current, total, (current / total) * 100)) -@borg.on(admin_cmd(pattern="ocrlanguages")) +@borg.on(slitu.admin_cmd(pattern="ocrlanguages")) async def get_ocr_languages(event): if event.fwd_from: return - languages = {} - languages["English"] = "eng" - languages["Arabic"] = "ara" - languages["Bulgarian"] = "bul" - languages["Chinese (Simplified)"] = "chs" - languages["Chinese (Traditional)"] = "cht" - languages["Croatian"] = "hrv" - languages["Czech"] = "cze" - languages["Danish"] = "dan" - languages["Dutch"] = "dut" - languages["Finnish"] = "fin" - languages["French"] = "fre" - languages["German"] = "ger" - languages["Greek"] = "gre" - languages["Hungarian"] = "hun" - languages["Korean"] = "kor" - languages["Italian"] = "ita" - languages["Japanese"] = "jpn" - languages["Polish"] = "pol" - languages["Portuguese"] = "por" - languages["Russian"] = "rus" - languages["Slovenian"] = "slv" - languages["Spanish"] = "spa" - languages["Swedish"] = "swe" - languages["Turkish"] = "tur" + languages = { + "English": "eng", + "Arabic": "ara", + "Bulgarian": "bul", + "Chinese (Simplified)": "chs", + "Chinese (Traditional)": "cht", + "Croatian": "hrv", + "Czech": "cze", + "Danish": "dan", + "Dutch": "dut", + "Finnish": "fin", + "French": "fre", + "German": "ger", + "Greek": "gre", + "Hungarian": "hun", + "Korean": "kor", + "Italian": "ita", + "Japanese": "jpn", + "Polish": "pol", + "Portuguese": "por", + "Russian": "rus", + "Slovenian": "slv", + "Spanish": "spa", + "Swedish": "swe", + "Turkish": "tur", + } a = json.dumps(languages, sort_keys=True, indent=4) await event.edit(str(a)) -@borg.on(admin_cmd(pattern="ocr (.*)")) +@borg.on(slitu.admin_cmd(pattern="ocr (.*)")) async def parse_ocr_space_api(event): if event.fwd_from: return @@ -108,7 +108,7 @@ async def parse_ocr_space_api(event): downloaded_file_name = await borg.download_media( await event.get_reply_message(), Config.TMP_DOWNLOAD_DIRECTORY, - progress_callback=progress + progress_callback=slitu.progress ) if downloaded_file_name.endswith((".webp")): downloaded_file_name = conv_image(downloaded_file_name) @@ -131,5 +131,3 @@ def conv_image(image): new_file_name = image + ".png" os.rename(image, new_file_name) return new_file_name - - diff --git a/stdplugins/pastebin.py b/stdplugins/pastebin.py index a298e43ed3..544e72ad8a 100644 --- a/stdplugins/pastebin.py +++ b/stdplugins/pastebin.py @@ -1,54 +1,111 @@ +# Copyright (C) 2020 by SpEcHiDe@Github, < https://github.com/SpEcHiDe >. +# +# This file is part of < https://github.com/SpEcHiDe/PyroGramBot > project, +# and is released under the +# "GNU Affero General Public License v3.0 License Agreement". +# Please see < https://github.com/SpEcHiDe/PyroGramBot/raw/master/COPYING > +# + """IX.IO pastebin like site Syntax: .paste""" -from telethon import events -import asyncio -from datetime import datetime import os -import requests -from uniborg.util import admin_cmd - +import aiohttp +from json import loads +from json.decoder import JSONDecodeError +from urllib.parse import urlparse -def progress(current, total): - logger.info("Downloaded {} of {}\nCompleted {}".format(current, total, (current / total) * 100)) - -@borg.on(admin_cmd(pattern="paste ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="paste (.*)")) async def _(event): if event.fwd_from: return - start = datetime.now() if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - input_str = event.pattern_match.group(1) + chosen_store = event.pattern_match.group(1) message = "SYNTAX: `.paste `" - if input_str: - message = input_str - elif event.reply_to_msg_id: + ohm = message + if event.reply_to_msg_id: previous_message = await event.get_reply_message() if previous_message.media: - downloaded_file_name = await borg.download_media( - previous_message, - Config.TMP_DOWNLOAD_DIRECTORY, - progress_callback=progress + downloaded_file_name = await previous_message.download_media( + Config.TMP_DOWNLOAD_DIRECTORY ) m_list = None with open(downloaded_file_name, "rb") as fd: m_list = fd.readlines() message = "" for m in m_list: - message += m.decode("UTF-8") + "\r\n" + message += m.decode("UTF-8") os.remove(downloaded_file_name) else: message = previous_message.message else: message = "SYNTAX: `.paste `" - url = "https://del.dog/documents" - r = requests.post(url, data=message.encode("UTF-8")).json() - url = f"https://del.dog/{r['key']}" - end = datetime.now() - ms = (end - start).seconds - if r["isUrl"]: - nurl = f"https://del.dog/v/{r['key']}" - await event.edit("Dogged to {} in {} seconds. GoTo Original URL: {}".format(url, ms, nurl)) - else: - await event.edit("Dogged to {} in {} seconds".format(url, ms)) + + if message != ohm: + json_paste_data = { + "content": message + } + # a dictionary to store different pastebin URIs + paste_bin_store_s = { + "nekobin": { + "URL": "https://nekobin.com/api/documents", + "RAV": "result.key", + "GAS": "https://github.com/nekobin/nekobin", + }, + "pasty": { + "URL": "https://pasty.lus.pm/api/v1/pastes", + "HEADERS": { + "User-Agent": "PyroGramBot/6.9", + "Content-Type": "application/json", + }, + "RAV": "id", + "GAS": "https://github.com/lus/pasty", + }, + "pasting": { + "URL": "https://pasting.codes/api", + }, + "ixio": { + "URL": "http://ix.io", + }, + } + # get the required pastebin URI + paste_store_ = paste_bin_store_s.get( + chosen_store, + paste_bin_store_s.get("pasty") + ) + + paste_store_url = paste_store_.get("URL") + paste_store_base_url_rp = urlparse(paste_store_url) + + # the pastebin sites, respond with only the "key" + # we need to prepend the BASE_URL of the appropriate site + paste_store_base_url = paste_store_base_url_rp.scheme + \ + "://" + \ + paste_store_base_url_rp.netloc + + async with aiohttp.ClientSession() as session: + response_d = await session.post( + paste_store_url, + json=json_paste_data, + headers=paste_store_.get("HEADERS") + ) + response_jn = await response_d.text() + try: + response_jn = loads(response_jn.strip()) + except JSONDecodeError: + # some sites, do not have JSON response + pass + + rk = paste_store_.get("RAV") + if rk: + rkp = rk.split(".") + for kp in rkp: + response_jn = response_jn.get(kp) + + else: + response_jn = response_jn[1:] + + required_url = paste_store_base_url + "/" + response_jn + await event.edit(required_url, link_preview=False) + diff --git a/stdplugins/periksa_peserta.py b/stdplugins/periksa_peserta.py new file mode 100644 index 0000000000..e3ea7f39b3 --- /dev/null +++ b/stdplugins/periksa_peserta.py @@ -0,0 +1,47 @@ +"""#Telegram #Failures + +#768 + +by @UniBorg""" + +from telethon.tl.functions.channels import GetParticipantRequest +from telethon.errors import UserNotParticipantError + + +@borg.on(slitu.admin_cmd(pattern="pep ?(.*)")) +async def _(event): + if event.fwd_from: + return + s_ = await event.reply(".") + input_str = event.pattern_match.group(1) + chat = event.chat_id + reply = await event.get_reply_message() + await event.delete() + if not input_str and reply: + input_str = reply.sender_id + else: + input_str = input_str.strip() + if input_str.isnumeric(): + input_str = int(input_str) + try: + rpoi = await event.client(GetParticipantRequest( + channel=chat, + user_id=input_str + )) + except UserNotParticipantError: + await s_.edit(f"user `{input_str}` has not joined `{chat}`") + else: + participant = rpoi.participant + new_ko = {} + available_kinds = ( + "user_id", + "promoted_by", + "kicked_by" + ) + for kind in available_kinds: + poid = getattr(participant, kind, None) + if poid is not None: + epoid = await event.client.get_entity(poid) + new_ko[kind] = epoid + await s_.edit(f"`{borg.secure_text(slitu.yaml_format(new_ko))}`") + diff --git a/stdplugins/pin_message.py b/stdplugins/pin_message.py index cc86cb011e..68b3b6eb1a 100644 --- a/stdplugins/pin_message.py +++ b/stdplugins/pin_message.py @@ -1,11 +1,9 @@ """Pins the replied message Syntax: .cpin [LOUD]""" -from telethon import events from telethon.tl import functions, types -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="cpin ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="cpin ?(.*)")) async def _(event): if event.fwd_from: return @@ -16,7 +14,7 @@ async def _(event): if event.message.reply_to_msg_id is not None: message_id = event.message.reply_to_msg_id try: - await borg(functions.messages.UpdatePinnedMessageRequest( + await event.client(functions.messages.UpdatePinnedMessageRequest( event.chat_id, message_id, silent diff --git a/stdplugins/ping.py b/stdplugins/ping.py index 2a7ec9e020..d0fde12352 100644 --- a/stdplugins/ping.py +++ b/stdplugins/ping.py @@ -1,13 +1,11 @@ -from telethon import events from datetime import datetime -from uniborg.util import admin_cmd, edit_or_reply -@borg.on(admin_cmd(pattern="ping", allow_sudo=True)) +@borg.on(slitu.admin_cmd(pattern="ping", allow_sudo=True)) async def _(event): if event.fwd_from: return - ed = await edit_or_reply(event, event.from_id, "...") + ed = await slitu.edit_or_reply(event, "...") start = datetime.now() await ed.edit("Pong!") end = datetime.now() diff --git a/stdplugins/polls.py b/stdplugins/polls.py index 8fce08f7a4..ff051d14b0 100644 --- a/stdplugins/polls.py +++ b/stdplugins/polls.py @@ -1,32 +1,31 @@ """Get Poll Info on non supported clients Syntax: .get_poll""" -from telethon import events -import asyncio -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="get_poll")) +@borg.on(slitu.admin_cmd(pattern="get_poll")) async def _(event): reply_message = await event.get_reply_message() - if reply_message.media is None: - await event.edit("Please reply to a media_type == @gPoll to view the questions and answers") - elif reply_message.media.poll is None: - await event.edit("Please reply to a media_type == @gPoll to view the questions and answers") + if reply_message.media is None or reply_message.media.poll is None: + await event.edit( + "Please reply to a media_type == @gPoll to view the questions and answers" + ) else: media = reply_message.media poll = media.poll closed_status = poll.closed answers = poll.answers question = poll.question - edit_caption = """Poll is Closed: {} -Question: {} -Answers: \n""".format(closed_status, question) + edit_caption = f"Poll is Closed: {closed_status}\n" + edit_caption += f"Question: {question}\n" + edit_caption += "Answers: \n" if closed_status: results = media.results - i = 0 - for result in results.results: - edit_caption += "{}> {} {}\n".format(result.option, answers[i].text, result.voters) - i += 1 + for i, result in enumerate(results.results): + edit_caption += "{}> {} {}\n".format( + result.option, + answers[i].text, + result.voters + ) edit_caption += "Total Voters: {}".format(results.total_voters) else: for answer in answers: diff --git a/stdplugins/power_tools.py b/stdplugins/power_tools.py index 210e87abe1..62c8906f5a 100644 --- a/stdplugins/power_tools.py +++ b/stdplugins/power_tools.py @@ -5,14 +5,12 @@ # This Source Code Form is subject to the terms of the GNU # General Public License, v.3.0. If a copy of the GPL was not distributed with this # file, You can obtain one at https://www.gnu.org/licenses/gpl-3.0.en.html -from telethon import events import asyncio import os import sys -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="restart")) +@borg.on(slitu.admin_cmd(pattern="restart")) async def _(event): if event.fwd_from: return @@ -22,16 +20,16 @@ async def _(event): # await event.edit("Restarting [███]...\n`.ping` me or `.helpme` to check if I am online") # await asyncio.sleep(2) await event.edit("Restarted. `.ping` me or `.helpme` to check if I am online") - await borg.disconnect() + await event.client.disconnect() # https://archive.is/im3rt os.execl(sys.executable, sys.executable, *sys.argv) # You probably don't need it but whatever quit() -@borg.on(admin_cmd(pattern="shutdown")) +@borg.on(slitu.admin_cmd(pattern="shutdown")) async def _(event): if event.fwd_from: return await event.edit("Turning off ...Manually turn me on later") - await borg.disconnect() + await event.client.disconnect() diff --git a/stdplugins/promote.py b/stdplugins/promote.py index 2673a7b338..cbc0a6a22b 100644 --- a/stdplugins/promote.py +++ b/stdplugins/promote.py @@ -1,13 +1,11 @@ """Reply to a user to .promote them in the current chat""" -from telethon import events import asyncio from datetime import datetime from telethon.tl.functions.channels import EditAdminRequest from telethon.tl.types import ChatAdminRights -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="promote ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="promote ?(.*)")) async def _(event): if event.fwd_from: return @@ -31,14 +29,14 @@ async def _(event): elif input_str: to_promote_id = input_str try: - await borg(EditAdminRequest(event.chat_id, to_promote_id, rights, "")) + await event.client(EditAdminRequest(event.chat_id, to_promote_id, rights, "")) except (Exception) as exc: await event.edit(str(exc)) else: await event.edit("Successfully Promoted") -@borg.on(admin_cmd(pattern="prankpromote ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="prankpromote ?(.*)")) async def _(event): if event.fwd_from: return @@ -55,7 +53,7 @@ async def _(event): elif input_str: to_promote_id = input_str try: - await borg(EditAdminRequest(event.chat_id, to_promote_id, rights, "")) + await event.client(EditAdminRequest(event.chat_id, to_promote_id, rights, "")) except (Exception) as exc: await event.edit(str(exc)) else: diff --git a/stdplugins/purge.py b/stdplugins/purge.py index 94a5e9c769..7c18730967 100644 --- a/stdplugins/purge.py +++ b/stdplugins/purge.py @@ -1,10 +1,8 @@ """Purge your messages without the admins seeing it in Recent Actions""" -from telethon import events import asyncio -from uniborg.util import admin_cmd -@borg.on(admin_cmd(pattern="purge ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="purge ?(.*)")) async def _(event): if event.fwd_from: return @@ -14,20 +12,20 @@ async def _(event): from_user = None input_str = event.pattern_match.group(1) if input_str: - from_user = await borg.get_entity(input_str) + from_user = await event.client.get_entity(input_str) logger.info(from_user) - async for message in borg.iter_messages( + async for message in event.client.iter_messages( event.chat_id, min_id=event.reply_to_msg_id, from_user=from_user ): - i = i + 1 + i += 1 msgs.append(message) - if len(msgs) == 100: - await borg.delete_messages(event.chat_id, msgs, revoke=True) + if len(msgs) >= 100: + await event.client.delete_messages(event.chat_id, msgs, revoke=True) msgs = [] - if len(msgs) <= 100: - await borg.delete_messages(event.chat_id, msgs, revoke=True) + if len(msgs) > 0: + await event.client.delete_messages(event.chat_id, msgs, revoke=True) msgs = [] await event.delete() else: diff --git a/stdplugins/qr_code.py b/stdplugins/qr_code.py index 7b116759ee..b923ccd1d9 100644 --- a/stdplugins/qr_code.py +++ b/stdplugins/qr_code.py @@ -2,11 +2,9 @@ Available Commands .getqr .makeqr """ -from telethon import events import asyncio from datetime import datetime import os -from uniborg.util import admin_cmd import qrcode from bs4 import BeautifulSoup @@ -15,7 +13,7 @@ def progress(current, total): logger.info("Downloaded {} of {}\nCompleted {}".format(current, total, (current / total) * 100)) -@borg.on(admin_cmd(pattern="getqr")) +@borg.on(slitu.admin_cmd(pattern="getqr")) async def _(event): if event.fwd_from: return @@ -34,21 +32,12 @@ async def _(event): "-F", "f=@" + downloaded_file_name + "", "https://zxing.org/w/decode" ] - process = await asyncio.create_subprocess_exec( - *command_to_exec, - # stdout must a pipe to be accessible as process.stdout - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - # Wait for the subprocess to finish - stdout, stderr = await process.communicate() - e_response = stderr.decode().strip() - t_response = stdout.decode().strip() + t_response, e_response = await slitu.run_command(command_to_exec) os.remove(downloaded_file_name) if not t_response: logger.info(e_response) logger.info(t_response) - await event.edit("@oo0pps .. something wrongings. Failed to decode QRCode") + await event.edit("oo0pps .. something wrongings. Failed to decode QRCode") return soup = BeautifulSoup(t_response, "html.parser") qr_contents = soup.find_all("pre")[0].text @@ -59,7 +48,7 @@ async def _(event): await event.edit(qr_contents) -@borg.on(admin_cmd(pattern="makeqr ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="makeqr ?(.*)")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/rapidleech.py b/stdplugins/rapidleech.py index c1af333a6d..8128f90db8 100644 --- a/stdplugins/rapidleech.py +++ b/stdplugins/rapidleech.py @@ -15,14 +15,9 @@ import re from bs4 import BeautifulSoup from telethon.utils import get_inner_text -from uniborg.util import admin_cmd -logger.info(Config.OPEN_LOAD_LOGIN) -# https://t.me/RoseSupport/33801 - - -@borg.on(admin_cmd(pattern="rl")) +@borg.on(slitu.admin_cmd(pattern="rl")) async def _(event): if event.fwd_from: return diff --git a/stdplugins/remove.bg.py b/stdplugins/remove.bg.py index 91105ccdea..fef2008137 100644 --- a/stdplugins/remove.bg.py +++ b/stdplugins/remove.bg.py @@ -20,13 +20,10 @@ import io import os import requests -from telethon import events -from uniborg.util import progress, admin_cmd -@borg.on(admin_cmd(pattern="remove\.bg ?(.*)")) +@borg.on(slitu.admin_cmd(pattern="remove\.bg ?(.*)")) async def _(event): - HELP_STR = "`.remove.bg` as reply to a media, or give a link as an argument to this command" if event.fwd_from: return if Config.REM_BG_API_KEY is None: @@ -56,6 +53,7 @@ async def _(event): await event.edit("sending to ReMove.BG") output_file_name = ReTrieveURL(input_str) else: + HELP_STR = "`.remove.bg` as reply to a media, or give a link as an argument to this command" await event.edit(HELP_STR) return contentType = output_file_name.headers.get("content-type") @@ -86,14 +84,13 @@ def ReTrieveFile(input_file_name): files = { "image_file": (input_file_name, open(input_file_name, "rb")), } - r = requests.post( + return requests.post( "https://api.remove.bg/v1.0/removebg", headers=headers, files=files, allow_redirects=True, stream=True ) - return r def ReTrieveURL(input_url): @@ -103,11 +100,10 @@ def ReTrieveURL(input_url): data = { "image_url": input_url } - r = requests.post( + return requests.post( "https://api.remove.bg/v1.0/removebg", headers=headers, data=data, allow_redirects=True, stream=True ) - return r diff --git a/stdplugins/rename.py b/stdplugins/rename.py deleted file mode 100644 index 8472b6ccc3..0000000000 --- a/stdplugins/rename.py +++ /dev/null @@ -1,226 +0,0 @@ -"""Rename Telegram Files -Syntax: -.rnupload file.name -.rnstreamupload file.name -By @Ck_ATR""" - -import asyncio -import time -from datetime import datetime -from hachoir.metadata import extractMetadata -from hachoir.parser import createParser -import math -import os -from pySmartDL import SmartDL -from telethon.tl.types import DocumentAttributeVideo -from uniborg.util import progress, humanbytes, time_formatter, admin_cmd - - -thumb_image_path = Config.TMP_DOWNLOAD_DIRECTORY + "/thumb_image.jpg" - - -@borg.on(admin_cmd(pattern="rndlup (.*)")) -async def _(event): - if event.fwd_from: - return - if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): - os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - thumb = None - if os.path.exists(thumb_image_path): - thumb = thumb_image_path - start = datetime.now() - input_str = event.pattern_match.group(1) - url = input_str - file_name = os.path.basename(url) - to_download_directory = Config.TMP_DOWNLOAD_DIRECTORY - if "|" in input_str: - url, file_name = input_str.split("|") - url = url.strip() - file_name = file_name.strip() - downloaded_file_name = os.path.join(to_download_directory, file_name) - downloader = SmartDL(url, downloaded_file_name, progress_bar=False) - downloader.start(blocking=False) - display_message = "" - c_time = time.time() - while not downloader.isFinished(): - total_length = downloader.filesize if downloader.filesize else None - downloaded = downloader.get_dl_size() - now = time.time() - diff = now - c_time - percentage = downloader.get_progress() * 100 - speed = downloader.get_speed() - elapsed_time = round(diff) * 1000 - progress_str = "[{0}{1}]\nProgress: {2}%".format( - ''.join(["█" for i in range(math.floor(percentage / 5))]), - ''.join(["░" for i in range(20 - math.floor(percentage / 5))]), - round(percentage, 2)) - estimated_total_time = downloader.get_eta(human=True) - try: - current_message = f"trying to download\n" - current_message += f"URL: {url}\n" - current_message += f"File Name: {file_name}\n" - current_message += f"{progress_str}\n" - current_message += f"{humanbytes(downloaded)} of {humanbytes(total_length)}\n" - current_message += f"ETA: {estimated_total_time}" - if round(diff % 10.00) == 0 and current_message != display_message: - await event.edit(current_message) - display_message = current_message - except Exception as e: - logger.info(str(e)) - end = datetime.now() - ms_dl = (end - start).seconds - if downloader.isSuccessful(): - await event.edit("Downloaded to `{}` in {} seconds.".format(downloaded_file_name, ms_dl)) - if os.path.exists(downloaded_file_name): - c_time = time.time() - await borg.send_file( - event.chat_id, - downloaded_file_name, - force_document=True, - supports_streaming=False, - allow_cache=False, - reply_to=event.message.id, - thumb=thumb, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") - ) - ) - end_two = datetime.now() - os.remove(downloaded_file_name) - ms_two = (end_two - end).seconds - await event.edit("Downloaded in {} seconds. Uploaded in {} seconds.".format(ms_dl, ms_two)) - else: - await event.edit("File Not Found {}".format(input_str)) - else: - await mone.edit("Incorrect URL\n {}".format(input_str)) - - -@borg.on(admin_cmd(pattern="rnupload (.*)")) -async def _(event): - if event.fwd_from: - return - thumb = None - if os.path.exists(thumb_image_path): - thumb = thumb_image_path - await event.edit("Rename & Upload in process 🙄🙇‍♂️🙇‍♂️🙇‍♀️ It might take some time if file size is big") - input_str = event.pattern_match.group(1) - if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): - os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - if event.reply_to_msg_id: - start = datetime.now() - file_name = input_str - reply_message = await event.get_reply_message() - to_download_directory = Config.TMP_DOWNLOAD_DIRECTORY - downloaded_file_name = os.path.join(to_download_directory, file_name) - c_time = time.time() - downloaded_file_name = await borg.download_media( - reply_message, - downloaded_file_name, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to download") - ) - ) - end = datetime.now() - ms_one = (end - start).seconds - if os.path.exists(downloaded_file_name): - c_time = time.time() - await borg.send_file( - event.chat_id, - downloaded_file_name, - force_document=True, - supports_streaming=False, - allow_cache=False, - reply_to=event.message.id, - thumb=thumb, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") - ) - ) - end_two = datetime.now() - os.remove(downloaded_file_name) - ms_two = (end_two - end).seconds - await event.edit("Downloaded in {} seconds. Uploaded in {} seconds.".format(ms_one, ms_two)) - else: - await event.edit("File Not Found {}".format(input_str)) - else: - await event.edit("Syntax // .rnupload file.name as reply to a Telegram media") - - -@borg.on(admin_cmd(pattern="rnstreamupload (.*)")) -async def _(event): - if event.fwd_from: - return - await event.edit("Rename & Upload as Streamable in process 🙄🙇‍♂️🙇‍♂️🙇‍♀️ It might take some time if file size is big") - input_str = event.pattern_match.group(1) - if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY): - os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY) - if event.reply_to_msg_id: - start = datetime.now() - file_name = input_str - reply_message = await event.get_reply_message() - c_time = time.time() - to_download_directory = Config.TMP_DOWNLOAD_DIRECTORY - downloaded_file_name = os.path.join(to_download_directory, file_name) - downloaded_file_name = await borg.download_media( - reply_message, - downloaded_file_name, - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to download") - ) - ) - end_one = datetime.now() - ms_one = (end_one - start).seconds - if os.path.exists(downloaded_file_name): - thumb = None - if os.path.exists(thumb_image_path): - thumb = thumb_image_path - start = datetime.now() - metadata = extractMetadata(createParser(downloaded_file_name)) - duration = 0 - width = 0 - height = 0 - if metadata.has("duration"): - duration = metadata.get('duration').seconds - if os.path.exists(thumb_image_path): - metadata = extractMetadata(createParser(thumb_image_path)) - if metadata.has("width"): - width = metadata.get("width") - if metadata.has("height"): - height = metadata.get("height") - # Telegram only works with MP4 files - # this is good, since with MKV files sent as streamable Telegram responds, - # Bad Request: VIDEO_CONTENT_TYPE_INVALID - c_time = time.time() - try: - await borg.send_file( - event.chat_id, - downloaded_file_name, - thumb=thumb, - caption=downloaded_file_name, - force_document=False, - allow_cache=False, - reply_to=event.message.id, - attributes=[ - DocumentAttributeVideo( - duration=duration, - w=width, - h=height, - round_message=False, - supports_streaming=True - ) - ], - progress_callback=lambda d, t: asyncio.get_event_loop().create_task( - progress(d, t, event, c_time, "trying to upload") - ) - ) - except Exception as e: - await event.edit(str(e)) - else: - end = datetime.now() - os.remove(downloaded_file_name) - ms_two = (end - end_one).seconds - await event.edit("Downloaded in {} seconds. Uploaded in {} seconds.".format(ms_one, ms_two)) - else: - await event.edit("File Not Found {}".format(input_str)) - else: - await event.edit("Syntax // .rnstreamupload file.name as reply to a Telegram media") diff --git a/stdplugins/sca.py b/stdplugins/sca.py index 503b2d4ce4..add6d1c342 100644 --- a/stdplugins/sca.py +++ b/stdplugins/sca.py @@ -2,11 +2,8 @@ Syntax: .sca