├── Dockerfile
├── LICENSE
├── Procfile
├── README.md
├── app.json
├── bot.py
├── config.py
├── helper
├── database.py
└── utils.py
├── plugins
├── admin_panel.py
├── auto_rename.py
├── file_rename.py
├── force_subs.py
├── start_&_cb.py
└── thumb_&_cap.py
├── render.yaml
├── requirements.txt
├── route.py
└── runtime.txt
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10
2 | WORKDIR /app
3 | COPY . /app/
4 | RUN pip install -r requirements.txt
5 | CMD ["python", "bot.py"]
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python bot.py
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
🩵 Thanks for Being Here 🩵
8 | 9 | 10 | ### CONFIGS VARIABLES 11 | 12 | * `BOT_TOKEN` - Get bot token from @BotFather 13 | * `API_ID` - From my.telegram.org 14 | * `API_HASH` - From my.telegram.org 15 | * `ADMIN` - Admin user id 16 | * `LOG_CHANNEL` - Bot Log Channel Id startswith -100 must. 17 | * `DB_URL` - Mongo Database URL from https://cloud.mongodb.com 18 | * `DB_NAME` - Your database name from mongoDB. (Optional) 19 | * `FORCE_SUB` - Your force sub channel username without @ (Optional) 20 | * `START_PIC` - Start message photo. (Optional) 21 | 22 | 23 | 24 | ### DEPLOYEMENT SUPPORT 25 | 26 |
28 |
29 |
30 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
/autorename Naruto Shippuden S02 - EPepisode - quality [Dual Audio] - @Madflix_Bots
48 |
49 | ➻ Your Current Auto Rename Format : {format_template}
"""
50 |
51 | ABOUT_TXT = f"""🤖 My Name : Auto Rename Bot ⚡
52 | 📝 Language : Python 3
53 | 📚 Library : Pyrogram 2.0
54 | 🚀 Server : Heroku
55 | 📢 Channel : Madflix Botz
56 | 🧑💻 Developer : Jishu Developer
57 |
58 | ♻️ Bot Made By : @Madflix_Bots"""
59 |
60 |
61 | THUMBNAIL_TXT = """🖼️ HOW TO SET THUMBNAIL
62 |
63 | ⦿ You Can Add Custom Thumbnail Simply By Sending A Photo To Me....
64 |
65 | ⦿ /viewthumb - Use This Command To See Your Thumbnail
66 | ⦿ /delthumb - Use This Command To Delete Your Thumbnail"""
67 |
68 | CAPTION_TXT = """📝 HOW TO SET CAPTION
69 |
70 | ⦿ /set_caption - Use This Command To Set Your Caption
71 | ⦿ /see_caption - Use This Command To See Your Caption
72 | ⦿ /del_caption - Use This Command To Delete Your Caption"""
73 |
74 | PROGRESS_BAR = """\n
75 | 📁 Size : {1} | {2}
76 | ⏳️ Done : {0}%
77 | 🚀 Speed : {3}/s
78 | ⏰️ ETA : {4} """
79 |
80 |
81 | DONATE_TXT = """🥲 Thanks For Showing Interest In Donation! ❤️
82 |
83 | If You Like My Bots & Projects, You Can 🎁 Donate Me Any Amount From 10 Rs Upto Your Choice.
84 |
85 | 🛍 UPI ID: madflixofficial@axl
"""
86 |
87 | HELP_TXT = """Hey {}
88 |
89 | Here Is The Help For My Commands."""
90 |
91 |
92 |
93 |
94 |
95 | # Jishu Developer
96 | # Don't Remove Credit 🥺
97 | # Telegram Channel @Madflix_Bots
98 | # Developer @JishuDeveloper
99 |
100 |
--------------------------------------------------------------------------------
/helper/database.py:
--------------------------------------------------------------------------------
1 | import motor.motor_asyncio
2 | from config import Config
3 | from .utils import send_log
4 |
5 | class Database:
6 |
7 | def __init__(self, uri, database_name):
8 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
9 | self.madflixbotz = self._client[database_name]
10 | self.col = self.madflixbotz.user
11 |
12 | def new_user(self, id):
13 | return dict(
14 | _id=int(id),
15 | file_id=None,
16 | caption=None,
17 | format_template=None # Add this line for the format template
18 | )
19 |
20 | async def add_user(self, b, m):
21 | u = m.from_user
22 | if not await self.is_user_exist(u.id):
23 | user = self.new_user(u.id)
24 | await self.col.insert_one(user)
25 | await send_log(b, u)
26 |
27 | async def is_user_exist(self, id):
28 | user = await self.col.find_one({'_id': int(id)})
29 | return bool(user)
30 |
31 | async def total_users_count(self):
32 | count = await self.col.count_documents({})
33 | return count
34 |
35 | async def get_all_users(self):
36 | all_users = self.col.find({})
37 | return all_users
38 |
39 | async def delete_user(self, user_id):
40 | await self.col.delete_many({'_id': int(user_id)})
41 |
42 | async def set_thumbnail(self, id, file_id):
43 | await self.col.update_one({'_id': int(id)}, {'$set': {'file_id': file_id}})
44 |
45 | async def get_thumbnail(self, id):
46 | user = await self.col.find_one({'_id': int(id)})
47 | return user.get('file_id', None)
48 |
49 | async def set_caption(self, id, caption):
50 | await self.col.update_one({'_id': int(id)}, {'$set': {'caption': caption}})
51 |
52 | async def get_caption(self, id):
53 | user = await self.col.find_one({'_id': int(id)})
54 | return user.get('caption', None)
55 |
56 | async def set_format_template(self, id, format_template):
57 | await self.col.update_one({'_id': int(id)}, {'$set': {'format_template': format_template}})
58 |
59 | async def get_format_template(self, id):
60 | user = await self.col.find_one({'_id': int(id)})
61 | return user.get('format_template', None)
62 |
63 | async def set_media_preference(self, id, media_type):
64 | await self.col.update_one({'_id': int(id)}, {'$set': {'media_type': media_type}})
65 |
66 | async def get_media_preference(self, id):
67 | user = await self.col.find_one({'_id': int(id)})
68 | return user.get('media_type', None)
69 |
70 |
71 |
72 | madflixbotz = Database(Config.DB_URL, Config.DB_NAME)
73 |
74 |
75 |
76 | # Jishu Developer
77 | # Don't Remove Credit 🥺
78 | # Telegram Channel @Madflix_Bots
79 | # Developer @JishuDeveloper
--------------------------------------------------------------------------------
/helper/utils.py:
--------------------------------------------------------------------------------
1 | import math, time
2 | from datetime import datetime
3 | from pytz import timezone
4 | from config import Config, Txt
5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
6 |
7 | async def progress_for_pyrogram(current, total, ud_type, message, start):
8 | now = time.time()
9 | diff = now - start
10 | if round(diff % 5.00) == 0 or current == total:
11 | percentage = current * 100 / total
12 | speed = current / diff
13 | elapsed_time = round(diff) * 1000
14 | time_to_completion = round((total - current) / speed) * 1000
15 | estimated_total_time = elapsed_time + time_to_completion
16 |
17 | elapsed_time = TimeFormatter(milliseconds=elapsed_time)
18 | estimated_total_time = TimeFormatter(milliseconds=estimated_total_time)
19 |
20 | progress = "{0}{1}".format(
21 | ''.join(["⬢" for i in range(math.floor(percentage / 5))]),
22 | ''.join(["⬡" for i in range(20 - math.floor(percentage / 5))])
23 | )
24 | tmp = progress + Txt.PROGRESS_BAR.format(
25 | round(percentage, 2),
26 | humanbytes(current),
27 | humanbytes(total),
28 | humanbytes(speed),
29 | estimated_total_time if estimated_total_time != '' else "0 s"
30 | )
31 | try:
32 | await message.edit(
33 | text=f"{ud_type}\n\n{tmp}",
34 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("✖️ Cancel ✖️", callback_data="close")]])
35 | )
36 | except:
37 | pass
38 |
39 |
40 |
41 | def humanbytes(size):
42 | if not size:
43 | return ""
44 | power = 2**10
45 | n = 0
46 | Dic_powerN = {0: ' ', 1: 'K', 2: 'M', 3: 'G', 4: 'T'}
47 | while size > power:
48 | size /= power
49 | n += 1
50 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'b'
51 |
52 |
53 | def TimeFormatter(milliseconds: int) -> str:
54 | seconds, milliseconds = divmod(int(milliseconds), 1000)
55 | minutes, seconds = divmod(seconds, 60)
56 | hours, minutes = divmod(minutes, 60)
57 | days, hours = divmod(hours, 24)
58 | tmp = ((str(days) + "d, ") if days else "") + \
59 | ((str(hours) + "h, ") if hours else "") + \
60 | ((str(minutes) + "m, ") if minutes else "") + \
61 | ((str(seconds) + "s, ") if seconds else "") + \
62 | ((str(milliseconds) + "ms, ") if milliseconds else "")
63 | return tmp[:-2]
64 |
65 | def convert(seconds):
66 | seconds = seconds % (24 * 3600)
67 | hour = seconds // 3600
68 | seconds %= 3600
69 | minutes = seconds // 60
70 | seconds %= 60
71 | return "%d:%02d:%02d" % (hour, minutes, seconds)
72 |
73 | async def send_log(b, u):
74 | if Config.LOG_CHANNEL is not None:
75 | curr = datetime.now(timezone("Asia/Kolkata"))
76 | date = curr.strftime('%d %B, %Y')
77 | time = curr.strftime('%I:%M:%S %p')
78 | await b.send_message(
79 | Config.LOG_CHANNEL,
80 | f"New User Started The Bot \n\nUser ID : `{u.id}` \nFirst Name : {u.first_name} \nLast Name : {u.last_name} \nUser Name : @{u.username} \nUser Mention : {u.mention} \nUser Link : Click Here\n\nDate: {date}\nTime: {time}\n\nBy: {b.mention}"
81 | )
82 |
83 |
84 |
85 |
86 | # Jishu Developer
87 | # Don't Remove Credit 🥺
88 | # Telegram Channel @Madflix_Bots
89 | # Developer @JishuDeveloper
--------------------------------------------------------------------------------
/plugins/admin_panel.py:
--------------------------------------------------------------------------------
1 | from config import Config, Txt
2 | from helper.database import madflixbotz
3 | from pyrogram.types import Message
4 | from pyrogram import Client, filters
5 | from pyrogram.errors import FloodWait, InputUserDeactivated, UserIsBlocked, PeerIdInvalid
6 | import os, sys, time, asyncio, logging, datetime
7 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
8 |
9 | logger = logging.getLogger(__name__)
10 | logger.setLevel(logging.INFO)
11 | ADMIN_USER_ID = Config.ADMIN
12 |
13 | # Flag to indicate if the bot is restarting
14 | is_restarting = False
15 |
16 | @Client.on_message(filters.private & filters.command("restart") & filters.user(ADMIN_USER_ID))
17 | async def restart_bot(b, m):
18 | global is_restarting
19 | if not is_restarting:
20 | is_restarting = True
21 | await m.reply_text("**🔄 Restarting.....**")
22 |
23 | # Gracefully stop the bot's event loop
24 | b.stop()
25 | time.sleep(2) # Adjust the delay duration based on your bot's shutdown time
26 |
27 | # Restart the bot process
28 | os.execl(sys.executable, sys.executable, *sys.argv)
29 |
30 |
31 | @Client.on_message(filters.private & filters.command(["tutorial"]))
32 | async def tutorial(bot,message):
33 | user_id = message.from_user.id
34 | format_template = await madflixbotz.get_format_template(user_id)
35 | await message.reply_text(
36 | text =Txt.FILE_NAME_TXT.format(format_template=format_template),
37 | disable_web_page_preview=True,
38 | reply_markup=InlineKeyboardMarkup([
39 | [InlineKeyboardButton("🦋 Admin",url = "https://t.me/CallAdminRobot"),
40 | InlineKeyboardButton("⚡ Tutorial",url = "https://t.me/MadflixBots_Support") ]])
41 | )
42 |
43 |
44 | @Client.on_message(filters.command(["stats", "status"]) & filters.user(Config.ADMIN))
45 | async def get_stats(bot, message):
46 | total_users = await madflixbotz.total_users_count()
47 | uptime = time.strftime("%Hh%Mm%Ss", time.gmtime(time.time() - bot.uptime))
48 | start_t = time.time()
49 | st = await message.reply('**Accessing The Details.....**')
50 | end_t = time.time()
51 | time_taken_s = (end_t - start_t) * 1000
52 | await st.edit(text=f"**--Bot Status--** \n\n**⌚️ Bot Uptime :** {uptime} \n**🐌 Current Ping :** `{time_taken_s:.3f} ms` \n**👭 Total Users :** `{total_users}`")
53 |
54 | @Client.on_message(filters.command("broadcast") & filters.user(Config.ADMIN) & filters.reply)
55 | async def broadcast_handler(bot: Client, m: Message):
56 | await bot.send_message(Config.LOG_CHANNEL, f"{m.from_user.mention} or {m.from_user.id} Is Started The Broadcast......")
57 | all_users = await madflixbotz.get_all_users()
58 | broadcast_msg = m.reply_to_message
59 | sts_msg = await m.reply_text("Broadcast Started..!")
60 | done = 0
61 | failed = 0
62 | success = 0
63 | start_time = time.time()
64 | total_users = await madflixbotz.total_users_count()
65 | async for user in all_users:
66 | sts = await send_msg(user['_id'], broadcast_msg)
67 | if sts == 200:
68 | success += 1
69 | else:
70 | failed += 1
71 | if sts == 400:
72 | await madflixbotz.delete_user(user['_id'])
73 | done += 1
74 | if not done % 20:
75 | await sts_msg.edit(f"Broadcast In Progress: \n\nTotal Users {total_users} \nCompleted : {done} / {total_users}\nSuccess : {success}\nFailed : {failed}")
76 | completed_in = datetime.timedelta(seconds=int(time.time() - start_time))
77 | await sts_msg.edit(f"Bʀᴏᴀᴅᴄᴀꜱᴛ Cᴏᴍᴩʟᴇᴛᴇᴅ: \nCᴏᴍᴩʟᴇᴛᴇᴅ Iɴ `{completed_in}`.\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nFailed: {failed}")
78 |
79 | async def send_msg(user_id, message):
80 | try:
81 | await message.copy(chat_id=int(user_id))
82 | return 200
83 | except FloodWait as e:
84 | await asyncio.sleep(e.value)
85 | return send_msg(user_id, message)
86 | except InputUserDeactivated:
87 | logger.info(f"{user_id} : Deactivated")
88 | return 400
89 | except UserIsBlocked:
90 | logger.info(f"{user_id} : Blocked The Bot")
91 | return 400
92 | except PeerIdInvalid:
93 | logger.info(f"{user_id} : User ID Invalid")
94 | return 400
95 | except Exception as e:
96 | logger.error(f"{user_id} : {e}")
97 | return 500
98 |
99 |
100 |
101 |
102 | # Jishu Developer
103 | # Don't Remove Credit 🥺
104 | # Telegram Channel @Madflix_Bots
105 | # Developer @JishuDeveloper
106 |
--------------------------------------------------------------------------------
/plugins/auto_rename.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from pyrogram.errors import FloodWait
3 | from helper.database import madflixbotz
4 |
5 | @Client.on_message(filters.private & filters.command("autorename"))
6 | async def auto_rename_command(client, message):
7 | user_id = message.from_user.id
8 |
9 | # Extract the format from the command
10 | format_template = message.text.split("/autorename", 1)[1].strip()
11 |
12 | # Save the format template to the database
13 | await madflixbotz.set_format_template(user_id, format_template)
14 |
15 | await message.reply_text("**Auto Rename Format Updated Successfully! ✅**")
16 |
17 | @Client.on_message(filters.private & filters.command("setmedia"))
18 | async def set_media_command(client, message):
19 | user_id = message.from_user.id
20 | media_type = message.text.split("/setmedia", 1)[1].strip().lower()
21 |
22 | # Save the preferred media type to the database
23 | await madflixbotz.set_media_preference(user_id, media_type)
24 |
25 | await message.reply_text(f"**Media Preference Set To :** {media_type} ✅")
26 |
27 |
28 |
29 |
30 |
31 |
32 | # Jishu Developer
33 | # Don't Remove Credit 🥺
34 | # Telegram Channel @Madflix_Bots
35 | # Developer @JishuDeveloper
36 |
--------------------------------------------------------------------------------
/plugins/file_rename.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from pyrogram.errors import FloodWait
3 | from pyrogram.types import InputMediaDocument, Message
4 | from PIL import Image
5 | from datetime import datetime
6 | from hachoir.metadata import extractMetadata
7 | from hachoir.parser import createParser
8 | from helper.utils import progress_for_pyrogram, humanbytes, convert
9 | from helper.database import madflixbotz
10 | from config import Config
11 | import os
12 | import time
13 | import re
14 |
15 | renaming_operations = {}
16 |
17 | # Pattern 1: S01E02 or S01EP02
18 | pattern1 = re.compile(r'S(\d+)(?:E|EP)(\d+)')
19 | # Pattern 2: S01 E02 or S01 EP02 or S01 - E01 or S01 - EP02
20 | pattern2 = re.compile(r'S(\d+)\s*(?:E|EP|-\s*EP)(\d+)')
21 | # Pattern 3: Episode Number After "E" or "EP"
22 | pattern3 = re.compile(r'(?:[([<{]?\s*(?:E|EP)\s*(\d+)\s*[)\]>}]?)')
23 | # Pattern 3_2: episode number after - [hyphen]
24 | pattern3_2 = re.compile(r'(?:\s*-\s*(\d+)\s*)')
25 | # Pattern 4: S2 09 ex.
26 | pattern4 = re.compile(r'S(\d+)[^\d]*(\d+)', re.IGNORECASE)
27 | # Pattern X: Standalone Episode Number
28 | patternX = re.compile(r'(\d+)')
29 | #QUALITY PATTERNS
30 | # Pattern 5: 3-4 digits before 'p' as quality
31 | pattern5 = re.compile(r'\b(?:.*?(\d{3,4}[^\dp]*p).*?|.*?(\d{3,4}p))\b', re.IGNORECASE)
32 | # Pattern 6: Find 4k in brackets or parentheses
33 | pattern6 = re.compile(r'[([<{]?\s*4k\s*[)\]>}]?', re.IGNORECASE)
34 | # Pattern 7: Find 2k in brackets or parentheses
35 | pattern7 = re.compile(r'[([<{]?\s*2k\s*[)\]>}]?', re.IGNORECASE)
36 | # Pattern 8: Find HdRip without spaces
37 | pattern8 = re.compile(r'[([<{]?\s*HdRip\s*[)\]>}]?|\bHdRip\b', re.IGNORECASE)
38 | # Pattern 9: Find 4kX264 in brackets or parentheses
39 | pattern9 = re.compile(r'[([<{]?\s*4kX264\s*[)\]>}]?', re.IGNORECASE)
40 | # Pattern 10: Find 4kx265 in brackets or parentheses
41 | pattern10 = re.compile(r'[([<{]?\s*4kx265\s*[)\]>}]?', re.IGNORECASE)
42 |
43 | def extract_quality(filename):
44 | # Try Quality Patterns
45 | match5 = re.search(pattern5, filename)
46 | if match5:
47 | print("Matched Pattern 5")
48 | quality5 = match5.group(1) or match5.group(2) # Extracted quality from both patterns
49 | print(f"Quality: {quality5}")
50 | return quality5
51 |
52 | match6 = re.search(pattern6, filename)
53 | if match6:
54 | print("Matched Pattern 6")
55 | quality6 = "4k"
56 | print(f"Quality: {quality6}")
57 | return quality6
58 |
59 | match7 = re.search(pattern7, filename)
60 | if match7:
61 | print("Matched Pattern 7")
62 | quality7 = "2k"
63 | print(f"Quality: {quality7}")
64 | return quality7
65 |
66 | match8 = re.search(pattern8, filename)
67 | if match8:
68 | print("Matched Pattern 8")
69 | quality8 = "HdRip"
70 | print(f"Quality: {quality8}")
71 | return quality8
72 |
73 | match9 = re.search(pattern9, filename)
74 | if match9:
75 | print("Matched Pattern 9")
76 | quality9 = "4kX264"
77 | print(f"Quality: {quality9}")
78 | return quality9
79 |
80 | match10 = re.search(pattern10, filename)
81 | if match10:
82 | print("Matched Pattern 10")
83 | quality10 = "4kx265"
84 | print(f"Quality: {quality10}")
85 | return quality10
86 |
87 | # Return "Unknown" if no pattern matches
88 | unknown_quality = "Unknown"
89 | print(f"Quality: {unknown_quality}")
90 | return unknown_quality
91 |
92 |
93 | def extract_episode_number(filename):
94 | # Try Pattern 1
95 | match = re.search(pattern1, filename)
96 | if match:
97 | print("Matched Pattern 1")
98 | return match.group(2) # Extracted episode number
99 |
100 | # Try Pattern 2
101 | match = re.search(pattern2, filename)
102 | if match:
103 | print("Matched Pattern 2")
104 | return match.group(2) # Extracted episode number
105 |
106 | # Try Pattern 3
107 | match = re.search(pattern3, filename)
108 | if match:
109 | print("Matched Pattern 3")
110 | return match.group(1) # Extracted episode number
111 |
112 | # Try Pattern 3_2
113 | match = re.search(pattern3_2, filename)
114 | if match:
115 | print("Matched Pattern 3_2")
116 | return match.group(1) # Extracted episode number
117 |
118 | # Try Pattern 4
119 | match = re.search(pattern4, filename)
120 | if match:
121 | print("Matched Pattern 4")
122 | return match.group(2) # Extracted episode number
123 |
124 | # Try Pattern X
125 | match = re.search(patternX, filename)
126 | if match:
127 | print("Matched Pattern X")
128 | return match.group(1) # Extracted episode number
129 |
130 | # Return None if no pattern matches
131 | return None
132 |
133 | # Example Usage:
134 | filename = "Naruto Shippuden S01 - EP07 - 1080p [Dual Audio] @Madflix_Bots.mkv"
135 | episode_number = extract_episode_number(filename)
136 | print(f"Extracted Episode Number: {episode_number}")
137 |
138 | # Inside the handler for file uploads
139 | @Client.on_message(filters.private & (filters.document | filters.video | filters.audio))
140 | async def auto_rename_files(client, message):
141 | user_id = message.from_user.id
142 | firstname = message.from_user.first_name
143 | format_template = await madflixbotz.get_format_template(user_id)
144 | media_preference = await madflixbotz.get_media_preference(user_id)
145 |
146 | if not format_template:
147 | return await message.reply_text("Please Set An Auto Rename Format First Using /autorename")
148 |
149 | # Extract information from the incoming file name
150 | if message.document:
151 | file_id = message.document.file_id
152 | file_name = message.document.file_name
153 | media_type = media_preference or "document" # Use preferred media type or default to document
154 | elif message.video:
155 | file_id = message.video.file_id
156 | file_name = f"{message.video.file_name}.mp4"
157 | media_type = media_preference or "video" # Use preferred media type or default to video
158 | elif message.audio:
159 | file_id = message.audio.file_id
160 | file_name = f"{message.audio.file_name}.mp3"
161 | media_type = media_preference or "audio" # Use preferred media type or default to audio
162 | else:
163 | return await message.reply_text("Unsupported File Type")
164 |
165 | print(f"Original File Name: {file_name}")
166 |
167 |
168 |
169 | # Check whether the file is already being renamed or has been renamed recently
170 | if file_id in renaming_operations:
171 | elapsed_time = (datetime.now() - renaming_operations[file_id]).seconds
172 | if elapsed_time < 10:
173 | print("File is being ignored as it is currently being renamed or was renamed recently.")
174 | return # Exit the handler if the file is being ignored
175 |
176 | # Mark the file as currently being renamed
177 | renaming_operations[file_id] = datetime.now()
178 |
179 | # Extract episode number and qualities
180 | episode_number = extract_episode_number(file_name)
181 |
182 | print(f"Extracted Episode Number: {episode_number}")
183 |
184 | if episode_number:
185 | placeholders = ["episode", "Episode", "EPISODE", "{episode}"]
186 | for placeholder in placeholders:
187 | format_template = format_template.replace(placeholder, str(episode_number), 1)
188 |
189 | # Add extracted qualities to the format template
190 | quality_placeholders = ["quality", "Quality", "QUALITY", "{quality}"]
191 | for quality_placeholder in quality_placeholders:
192 | if quality_placeholder in format_template:
193 | extracted_qualities = extract_quality(file_name)
194 | if extracted_qualities == "Unknown":
195 | await message.reply_text("I Was Not Able To Extract The Quality Properly. Renaming As 'Unknown'...")
196 | # Mark the file as ignored
197 | del renaming_operations[file_id]
198 | return # Exit the handler if quality extraction fails
199 |
200 | format_template = format_template.replace(quality_placeholder, "".join(extracted_qualities))
201 |
202 | _, file_extension = os.path.splitext(file_name)
203 | new_file_name = f"{format_template}{file_extension}"
204 | file_path = f"downloads/{new_file_name}"
205 | file = message
206 |
207 | download_msg = await message.reply_text(text="Trying To Download.....")
208 | try:
209 | path = await client.download_media(message=file, file_name=file_path, progress=progress_for_pyrogram, progress_args=("Download Started....", download_msg, time.time()))
210 | except Exception as e:
211 | # Mark the file as ignored
212 | del renaming_operations[file_id]
213 | return await download_msg.edit(e)
214 |
215 | duration = 0
216 | try:
217 | metadata = extractMetadata(createParser(file_path))
218 | if metadata.has("duration"):
219 | duration = metadata.get('duration').seconds
220 | except Exception as e:
221 | print(f"Error getting duration: {e}")
222 |
223 | upload_msg = await download_msg.edit("Trying To Uploading.....")
224 | ph_path = None
225 | c_caption = await madflixbotz.get_caption(message.chat.id)
226 | c_thumb = await madflixbotz.get_thumbnail(message.chat.id)
227 |
228 | caption = c_caption.format(filename=new_file_name, filesize=humanbytes(message.document.file_size), duration=convert(duration)) if c_caption else f"**{new_file_name}**"
229 |
230 | if c_thumb:
231 | ph_path = await client.download_media(c_thumb)
232 | print(f"Thumbnail downloaded successfully. Path: {ph_path}")
233 | elif media_type == "video" and message.video.thumbs:
234 | ph_path = await client.download_media(message.video.thumbs[0].file_id)
235 |
236 | if ph_path:
237 | Image.open(ph_path).convert("RGB").save(ph_path)
238 | img = Image.open(ph_path)
239 | img.resize((320, 320))
240 | img.save(ph_path, "JPEG")
241 |
242 |
243 | try:
244 | type = media_type # Use 'media_type' variable instead
245 | if type == "document":
246 | await client.send_document(
247 | message.chat.id,
248 | document=file_path,
249 | thumb=ph_path,
250 | caption=caption,
251 | progress=progress_for_pyrogram,
252 | progress_args=("Upload Started.....", upload_msg, time.time())
253 | )
254 | elif type == "video":
255 | await client.send_video(
256 | message.chat.id,
257 | video=file_path,
258 | caption=caption,
259 | thumb=ph_path,
260 | duration=duration,
261 | progress=progress_for_pyrogram,
262 | progress_args=("Upload Started.....", upload_msg, time.time())
263 | )
264 | elif type == "audio":
265 | await client.send_audio(
266 | message.chat.id,
267 | audio=file_path,
268 | caption=caption,
269 | thumb=ph_path,
270 | duration=duration,
271 | progress=progress_for_pyrogram,
272 | progress_args=("Upload Started.....", upload_msg, time.time())
273 | )
274 | except Exception as e:
275 | os.remove(file_path)
276 | if ph_path:
277 | os.remove(ph_path)
278 | # Mark the file as ignored
279 | return await upload_msg.edit(f"Error: {e}")
280 |
281 | await download_msg.delete()
282 | os.remove(file_path)
283 | if ph_path:
284 | os.remove(ph_path)
285 |
286 | # Remove the entry from renaming_operations after successful renaming
287 | del renaming_operations[file_id]
288 |
289 |
290 |
291 |
292 | # Jishu Developer
293 | # Don't Remove Credit 🥺
294 | # Telegram Channel @Madflix_Bots
295 | # Developer @JishuDeveloper
296 |
--------------------------------------------------------------------------------
/plugins/force_subs.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters, enums
2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
3 | from pyrogram.errors import UserNotParticipant
4 | from config import Config
5 | from helper.database import madflixbotz
6 |
7 | async def not_subscribed(_, client, message):
8 | await madflixbotz.add_user(client, message)
9 | if not Config.FORCE_SUB:
10 | return False
11 | try:
12 | user = await client.get_chat_member(Config.FORCE_SUB, message.from_user.id)
13 | if user.status == enums.ChatMemberStatus.BANNED:
14 | return True
15 | else:
16 | return False
17 | except UserNotParticipant:
18 | pass
19 | return True
20 |
21 |
22 | @Client.on_message(filters.private & filters.create(not_subscribed))
23 | async def forces_sub(client, message):
24 | buttons = [[InlineKeyboardButton(text="🔺 Update Channel 🔺", url=f"https://t.me/{Config.FORCE_SUB}") ]]
25 | text = "Hello Dear \n\nYou Need To Join In My Channel To Use Me\n\nKindly Please Join Channel"
26 | try:
27 | user = await client.get_chat_member(Config.FORCE_SUB, message.from_user.id)
28 | if user.status == enums.ChatMemberStatus.BANNED:
29 | return await client.send_message(message.from_user.id, text="Sorry You Are Banned To Use Me")
30 | except UserNotParticipant:
31 | return await message.reply_text(text=text, reply_markup=InlineKeyboardMarkup(buttons))
32 | return await message.reply_text(text=text, reply_markup=InlineKeyboardMarkup(buttons))
33 |
34 |
35 |
36 |
37 | # Jishu Developer
38 | # Don't Remove Credit 🥺
39 | # Telegram Channel @Madflix_Bots
40 | # Developer @JishuDeveloper
--------------------------------------------------------------------------------
/plugins/start_&_cb.py:
--------------------------------------------------------------------------------
1 | import random
2 | from pyrogram import Client, filters
3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, ForceReply, CallbackQuery, Message, InputMediaPhoto
4 |
5 | from helper.database import madflixbotz
6 | from config import Config, Txt
7 |
8 | @Client.on_message(filters.private & filters.command("start"))
9 | async def start(client, message):
10 | user = message.from_user
11 | await madflixbotz.add_user(client, message)
12 | button = InlineKeyboardMarkup([[
13 | InlineKeyboardButton('📢 Updates', url='https://t.me/Madflix_Bots'),
14 | InlineKeyboardButton('💬 Support', url='https://t.me/MadflixBots_Support')
15 | ],[
16 | InlineKeyboardButton('⚙️ Help', callback_data='help'),
17 | InlineKeyboardButton('💙 About', callback_data='about')
18 | ],[
19 | InlineKeyboardButton("🧑💻 Developer 🧑💻", url='https://t.me/CallAdminRobot')
20 | ]])
21 | if Config.START_PIC:
22 | await message.reply_photo(Config.START_PIC, caption=Txt.START_TXT.format(user.mention), reply_markup=button)
23 | else:
24 | await message.reply_text(text=Txt.START_TXT.format(user.mention), reply_markup=button, disable_web_page_preview=True)
25 |
26 | @Client.on_callback_query()
27 | async def cb_handler(client, query: CallbackQuery):
28 | data = query.data
29 | user_id = query.from_user.id
30 |
31 | if data == "home":
32 | await query.message.edit_text(
33 | text=Txt.START_TXT.format(query.from_user.mention),
34 | disable_web_page_preview=True,
35 | reply_markup=InlineKeyboardMarkup([[
36 | InlineKeyboardButton('📢 Updates', url='https://t.me/Madflix_Bots'),
37 | InlineKeyboardButton('💬 Support', url='https://t.me/MadflixBots_Support')
38 | ],[
39 | InlineKeyboardButton('⚙️ Help', callback_data='help'),
40 | InlineKeyboardButton('💙 About', callback_data='about')
41 | ],[
42 | InlineKeyboardButton("🧑💻 Developer 🧑💻", url='https://t.me/CallAdminRobot')
43 | ]])
44 | )
45 | elif data == "caption":
46 | await query.message.edit_text(
47 | text=Txt.CAPTION_TXT,
48 | disable_web_page_preview=True,
49 | reply_markup=InlineKeyboardMarkup([[
50 | InlineKeyboardButton("✖️ Close", callback_data="close"),
51 | InlineKeyboardButton("🔙 Back", callback_data="help")
52 | ]])
53 | )
54 | elif data == "help":
55 | await query.message.edit_text(
56 | text=Txt.HELP_TXT.format(client.mention),
57 | disable_web_page_preview=True,
58 | reply_markup=InlineKeyboardMarkup([[
59 | InlineKeyboardButton("⚙️ Setup AutoRename Format ⚙️", callback_data='file_names')
60 | ],[
61 | InlineKeyboardButton('🖼️ Thumbnail', callback_data='thumbnail'),
62 | InlineKeyboardButton('✏️ Caption', callback_data='caption')
63 | ],[
64 | InlineKeyboardButton('🏠 Home', callback_data='home'),
65 | InlineKeyboardButton('💰 Donate', callback_data='donate')
66 | ]])
67 | )
68 | elif data == "donate":
69 | await query.message.edit_text(
70 | text=Txt.DONATE_TXT,
71 | disable_web_page_preview=True,
72 | reply_markup=InlineKeyboardMarkup([[
73 | InlineKeyboardButton("✖️ Close", callback_data="close"),
74 | InlineKeyboardButton("🔙 Back", callback_data="help")
75 | ]])
76 | )
77 |
78 | elif data == "file_names":
79 | format_template = await madflixbotz.get_format_template(user_id)
80 | await query.message.edit_text(
81 | text=Txt.FILE_NAME_TXT.format(format_template=format_template),
82 | disable_web_page_preview=True,
83 | reply_markup=InlineKeyboardMarkup([[
84 | InlineKeyboardButton("✖️ Close", callback_data="close"),
85 | InlineKeyboardButton("🔙 Back", callback_data="help")
86 | ]])
87 | )
88 |
89 | elif data == "thumbnail":
90 | await query.message.edit_caption(
91 | caption=Txt.THUMBNAIL_TXT,
92 | reply_markup=InlineKeyboardMarkup([[
93 | InlineKeyboardButton("✖️ Close", callback_data="close"),
94 | InlineKeyboardButton("🔙 Back", callback_data="help"),
95 | ]]),
96 | )
97 |
98 | elif data == "about":
99 | await query.message.edit_text(
100 | text=Txt.ABOUT_TXT,
101 | disable_web_page_preview=True,
102 | reply_markup=InlineKeyboardMarkup([[
103 | InlineKeyboardButton("✖️ Close", callback_data="close"),
104 | InlineKeyboardButton("🔙 Back", callback_data="home")
105 | ]])
106 | )
107 |
108 |
109 | elif data == "close":
110 | try:
111 | await query.message.delete()
112 | await query.message.reply_to_message.delete()
113 | await query.message.continue_propagation()
114 | except:
115 | await query.message.delete()
116 | await query.message.continue_propagation()
117 |
118 |
119 |
120 |
121 |
122 |
123 | # Jishu Developer
124 | # Don't Remove Credit 🥺
125 | # Telegram Channel @Madflix_Bots
126 | # Developer @JishuDeveloper
127 |
--------------------------------------------------------------------------------
/plugins/thumb_&_cap.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from helper.database import madflixbotz
3 |
4 | @Client.on_message(filters.private & filters.command('set_caption'))
5 | async def add_caption(client, message):
6 | if len(message.command) == 1:
7 | return await message.reply_text("**Give The Caption\n\nExample :- `/set_caption 📕Name ➠ : {filename} \n\n🔗 Size ➠ : {filesize} \n\n⏰ Duration ➠ : {duration}`**")
8 | caption = message.text.split(" ", 1)[1]
9 | await madflixbotz.set_caption(message.from_user.id, caption=caption)
10 | await message.reply_text("**Your Caption Successfully Added ✅**")
11 |
12 | @Client.on_message(filters.private & filters.command('del_caption'))
13 | async def delete_caption(client, message):
14 | caption = await madflixbotz.get_caption(message.from_user.id)
15 | if not caption:
16 | return await message.reply_text("**You Don't Have Any Caption ❌**")
17 | await madflixbotz.set_caption(message.from_user.id, caption=None)
18 | await message.reply_text("**Your Caption Successfully Deleted 🗑️**")
19 |
20 | @Client.on_message(filters.private & filters.command(['see_caption', 'view_caption']))
21 | async def see_caption(client, message):
22 | caption = await madflixbotz.get_caption(message.from_user.id)
23 | if caption:
24 | await message.reply_text(f"**Your Caption :**\n\n`{caption}`")
25 | else:
26 | await message.reply_text("**You Don't Have Any Caption ❌**")
27 |
28 |
29 | @Client.on_message(filters.private & filters.command(['view_thumb', 'viewthumb']))
30 | async def viewthumb(client, message):
31 | thumb = await madflixbotz.get_thumbnail(message.from_user.id)
32 | if thumb:
33 | await client.send_photo(chat_id=message.chat.id, photo=thumb)
34 | else:
35 | await message.reply_text("**You Don't Have Any Thumbnail ❌**")
36 |
37 | @Client.on_message(filters.private & filters.command(['del_thumb', 'delthumb']))
38 | async def removethumb(client, message):
39 | await madflixbotz.set_thumbnail(message.from_user.id, file_id=None)
40 | await message.reply_text("**Thumbnail Deleted Successfully 🗑️**")
41 |
42 | @Client.on_message(filters.private & filters.photo)
43 | async def addthumbs(client, message):
44 | mkn = await message.reply_text("Please Wait ...")
45 | await madflixbotz.set_thumbnail(message.from_user.id, file_id=message.photo.file_id)
46 | await mkn.edit("**Thumbnail Saved Successfully ✅️**")
47 |
48 |
49 |
50 |
51 |
52 | # Jishu Developer
53 | # Don't Remove Credit 🥺
54 | # Telegram Channel @Madflix_Bots
55 | # Developer @JishuDeveloper
--------------------------------------------------------------------------------
/render.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | - type: web
3 | plan: free
4 | name: auto-rename-bot
5 | env: python
6 | buildCommand: pip install -r requirements.txt
7 | startCommand: python bot.py
8 | repo: https://github.com/jishudeveloper/Auto-Rename-Bot.git
9 | branch: main
10 | autoDeploy: false
11 | envVars:
12 | - key: BOT_TOKEN
13 | sync: false
14 | - key: API_ID
15 | sync: false
16 | - key: API_HASH
17 | sync: false
18 | - key: FORCE_SUB
19 | sync: false
20 | - key: LOG_CHANNEL
21 | sync: false
22 | - key: DB_NAME
23 | sync: false
24 | - key: DB_URL
25 | sync: false
26 | - key: START_PIC
27 | sync: false
28 | - key: ADMIN
29 | sync: false
30 | - key: WEBHOOK
31 | sync: false
32 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyrogram==2.0.83
2 | TgCrypto
3 | motor
4 | dnspython
5 | hachoir
6 | Pillow
7 | aiohttp
8 | pytz
9 | psutil
10 |
--------------------------------------------------------------------------------
/route.py:
--------------------------------------------------------------------------------
1 | from aiohttp import web
2 |
3 | routes = web.RouteTableDef()
4 |
5 | @routes.get("/", allow_head=True)
6 | async def root_route_handler(request):
7 | return web.json_response("Madflix_Bots")
8 |
9 |
10 | async def web_server():
11 | web_app = web.Application(client_max_size=30000000)
12 | web_app.add_routes(routes)
13 | return web_app
14 |
15 |
16 |
17 | # Jishu Developer
18 | # Don't Remove Credit 🥺
19 | # Telegram Channel @Madflix_Bots
20 | # Developer @JishuDeveloper
21 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.10.8
2 |
--------------------------------------------------------------------------------