- Added sudo using database
NOTE: redeploy recommended to generating database, or you can go to your herokuapp > resources > add-ons > then serach Heroku Postgres > hit Submit Order Form, then copy your database url from DATABASE_URL > Heroku config vars
- mirror: Fix for uploading telegram file_name of None type
- gdriveTools: Fix infinite loop when hitting rate limits

Co-authored-by: Sreeraj V R <SVR666@users.noreply.github.com>
Co-authored-by: Gautam Kumar <gautamajay52@gmail.com>
Co-authored-by: KenHV <yo@kenharris.xyz>
This commit is contained in:
Hafitz Setya 2021-05-17 15:36:46 +07:00 committed by GitHub
parent 9d969f3ab6
commit 6df4486ca5
Signed by untrusted user: GitHub
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 359 additions and 79 deletions

View File

@ -7,11 +7,11 @@ This is a Telegram bot writen in Python for mirroring files on the Internet to o
## Additional Features ## Additional Features
- Mirroring Uptobox.com links to Google Drive (Uptobox account must be premium) - Mirroring Uptobox.com links to Google Drive (Uptobox account must be premium)
- Sudo support (DWYOR, Sudo User can restart your bot and delete your Drive file)
- Get detailed info about replied media - Get detailed info about replied media
- Nyaa.si and Sukebei Torrent search - Nyaa.si and Sukebei Torrent search
- Speedtest with picture results - Speedtest with picture results
- Limiting Torrent size support - Limiting Torrent size support
- Sudo with database support
- Check Heroku dynos stats - Check Heroku dynos stats
- Custom image support - Custom image support
- Racaty.net support - Racaty.net support
@ -63,11 +63,56 @@ Install Docker by following the [official Docker docs](https://docs.docker.com/e
``` ```
sudo pacman -S docker python sudo pacman -S docker python
``` ```
- Install dependencies for running setup scripts: - Install dependencies for running setup scripts:
``` ```
pip3 install -r requirements-cli.txt pip3 install -r requirements-cli.txt
``` ```
## Generate Database
<details>
<summary><b>Click here for more details</b></summary>
**1. The easy way**
- Make new Heroku blank app
- Go to your Heroku blank app
- Go to resources
- In Add-ons search **Heroku Postgres**
- Hit **Submit Order Form**
- Copy your Database URL from Heroku Config Vars > **DATABASE_URL**
**2. The hard way**
- Install Postgresql:
```
sudo apt-get update && sudo apt-get install postgresql
```
- Change to the Postgres user:
```
sudo su - postgres
```
- Create a new database user (change YOUR_USER appropriately):
```
createuser -P -s -e YOUR_USER
```
This will be followed by you needing to input your password.
- Create a new database table:
```
createdb -O YOUR_USER YOUR_DB_NAME
```
Change YOUR_USER and YOUR_DB_NAME appropriately.
- Finally:
```
psql YOUR_DB_NAME -h YOUR_HOST YOUR_USER
```
This will allow you to connect to your database via your terminal. By default, YOUR_HOST should be 0.0.0.0:5432.
You should now be able to build your database URL. This will be:
```
sqldbtype://username:pw@hostname:port/db_name
```
Replace sqldbtype with whichever db youre using (eg postgres, mysql, sqllite, etc) repeat for your username, password, hostname (localhost?), port (5432?), and db name.
**NOTE**: If you deploying on Heroku, no need to generate database manually, because it will automatic generate database
</details>
## Setting up config file ## Setting up config file
<details> <details>
@ -86,8 +131,8 @@ Fill up rest of the fields. Meaning of each fields are discussed below:
- **DOWNLOAD_DIR**: The path to the local folder where the downloads should be downloaded to - **DOWNLOAD_DIR**: The path to the local folder where the downloads should be downloaded to
- **DOWNLOAD_STATUS_UPDATE_INTERVAL**: A short interval of time in seconds after which the Mirror progress message is updated. (I recommend to keep it `5` seconds at least) - **DOWNLOAD_STATUS_UPDATE_INTERVAL**: A short interval of time in seconds after which the Mirror progress message is updated. (I recommend to keep it `5` seconds at least)
- **OWNER_ID**: The Telegram user ID (not username) of the Owner of the bot - **OWNER_ID**: The Telegram user ID (not username) of the Owner of the bot
- **SUDO_USER**: (Optional field) Multiple Telegram user ID (not username) separate by space.
- **AUTHORIZED_CHATS**: Fill user_id and chat_id of you want to authorize. - **AUTHORIZED_CHATS**: Fill user_id and chat_id of you want to authorize.
- **DATABASE_URL**: Your Database URL. See [Generate Database](https://github.com/breakdowns/slam-mirrorbot/tree/master#generate-database) to generate database. (**NOTE**: If you deploying on Heroku, no need to generate database manually, because it will automatic generate database)
- **AUTO_DELETE_MESSAGE_DURATION**: Interval of time (in seconds), after which the bot deletes it's message (and command message) which is expected to be viewed instantly. (**Note**: Set to `-1` to never automatically delete messages) - **AUTO_DELETE_MESSAGE_DURATION**: Interval of time (in seconds), after which the bot deletes it's message (and command message) which is expected to be viewed instantly. (**Note**: Set to `-1` to never automatically delete messages)
- **IS_TEAM_DRIVE**: (Optional field) Set to `True` if `GDRIVE_FOLDER_ID` is from a Team Drive else `False` or Leave it empty. - **IS_TEAM_DRIVE**: (Optional field) Set to `True` if `GDRIVE_FOLDER_ID` is from a Team Drive else `False` or Leave it empty.
- **USE_SERVICE_ACCOUNTS**: (Optional field) (Leave empty if unsure) Whether to use Service Accounts or not. For this to work see [Using service accounts](https://github.com/breakdowns/slam-mirrorbot#generate-service-accounts-what-is-service-account) section below. - **USE_SERVICE_ACCOUNTS**: (Optional field) (Leave empty if unsure) Whether to use Service Accounts or not. For this to work see [Using service accounts](https://github.com/breakdowns/slam-mirrorbot#generate-service-accounts-what-is-service-account) section below.

View File

@ -38,10 +38,6 @@
"description": "The Telegram User ID of the Owner of the Bot. Get it by using /info in @MissRose_bot.", "description": "The Telegram User ID of the Owner of the Bot. Get it by using /info in @MissRose_bot.",
"required": true "required": true
}, },
"SUDO_USER": {
"description": "Multiple Telegram user ID (not username) separate by space.",
"required": false
},
"AUTO_DELETE_MESSAGE_DURATION": { "AUTO_DELETE_MESSAGE_DURATION": {
"description": "Interval of time (in seconds), after which the bot deletes it's message (and command message) which is expected to be viewed instantly. Note: Set to -1 to never automatically delete messages.", "description": "Interval of time (in seconds), after which the bot deletes it's message (and command message) which is expected to be viewed instantly. Note: Set to -1 to never automatically delete messages.",
"required": true "required": true
@ -153,5 +149,10 @@
"description": "Fill your URL if you are using extra buttons.", "description": "Fill your URL if you are using extra buttons.",
"required": false "required": false
} }
} },
"addons": [
{
"plan": "heroku-postgresql"
}
]
} }

