├── drive_folder
├── bot
├── helper
│ ├── __init__.py
│ ├── drive_utils
│ │ ├── __init__.py
│ │ └── gdriveTools.py
│ └── telegram_helper
│ │ ├── __init__.py
│ │ ├── bot_commands.py
│ │ ├── button_builder.py
│ │ ├── filters.py
│ │ └── message_utils.py
├── modules
│ ├── __init__.py
│ ├── list.py
│ └── authorize.py
├── __main__.py
└── __init__.py
├── heroku.yml
├── captain-definition
├── start.sh
├── .gitignore
├── requirements.txt
├── Dockerfile
├── telegraph_token.py
├── config_sample.env
├── generate_drive_token.py
├── app.json
├── driveid.py
├── .github
└── workflows
│ └── codeql-analysis.yml
├── README.md
└── LICENSE
/drive_folder:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/helper/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/modules/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/helper/drive_utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/helper/telegram_helper/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/heroku.yml:
--------------------------------------------------------------------------------
1 | build:
2 | docker:
3 | worker: Dockerfile
4 |
--------------------------------------------------------------------------------
/captain-definition:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 2,
3 | "dockerfilePath": "./Dockerfile"
4 | }
5 |
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | wget $CRED_URL -O credentials.json && wget $TOKEN_URL -O token.pickle && wget $DRIVE_FILE -O drive_folder && python3 -m bot
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | config.env
2 | *.pyc
3 | downloads/*
4 | download/*
5 | data*
6 | .vscode
7 | .idea
8 | *.json
9 | *.pickle
10 | authorized_chats.txt
11 | log.txt
12 | accounts/*
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | python-telegram-bot==12.6.1
3 | google-api-python-client>=1.7.11,<1.7.20
4 | google-auth-httplib2>=0.0.3,<0.1.0
5 | google-auth-oauthlib>=0.4.1,<0.10.0
6 | python-dotenv>=0.10
7 | telegraph
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/devilld/py-dev
2 |
3 | WORKDIR /BOT
4 |
5 | RUN chmod -R 777 /BOT
6 |
7 | COPY requirements.txt .
8 | RUN pip3 install --no-cache-dir -r requirements.txt
9 |
10 | COPY . .
11 |
12 | CMD ["bash","start.sh"]
13 |
--------------------------------------------------------------------------------
/telegraph_token.py:
--------------------------------------------------------------------------------
1 | from telegraph import Telegraph
2 |
3 | telegraph = Telegraph()
4 | telegraph.create_account(short_name=input("Enter a username for your Telegra.ph : "))
5 |
6 | print(f"Your Telegra.ph token ==> {telegraph.get_access_token()}")
--------------------------------------------------------------------------------
/config_sample.env:
--------------------------------------------------------------------------------
1 | #Remove this line before deploying
2 | _____REMOVE_THIS_LINE_____=True
3 |
4 | # ENTER BOT TOKEN (Get your BOT_TOKEN by talking to @botfather)
5 | BOT_TOKEN = ""
6 | OWNER_ID =
7 | TELEGRAPH_TOKEN = "420dffda0cc030ce6eb582c7287e179f166e8c69ebecfd63238b543763d0" # You can change it by your own
8 |
--------------------------------------------------------------------------------
/bot/helper/telegram_helper/bot_commands.py:
--------------------------------------------------------------------------------
1 | class _BotCommands:
2 | def __init__(self):
3 | self.StartCommand = 'start'
4 | self.ListCommand = 'list'
5 | self.AuthorizedUsersCommand = 'users'
6 | self.AuthorizeCommand = 'auth'
7 | self.UnAuthorizeCommand = 'unauth'
8 | self.LogCommand = 'log'
9 |
10 | BotCommands = _BotCommands()
11 |
--------------------------------------------------------------------------------
/bot/helper/telegram_helper/button_builder.py:
--------------------------------------------------------------------------------
1 | from telegram import InlineKeyboardButton
2 |
3 | class ButtonMaker:
4 | def __init__(self):
5 | self.button = []
6 |
7 | def buildbutton(self, key, link):
8 | self.button.append(InlineKeyboardButton(text = key, url = link))
9 |
10 | def build_menu(self, n_cols, footer_buttons=None, header_buttons=None):
11 | menu = [self.button[i:i + n_cols] for i in range(0, len(self.button), n_cols)]
12 | if header_buttons:
13 | menu.insert(0, header_buttons)
14 | if footer_buttons:
15 | menu.append(footer_buttons)
16 | return menu
17 |
--------------------------------------------------------------------------------
/bot/helper/telegram_helper/filters.py:
--------------------------------------------------------------------------------
1 | from telegram.ext import BaseFilter
2 | from telegram import Message
3 | from bot import AUTHORIZED_CHATS, OWNER_ID
4 |
5 | class CustomFilters:
6 | class _OwnerFilter(BaseFilter):
7 | def filter(self, message):
8 | return bool(message.from_user.id == OWNER_ID)
9 |
10 | owner_filter = _OwnerFilter()
11 |
12 | class _AuthorizedUserFilter(BaseFilter):
13 | def filter(self, message):
14 | id = message.from_user.id
15 | return bool(id in AUTHORIZED_CHATS or id == OWNER_ID)
16 |
17 | authorized_user = _AuthorizedUserFilter()
18 |
19 | class _AuthorizedChat(BaseFilter):
20 | def filter(self, message):
21 | return bool(message.chat.id in AUTHORIZED_CHATS)
22 |
23 | authorized_chat = _AuthorizedChat()
24 |
--------------------------------------------------------------------------------
/generate_drive_token.py:
--------------------------------------------------------------------------------
1 | import pickle
2 | import os
3 | from google_auth_oauthlib.flow import InstalledAppFlow
4 | from google.auth.transport.requests import Request
5 |
6 | credentials = None
7 | __G_DRIVE_TOKEN_FILE = "token.pickle"
8 | __OAUTH_SCOPE = ["https://www.googleapis.com/auth/drive"]
9 | if os.path.exists(__G_DRIVE_TOKEN_FILE):
10 | with open(__G_DRIVE_TOKEN_FILE, 'rb') as f:
11 | credentials = pickle.load(f)
12 | if credentials is None or not credentials.valid:
13 | if credentials and credentials.expired and credentials.refresh_token:
14 | credentials.refresh(Request())
15 | else:
16 | flow = InstalledAppFlow.from_client_secrets_file(
17 | 'credentials.json', __OAUTH_SCOPE)
18 | credentials = flow.run_console(port=0)
19 |
20 | # Save the credentials for the next run
21 | with open(__G_DRIVE_TOKEN_FILE, 'wb') as token:
22 | pickle.dump(credentials, token)
--------------------------------------------------------------------------------
/bot/modules/list.py:
--------------------------------------------------------------------------------
1 | from telegram.ext import CommandHandler, run_async
2 | from bot.helper.drive_utils.gdriveTools import GoogleDriveHelper
3 | from bot import LOGGER, dispatcher
4 | from bot.helper.telegram_helper.message_utils import sendMessage, editMessage
5 | from bot.helper.telegram_helper.filters import CustomFilters
6 | from bot.helper.telegram_helper.bot_commands import BotCommands
7 |
8 | @run_async
9 | def list_drive(update,context):
10 | try:
11 | search = update.message.text.split(' ',maxsplit=1)[1]
12 | except IndexError:
13 | sendMessage('send a search key along with command', context.bot, update)
14 | return
15 |
16 | reply = sendMessage('Searching...', context.bot, update)
17 |
18 | LOGGER.info(f"Searching: {search}")
19 |
20 | gdrive = GoogleDriveHelper(None)
21 | msg, button = gdrive.drive_list(search)
22 |
23 | editMessage(msg,reply,button)
24 |
25 |
26 | list_handler = CommandHandler(BotCommands.ListCommand, list_drive,filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
27 | dispatcher.add_handler(list_handler)
28 |
--------------------------------------------------------------------------------
/bot/helper/telegram_helper/message_utils.py:
--------------------------------------------------------------------------------
1 | from telegram.message import Message
2 | from telegram.update import Update
3 | import time
4 | from bot import LOGGER, bot
5 | from telegram.error import TimedOut, BadRequest
6 | from bot import bot
7 | from telegram import InlineKeyboardMarkup
8 |
9 |
10 | def sendMessage(text: str, bot, update: Update):
11 | try:
12 | return bot.send_message(update.message.chat_id,
13 | reply_to_message_id=update.message.message_id,
14 | text=text, parse_mode='HTMl')
15 | except Exception as e:
16 | LOGGER.error(str(e))
17 |
18 | def editMessage(text: str, message: Message, reply_markup=None):
19 | try:
20 | bot.edit_message_text(text=text, message_id=message.message_id,
21 | chat_id=message.chat.id,reply_markup=reply_markup,
22 | parse_mode='HTMl')
23 | except Exception as e:
24 | LOGGER.error(str(e))
25 |
26 | def sendLogFile(bot, update: Update):
27 | with open('log.txt', 'rb') as f:
28 | bot.send_document(document=f, filename=f.name,
29 | reply_to_message_id=update.message.message_id,
30 | chat_id=update.message.chat_id)
31 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Drive Search Bot",
3 | "description": "Search file inside the google drive",
4 | "logo": "https://i.ibb.co/m6V57dy/ds.jpg",
5 | "keywords": [
6 | "telegram",
7 | "bot",
8 | "aria",
9 | "python"
10 | ],
11 | "repository": "https://github.com/devillD/Drive-Search-Bot.git",
12 | "website": "https://github.com/devillD/Drive-Search-Bot/tree/master",
13 | "success_url": "https://github.com/devillD/Drive-Search-Bot/tree/master/README.md",
14 | "stack": "container",
15 | "env": {
16 | "BOT_TOKEN": {
17 | "description": "The telegram bot token that you get from @BotFather.",
18 | "required": true
19 | },
20 | "OWNER_ID": {
21 | "description": "The Telegram user ID (not username) of the owner of the bot.",
22 | "required": true
23 | },
24 | "TELEGRAPH_TOKEN": {
25 | "description": "Generate using python3 generate_telegraph_token.py.",
26 | "required": true
27 | },
28 | "CRED_URL": {
29 | "description": "Credentials.json file direct url",
30 | "required": true
31 | },
32 | "TOKEN_URL": {
33 | "description": "token.pickle file direct url",
34 | "required": true
35 | },
36 | "DRIVE_FILE": {
37 | "description": "drive_folder file direct url",
38 | "required": true
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/bot/__main__.py:
--------------------------------------------------------------------------------
1 | from telegram.ext import CommandHandler, run_async
2 | from bot import dispatcher, updater, botStartTime
3 | from bot.helper.telegram_helper.bot_commands import BotCommands
4 | from bot.helper.telegram_helper.message_utils import *
5 | from .helper.telegram_helper.filters import CustomFilters
6 | from .modules import authorize, list
7 | from telegram import ParseMode, BotCommand
8 |
9 | @run_async
10 | def start(update, context):
11 | LOGGER.info('UID: {} - UN: {} - MSG: {}'.format(update.message.chat.id,update.message.chat.username,update.message.text))
12 | if update.message.chat.type == "private" :
13 | sendMessage(f"Hey {update.message.chat.first_name}. Welcome to LoaderX Bot", context.bot, update)
14 | else :
15 | sendMessage("Am alive :)", context.bot, update)
16 |
17 | @run_async
18 | def log(update, context):
19 | sendLogFile(context.bot, update)
20 |
21 | botcmnd = [
22 | BotCommand(f'{BotCommands.ListCommand}', ' 🔎 Search on team drive✨'),
23 | BotCommand(f'{BotCommands.LogCommand}','📄 Get Logs [owner only]'),
24 |
25 | ]
26 |
27 | def main():
28 |
29 | start_handler = CommandHandler(BotCommands.StartCommand, start, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
30 | log_handler = CommandHandler(BotCommands.LogCommand, log, filters=CustomFilters.owner_filter)
31 |
32 | dispatcher.add_handler(start_handler)
33 | dispatcher.add_handler(log_handler)
34 |
35 | bot.set_my_commands(botcmnd)
36 |
37 | updater.start_polling()
38 | LOGGER.info("Yeah am running!")
39 | updater.idle()
40 |
41 | main()
42 |
--------------------------------------------------------------------------------
/driveid.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | print("\n\n"\
4 | " Bot is not able to search in subfolder so if you likes to search\n"\
5 | " in a specific folder then u can add that folder id to search\n\n"
6 | " drive/folder NAME --> anything that u likes\n"\
7 | " drive/folder ID --> drive id or folder id of folders in which u likes to search\n"\
8 | " drive/folder INDEX URL --> enter index url. If its a folder then open your index site\n" \
9 | " goto the respective folder and copy the url from address bar\n")
10 | msg = ''
11 | if os.path.exists('drive_folder'):
12 | with open('drive_folder', 'r+') as f:
13 | lines = f.read()
14 | if not re.match(r'^\s*$', lines):
15 | print(lines)
16 | print("\n\n"\
17 | " DO YOU WISH TO KEEP THE ABOVE DETAILS THAT YOU PREVIOUSLY ADDED???? ENTER (y/n)\n"\
18 | " IF NOTHING SHOWS ENTER n")
19 | while (1):
20 | choice = input()
21 | if choice == 'y' or choice == 'Y':
22 | msg = f'{lines}'
23 | break
24 | elif choice == 'n' or choice == 'N':
25 | break
26 | else:
27 | print("\n\n DO YOU WISH TO KEEP THE ABOVE DETAILS ???? y/n <=== this is option ..... OPEN YOUR EYES & READ...")
28 | num = int(input(" How Many Drive/Folder You Likes To Add : "))
29 | count = 1
30 | while count <= num :
31 | print(f"\n > DRIVE/FOLDER - {count}\n")
32 | name = input(" Enter Drive/Folder NAME (anything) : ")
33 | id = input(" Enter Drive/Folder ID : ")
34 | index = input(" Enter Drive/Folder INDEX URL (optional) : ")
35 | if not name or not id:
36 | print("\n\n ERROR : Dont leave the name/id without filling.")
37 | exit(1)
38 | name=name.replace(" ", "_")
39 | if index:
40 | if index[-1] == "/":
41 | index = index[:-1]
42 | else:
43 | index = ''
44 | count+=1
45 | msg += f"{name} {id} {index}\n"
46 | with open('drive_folder', 'w') as file:
47 | file.truncate(0)
48 | file.write(msg)
49 | print("\n\n Done!")
--------------------------------------------------------------------------------
/bot/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import time
4 |
5 | import telegram.ext as tg
6 | from dotenv import load_dotenv
7 |
8 | from telegraph import Telegraph
9 |
10 | botStartTime = time.time()
11 | if os.path.exists('log.txt'):
12 | with open('log.txt', 'r+') as f:
13 | f.truncate(0)
14 |
15 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
16 | handlers=[logging.FileHandler('log.txt'), logging.StreamHandler()],
17 | level=logging.INFO)
18 |
19 | load_dotenv('config.env')
20 |
21 | def getConfig(name: str):
22 | return os.environ[name]
23 |
24 | LOGGER = logging.getLogger(__name__)
25 |
26 | try:
27 | if bool(getConfig('_____REMOVE_THIS_LINE_____')):
28 | logging.error('The README.md file there to be read! Exiting now!')
29 | exit()
30 | except KeyError:
31 | pass
32 |
33 | BOT_TOKEN = None
34 |
35 | AUTHORIZED_CHATS = set()
36 |
37 | AUTHORIZED_CHATS = set()
38 | if os.path.exists('authorized_chats.txt'):
39 | with open('authorized_chats.txt', 'r+') as f:
40 | lines = f.readlines()
41 | for line in lines:
42 | AUTHORIZED_CHATS.add(int(line.split()[0]))
43 |
44 | try:
45 | BOT_TOKEN = getConfig('BOT_TOKEN')
46 | OWNER_ID = int(getConfig('OWNER_ID'))
47 | telegraph_token = getConfig('TELEGRAPH_TOKEN')
48 | except KeyError as e:
49 | LOGGER.error("One or more env variables missing! Exiting now")
50 | exit(1)
51 |
52 | DRIVE_NAME = []
53 | DRIVE_ID = []
54 | INDEX_URL = []
55 |
56 | if os.path.exists('drive_folder'):
57 | with open('drive_folder', 'r+') as f:
58 | lines = f.readlines()
59 | for line in lines:
60 | temp = line.strip().split()
61 | DRIVE_NAME.append(temp[0].replace("_", " "))
62 | DRIVE_ID.append(temp[1])
63 | try:
64 | INDEX_URL.append(temp[2])
65 | except IndexError as e:
66 | INDEX_URL.append(None)
67 |
68 | if DRIVE_ID :
69 | pass
70 | else :
71 | LOGGER.error("The README.md file there to be read! Exiting now!")
72 | exit(1)
73 |
74 | telegra_ph = Telegraph(access_token=telegraph_token)
75 |
76 | updater = tg.Updater(token=BOT_TOKEN,use_context=True)
77 | bot = updater.bot
78 | dispatcher = updater.dispatcher
79 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '21 16 * * 2'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'python' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v2
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v1
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
54 | # If this step fails, then you should remove it and run the build manually (see below)
55 | - name: Autobuild
56 | uses: github/codeql-action/autobuild@v1
57 |
58 | # ℹ️ Command-line programs to run using the OS shell.
59 | # 📚 https://git.io/JvXDl
60 |
61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
62 | # and modify them (or add more) to build your code if your project
63 | # uses a compiled language
64 |
65 | #- run: |
66 | # make bootstrap
67 | # make release
68 |
69 | - name: Perform CodeQL Analysis
70 | uses: github/codeql-action/analyze@v1
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Deploying on Heroku
2 | ### Auto
3 | [](https://heroku.com/deploy?template=https://github.com/devillD/Drive-Search-Bot.git)
4 |
5 | # What is this repo about?
6 | This is a telegram bot writen in python for searching files in Drive.
7 |
8 | # How to deploy?
9 |
10 | - Clone this repo:
11 | ```
12 | git clone https://github.com/svr666/search-bot search-bot/
13 | cd search-bot
14 | ```
15 |
16 | ### Install requirements
17 |
18 | - For Debian based distros
19 | ```
20 | sudo apt install python3
21 | sudo snap install docker
22 | ```
23 | - For Arch and it's derivatives:
24 | ```
25 | sudo pacman -S docker python
26 | ```
27 |
28 | ## Setting up config file
29 | ```
30 | cp config_sample.env config.env
31 | ```
32 | - Remove the first line saying:
33 | ```
34 | _____REMOVE_THIS_LINE_____=True
35 | ```
36 | Fill up rest of the fields. Meaning of each fields are discussed below:
37 | - **BOT_TOKEN** : The telegram bot token that you get from @BotFather
38 | - **OWNER_ID** : The Telegram user ID (not username) of the owner of the bot
39 | - **TELEGRAPH_TOKEN** : The token generated by running:
40 | ```
41 | python3 telegraph_token.py
42 | ```
43 |
44 | ## Setting up drive_folder file
45 |
46 | - The bot is unable to search in sub-directories, but you can specify directories in which you wanna search.
47 | - Add drive/folder name(anything that u likes), drive id/folder id & index url(optional) corresponding to each id.
48 | - If you are adding a folder id and you wish to use index url, then add index url corresponding to that folder.
49 |
50 | - Run driveid.py and follow the screen.
51 | ```
52 | python3 driveid.py
53 | ```
54 |
55 | ## Getting Google OAuth API credential file
56 |
57 | - Visit the [Google Cloud Console](https://console.developers.google.com/apis/credentials)
58 | - Go to the OAuth Consent tab, fill it, and save.
59 | - Go to the Credentials tab and click Create Credentials -> OAuth Client ID
60 | - Choose Desktop and Create.
61 | - Use the download button to download your credentials.
62 | - Move that file to the root of search-bot, and rename it to credentials.json
63 | - Visit [Google API page](https://console.developers.google.com/apis/library)
64 | - Search for Drive and enable it if it is disabled
65 | - Finally, run the script to generate token file (token.pickle) for Google Drive:
66 | ```
67 | pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
68 | python3 generate_drive_token.py
69 | ```
70 |
71 | ### Menual - Install [Heroku cli](https://devcenter.heroku.com/articles/heroku-cli)
72 | - Login into your heroku account with command:
73 | ```
74 | heroku login
75 | ```
76 | - Create a new heroku app:
77 | ```
78 | heroku create appname
79 | ```
80 | - Select This App in your Heroku-cli:
81 | ```
82 | heroku git:remote -a appname
83 | ```
84 | - Change Dyno Stack to a Docker Container:
85 | ```
86 | heroku stack:set container
87 | ```
88 | - Add Private Credentials and Config Stuff:
89 | ```
90 | git add -f credentials.json token.pickle config.env heroku.yml
91 | ```
92 | - Commit new changes:
93 | ```
94 | git commit -m "Added Creds."
95 | ```
96 | - Push Code to Heroku:
97 | ```
98 | git push heroku master --force
99 | ```
100 | - Restart Worker by these commands:
101 | ```
102 | heroku ps:scale worker=0
103 | ```
104 | ```
105 | heroku ps:scale worker=1
106 | ```
107 | Heroku-Note: Doing authorizations ( /authorize command ) through telegram wont be permanent as heroku uses ephemeral filesystem. They will be reset on each dyno boot. As a workaround you can:
108 | - Make a file authorized_chats.txt and write the user names and chat_id of you want to authorize, each separated by new line
109 | - Then force add authorized_chats.txt to git and push it to heroku
110 | ```
111 | git add authorized_chats.txt -f
112 | git commit -asm "Added hardcoded authorized_chats.txt"
113 | git push heroku heroku:master
114 | ```
115 |
116 | ## Deploying on Server
117 | - Start docker daemon (skip if already running):
118 | ```
119 | sudo dockerd
120 | ```
121 | - Build Docker image:
122 | ```
123 | sudo docker build . -t search-bot
124 | ```
125 | - Run the image:
126 | ```
127 | sudo docker run search-bot
128 | ```
129 | # Credits :
130 |
131 | - python-aria-mirror-bot - [lzzy12](https://github.com/lzzy12/python-aria-mirror-bot)
132 |
--------------------------------------------------------------------------------
/bot/modules/authorize.py:
--------------------------------------------------------------------------------
1 | from bot.helper.telegram_helper.message_utils import sendMessage
2 | from telegram.ext import run_async
3 | from bot import AUTHORIZED_CHATS, dispatcher
4 | from telegram.ext import CommandHandler
5 | from bot.helper.telegram_helper.filters import CustomFilters
6 | from telegram import Update
7 | from bot.helper.telegram_helper.bot_commands import BotCommands
8 |
9 | @run_async
10 | def authorize(update,context):
11 | reply_message = update.message.reply_to_message
12 | message_ = update.message.text.split(' ')
13 | msg = ''
14 | with open('authorized_chats.txt', 'a') as file:
15 | if len(message_) == 2:
16 | chat_id = int(message_[1])
17 | if chat_id not in AUTHORIZED_CHATS:
18 | file.write(f'{chat_id}\n')
19 | AUTHORIZED_CHATS.add(chat_id)
20 | msg = 'Chat authorized'
21 | else:
22 | msg = 'User already authorized'
23 | else:
24 | if reply_message is None:
25 | # Trying to authorize a chat
26 | chat_id = update.effective_chat.id
27 | if chat_id not in AUTHORIZED_CHATS:
28 | file.write(f'{chat_id}\n')
29 | AUTHORIZED_CHATS.add(chat_id)
30 | msg = 'Chat authorized'
31 | else:
32 | msg = 'Already authorized chat'
33 | else:
34 | # Trying to authorize someone in specific
35 | user_id = reply_message.from_user.id
36 | if user_id not in AUTHORIZED_CHATS:
37 | file.write(f'{user_id}\n')
38 | AUTHORIZED_CHATS.add(user_id)
39 | msg = 'Person Authorized to use the bot!'
40 | else:
41 | msg = 'Person already authorized'
42 | sendMessage(msg, context.bot, update)
43 |
44 |
45 | @run_async
46 | def unauthorize(update,context):
47 | reply_message = update.message.reply_to_message
48 | message_ = update.message.text.split(' ')
49 | if len(message_) == 2:
50 | chat_id = int(message_[1])
51 | if chat_id in AUTHORIZED_CHATS:
52 | AUTHORIZED_CHATS.remove(chat_id)
53 | msg = 'Chat unauthorized'
54 | else:
55 | msg = 'User already unauthorized'
56 | else:
57 | if reply_message is None:
58 | # Trying to unauthorize a chat
59 | chat_id = update.effective_chat.id
60 | if chat_id in AUTHORIZED_CHATS:
61 | AUTHORIZED_CHATS.remove(chat_id)
62 | msg = 'Chat unauthorized'
63 | else:
64 | msg = 'Already unauthorized chat'
65 | else:
66 | # Trying to authorize someone in specific
67 | user_id = reply_message.from_user.id
68 | if user_id in AUTHORIZED_CHATS:
69 | AUTHORIZED_CHATS.remove(user_id)
70 | msg = 'Person unauthorized to use the bot!'
71 | else:
72 | msg = 'Person already unauthorized!'
73 | with open('authorized_chats.txt', 'a') as file:
74 | file.truncate(0)
75 | for i in AUTHORIZED_CHATS:
76 | file.write(f'{i}\n')
77 | sendMessage(msg, context.bot, update)
78 |
79 |
80 | @run_async
81 | def sendAuthChats(update,context):
82 | users = ''
83 | for user in AUTHORIZED_CHATS :
84 | users += f"{user}\n"
85 | users = users if users != '' else "None"
86 | sendMessage(f'Authorized Chats are : \n{users}\n', context.bot, update)
87 |
88 |
89 | send_auth_handler = CommandHandler(command=BotCommands.AuthorizedUsersCommand, callback=sendAuthChats,
90 | filters=CustomFilters.owner_filter)
91 | authorize_handler = CommandHandler(command=BotCommands.AuthorizeCommand, callback=authorize,
92 | filters=CustomFilters.owner_filter)
93 | unauthorize_handler = CommandHandler(command=BotCommands.UnAuthorizeCommand, callback=unauthorize,
94 | filters=CustomFilters.owner_filter)
95 |
96 | dispatcher.add_handler(send_auth_handler)
97 | dispatcher.add_handler(authorize_handler)
98 | dispatcher.add_handler(unauthorize_handler)
99 |
100 |
101 |
--------------------------------------------------------------------------------
/bot/helper/drive_utils/gdriveTools.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pickle
3 |
4 | import requests
5 | import logging
6 |
7 | from google.auth.transport.requests import Request
8 | from google_auth_oauthlib.flow import InstalledAppFlow
9 | from googleapiclient.discovery import build
10 | from googleapiclient.errors import HttpError
11 |
12 | from telegram import InlineKeyboardMarkup
13 | from bot.helper.telegram_helper import button_builder
14 | from bot import DRIVE_NAME, DRIVE_ID, INDEX_URL, telegra_ph
15 |
16 | LOGGER = logging.getLogger(__name__)
17 | logging.getLogger('googleapiclient.discovery').setLevel(logging.ERROR)
18 |
19 | SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
20 | TELEGRAPHLIMIT = 95
21 |
22 | class GoogleDriveHelper:
23 | def __init__(self, name=None, listener=None):
24 | self.__G_DRIVE_TOKEN_FILE = "token.pickle"
25 | # Check https://developers.google.com/drive/scopes for all available scopes
26 | self.__OAUTH_SCOPE = ['https://www.googleapis.com/auth/drive']
27 | self.__service = self.authorize()
28 | self.telegraph_content = []
29 | self.path = []
30 |
31 | def get_readable_file_size(self,size_in_bytes) -> str:
32 | if size_in_bytes is None:
33 | return '0B'
34 | index = 0
35 | size_in_bytes = int(size_in_bytes)
36 | while size_in_bytes >= 1024:
37 | size_in_bytes /= 1024
38 | index += 1
39 | try:
40 | return f'{round(size_in_bytes, 2)}{SIZE_UNITS[index]}'
41 | except IndexError:
42 | return 'File too large'
43 |
44 | def authorize(self):
45 | # Get credentials
46 | credentials = None
47 | if os.path.exists(self.__G_DRIVE_TOKEN_FILE):
48 | with open(self.__G_DRIVE_TOKEN_FILE, 'rb') as f:
49 | credentials = pickle.load(f)
50 | if credentials is None or not credentials.valid:
51 | if credentials and credentials.expired and credentials.refresh_token:
52 | credentials.refresh(Request())
53 | else:
54 | flow = InstalledAppFlow.from_client_secrets_file(
55 | 'credentials.json', self.__OAUTH_SCOPE)
56 | LOGGER.info(flow)
57 | credentials = flow.run_console(port=0)
58 |
59 | # Save the credentials for the next run
60 | with open(self.__G_DRIVE_TOKEN_FILE, 'wb') as token:
61 | pickle.dump(credentials, token)
62 | return build('drive', 'v3', credentials=credentials, cache_discovery=False)
63 |
64 | def drive_query(self, parent_id, fileName):
65 | query = f"'{parent_id}' in parents and (name contains '{fileName}')"
66 | response = self.__service.files().list(supportsTeamDrives=True,
67 | includeTeamDriveItems=True,
68 | q=query,
69 | spaces='drive',
70 | pageSize=200,
71 | fields='files(id, name, mimeType, size)',
72 | orderBy='modifiedTime desc').execute()["files"]
73 | return response
74 |
75 | def edit_telegraph(self):
76 | nxt_page = 1
77 | prev_page = 0
78 | for content in self.telegraph_content :
79 | if nxt_page == 1 :
80 | content += f'Next'
81 | nxt_page += 1
82 | else :
83 | if prev_page <= self.num_of_path:
84 | content += f'Prev'
85 | prev_page += 1
86 | if nxt_page < self.num_of_path:
87 | content += f' | Next'
88 | nxt_page += 1
89 | telegra_ph.edit_page(path = self.path[prev_page],
90 | title = 'LoaderX',
91 | html_content=content)
92 | return
93 |
94 | def drive_list(self, fileName):
95 | msg = ''
96 | INDEX = -1
97 | content_count = 0
98 | add_title_msg = True
99 | for parent_id in DRIVE_ID :
100 | response = self.drive_query(parent_id, fileName)
101 | INDEX += 1
102 | if response:
103 | if add_title_msg == True:
104 | msg = f'
{file.get('name')} (folder){file.get('name')} ({self.get_readable_file_size(file.get('size'))})