View File

@ -11,6 +11,9 @@ from dotenv import load_dotenv
from pyrogram import Client from pyrogram import Client
from telegraph import Telegraph from telegraph import Telegraph
import psycopg2
from psycopg2 import Error
import socket import socket
import faulthandler import faulthandler
faulthandler.enable() faulthandler.enable()
@ -26,6 +29,8 @@ logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s
handlers=[logging.FileHandler('log.txt'), logging.StreamHandler()], handlers=[logging.FileHandler('log.txt'), logging.StreamHandler()],
level=logging.INFO) level=logging.INFO)
LOGGER = logging.getLogger(__name__)
load_dotenv('config.env') load_dotenv('config.env')
Interval = [] Interval = []
@ -34,8 +39,17 @@ Interval = []
def getConfig(name: str): def getConfig(name: str):
return os.environ[name] return os.environ[name]
def mktable():
LOGGER = logging.getLogger(__name__) try:
conn = psycopg2.connect(DB_URI)
cur = conn.cursor()
sql = "CREATE TABLE users (uid bigint, sudo boolean DEFAULT FALSE);"
cur.execute(sql)
conn.commit()
LOGGER.info("Table Created!")
except Error as e:
LOGGER.error(e)
exit(1)
try: try:
if bool(getConfig('_____REMOVE_THIS_LINE_____')): if bool(getConfig('_____REMOVE_THIS_LINE_____')):
@ -65,12 +79,7 @@ status_reply_dict = {}
download_dict = {} download_dict = {}
# Stores list of users and chats the bot is authorized to use in # Stores list of users and chats the bot is authorized to use in
AUTHORIZED_CHATS = set() AUTHORIZED_CHATS = set()
if os.path.exists('authorized_chats.txt'): SUDO_USERS = set()
with open('authorized_chats.txt', 'r+') as f:
lines = f.readlines()
for line in lines:
# LOGGER.info(line.split())
AUTHORIZED_CHATS.add(int(line.split()[0]))
try: try:
achats = getConfig('AUTHORIZED_CHATS') achats = getConfig('AUTHORIZED_CHATS')
achats = achats.split(" ") achats = achats.split(" ")
@ -81,13 +90,13 @@ except:
try: try:
BOT_TOKEN = getConfig('BOT_TOKEN') BOT_TOKEN = getConfig('BOT_TOKEN')
DB_URI = getConfig('DATABASE_URL')
parent_id = getConfig('GDRIVE_FOLDER_ID') parent_id = getConfig('GDRIVE_FOLDER_ID')
DOWNLOAD_DIR = getConfig('DOWNLOAD_DIR') DOWNLOAD_DIR = getConfig('DOWNLOAD_DIR')
if DOWNLOAD_DIR[-1] != '/' or DOWNLOAD_DIR[-1] != '\\': if DOWNLOAD_DIR[-1] != '/' or DOWNLOAD_DIR[-1] != '\\':
DOWNLOAD_DIR = DOWNLOAD_DIR + '/' DOWNLOAD_DIR = DOWNLOAD_DIR + '/'
DOWNLOAD_STATUS_UPDATE_INTERVAL = int(getConfig('DOWNLOAD_STATUS_UPDATE_INTERVAL')) DOWNLOAD_STATUS_UPDATE_INTERVAL = int(getConfig('DOWNLOAD_STATUS_UPDATE_INTERVAL'))
OWNER_ID = int(getConfig('OWNER_ID')) OWNER_ID = int(getConfig('OWNER_ID'))
SUDO_USER = tuple(filter(lambda x: x, map(int, os.environ.get("SUDO_USER", "").split())))
AUTO_DELETE_MESSAGE_DURATION = int(getConfig('AUTO_DELETE_MESSAGE_DURATION')) AUTO_DELETE_MESSAGE_DURATION = int(getConfig('AUTO_DELETE_MESSAGE_DURATION'))
TELEGRAM_API = getConfig('TELEGRAM_API') TELEGRAM_API = getConfig('TELEGRAM_API')
TELEGRAM_HASH = getConfig('TELEGRAM_HASH') TELEGRAM_HASH = getConfig('TELEGRAM_HASH')
@ -95,6 +104,26 @@ except KeyError as e:
LOGGER.error("One or more env variables missing! Exiting now") LOGGER.error("One or more env variables missing! Exiting now")
exit(1) exit(1)
try:
conn = psycopg2.connect(DB_URI)
cur = conn.cursor()
sql = "SELECT * from users;"
cur.execute(sql)
rows = cur.fetchall() #returns a list ==> (uid, sudo)
for row in rows:
AUTHORIZED_CHATS.add(row[0])
if row[1]:
SUDO_USERS.add(row[0])
except Error as e:
if 'relation "users" does not exist' in str(e):
mktable()
else:
LOGGER.error(e)
exit(1)
finally:
cur.close()
conn.close()
LOGGER.info("Generating USER_SESSION_STRING") LOGGER.info("Generating USER_SESSION_STRING")
with Client(':memory:', api_id=int(TELEGRAM_API), api_hash=TELEGRAM_HASH, bot_token=BOT_TOKEN) as app: with Client(':memory:', api_id=int(TELEGRAM_API), api_hash=TELEGRAM_HASH, bot_token=BOT_TOKEN) as app:
USER_SESSION_STRING = app.export_session_string() USER_SESSION_STRING = app.export_session_string()

View File

@ -10,7 +10,7 @@ import pytz
import time import time
from telegram import ParseMode, BotCommand, InlineKeyboardMarkup, InlineKeyboardButton from telegram import ParseMode, BotCommand, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import CommandHandler, run_async from telegram.ext import CommandHandler, run_async
from bot import dispatcher, updater, botStartTime, AUTHORIZED_CHATS, SUDO_USER, IMAGE_URL from bot import dispatcher, updater, botStartTime, IMAGE_URL
from bot.helper.ext_utils import fs_utils from bot.helper.ext_utils import fs_utils
from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.telegram_helper.message_utils import * from bot.helper.telegram_helper.message_utils import *
@ -56,14 +56,6 @@ Type /{BotCommands.HelpCommand} to get a list of available commands
update.effective_message.reply_photo(IMAGE_URL, start_string, parse_mode=ParseMode.MARKDOWN) update.effective_message.reply_photo(IMAGE_URL, start_string, parse_mode=ParseMode.MARKDOWN)
@run_async
def chat_list(update, context):
chat_list = sudo = ''
chat_list += '\n'.join(str(id) for id in AUTHORIZED_CHATS)
sudo += '\n'.join(str(id) for id in SUDO_USER)
sendMessage(f'<b><u>Authorized Chats</u></b>\n{chat_list}\n<b><u>Sudo Users</u></b>\n{sudo}', context.bot, update)
@run_async @run_async
def repo(update, context): def repo(update, context):
button = [ button = [
@ -99,10 +91,10 @@ def log(update, context):
@run_async @run_async
def bot_help(update, context): def bot_help(update, context):
help_string = f''' help_string_adm = f'''
/{BotCommands.HelpCommand}: To get this message /{BotCommands.HelpCommand}: To get this message
/{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to Google Drive /{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to Google Drive.
/{BotCommands.UnzipMirrorCommand} [download_url][magnet_link]: Starts mirroring and if downloaded file is any archive, extracts it to Google Drive /{BotCommands.UnzipMirrorCommand} [download_url][magnet_link]: Starts mirroring and if downloaded file is any archive, extracts it to Google Drive
@ -110,6 +102,8 @@ def bot_help(update, context):
/{BotCommands.CloneCommand}: Copy file/folder to Google Drive /{BotCommands.CloneCommand}: Copy file/folder to Google Drive
/{BotCommands.DeleteCommand} [link]: Delete file from Google Drive (Only Owner & Sudo)
/{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl. Click /{BotCommands.WatchCommand} for more help. /{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl. Click /{BotCommands.WatchCommand} for more help.
/{BotCommands.TarWatchCommand} [youtube-dl supported link]: Mirror through youtube-dl and tar before uploading /{BotCommands.TarWatchCommand} [youtube-dl supported link]: Mirror through youtube-dl and tar before uploading
@ -124,7 +118,13 @@ def bot_help(update, context):
/{BotCommands.AuthorizeCommand}: Authorize a chat or a user to use the bot (Can only be invoked by Owner & Sudo of the bot) /{BotCommands.AuthorizeCommand}: Authorize a chat or a user to use the bot (Can only be invoked by Owner & Sudo of the bot)
/{BotCommands.AuthListCommand}: See Authorized list & Sudo User (Can only be invoked by Owner & Sudo of the bot) /{BotCommands.UnAuthorizeCommand}: Unauthorize a chat or a user to use the bot (Can only be invoked by Owner & Sudo of the bot)
/{BotCommands.AuthorizedUsersCommand}: Show authorized users (Only Owner & Sudo)
/{BotCommands.AddSudoCommand}: Add sudo user (Only Owner)
/{BotCommands.RmSudoCommand}: Remove sudo users (Only Owner)
/{BotCommands.LogCommand}: Get a log file of the bot. Handy for getting crash reports /{BotCommands.LogCommand}: Get a log file of the bot. Handy for getting crash reports
@ -144,7 +144,47 @@ def bot_help(update, context):
/stickerhelp: Get help for Stickers module. /stickerhelp: Get help for Stickers module.
''' '''
sendMessage(help_string, context.bot, update)
help_string = f'''
/{BotCommands.HelpCommand}: To get this message
/{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to Google Drive.
/{BotCommands.UnzipMirrorCommand} [download_url][magnet_link]: Starts mirroring and if downloaded file is any archive, extracts it to Google Drive
/{BotCommands.TarMirrorCommand} [download_url][magnet_link]: Start mirroring and upload the archived (.tar) version of the download
/{BotCommands.CloneCommand}: Copy file/folder to Google Drive
/{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl. Click /{BotCommands.WatchCommand} for more help.
/{BotCommands.TarWatchCommand} [youtube-dl supported link]: Mirror through youtube-dl and tar before uploading
/{BotCommands.CancelMirror}: Reply to the message by which the download was initiated and that download will be cancelled
/{BotCommands.StatusCommand}: Shows a status of all the downloads
/{BotCommands.ListCommand} [search term]: Searches the search term in the Google Drive, if found replies with the link
/{BotCommands.StatsCommand}: Show Stats of the machine the bot is hosted on
/{BotCommands.SpeedCommand}: Check Internet Speed of the Host
/{BotCommands.RepoCommand}: Get the bot repo.
/mediainfo: Get detailed info about replied media.
/tshelp: Get help for Torrent search module.
/weebhelp: Get help for Anime, Manga, and Character module.
/stickerhelp: Get help for Stickers module.
'''
if CustomFilters.sudo_user(update) or CustomFilters.owner_filter(update):
sendMessage(help_string_adm, context.bot, update)
else:
sendMessage(help_string, context.bot, update)
botcmds = [ botcmds = [
@ -183,15 +223,14 @@ def main():
ping_handler = CommandHandler(BotCommands.PingCommand, ping, ping_handler = CommandHandler(BotCommands.PingCommand, ping,
filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
restart_handler = CommandHandler(BotCommands.RestartCommand, restart, restart_handler = CommandHandler(BotCommands.RestartCommand, restart,
filters=CustomFilters.owner_filter) filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
help_handler = CommandHandler(BotCommands.HelpCommand, help_handler = CommandHandler(BotCommands.HelpCommand,
bot_help, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) bot_help, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
stats_handler = CommandHandler(BotCommands.StatsCommand, stats_handler = CommandHandler(BotCommands.StatsCommand,
stats, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) stats, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
log_handler = CommandHandler(BotCommands.LogCommand, log, filters=CustomFilters.owner_filter) log_handler = CommandHandler(BotCommands.LogCommand, log, filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
repo_handler = CommandHandler(BotCommands.RepoCommand, repo, repo_handler = CommandHandler(BotCommands.RepoCommand, repo,
filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
authlist_handler = CommandHandler(BotCommands.AuthListCommand, chat_list, filters=CustomFilters.owner_filter)
dispatcher.add_handler(start_handler) dispatcher.add_handler(start_handler)
dispatcher.add_handler(ping_handler) dispatcher.add_handler(ping_handler)
dispatcher.add_handler(restart_handler) dispatcher.add_handler(restart_handler)
@ -199,7 +238,6 @@ def main():
dispatcher.add_handler(stats_handler) dispatcher.add_handler(stats_handler)
dispatcher.add_handler(log_handler) dispatcher.add_handler(log_handler)
dispatcher.add_handler(repo_handler) dispatcher.add_handler(repo_handler)
dispatcher.add_handler(authlist_handler)
updater.start_polling() updater.start_polling()
LOGGER.info("Bot Started!") LOGGER.info("Bot Started!")
signal.signal(signal.SIGINT, fs_utils.exit_clean_up) signal.signal(signal.SIGINT, fs_utils.exit_clean_up)

View File

@ -0,0 +1,78 @@
import psycopg2
from psycopg2 import Error
from bot import AUTHORIZED_CHATS, SUDO_USERS, DB_URI, LOGGER
class DbManger:
def __init__(self):
self.err = False
def connect(self):
try:
self.conn = psycopg2.connect(DB_URI)
self.cur = self.conn.cursor()
except psycopg2.DatabaseError as error :
LOGGER.error("Error in dbMang : ", error)
self.err = True
def disconnect(self):
self.cur.close()
self.conn.close()
def db_auth(self,chat_id: int):
self.connect()
if self.err :
return "There's some error check log for details"
else:
sql = 'INSERT INTO users VALUES ({});'.format(chat_id)
self.cur.execute(sql)
self.conn.commit()
self.disconnect()
AUTHORIZED_CHATS.add(chat_id)
return 'Authorized successfully'
def db_unauth(self,chat_id: int):
self.connect()
if self.err :
return "There's some error check log for details"
else:
sql = 'DELETE from users where uid = {};'.format(chat_id)
self.cur.execute(sql)
self.conn.commit()
self.disconnect()
AUTHORIZED_CHATS.remove(chat_id)
if chat_id in SUDO_USERS:
SUDO_USERS.remove(chat_id)
return 'Unauthorized successfully'
def db_addsudo(self,chat_id: int):
self.connect()
if self.err :
return "There's some error check log for details"
else:
if chat_id in AUTHORIZED_CHATS:
sql = 'UPDATE users SET sudo = TRUE where uid = {};'.format(chat_id)
self.cur.execute(sql)
self.conn.commit()
self.disconnect()
SUDO_USERS.add(chat_id)
return 'Successfully promoted as sudo'
else:
sql = 'INSERT INTO users VALUES ({},TRUE);'.format(chat_id)
self.cur.execute(sql)
self.conn.commit()
self.disconnect()
AUTHORIZED_CHATS.add(chat_id)
SUDO_USERS.add(chat_id)
return 'Successfully Authorized and promoted as sudo'
def db_rmsudo(self,chat_id: int):
self.connect()
if self.err :
return "There's some error check log for details"
else:
sql = 'UPDATE users SET sudo = FALSE where uid = {};'.format(chat_id)
self.cur.execute(sql)
self.conn.commit()
self.disconnect()
SUDO_USERS.remove(chat_id)
return 'Successfully removed from Sudo'

View File

@ -128,11 +128,12 @@ class GoogleDriveHelper:
global SERVICE_ACCOUNT_INDEX global SERVICE_ACCOUNT_INDEX
service_account_count = len(os.listdir("accounts")) service_account_count = len(os.listdir("accounts"))
if SERVICE_ACCOUNT_INDEX == service_account_count - 1: if SERVICE_ACCOUNT_INDEX == service_account_count - 1:
SERVICE_ACCOUNT_INDEX = 0 return False
SERVICE_ACCOUNT_INDEX += 1 SERVICE_ACCOUNT_INDEX += 1
LOGGER.info(f"Switching to {SERVICE_ACCOUNT_INDEX}.json service account") LOGGER.info(f"Switching to {SERVICE_ACCOUNT_INDEX}.json service account")
self.__service = self.authorize() self.__service = self.authorize()
return True
@retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5),
retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG))
def __set_permission(self, drive_id): def __set_permission(self, drive_id):
@ -189,7 +190,8 @@ class GoogleDriveHelper:
reason = json.loads(err.content).get('error').get('errors')[0].get('reason') reason = json.loads(err.content).get('error').get('errors')[0].get('reason')
if reason == 'userRateLimitExceeded' or reason == 'dailyLimitExceeded': if reason == 'userRateLimitExceeded' or reason == 'dailyLimitExceeded':
if USE_SERVICE_ACCOUNTS: if USE_SERVICE_ACCOUNTS:
self.switchServiceAccount() if not self.switchServiceAccount():
return None
LOGGER.info(f"Got: {reason}, Trying Again.") LOGGER.info(f"Got: {reason}, Trying Again.")
return self.upload_file(file_path, file_name, mime_type, parent_id) return self.upload_file(file_path, file_name, mime_type, parent_id)
else: else:
@ -270,7 +272,8 @@ class GoogleDriveHelper:
reason = json.loads(err.content).get('error').get('errors')[0].get('reason') reason = json.loads(err.content).get('error').get('errors')[0].get('reason')
if reason == 'userRateLimitExceeded' or reason == 'dailyLimitExceeded': if reason == 'userRateLimitExceeded' or reason == 'dailyLimitExceeded':
if USE_SERVICE_ACCOUNTS: if USE_SERVICE_ACCOUNTS:
self.switchServiceAccount() if not self.switchServiceAccount():
raise err
LOGGER.info(f"Got: {reason}, Trying Again.") LOGGER.info(f"Got: {reason}, Trying Again.")
return self.copyFile(file_id,dest_id) return self.copyFile(file_id,dest_id)
else: else:
@ -569,7 +572,7 @@ class GoogleDriveHelper:
if self.num_of_path > 1: if self.num_of_path > 1:
self.edit_telegraph() self.edit_telegraph()
msg = f"<b>🔎 Search Results For <i>{fileName}</i></b> \n<b>📚 Found {len(response['files'])} results</b>" msg = f"<b>🔎 Found {len(response['files'])} results for <i>{fileName}</i></b>"
buttons = button_build.ButtonMaker() buttons = button_build.ButtonMaker()
buttons.buildbutton("HERE", f"https://telegra.ph/{self.path[0]}") buttons.buildbutton("HERE", f"https://telegra.ph/{self.path[0]}")

View File

@ -8,9 +8,11 @@ class _BotCommands:
self.CancelAllCommand = 'cancelall' self.CancelAllCommand = 'cancelall'
self.ListCommand = 'list' self.ListCommand = 'list'
self.StatusCommand = 'status' self.StatusCommand = 'status'
self.AuthorizedUsersCommand = 'users'
self.AuthorizeCommand = 'authorize' self.AuthorizeCommand = 'authorize'
self.UnAuthorizeCommand = 'unauthorize' self.UnAuthorizeCommand = 'unauthorize'
self.AuthListCommand = 'authlist' self.AddSudoCommand = 'addsudo'
self.RmSudoCommand = 'rmsudo'
self.PingCommand = 'ping' self.PingCommand = 'ping'
self.RestartCommand = 'restart' self.RestartCommand = 'restart'
self.StatsCommand = 'stats' self.StatsCommand = 'stats'

View File

@ -1,20 +1,19 @@
from telegram.ext import BaseFilter from telegram.ext import BaseFilter
from telegram import Message from telegram import Message
from bot import AUTHORIZED_CHATS, OWNER_ID, SUDO_USER, download_dict, download_dict_lock from bot import AUTHORIZED_CHATS, SUDO_USERS, OWNER_ID, download_dict, download_dict_lock
class CustomFilters: class CustomFilters:
class _OwnerFilter(BaseFilter): class _OwnerFilter(BaseFilter):
def filter(self, message): def filter(self, message):
id = message.from_user.id return bool(message.from_user.id == OWNER_ID)
return bool(message.from_user.id == OWNER_ID or id in SUDO_USER)
owner_filter = _OwnerFilter() owner_filter = _OwnerFilter()
class _AuthorizedUserFilter(BaseFilter): class _AuthorizedUserFilter(BaseFilter):
def filter(self, message): def filter(self, message):
id = message.from_user.id id = message.from_user.id
return bool(id in AUTHORIZED_CHATS or id == OWNER_ID or id in SUDO_USER) return bool(id in AUTHORIZED_CHATS or id == OWNER_ID)
authorized_user = _AuthorizedUserFilter() authorized_user = _AuthorizedUserFilter()
@ -24,10 +23,16 @@ class CustomFilters:
authorized_chat = _AuthorizedChat() authorized_chat = _AuthorizedChat()
class _SudoUser(BaseFilter):
def filter(self,message):
return bool(message.from_user.id in SUDO_USERS)
sudo_user = _SudoUser()
class _MirrorOwner(BaseFilter): class _MirrorOwner(BaseFilter):
def filter(self, message: Message): def filter(self, message: Message):
user_id = message.from_user.id user_id = message.from_user.id
if user_id in SUDO_USER: if user_id == OWNER_ID:
return True return True
args = str(message.text).split(' ') args = str(message.text).split(' ')
if len(args) > 1: if len(args) > 1:

View File

@ -1,69 +1,145 @@
from bot.helper.telegram_helper.message_utils import sendMessage from bot.helper.telegram_helper.message_utils import sendMessage
from telegram.ext import run_async from telegram.ext import run_async
from bot import AUTHORIZED_CHATS, dispatcher from bot import AUTHORIZED_CHATS, SUDO_USERS, dispatcher
from telegram.ext import CommandHandler from telegram.ext import CommandHandler
from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.filters import CustomFilters
from telegram.ext import Filters from telegram.ext import Filters
from telegram import Update from telegram import Update
from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.ext_utils.db_handler import DbManger
@run_async @run_async
def authorize(update,context): def authorize(update,context):
reply_message = None
message_ = None
reply_message = update.message.reply_to_message reply_message = update.message.reply_to_message
msg = '' message_ = update.message.text.split(' ')
with open('authorized_chats.txt', 'a') as file: if len(message_) == 2:
chat_id = int(message_[1])
if chat_id not in AUTHORIZED_CHATS:
msg = DbManger().db_auth(chat_id)
else:
msg = 'User already authorized'
else:
if reply_message is None: if reply_message is None:
# Trying to authorize a chat # Trying to authorize a chat
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
if chat_id not in AUTHORIZED_CHATS: if chat_id not in AUTHORIZED_CHATS:
file.write(f'{chat_id}\n') msg = DbManger().db_auth(chat_id)
AUTHORIZED_CHATS.add(chat_id)
msg = 'Chat authorized'
else: else:
msg = 'Already authorized chat' msg = 'Already authorized chat'
else: else:
# Trying to authorize someone in specific # Trying to authorize someone in specific
user_id = reply_message.from_user.id user_id = reply_message.from_user.id
if user_id not in AUTHORIZED_CHATS: if user_id not in AUTHORIZED_CHATS:
file.write(f'{user_id}\n') msg = DbManger().db_auth(user_id)
AUTHORIZED_CHATS.add(user_id)
msg = 'Person Authorized to use the bot!'
else: else:
msg = 'Person already authorized' msg = 'User already authorized'
sendMessage(msg, context.bot, update) sendMessage(msg, context.bot, update)
@run_async @run_async
def unauthorize(update,context): def unauthorize(update,context):
reply_message = None
message_ = None
reply_message = update.message.reply_to_message reply_message = update.message.reply_to_message
if reply_message is None: message_ = update.message.text.split(' ')
# Trying to unauthorize a chat if len(message_) == 2:
chat_id = update.effective_chat.id chat_id = int(message_[1])
if chat_id in AUTHORIZED_CHATS: if chat_id in AUTHORIZED_CHATS:
AUTHORIZED_CHATS.remove(chat_id) msg = DbManger().db_unauth(chat_id)
msg = 'Chat unauthorized'
else: else:
msg = 'Already unauthorized chat' msg = 'User already unauthorized'
else: else:
# Trying to authorize someone in specific if reply_message is None:
user_id = reply_message.from_user.id # Trying to unauthorize a chat
if user_id in AUTHORIZED_CHATS: chat_id = update.effective_chat.id
AUTHORIZED_CHATS.remove(user_id) if chat_id in AUTHORIZED_CHATS:
msg = 'Person unauthorized to use the bot!' msg = DbManger().db_unauth(chat_id)
else:
msg = 'Already unauthorized chat'
else: else:
msg = 'Person already unauthorized!' # Trying to authorize someone in specific
with open('authorized_chats.txt', 'a') as file: user_id = reply_message.from_user.id
file.truncate(0) if user_id in AUTHORIZED_CHATS:
for i in AUTHORIZED_CHATS: msg = DbManger().db_unauth(user_id)
file.write(f'{i}\n') else:
msg = 'User already unauthorized'
sendMessage(msg, context.bot, update) sendMessage(msg, context.bot, update)
@run_async
def addSudo(update,context):
reply_message = None
message_ = None
reply_message = update.message.reply_to_message
message_ = update.message.text.split(' ')
if len(message_) == 2:
chat_id = int(message_[1])
if chat_id not in SUDO_USERS:
msg = DbManger().db_addsudo(chat_id)
else:
msg = 'Already Sudo'
else:
if reply_message is None:
msg = "Give ID or Reply To message of whom you want to Promote"
else:
# Trying to authorize someone in specific
user_id = reply_message.from_user.id
if user_id not in SUDO_USERS:
msg = DbManger().db_addsudo(user_id)
else:
msg = 'Already Sudo'
sendMessage(msg, context.bot, update)
@run_async
def removeSudo(update,context):
reply_message = None
message_ = None
reply_message = update.message.reply_to_message
message_ = update.message.text.split(' ')
if len(message_) == 2:
chat_id = int(message_[1])
if chat_id in SUDO_USERS:
msg = DbManger().db_rmsudo(chat_id)
else:
msg = 'Not a Sudo'
else:
if reply_message is None:
msg = "Give ID or Reply To message of whom you want to remove from Sudo"
else:
user_id = reply_message.from_user.id
if user_id in SUDO_USERS:
msg = DbManger().db_rmsudo(user_id)
else:
msg = 'Not a Sudo'
sendMessage(msg, context.bot, update)
@run_async
def sendAuthChats(update,context):
user = sudo = ''
user += '\n'.join(str(id) for id in AUTHORIZED_CHATS)
sudo += '\n'.join(str(id) for id in SUDO_USERS)
sendMessage(f'<b><u>Authorized Chats</u></b>\n{user}\n<b><u>Sudo Users</u></b>\n{sudo}', context.bot, update)
send_auth_handler = CommandHandler(command=BotCommands.AuthorizedUsersCommand, callback=sendAuthChats,
filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
authorize_handler = CommandHandler(command=BotCommands.AuthorizeCommand, callback=authorize, authorize_handler = CommandHandler(command=BotCommands.AuthorizeCommand, callback=authorize,
filters=CustomFilters.owner_filter & Filters.group) filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
unauthorize_handler = CommandHandler(command=BotCommands.UnAuthorizeCommand, callback=unauthorize, unauthorize_handler = CommandHandler(command=BotCommands.UnAuthorizeCommand, callback=unauthorize,
filters=CustomFilters.owner_filter & Filters.group) filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
addsudo_handler = CommandHandler(command=BotCommands.AddSudoCommand, callback=addSudo,
filters=CustomFilters.owner_filter)
removesudo_handler = CommandHandler(command=BotCommands.RmSudoCommand, callback=removeSudo,
filters=CustomFilters.owner_filter)
dispatcher.add_handler(send_auth_handler)
dispatcher.add_handler(authorize_handler) dispatcher.add_handler(authorize_handler)
dispatcher.add_handler(unauthorize_handler) dispatcher.add_handler(unauthorize_handler)
dispatcher.add_handler(addsudo_handler)
dispatcher.add_handler(removesudo_handler)

View File

@ -25,5 +25,5 @@ def deletefile(update, context):
threading.Thread(target=auto_delete_message, args=(context.bot, update.message, reply_message)).start() threading.Thread(target=auto_delete_message, args=(context.bot, update.message, reply_message)).start()
delete_handler = CommandHandler(command=BotCommands.DeleteCommand, callback=deletefile, filters=CustomFilters.owner_filter) delete_handler = CommandHandler(command=BotCommands.DeleteCommand, callback=deletefile, filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
dispatcher.add_handler(delete_handler) dispatcher.add_handler(delete_handler)

View File

@ -59,7 +59,9 @@ class MirrorListener(listeners.MirrorListeners):
download = download_dict[self.uid] download = download_dict[self.uid]
name = download.name() name = download.name()
size = download.size_raw() size = download.size_raw()
m_path = f'{DOWNLOAD_DIR}{self.uid}/{download.name()}' if name is None: # when pyrogram's media.file_name is of NoneType
name = os.listdir(f'{DOWNLOAD_DIR}{self.uid}')[0]
m_path = f'{DOWNLOAD_DIR}{self.uid}/{name}'
if self.isTar: if self.isTar:
download.is_archiving = True download.is_archiving = True
try: try:

View File

@ -77,6 +77,6 @@ def dyno_usage(update, context):
dyno_usage_handler = CommandHandler(command=BotCommands.UsageCommand, callback=dyno_usage, dyno_usage_handler = CommandHandler(command=BotCommands.UsageCommand, callback=dyno_usage,
filters=CustomFilters.owner_filter) filters=CustomFilters.owner_filter | CustomFilters.sudo_user)
dispatcher.add_handler(dyno_usage_handler) dispatcher.add_handler(dyno_usage_handler)

View File

@ -11,9 +11,9 @@ AUTO_DELETE_MESSAGE_DURATION = 20
IS_TEAM_DRIVE = "" IS_TEAM_DRIVE = ""
TELEGRAM_API = TELEGRAM_API =
TELEGRAM_HASH = "" TELEGRAM_HASH = ""
DATABASE_URL =
# Optional config # Optional config
AUTHORIZED_CHATS = "" AUTHORIZED_CHATS = ""
SUDO_USER =
USE_SERVICE_ACCOUNTS = "" USE_SERVICE_ACCOUNTS = ""
INDEX_URL = "" INDEX_URL = ""
UPTOBOX_TOKEN = "" UPTOBOX_TOKEN = ""

View File

@ -25,3 +25,4 @@ lxml
telegraph telegraph
pytz pytz
html-telegraph-poster>=0.2.31 html-telegraph-poster>=0.2.31
psycopg2-binary