├── assets
├── Test
├── AJAX.png
├── logo.jpg
├── logoo.jpg
└── Picsart_22-02-20_13-02-59-464.jpg
├── plugins
├── modules
│ ├── @
│ └── carbon.py
├── channel.py
├── function.py
├── broadcast.py
├── banned.py
├── inline.py
├── connection.py
├── misc.py
├── index.py
├── filters.py
├── commands.py
├── p_ttishow.py
└── pm_filter.py
├── runtime.txt
├── Procfile
├── heroku.yml
├── Dockerfile
├── start.sh
├── logging.conf
├── sample_info.py
├── requirements.txt
├── bot.py
├── .gitignore
├── database
├── filters_mdb.py
├── connections_mdb.py
├── users_chats_db.py
└── ia_filterdb.py
├── info.py
├── README.md
├── app.json
├── Script.py
├── utils.py
└── LICENSE
/assets/Test:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/modules/@:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.8.7
2 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python3 bot.py
--------------------------------------------------------------------------------
/heroku.yml:
--------------------------------------------------------------------------------
1 | build:
2 | docker:
3 | worker: Dockerfile
--------------------------------------------------------------------------------
/assets/AJAX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/AJAX.png
--------------------------------------------------------------------------------
/assets/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/logo.jpg
--------------------------------------------------------------------------------
/assets/logoo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/logoo.jpg
--------------------------------------------------------------------------------
/assets/Picsart_22-02-20_13-02-59-464.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/Picsart_22-02-20_13-02-59-464.jpg
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-slim-buster
2 |
3 | RUN apt update && apt upgrade -y
4 | RUN apt install git -y
5 | COPY requirements.txt /requirements.txt
6 |
7 | RUN cd /
8 | RUN pip3 install -U pip && pip3 install -U -r requirements.txt
9 | RUN mkdir /EvaMaria
10 | WORKDIR /EvaMaria
11 | COPY start.sh /start.sh
12 | CMD ["/bin/bash", "/start.sh"]
13 |
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | if [ -z $UPSTREAM_REPO ]
2 | then
3 | echo "Cloning main Repository"
4 | git clone https://github.com/Aadhi000/Ajax.git /Ajax
5 | else
6 | echo "Cloning Custom Repo from $UPSTREAM_REPO "
7 | git clone $UPSTREAM_REPO /Ajax
8 | fi
9 | cd /Ajax
10 | pip3 install -U -r requirements.txt
11 | echo "Starting ᗩᒍᗩ᙭....🔥"
12 | python3 bot.py
13 |
--------------------------------------------------------------------------------
/plugins/channel.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from info import CHANNELS
3 | from database.ia_filterdb import save_file
4 |
5 | media_filter = filters.document | filters.video | filters.audio
6 |
7 |
8 | @Client.on_message(filters.chat(CHANNELS) & media_filter)
9 | async def media(bot, message):
10 | """Media Handler"""
11 | for file_type in ("document", "video", "audio"):
12 | media = getattr(message, file_type, None)
13 | if media is not None:
14 | break
15 | else:
16 | return
17 |
18 | media.file_type = file_type
19 | media.caption = message.caption
20 | await save_file(media)
--------------------------------------------------------------------------------
/plugins/function.py:
--------------------------------------------------------------------------------
1 | from asyncio import gather
2 | from datetime import datetime, timedelta
3 | from io import BytesIO
4 | from math import atan2, cos, radians, sin, sqrt
5 | from os import execvp
6 | from random import randint
7 | from re import findall
8 | from re import sub as re_sub
9 | from sys import executable
10 | from aiohttp import ClientSession
11 |
12 | import aiofiles
13 | from PIL import Image
14 | from pyrogram.types import Message
15 |
16 | aiohttpsession = ClientSession()
17 |
18 | async def make_carbon(code):
19 | url = "https://carbonara.vercel.app/api/cook"
20 | async with aiohttpsession.post(url, json={"code": code}) as resp:
21 | image = BytesIO(await resp.read())
22 | image.name = "carbon.png"
23 | return image
24 |
--------------------------------------------------------------------------------
/logging.conf:
--------------------------------------------------------------------------------
1 | [loggers]
2 | keys=root
3 |
4 | [handlers]
5 | keys=consoleHandler,fileHandler
6 |
7 | [formatters]
8 | keys=consoleFormatter,fileFormatter
9 |
10 | [logger_root]
11 | level=DEBUG
12 | handlers=consoleHandler,fileHandler
13 |
14 | [handler_consoleHandler]
15 | class=StreamHandler
16 | level=INFO
17 | formatter=consoleFormatter
18 | args=(sys.stdout,)
19 |
20 | [handler_fileHandler]
21 | class=FileHandler
22 | level=ERROR
23 | formatter=fileFormatter
24 | args=('TelegramBot.log','w',)
25 |
26 | [formatter_consoleFormatter]
27 | format=%(asctime)s - %(lineno)d - %(name)s - %(module)s - %(levelname)s - %(message)s
28 | datefmt=%I:%M:%S %p
29 |
30 | [formatter_fileFormatter]
31 | format=[%(asctime)s:%(name)s:%(lineno)d:%(levelname)s] %(message)s
32 | datefmt=%m/%d/%Y %I:%M:%S %p
--------------------------------------------------------------------------------
/sample_info.py:
--------------------------------------------------------------------------------
1 | # Bot information
2 | SESSION = 'Media_search'
3 | USER_SESSION = 'User_Bot'
4 | API_ID = 12345
5 | API_HASH = '0123456789abcdef0123456789abcdef'
6 | BOT_TOKEN = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'
7 | USERBOT_STRING_SESSION = ''
8 |
9 | # Bot settings
10 | CACHE_TIME = 300
11 | USE_CAPTION_FILTER = False
12 |
13 | # Admins, Channels & Users
14 | ADMINS = [12345789, 'admin123', 98765432]
15 | CHANNELS = [-10012345678, -100987654321, 'channelusername']
16 | AUTH_USERS = []
17 | AUTH_CHANNEL = None
18 |
19 | # MongoDB information
20 | DATABASE_URI = "mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb]?retryWrites=true&w=majority"
21 | DATABASE_NAME = 'Telegram'
22 | COLLECTION_NAME = 'channel_files' # If you are using the same database, then use different collection name for each bot
23 |
24 |
25 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | git+https://github.com/subinps/pyrogram@inline-m
2 | tgcrypto
3 | pymongo[srv]==3.11.4
4 | motor==2.4.0
5 | marshmallow==3.12.2
6 | python-telegram-bot==11.1.0
7 | umongo==3.0.0
8 | requests
9 | bs4
10 | Pyromod
11 | imdbpy==2021.4.18
12 | youtube-dl
13 | youtube_search
14 | requests
15 | googletrans==3.1.0a0
16 | telegraph
17 | beautifulsoup4
18 | aiohttp==3.7.4
19 | gTTS
20 | googletrans==3.1.0a0
21 | NumPy
22 | glitch_this
23 | opencv-python-headless
24 | youtube-search-python==1.4.6
25 | yt-dlp
26 | pypng
27 | Pillow
28 | wget
29 | aiofiles
30 | psutil
31 | wheel
32 | humanize
33 | ytthumb
34 | pypdf2
35 | PyPDF2
36 | pyshorteners
37 | ffmpeg-python
38 | TgCrypto
39 | py-tgcalls
40 | python-dotenv
41 | youtube_search_python
42 | requests
43 | aiohttp
44 | aiofiles
45 | asyncio
46 | youtube_search
47 | search_engine_parser
48 | ffmpeg-python
49 | ffmpeg
50 | Pillow
51 | ujson
52 |
--------------------------------------------------------------------------------
/plugins/modules/carbon.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 | from aiohttp import ClientSession
3 | from pyrogram import Client as bot
4 | from plugins.function import make_carbon
5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
6 | aiohttpsession = ClientSession()
7 |
8 | C = "**𝙼𝙰𝙳𝙴 𝙱𝚈 [AYUSH](https://t.me/Aks_support01_bot)**"
9 | F = InlineKeyboardMarkup(
10 | [[
11 | InlineKeyboardButton("𝚄𝙿𝙳𝙰𝚃𝙴𝚉 𝙲𝙷𝙰𝙽𝙽𝙴𝙻", url="https://t.me/Imdb_updates")
12 | ]]
13 | )
14 |
15 |
16 |
17 |
18 | @bot.on_message(filters.command("carbon"))
19 | async def carbon_func(_, message):
20 | if not message.reply_to_message:
21 | return await message.reply_text(
22 | "**𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 𝚃𝙾 𝙼𝙰𝙺𝙴 𝙲𝙰𝚁𝙱𝙾𝙽.**"
23 | )
24 | if not message.reply_to_message.text:
25 | return await message.reply_text(
26 | "**𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 𝚃𝙾 𝙼𝙰𝙺𝙴 𝙲𝙰𝚁𝙱𝙾𝙽.**"
27 | )
28 | user_id = message.from_user.id
29 | m = await message.reply_text("**𝙲𝚁𝙴𝙰𝚃𝙸𝙽𝙶 𝙲𝙰𝚁𝙱𝙾𝙽...**")
30 | carbon = await make_carbon(message.reply_to_message.text)
31 | await m.edit("**𝚄𝙿𝙻𝙾𝙰𝙳𝙸𝙽𝙶 𝙲𝙰𝚁𝙱𝙾𝙽...**")
32 | await message.reply_photo(
33 | photo=carbon,
34 | caption=C,
35 | reply_markup=F)
36 | await m.delete()
37 | carbon.close()
38 |
--------------------------------------------------------------------------------
/bot.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import logging.config
3 |
4 | # Get logging configurations
5 | logging.config.fileConfig('logging.conf')
6 | logging.getLogger().setLevel(logging.INFO)
7 | logging.getLogger("pyrogram").setLevel(logging.ERROR)
8 | logging.getLogger("imdbpy").setLevel(logging.ERROR)
9 |
10 | from pyrogram import Client, __version__
11 | from pyrogram.raw.all import layer
12 | from database.ia_filterdb import Media
13 | from database.users_chats_db import db
14 | from info import SESSION, API_ID, API_HASH, BOT_TOKEN, LOG_STR
15 | from utils import temp
16 |
17 | class Bot(Client):
18 |
19 | def __init__(self):
20 | super().__init__(
21 | session_name=SESSION,
22 | api_id=API_ID,
23 | api_hash=API_HASH,
24 | bot_token=BOT_TOKEN,
25 | workers=50,
26 | plugins={"root": "plugins"},
27 | sleep_threshold=5,
28 | )
29 |
30 | async def start(self):
31 | b_users, b_chats = await db.get_banned()
32 | temp.BANNED_USERS = b_users
33 | temp.BANNED_CHATS = b_chats
34 | await super().start()
35 | await Media.ensure_indexes()
36 | me = await self.get_me()
37 | temp.ME = me.id
38 | temp.U_NAME = me.username
39 | temp.B_NAME = me.first_name
40 | self.username = '@' + me.username
41 | logging.info(f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}.")
42 | logging.info(LOG_STR)
43 |
44 | async def stop(self, *args):
45 | await super().stop()
46 | logging.info("Bot stopped. Bye.")
47 |
48 |
49 | app = Bot()
50 | app.run()
51 |
--------------------------------------------------------------------------------
/plugins/broadcast.py:
--------------------------------------------------------------------------------
1 |
2 | from pyrogram import Client, filters
3 | import datetime
4 | import time
5 | from database.users_chats_db import db
6 | from info import ADMINS
7 | from utils import broadcast_messages
8 | import asyncio
9 |
10 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply)
11 | # https://t.me/GetTGLink/4178
12 | async def verupikkals(bot, message):
13 | users = await db.get_all_users()
14 | b_msg = message.reply_to_message
15 | sts = await message.reply_text(
16 | text='Broadcasting your messages...'
17 | )
18 | start_time = time.time()
19 | total_users = await db.total_users_count()
20 | done = 0
21 | blocked = 0
22 | deleted = 0
23 | failed =0
24 |
25 | success = 0
26 | async for user in users:
27 | pti, sh = await broadcast_messages(int(user['id']), b_msg)
28 | if pti:
29 | success += 1
30 | elif pti == False:
31 | if sh == "Bocked":
32 | blocked+=1
33 | elif sh == "Deleted":
34 | deleted += 1
35 | elif sh == "Error":
36 | failed += 1
37 | done += 1
38 | await asyncio.sleep(2)
39 | if not done % 20:
40 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}")
41 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time))
42 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}")
--------------------------------------------------------------------------------
/plugins/banned.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from utils import temp
3 | from pyrogram.types import Message
4 | from database.users_chats_db import db
5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
6 | from info import SUPPORT_CHAT
7 | async def banned_users(_, client, message: Message):
8 | return (
9 | message.from_user is not None or not message.sender_chat
10 | ) and message.from_user.id in temp.BANNED_USERS
11 |
12 | banned_user = filters.create(banned_users)
13 |
14 | async def disabled_chat(_, client, message: Message):
15 | return message.chat.id in temp.BANNED_CHATS
16 |
17 | disabled_group=filters.create(disabled_chat)
18 |
19 |
20 | @Client.on_message(filters.private & banned_user & filters.incoming)
21 | async def ban_reply(bot, message):
22 | ban = await db.get_ban_status(message.from_user.id)
23 | await message.reply(f'Sorry Dude, You are Banned to use be. \nBan Reason: {ban["ban_reason"]}')
24 |
25 | @Client.on_message(filters.group & disabled_group & filters.incoming)
26 | async def grp_bd(bot, message):
27 | buttons = [[
28 | InlineKeyboardButton('𝙾𝚆𝙽𝙴𝚁', url=f'https://t.me/{SUPPORT_CHAT}')
29 | ]]
30 | reply_markup=InlineKeyboardMarkup(buttons)
31 | vazha = await db.get_chat(message.chat.id)
32 | k = await message.reply(
33 | text=f"CHAT NOT ALLOWED 🐞\n\n 𝙼𝚈 𝙾𝚆𝙽𝙴𝚁 𝙷𝙰𝚂 𝚁𝙴𝚂𝚃𝚁𝙸𝙲𝚃𝙴𝙳 𝙼𝙴 𝙵𝚁𝙾𝙼 𝚆𝙾𝚁𝙺𝙸𝙽𝙶 𝙷𝙴𝚁𝙴 ! 𝙸𝙵 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙺𝙽𝙾𝚆 𝙼𝙾𝚁𝙴 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙾𝚆𝙽𝙴𝚁..\nReason : {vazha['reason']}.",
34 | reply_markup=reply_markup)
35 | try:
36 | await k.pin()
37 | except:
38 | pass
39 | await bot.leave_chat(message.chat.id)
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Personal files
2 | *.session
3 | *.session-journal
4 | .vscode
5 | *test*.py
6 | setup.cfg
7 |
8 | # Byte-compiled / optimized / DLL files
9 | __pycache__/
10 | *.py[cod]
11 | *$py.class
12 |
13 | # C extensions
14 | *.so
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | share/python-wheels/
31 | *.egg-info/
32 | .installed.cfg
33 | *.egg
34 | MANIFEST
35 |
36 | # PyInstaller
37 | # Usually these files are written by a python script from a template
38 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
39 | *.manifest
40 | *.spec
41 |
42 | # Installer logs
43 | pip-log.txt
44 | pip-delete-this-directory.txt
45 |
46 | # Unit test / coverage reports
47 | htmlcov/
48 | .tox/
49 | .nox/
50 | .coverage
51 | .coverage.*
52 | .cache
53 | nosetests.xml
54 | coverage.xml
55 | *.cover
56 | *.py,cover
57 | .hypothesis/
58 | .pytest_cache/
59 | cover/
60 |
61 | # Translations
62 | *.mo
63 | *.pot
64 |
65 | # Django stuff:
66 | *.log
67 | local_settings.py
68 | db.sqlite3
69 | db.sqlite3-journal
70 |
71 | # Flask stuff:
72 | instance/
73 | .webassets-cache
74 |
75 | # Scrapy stuff:
76 | .scrapy
77 |
78 | # Sphinx documentation
79 | docs/_build/
80 |
81 | # PyBuilder
82 | .pybuilder/
83 | target/
84 |
85 | # Jupyter Notebook
86 | .ipynb_checkpoints
87 |
88 | # IPython
89 | profile_default/
90 | ipython_config.py
91 |
92 | # pyenv
93 | # For a library or package, you might want to ignore these files since the code is
94 | # intended to run in multiple environments; otherwise, check them in:
95 | # .python-version
96 |
97 | # pipenv
98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
101 | # install all needed dependencies.
102 | #Pipfile.lock
103 |
104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
105 | __pypackages__/
106 |
107 | # Celery stuff
108 | celerybeat-schedule
109 | celerybeat.pid
110 |
111 | # SageMath parsed files
112 | *.sage.py
113 |
114 | # Environments
115 | .env
116 | .venv
117 | env/
118 | venv/
119 | ENV/
120 | env.bak/
121 | venv.bak/
122 |
123 | # Spyder project settings
124 | .spyderproject
125 | .spyproject
126 |
127 | # Rope project settings
128 | .ropeproject
129 |
130 | # mkdocs documentation
131 | /site
132 |
133 | # mypy
134 | .mypy_cache/
135 | .dmypy.json
136 | dmypy.json
137 |
138 | # Pyre type checker
139 | .pyre/
140 |
141 | # pytype static type analyzer
142 | .pytype/
143 |
144 | # Cython debug symbols
145 | cython_debug/
146 | config.py
147 | .goutputstream-VAFWB1
148 | result.json
149 |
--------------------------------------------------------------------------------
/database/filters_mdb.py:
--------------------------------------------------------------------------------
1 | import pymongo
2 | from info import DATABASE_URI, DATABASE_NAME
3 | import logging
4 | logger = logging.getLogger(__name__)
5 | logger.setLevel(logging.ERROR)
6 |
7 | myclient = pymongo.MongoClient(DATABASE_URI)
8 | mydb = myclient[DATABASE_NAME]
9 |
10 |
11 |
12 | async def add_filter(grp_id, text, reply_text, btn, file, alert):
13 | mycol = mydb[str(grp_id)]
14 | # mycol.create_index([('text', 'text')])
15 |
16 | data = {
17 | 'text':str(text),
18 | 'reply':str(reply_text),
19 | 'btn':str(btn),
20 | 'file':str(file),
21 | 'alert':str(alert)
22 | }
23 |
24 | try:
25 | mycol.update_one({'text': str(text)}, {"$set": data}, upsert=True)
26 | except:
27 | logger.exception('Some error occured!', exc_info=True)
28 |
29 |
30 | async def find_filter(group_id, name):
31 | mycol = mydb[str(group_id)]
32 |
33 | query = mycol.find( {"text":name})
34 | # query = mycol.find( { "$text": {"$search": name}})
35 | try:
36 | for file in query:
37 | reply_text = file['reply']
38 | btn = file['btn']
39 | fileid = file['file']
40 | try:
41 | alert = file['alert']
42 | except:
43 | alert = None
44 | return reply_text, btn, alert, fileid
45 | except:
46 | return None, None, None, None
47 |
48 |
49 | async def get_filters(group_id):
50 | mycol = mydb[str(group_id)]
51 |
52 | texts = []
53 | query = mycol.find()
54 | try:
55 | for file in query:
56 | text = file['text']
57 | texts.append(text)
58 | except:
59 | pass
60 | return texts
61 |
62 |
63 | async def delete_filter(message, text, group_id):
64 | mycol = mydb[str(group_id)]
65 |
66 | myquery = {'text':text }
67 | query = mycol.count_documents(myquery)
68 | if query == 1:
69 | mycol.delete_one(myquery)
70 | await message.reply_text(
71 | f"'`{text}`' deleted. I'll not respond to that filter anymore.",
72 | quote=True,
73 | parse_mode="md"
74 | )
75 | else:
76 | await message.reply_text("Couldn't find that filter!", quote=True)
77 |
78 |
79 | async def del_all(message, group_id, title):
80 | if str(group_id) not in mydb.list_collection_names():
81 | await message.edit_text(f"Nothing to remove in {title}!")
82 | return
83 |
84 | mycol = mydb[str(group_id)]
85 | try:
86 | mycol.drop()
87 | await message.edit_text(f"All filters from {title} has been removed")
88 | except:
89 | await message.edit_text("Couldn't remove all filters from group!")
90 | return
91 |
92 |
93 | async def count_filters(group_id):
94 | mycol = mydb[str(group_id)]
95 |
96 | count = mycol.count()
97 | if count == 0:
98 | return False
99 | else:
100 | return count
101 |
102 |
103 | async def filter_stats():
104 | collections = mydb.list_collection_names()
105 |
106 | if "CONNECTION" in collections:
107 | collections.remove("CONNECTION")
108 |
109 | totalcount = 0
110 | for collection in collections:
111 | mycol = mydb[collection]
112 | count = mycol.count()
113 | totalcount += count
114 |
115 | totalcollections = len(collections)
116 |
117 | return totalcollections, totalcount
118 |
--------------------------------------------------------------------------------
/database/connections_mdb.py:
--------------------------------------------------------------------------------
1 | import pymongo
2 |
3 | from info import DATABASE_URI, DATABASE_NAME
4 |
5 | import logging
6 | logger = logging.getLogger(__name__)
7 | logger.setLevel(logging.ERROR)
8 |
9 | myclient = pymongo.MongoClient(DATABASE_URI)
10 | mydb = myclient[DATABASE_NAME]
11 | mycol = mydb['CONNECTION']
12 |
13 |
14 | async def add_connection(group_id, user_id):
15 | query = mycol.find_one(
16 | { "_id": user_id },
17 | { "_id": 0, "active_group": 0 }
18 | )
19 | if query is not None:
20 | group_ids = [x["group_id"] for x in query["group_details"]]
21 | if group_id in group_ids:
22 | return False
23 |
24 | group_details = {
25 | "group_id" : group_id
26 | }
27 |
28 | data = {
29 | '_id': user_id,
30 | 'group_details' : [group_details],
31 | 'active_group' : group_id,
32 | }
33 |
34 | if mycol.count_documents( {"_id": user_id} ) == 0:
35 | try:
36 | mycol.insert_one(data)
37 | return True
38 | except:
39 | logger.exception('Some error occured!', exc_info=True)
40 |
41 | else:
42 | try:
43 | mycol.update_one(
44 | {'_id': user_id},
45 | {
46 | "$push": {"group_details": group_details},
47 | "$set": {"active_group" : group_id}
48 | }
49 | )
50 | return True
51 | except:
52 | logger.exception('Some error occured!', exc_info=True)
53 |
54 |
55 | async def active_connection(user_id):
56 |
57 | query = mycol.find_one(
58 | { "_id": user_id },
59 | { "_id": 0, "group_details": 0 }
60 | )
61 | if not query:
62 | return None
63 |
64 | group_id = query['active_group']
65 | if group_id != None:
66 | return int(group_id)
67 | else:
68 | return None
69 |
70 |
71 | async def all_connections(user_id):
72 | query = mycol.find_one(
73 | { "_id": user_id },
74 | { "_id": 0, "active_group": 0 }
75 | )
76 | if query is not None:
77 | return [x["group_id"] for x in query["group_details"]]
78 | else:
79 | return None
80 |
81 |
82 | async def if_active(user_id, group_id):
83 | query = mycol.find_one(
84 | { "_id": user_id },
85 | { "_id": 0, "group_details": 0 }
86 | )
87 | return query is not None and query['active_group'] == group_id
88 |
89 |
90 | async def make_active(user_id, group_id):
91 | update = mycol.update_one(
92 | {'_id': user_id},
93 | {"$set": {"active_group" : group_id}}
94 | )
95 | return update.modified_count != 0
96 |
97 |
98 | async def make_inactive(user_id):
99 | update = mycol.update_one(
100 | {'_id': user_id},
101 | {"$set": {"active_group" : None}}
102 | )
103 | return update.modified_count != 0
104 |
105 |
106 | async def delete_connection(user_id, group_id):
107 |
108 | try:
109 | update = mycol.update_one(
110 | {"_id": user_id},
111 | {"$pull" : { "group_details" : {"group_id":group_id} } }
112 | )
113 | if update.modified_count == 0:
114 | return False
115 | query = mycol.find_one(
116 | { "_id": user_id },
117 | { "_id": 0 }
118 | )
119 | if len(query["group_details"]) >= 1:
120 | if query['active_group'] == group_id:
121 | prvs_group_id = query["group_details"][len(query["group_details"]) - 1]["group_id"]
122 |
123 | mycol.update_one(
124 | {'_id': user_id},
125 | {"$set": {"active_group" : prvs_group_id}}
126 | )
127 | else:
128 | mycol.update_one(
129 | {'_id': user_id},
130 | {"$set": {"active_group" : None}}
131 | )
132 | return True
133 | except Exception as e:
134 | logger.exception(f'Some error occured! {e}', exc_info=True)
135 | return False
136 |
137 |
--------------------------------------------------------------------------------
/info.py:
--------------------------------------------------------------------------------
1 | import re
2 | from os import environ
3 |
4 | id_pattern = re.compile(r'^.\d+$')
5 | def is_enabled(value, default):
6 | if value.lower() in ["true", "yes", "1", "enable", "y"]:
7 | return True
8 | elif value.lower() in ["false", "no", "0", "disable", "n"]:
9 | return False
10 | else:
11 | return default
12 |
13 | # Bot information
14 | SESSION = environ.get('SESSION', 'Media_search')
15 | API_ID = int(environ['API_ID'])
16 | API_HASH = environ['API_HASH']
17 | BOT_TOKEN = environ['BOT_TOKEN']
18 |
19 | # Bot settings
20 | CACHE_TIME = int(environ.get('CACHE_TIME', 300))
21 | USE_CAPTION_FILTER = bool(environ.get('USE_CAPTION_FILTER', False))
22 | PICS = (environ.get('PICS', 'https://telegra.ph/file/3d87cdb638b5444198c59.jpg https://telegra.ph/file/2140af3c0cb1c848ef5a0.jpg https://telegra.ph/file/f5c3720b2ce9d1d97d59f.jpg')).split()
23 |
24 | # Admins, Channels & Users
25 | ADMINS = [int(admin) if id_pattern.search(admin) else admin for admin in environ.get('ADMINS', '').split()]
26 | CHANNELS = [int(ch) if id_pattern.search(ch) else ch for ch in environ.get('CHANNELS', '0').split()]
27 | auth_users = [int(user) if id_pattern.search(user) else user for user in environ.get('AUTH_USERS', '').split()]
28 | AUTH_USERS = (auth_users + ADMINS) if auth_users else []
29 | auth_channel = environ.get('AUTH_CHANNEL')
30 | auth_grp = environ.get('AUTH_GROUP')
31 | AUTH_CHANNEL = int(auth_channel) if auth_channel and id_pattern.search(auth_channel) else None
32 | AUTH_GROUPS = [int(ch) for ch in auth_grp.split()] if auth_grp else None
33 |
34 | # MongoDB information
35 | DATABASE_URI = environ.get('DATABASE_URI', "")
36 | DATABASE_NAME = environ.get('DATABASE_NAME', "Rajappan")
37 | COLLECTION_NAME = environ.get('COLLECTION_NAME', 'Telegram_files')
38 |
39 | # Others
40 | LOG_CHANNEL = int(environ.get('LOG_CHANNEL', 0))
41 | SUPPORT_CHAT = environ.get('SUPPORT_CHAT', 'TeamEvamaria')
42 | P_TTI_SHOW_OFF = is_enabled((environ.get('P_TTI_SHOW_OFF', "False")), False)
43 | IMDB = is_enabled((environ.get('IMDB', "True")), True)
44 | SINGLE_BUTTON = is_enabled((environ.get('SINGLE_BUTTON', "False")), False)
45 | CUSTOM_FILE_CAPTION = environ.get("CUSTOM_FILE_CAPTION", None)
46 | IMDB_TEMPLATE = environ.get("IMDB_TEMPLATE", "Query: {query} \nIMDb Data:\n\n🏷 Title: {title}\n🎭 Genres: {genres}\n📆 Year: {year}\n🌟 Rating: {rating} / 10")
47 | LONG_IMDB_DESCRIPTION = is_enabled(environ.get("LONG_IMDB_DESCRIPTION", "False"), False)
48 | SPELL_CHECK_REPLY = is_enabled(environ.get("SPELL_CHECK_REPLY", "True"), True)
49 | MAX_LIST_ELM = environ.get("MAX_LIST_ELM", None)
50 | INDEX_REQ_CHANNEL = int(environ.get('INDEX_REQ_CHANNEL', 'LOG_CHANNEL'))
51 |
52 | LOG_STR = "Current Cusomized Configurations are:-\n"
53 | LOG_STR += ("IMDB Results are enabled, Bot will be showing imdb details for you queries.\n" if IMDB else "IMBD Results are disabled.\n")
54 | LOG_STR += ("P_TTI_SHOW_OFF found , Users will be redirected to send /start to Bot PM instead of sending file file directly\n" if P_TTI_SHOW_OFF else "P_TTI_SHOW_OFF is disabled files will be send in PM, instead of sending start.\n")
55 | LOG_STR += ("SINGLE_BUTTON is Found, filename and files size will be shown in a single button instead of two seperate buttons\n" if SINGLE_BUTTON else "SINGLE_BUTTON is disabled , filename and file_sixe will be shown as diffrent buttons\n")
56 | LOG_STR += (f"CUSTOM_FILE_CAPTION enabled with value {CUSTOM_FILE_CAPTION}, your files will be send along with this customized caption.\n" if CUSTOM_FILE_CAPTION else "No CUSTOM_FILE_CAPTION Found, Default captions of file will be used.\n")
57 | LOG_STR += ("Long IMDB storyline enabled." if LONG_IMDB_DESCRIPTION else "LONG_IMDB_DESCRIPTION is disabled , Plot will be shorter.\n")
58 | LOG_STR += ("Spell Check Mode Is Enabled, bot will be suggesting related movies if movie not found\n" if SPELL_CHECK_REPLY else "SPELL_CHECK_REPLY Mode disabled\n")
59 | LOG_STR += (f"MAX_LIST_ELM Found, long list will be shortened to first {MAX_LIST_ELM} elements\n" if MAX_LIST_ELM else "Full List of casts and crew will be shown in imdb template, restrict them by adding a value to MAX_LIST_ELM\n")
60 | LOG_STR += f"Your Currect IMDB template is {IMDB_TEMPLATE}"
61 |
--------------------------------------------------------------------------------
/database/users_chats_db.py:
--------------------------------------------------------------------------------
1 | # https://github.com/odysseusmax/animated-lamp/blob/master/bot/database/database.py
2 | import motor.motor_asyncio
3 | from info import DATABASE_NAME, DATABASE_URI
4 |
5 | class Database:
6 |
7 | def __init__(self, uri, database_name):
8 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
9 | self.db = self._client[database_name]
10 | self.col = self.db.users
11 | self.grp = self.db.groups
12 |
13 |
14 | def new_user(self, id, name):
15 | return dict(
16 | id = id,
17 | name = name,
18 | ban_status=dict(
19 | is_banned=False,
20 | ban_reason="",
21 | ),
22 | )
23 |
24 |
25 | def new_group(self, id, title):
26 | return dict(
27 | id = id,
28 | title = title,
29 | chat_status=dict(
30 | is_disabled=False,
31 | reason="",
32 | ),
33 | )
34 |
35 | async def add_user(self, id, name):
36 | user = self.new_user(id, name)
37 | await self.col.insert_one(user)
38 |
39 | async def is_user_exist(self, id):
40 | user = await self.col.find_one({'id':int(id)})
41 | return bool(user)
42 |
43 | async def total_users_count(self):
44 | count = await self.col.count_documents({})
45 | return count
46 |
47 | async def remove_ban(self, id):
48 | ban_status = dict(
49 | is_banned=False,
50 | ban_reason=''
51 | )
52 | await self.col.update_one({'id': id}, {'$set': {'ban_status': ban_status}})
53 |
54 | async def ban_user(self, user_id, ban_reason="No Reason"):
55 | ban_status = dict(
56 | is_banned=True,
57 | ban_reason=ban_reason
58 | )
59 | await self.col.update_one({'id': user_id}, {'$set': {'ban_status': ban_status}})
60 |
61 | async def get_ban_status(self, id):
62 | default = dict(
63 | is_banned=False,
64 | ban_reason=''
65 | )
66 | user = await self.col.find_one({'id':int(id)})
67 | if not user:
68 | return default
69 | return user.get('ban_status', default)
70 |
71 | async def get_all_users(self):
72 | return self.col.find({})
73 |
74 |
75 | async def delete_user(self, user_id):
76 | await self.col.delete_many({'id': int(user_id)})
77 |
78 |
79 | async def get_banned(self):
80 | users = self.col.find({'ban_status.is_banned': True})
81 | chats = self.grp.find({'chat_status.is_disabled': True})
82 | b_chats = [chat['id'] async for chat in chats]
83 | b_users = [user['id'] async for user in users]
84 | return b_users, b_chats
85 |
86 |
87 |
88 | async def add_chat(self, chat, title):
89 | chat = self.new_group(chat, title)
90 | await self.grp.insert_one(chat)
91 |
92 |
93 | async def get_chat(self, chat):
94 | chat = await self.grp.find_one({'id':int(chat)})
95 | if not chat:
96 | return False
97 | else:
98 | return chat.get('chat_status')
99 |
100 |
101 | async def re_enable_chat(self, id):
102 | chat_status=dict(
103 | is_disabled=False,
104 | reason="",
105 | )
106 | await self.grp.update_one({'id': int(id)}, {'$set': {'chat_status': chat_status}})
107 |
108 |
109 | async def disable_chat(self, chat, reason="No Reason"):
110 | chat_status=dict(
111 | is_disabled=True,
112 | reason=reason,
113 | )
114 | await self.grp.update_one({'id': int(chat)}, {'$set': {'chat_status': chat_status}})
115 |
116 |
117 | async def total_chat_count(self):
118 | count = await self.grp.count_documents({})
119 | return count
120 |
121 |
122 | async def get_all_chats(self):
123 | return self.grp.find({})
124 |
125 |
126 | async def get_db_size(self):
127 | return (await self.db.command("dbstats"))['dataSize']
128 |
129 |
130 | db = Database(DATABASE_URI, DATABASE_NAME)
131 |
--------------------------------------------------------------------------------
/plugins/inline.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from pyrogram import Client, emoji, filters
3 | from pyrogram.errors.exceptions.bad_request_400 import QueryIdInvalid
4 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultCachedDocument
5 | from database.ia_filterdb import get_search_results
6 | from utils import is_subscribed, get_size
7 | from info import CACHE_TIME, AUTH_USERS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION
8 |
9 | logger = logging.getLogger(__name__)
10 | cache_time = 0 if AUTH_USERS or AUTH_CHANNEL else CACHE_TIME
11 |
12 |
13 | @Client.on_inline_query(filters.user(AUTH_USERS) if AUTH_USERS else None)
14 | async def answer(bot, query):
15 | """Show search results for given inline query"""
16 |
17 | if AUTH_CHANNEL and not await is_subscribed(bot, query):
18 | await query.answer(results=[],
19 | cache_time=0,
20 | switch_pm_text='You have to subscribe my channel to use the bot',
21 | switch_pm_parameter="subscribe")
22 | return
23 |
24 | results = []
25 | if '|' in query.query:
26 | string, file_type = query.query.split('|', maxsplit=1)
27 | string = string.strip()
28 | file_type = file_type.strip().lower()
29 | else:
30 | string = query.query.strip()
31 | file_type = None
32 |
33 | offset = int(query.offset or 0)
34 | reply_markup = get_reply_markup(query=string)
35 | files, next_offset, total = await get_search_results(string,
36 | file_type=file_type,
37 | max_results=10,
38 | offset=offset)
39 |
40 | for file in files:
41 | title=file.file_name
42 | size=get_size(file.file_size)
43 | f_caption=file.caption
44 | if CUSTOM_FILE_CAPTION:
45 | try:
46 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption)
47 | except Exception as e:
48 | logger.exception(e)
49 | f_caption=f_caption
50 | if f_caption is None:
51 | f_caption = f"{file.file_name}"
52 | results.append(
53 | InlineQueryResultCachedDocument(
54 | title=file.file_name,
55 | file_id=file.file_id,
56 | caption=f_caption,
57 | description=f'Size: {get_size(file.file_size)}\nType: {file.file_type}',
58 | reply_markup=reply_markup))
59 |
60 | if results:
61 | switch_pm_text = f"{emoji.FILE_FOLDER} Results - {total}"
62 | if string:
63 | switch_pm_text += f" for {string}"
64 | try:
65 | await query.answer(results=results,
66 | is_personal = True,
67 | cache_time=cache_time,
68 | switch_pm_text=switch_pm_text,
69 | switch_pm_parameter="start",
70 | next_offset=str(next_offset))
71 | except QueryIdInvalid:
72 | pass
73 | except Exception as e:
74 | logging.exception(str(e))
75 | await query.answer(results=[], is_personal=True,
76 | cache_time=cache_time,
77 | switch_pm_text=str(e)[:63],
78 | switch_pm_parameter="error")
79 | else:
80 | switch_pm_text = f'{emoji.CROSS_MARK} No results'
81 | if string:
82 | switch_pm_text += f' for "{string}"'
83 |
84 | await query.answer(results=[],
85 | is_personal = True,
86 | cache_time=cache_time,
87 | switch_pm_text=switch_pm_text,
88 | switch_pm_parameter="okay")
89 |
90 |
91 | def get_reply_markup(query):
92 | buttons = [
93 | [
94 | InlineKeyboardButton('♻️ 𝗦𝗲𝗮𝗿𝗰𝗵 𝗔𝗴𝗮𝗶𝗻 ♻️', switch_inline_query_current_chat=query)
95 | ],[
96 | InlineKeyboardButton('♥️ 𝗖𝗵𝗮𝗻𝗻𝗲𝗹 ♥️', url='https://t.me/+veUIdIW2CQ5mOGU5')
97 | ]
98 | ]
99 | return InlineKeyboardMarkup(buttons)
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
52 |
53 |
54 |
55 |
56 |
61 |
62 | git clone https://github.com/CyniteOfficial/Auto-Filter-Bot 63 | # Install Packages 64 | pip3 install -r requirements.txt 65 | Edit info.py with variables as given below then run bot 66 | python3 bot.py 67 |68 | 69 |
add a filter in chat
44 | ➾ /filters - list all the filters of a chat
45 | ➾ /del - delete a specific filter in chat
46 | ➾ /delall - delete the whole filters in a chat (chat owner only)"""
47 | BUTTON_TXT = """Help: Buttons
48 |
49 | - Zsearcher Supports both url and alert inline buttons.
50 |
51 | NOTE:
52 | 1. Telegram will not allows you to send buttons without any content, so content is mandatory.
53 | 2. Zsᴇᴀʀᴄʜᴇʀ supports buttons with any telegram media type.
54 | 3. Buttons should be properly parsed as markdown format
55 |
56 | URL buttons:
57 | [Button Text](buttonurl:https://t.me/Cynitebots)
58 |
59 | Alert buttons:
60 | [Button Text](buttonalert:This is an alert message)"""
61 | AUTOFILTER_TXT = """Help: Auto Filter
62 |
63 | NOTE:
64 | 1. Make me the admin of your channel if it's private.
65 | 2. make sure that your channel does not contains camrips, porn and fake files.
66 | 3. Forward the last message to me with quotes.
67 | I'll add all the files in that channel to my db."""
68 | CONNECTION_TXT = """Help: Connections
69 |
70 | - Used to connect bot to PM for managing filters
71 | - it helps to avoid spamming in groups.
72 |
73 | NOTE:
74 | 1. Only admins can add a connection.
75 | 2. Send /connect for connecting me to ur PM
76 |
77 | Commands and Usage:
78 | ➾ /connect - connect a particular chat to your PM
79 | ➾ /disconnect - disconnect from a chat
80 | ➾ /connections - list all your connections"""
81 | EXTRAMOD_TXT = """Help: Extra Modules
82 |
83 | NOTE:
84 | These are the extra features of Zsᴇᴀʀᴄʜᴇʀ
85 |
86 | Commands and Usage:
87 | ➾ /id - get id of a specifed user.
88 | ➾ /info - get information about a user.
89 | ➾ /imdb - get the film information from IMDb source.
90 | ➾ /search - get the film information from various sources."""
91 | ADMIN_TXT = """Help: Admin mods
92 |
93 | NOTE:
94 | This module only works for my OᗯᑎEᖇ⚡
95 |
96 | Commands and Usage:
97 | ➾ /logs - to get the rescent errors
98 | ➾ /stats - to get status of files in db.
99 | ➾ /delete - to delete a specific file from db.
100 | ➾ /users - to get list of my users and ids.
101 | ➾ /chats - to get list of the my chats and ids
102 | ➾ /leave - to leave from a chat.
103 | ➾ /disable - do disable a chat.
104 | ➾ /ban - to ban a user.
105 | ➾ /unban - to unban a user.
106 | ➾ /channel - to get list of total connected channels
107 | ➾ /broadcast - to broadcast a message to all users"""
108 | STATUS_TXT = """✮ 𝚃𝙾𝚃𝙰𝙻 𝙵𝙸𝙻𝙴𝚂: {}
109 | ✮ 𝚃𝙾𝚃𝙰𝙻 𝚄𝚂𝙴𝚁𝚂: {}
110 | ✮ 𝚃𝙾𝚃𝙰𝙻 𝙲𝙷𝙰𝚃𝚂: {}
111 | ✮ 𝚄𝚂𝙴𝙳 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱
112 | ✮ 𝙵𝚁𝙴𝙴 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱"""
113 | LOG_TEXT_G = """#𝐍𝐞𝐰𝐆𝐫𝐨𝐮𝐩
114 | ✮ 𝐆𝐫𝐨𝐮𝐩 ›› {}({})
115 | ✮ 𝐓𝐨𝐭𝐚𝐥 𝐌𝐞𝐦𝐛𝐞𝐫𝐬 ›› {}
116 | ✮ 𝐀𝐝𝐝𝐞𝐝 𝐁𝐲 ›› {}
117 | """
118 | LOG_TEXT_P = """#𝐍𝐞𝐰𝐔𝐬𝐞𝐫
119 | ✮ 𝐈𝐃 ›› {}
120 | ✮ 𝐍𝐚𝐦𝐞 ›› {}
121 | """
122 | CARBON_TXT = """ 𝙲𝙰𝚁𝙱𝙾𝙽 𝙼𝙾𝙳𝚄𝙻𝙴
123 |
124 | 𝚈𝙾𝚄 𝙲𝙰𝙽 𝙱𝙴𝙰𝚄𝚃𝙸𝙵𝚈 𝚈𝙾𝚄𝚁 𝙲𝙾𝙳𝙴𝚂 𝙱𝚈 𝚄𝚂𝙸𝙽𝙶 𝚃𝙷𝚂 𝙵𝙴𝙰𝚃𝚄𝚁𝙴...
125 |
126 | 𝙲𝙾𝙼𝙼𝙰𝙽𝙳.!
127 | /carbon ›› 𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴
128 |
129 | 𝚆𝙾𝚁𝙺𝚂 𝙾𝙽 𝙱𝙾𝚃𝙷 𝙶𝚁𝙾𝚄𝙿 𝙰𝙽𝙳 𝙿𝙼
130 | 𝙲𝚁𝙴𝙳𝙸𝚃𝚂 ›› ᴛᴇᴄʜɴɪᴄᴀʟ-ᴄʏɴɪᴛᴇ"""
131 |
--------------------------------------------------------------------------------
/plugins/connection.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters, Client
2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
3 | from database.connections_mdb import add_connection, all_connections, if_active, delete_connection
4 | from info import ADMINS
5 | import logging
6 | logger = logging.getLogger(__name__)
7 | logger.setLevel(logging.ERROR)
8 | @Client.on_message((filters.private | filters.group) & filters.command('connect'))
9 | async def addconnection(client,message):
10 | userid = message.from_user.id if message.from_user else None
11 | if not userid:
12 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
13 | chat_type = message.chat.type
14 |
15 | if chat_type == "private":
16 | try:
17 | cmd, group_id = message.text.split(" ", 1)
18 | except:
19 | await message.reply_text(
20 | "Enter in correct format!\n\n"
21 | "/connect groupid\n\n"
22 | "Get your Group id by adding this bot to your group and use /id",
23 | quote=True
24 | )
25 | return
26 |
27 | elif chat_type in ["group", "supergroup"]:
28 | group_id = message.chat.id
29 |
30 | try:
31 | st = await client.get_chat_member(group_id, userid)
32 | if (
33 | st.status != "administrator"
34 | and st.status != "creator"
35 | and str(userid) not in ADMINS
36 | ):
37 | await message.reply_text("You should be an admin in Given group!", quote=True)
38 | return
39 | except Exception as e:
40 | logger.exception(e)
41 | await message.reply_text(
42 | "Invalid Group ID!\n\nIf correct, Make sure I'm present in your group!!",
43 | quote=True,
44 | )
45 |
46 | return
47 | try:
48 | st = await client.get_chat_member(group_id, "me")
49 | if st.status == "administrator":
50 | ttl = await client.get_chat(group_id)
51 | title = ttl.title
52 |
53 | addcon = await add_connection(str(group_id), str(userid))
54 | if addcon:
55 | await message.reply_text(
56 | f"Sucessfully connected to **{title}**\nNow manage your group from my pm !",
57 | quote=True,
58 | parse_mode="md"
59 | )
60 | if chat_type in ["group", "supergroup"]:
61 | await client.send_message(
62 | userid,
63 | f"Connected to **{title}** !",
64 | parse_mode="md"
65 | )
66 | else:
67 | await message.reply_text(
68 | "You're already connected to this chat!",
69 | quote=True
70 | )
71 | else:
72 | await message.reply_text("Add me as an admin in group", quote=True)
73 | except Exception as e:
74 | logger.exception(e)
75 | await message.reply_text('Some error occured! Try again later.', quote=True)
76 | return
77 |
78 |
79 | @Client.on_message((filters.private | filters.group) & filters.command('disconnect'))
80 | async def deleteconnection(client,message):
81 | userid = message.from_user.id if message.from_user else None
82 | if not userid:
83 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
84 | chat_type = message.chat.type
85 |
86 | if chat_type == "private":
87 | await message.reply_text("Run /connections to view or disconnect from groups!", quote=True)
88 |
89 | elif chat_type in ["group", "supergroup"]:
90 | group_id = message.chat.id
91 |
92 | st = await client.get_chat_member(group_id, userid)
93 | if (
94 | st.status != "administrator"
95 | and st.status != "creator"
96 | and str(userid) not in ADMINS
97 | ):
98 | return
99 |
100 | delcon = await delete_connection(str(userid), str(group_id))
101 | if delcon:
102 | await message.reply_text("Successfully disconnected from this chat", quote=True)
103 | else:
104 | await message.reply_text("This chat isn't connected to me!\nDo /connect to connect.", quote=True)
105 |
106 |
107 |
108 | @Client.on_message(filters.private & filters.command(["connections"]))
109 | async def connections(client,message):
110 | userid = message.from_user.id
111 |
112 | groupids = await all_connections(str(userid))
113 | if groupids is None:
114 | await message.reply_text(
115 | "There are no active connections!! Connect to some groups first.",
116 | quote=True
117 | )
118 | return
119 | buttons = []
120 | for groupid in groupids:
121 | try:
122 | ttl = await client.get_chat(int(groupid))
123 | title = ttl.title
124 | active = await if_active(str(userid), str(groupid))
125 | act = " - ACTIVE" if active else ""
126 | buttons.append(
127 | [
128 | InlineKeyboardButton(
129 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}"
130 | )
131 | ]
132 | )
133 | except:
134 | pass
135 | if buttons:
136 | await message.reply_text(
137 | "Your connected group details ;\n\n",
138 | reply_markup=InlineKeyboardMarkup(buttons),
139 | quote=True
140 | )
141 | else:
142 | await message.reply_text(
143 | "There are no active connections!! Connect to some groups first.",
144 | quote=True
145 | )
146 |
--------------------------------------------------------------------------------
/plugins/misc.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pyrogram import Client, filters
3 | from pyrogram.errors.exceptions.bad_request_400 import UserNotParticipant, MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty
4 | from info import IMDB_TEMPLATE
5 | from utils import extract_user, get_file_id, get_poster, last_online
6 | import time
7 | from datetime import datetime
8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
9 | import logging
10 | logger = logging.getLogger(__name__)
11 | logger.setLevel(logging.ERROR)
12 |
13 | @Client.on_message(filters.command('id'))
14 | async def showid(client, message):
15 | chat_type = message.chat.type
16 | if chat_type == "private":
17 | user_id = message.chat.id
18 | first = message.from_user.first_name
19 | last = message.from_user.last_name or ""
20 | username = message.from_user.username
21 | dc_id = message.from_user.dc_id or ""
22 | await message.reply_text(
23 | f"➪ First Name: {first}\n➪ Last Name: {last}\n➪ Username: {username}\n➪ Telegram ID: {user_id}\n➪ Data Centre: {dc_id}",
24 | quote=True
25 | )
26 |
27 | elif chat_type in ["group", "supergroup"]:
28 | _id = ""
29 | _id += (
30 | "➛ Chat ID: "
31 | f"{message.chat.id}\n"
32 | )
33 | if message.reply_to_message:
34 | _id += (
35 | "➛ User ID: "
36 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n"
37 | "➛ Replied User ID: "
38 | f"{message.reply_to_message.from_user.id if message.reply_to_message.from_user else 'Anonymous'}\n"
39 | )
40 | file_info = get_file_id(message.reply_to_message)
41 | else:
42 | _id += (
43 | "➛ User ID: "
44 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n"
45 | )
46 | file_info = get_file_id(message)
47 | if file_info:
48 | _id += (
49 | f"{file_info.message_type}: "
50 | f"{file_info.file_id}\n"
51 | )
52 | await message.reply_text(
53 | _id,
54 | quote=True
55 | )
56 |
57 | @Client.on_message(filters.command(["info"]))
58 | async def who_is(client, message):
59 | # https://github.com/SpEcHiDe/PyroGramBot/blob/master/pyrobot/plugins/admemes/whois.py#L19
60 | status_message = await message.reply_text(
61 | "`𝗦𝗲𝗮𝗿𝗰𝗵𝗶𝗻𝗴 𝗨𝘀𝗲𝗿...`"
62 | )
63 | await status_message.edit(
64 | "`𝗔𝗰𝗰𝗲𝘀𝘀𝗶𝗻𝗴 𝗜𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻...`"
65 | )
66 | from_user = None
67 | from_user_id, _ = extract_user(message)
68 | try:
69 | from_user = await client.get_users(from_user_id)
70 | except Exception as error:
71 | await status_message.edit(str(error))
72 | return
73 | if from_user is None:
74 | return await status_message.edit("no valid user_id / message specified")
75 | message_out_str = ""
76 | message_out_str += f"➾ First Name: {from_user.first_name}\n"
77 | last_name = from_user.last_name or "None"
78 | message_out_str += f"➾ Last Name: {last_name}\n"
79 | message_out_str += f"➾ Telegram ID: {from_user.id}\n"
80 | username = from_user.username or "None"
81 | dc_id = from_user.dc_id or "[User Doesnt Have A Valid DP]"
82 | message_out_str += f"➾ Data Centre: {dc_id}\n"
83 | message_out_str += f"➾ User Name: @{username}\n"
84 | message_out_str += f"➾ User 𝖫𝗂𝗇𝗄: Click Here\n"
85 | if message.chat.type in (("supergroup", "channel")):
86 | try:
87 | chat_member_p = await message.chat.get_member(from_user.id)
88 | joined_date = datetime.fromtimestamp(
89 | chat_member_p.joined_date or time.time()
90 | ).strftime("%Y.%m.%d %H:%M:%S")
91 | message_out_str += (
92 | "➾ Joined this Chat on: "
93 | f"{joined_date}"
94 | "\n"
95 | )
96 | except UserNotParticipant:
97 | pass
98 | chat_photo = from_user.photo
99 | if chat_photo:
100 | local_user_photo = await client.download_media(
101 | message=chat_photo.big_file_id
102 | )
103 | buttons = [[
104 | InlineKeyboardButton('🔐 𝗖𝗹𝗼𝘀𝗲 🔐', callback_data='close_data')
105 | ]]
106 | reply_markup = InlineKeyboardMarkup(buttons)
107 | await message.reply_photo(
108 | photo=local_user_photo,
109 | quote=True,
110 | reply_markup=reply_markup,
111 | caption=message_out_str,
112 | parse_mode="html",
113 | disable_notification=True
114 | )
115 | os.remove(local_user_photo)
116 | else:
117 | buttons = [[
118 | InlineKeyboardButton('🔐 𝗖𝗹𝗼𝘀𝗲 🔐', callback_data='close_data')
119 | ]]
120 | reply_markup = InlineKeyboardMarkup(buttons)
121 | await message.reply_text(
122 | text=message_out_str,
123 | reply_markup=reply_markup,
124 | quote=True,
125 | parse_mode="html",
126 | disable_notification=True
127 | )
128 | await status_message.delete()
129 |
130 | @Client.on_message(filters.command(["imdb", 'search']))
131 | async def imdb_search(client, message):
132 | if ' ' in message.text:
133 | k = await message.reply('Searching ImDB')
134 | r, title = message.text.split(None, 1)
135 | movies = await get_poster(title, bulk=True)
136 | if not movies:
137 | return await message.reply("No results Found")
138 | btn = [
139 | [
140 | InlineKeyboardButton(
141 | text=f"{movie.get('title')} - {movie.get('year')}",
142 | callback_data=f"imdb#{movie.movieID}",
143 | )
144 | ]
145 | for movie in movies
146 | ]
147 | await k.edit('Here is what i found on IMDb', reply_markup=InlineKeyboardMarkup(btn))
148 | else:
149 | await message.reply('Give me a movie / series Name')
150 |
151 | @Client.on_callback_query(filters.regex('^imdb'))
152 | async def imdb_callback(bot: Client, quer_y: CallbackQuery):
153 | i, movie = quer_y.data.split('#')
154 | imdb = await get_poster(query=movie, id=True)
155 | btn = [
156 | [
157 | InlineKeyboardButton(
158 | text=f"{imdb.get('title')}",
159 | url=imdb['url'],
160 | )
161 | ]
162 | ]
163 | message = quer_y.message.reply_to_message or quer_y.message
164 | if imdb:
165 | caption = IMDB_TEMPLATE.format(
166 | query = imdb['title'],
167 | title = imdb['title'],
168 | votes = imdb['votes'],
169 | aka = imdb["aka"],
170 | seasons = imdb["seasons"],
171 | box_office = imdb['box_office'],
172 | localized_title = imdb['localized_title'],
173 | kind = imdb['kind'],
174 | imdb_id = imdb["imdb_id"],
175 | cast = imdb["cast"],
176 | runtime = imdb["runtime"],
177 | countries = imdb["countries"],
178 | certificates = imdb["certificates"],
179 | languages = imdb["languages"],
180 | director = imdb["director"],
181 | writer = imdb["writer"],
182 | producer = imdb["producer"],
183 | composer = imdb["composer"],
184 | cinematographer = imdb["cinematographer"],
185 | music_team = imdb["music_team"],
186 | distributors = imdb["distributors"],
187 | release_date = imdb['release_date'],
188 | year = imdb['year'],
189 | genres = imdb['genres'],
190 | poster = imdb['poster'],
191 | plot = imdb['plot'],
192 | rating = imdb['rating'],
193 | url = imdb['url'],
194 | **locals()
195 | )
196 | else:
197 | caption = "No Results"
198 | if imdb.get('poster'):
199 | try:
200 | await quer_y.message.reply_photo(photo=imdb['poster'], caption=caption, reply_markup=InlineKeyboardMarkup(btn))
201 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty):
202 | pic = imdb.get('poster')
203 | poster = pic.replace('.jpg', "._V1_UX360.jpg")
204 | await quer_y.message.reply_photo(photo=poster, caption=caption, reply_markup=InlineKeyboardMarkup(btn))
205 | except Exception as e:
206 | logger.exception(e)
207 | await quer_y.message.reply(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False)
208 | await quer_y.message.delete()
209 | else:
210 | await quer_y.message.edit(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False)
211 | await quer_y.answer()
212 |
213 |
214 |
215 |
--------------------------------------------------------------------------------
/plugins/index.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import asyncio
3 | from pyrogram import Client, filters
4 | from pyrogram.errors import FloodWait
5 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, ChatAdminRequired, UsernameInvalid, UsernameNotModified
6 | from info import ADMINS, LOG_CHANNEL
7 | from database.ia_filterdb import save_file
8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
9 | from utils import temp
10 | import re
11 | logger = logging.getLogger(__name__)
12 | logger.setLevel(logging.INFO)
13 | lock = asyncio.Lock()
14 |
15 |
16 | @Client.on_callback_query(filters.regex(r'^index'))
17 | async def index_files(bot, query):
18 | if query.data.startswith('index_cancel'):
19 | temp.CANCEL = True
20 | return await query.answer("Cancelling Indexing")
21 | _, raju, chat, lst_msg_id, from_user = query.data.split("#")
22 | if raju == 'reject':
23 | await query.message.delete()
24 | await bot.send_message(int(from_user),
25 | f'Your Submission for indexing {chat} has been decliened by our moderators.',
26 | reply_to_message_id=int(lst_msg_id))
27 | return
28 |
29 | if lock.locked():
30 | return await query.answer('Wait until previous process complete.', show_alert=True)
31 | msg = query.message
32 |
33 | await query.answer('𝗖𝗵𝗲𝗰𝗸𝗶𝗻𝗴...⏳😜', show_alert=True)
34 | if int(from_user) not in ADMINS:
35 | await bot.send_message(int(from_user),
36 | f'Your Submission for indexing {chat} has been accepted by our moderators and will be added soon.',
37 | reply_to_message_id=int(lst_msg_id))
38 | await msg.edit(
39 | "Starting Indexing",
40 | reply_markup=InlineKeyboardMarkup(
41 | [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]]
42 | )
43 | )
44 | try:
45 | chat = int(chat)
46 | except:
47 | chat = chat
48 | await index_files_to_db(int(lst_msg_id), chat, msg, bot)
49 |
50 |
51 | @Client.on_message((filters.forwarded | (filters.regex("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$")) & filters.text ) & filters.private & filters.incoming)
52 | async def send_for_index(bot, message):
53 | if message.text:
54 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$")
55 | match = regex.match(message.text)
56 | if not match:
57 | return await message.reply('Invalid link')
58 | chat_id = match.group(4)
59 | last_msg_id = int(match.group(5))
60 | if chat_id.isnumeric():
61 | chat_id = int(("-100" + chat_id))
62 | elif message.forward_from_chat.type == 'channel':
63 | last_msg_id = message.forward_from_message_id
64 | chat_id = message.forward_from_chat.username or message.forward_from_chat.id
65 | else:
66 | return
67 | try:
68 | await bot.get_chat(chat_id)
69 | except ChannelInvalid:
70 | return await message.reply('This may be a private channel / group. Make me an admin over there to index the files.')
71 | except (UsernameInvalid, UsernameNotModified):
72 | return await message.reply('Invalid Link specified.')
73 | except Exception as e:
74 | logger.exception(e)
75 | return await message.reply(f'Errors - {e}')
76 | try:
77 | k = await bot.get_messages(chat_id, last_msg_id)
78 | except:
79 | return await message.reply('Make Sure That Iam An Admin In The Channel, if channel is private')
80 | if k.empty:
81 | return await message.reply('This may be group and iam not a admin of the group.')
82 |
83 | if message.from_user.id in ADMINS:
84 | buttons = [
85 | [
86 | InlineKeyboardButton('𝗬𝗲𝘀',
87 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}')
88 | ],
89 | [
90 | InlineKeyboardButton('𝗖𝗹𝗼𝘀𝗲', callback_data='close_data'),
91 | ]
92 | ]
93 | reply_markup = InlineKeyboardMarkup(buttons)
94 | return await message.reply(
95 | f'Do you Want To Index This Channel/ Group ?\n\nChat ID/ Username: {chat_id}\nLast Message ID: {last_msg_id}',
96 | reply_markup=reply_markup)
97 |
98 | if type(chat_id) is int:
99 | try:
100 | link = (await bot.create_chat_invite_link(chat_id)).invite_link
101 | except ChatAdminRequired:
102 | return await message.reply('Make sure iam an admin in the chat and have permission to invite users.')
103 | else:
104 | link = f"@{message.forward_from_chat.username}"
105 | buttons = [
106 | [
107 | InlineKeyboardButton('😍 𝗔𝗰𝗰𝗲𝗽𝘁 𝗜𝗻𝗱𝗲𝘅 😍',
108 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}')
109 | ],
110 | [
111 | InlineKeyboardButton('😥 𝗥𝗲𝗷𝗲𝗰𝘁 𝗜𝗻𝗱𝗲𝘅 😥',
112 | callback_data=f'index#reject#{chat_id}#{message.message_id}#{message.from_user.id}'),
113 | ]
114 | ]
115 | reply_markup = InlineKeyboardMarkup(buttons)
116 | await bot.send_message(LOG_CHANNEL,
117 | f'#IndexRequest\n\nBy : {message.from_user.mention} ({message.from_user.id})\nChat ID/ Username - {chat_id}\nLast Message ID - {last_msg_id}\nInviteLink - {link}',
118 | reply_markup=reply_markup)
119 | await message.reply('ThankYou For the Contribution, Wait For My Moderators to verify the files.')
120 |
121 |
122 | @Client.on_message(filters.command('setskip') & filters.user(ADMINS))
123 | async def set_skip_number(bot, message):
124 | if ' ' in message.text:
125 | _, skip = message.text.split(" ")
126 | try:
127 | skip = int(skip)
128 | except:
129 | return await message.reply("Skip number should be an integer.")
130 | await message.reply(f"Succesfully set SKIP number as {skip}")
131 | temp.CURRENT = int(skip)
132 | else:
133 | await message.reply("Give me a skip number")
134 |
135 |
136 | async def index_files_to_db(lst_msg_id, chat, msg, bot):
137 | total_files = 0
138 | duplicate = 0
139 | errors = 0
140 | deleted = 0
141 | no_media = 0
142 | async with lock:
143 | try:
144 | total = lst_msg_id + 1
145 | current = temp.CURRENT
146 | temp.CANCEL = False
147 | while current < total:
148 | if temp.CANCEL:
149 | await msg.edit("Succesfully Cancelled")
150 | break
151 | try:
152 | message = await bot.get_messages(chat_id=chat, message_ids=current, replies=0)
153 | except FloodWait as e:
154 | await asyncio.sleep(e.x)
155 | message = await bot.get_messages(
156 | chat,
157 | current,
158 | replies=0
159 | )
160 | except Exception as e:
161 | logger.exception(e)
162 | try:
163 | for file_type in ("document", "video", "audio"):
164 | media = getattr(message, file_type, None)
165 | if media is not None:
166 | break
167 | else:
168 | continue
169 | media.file_type = file_type
170 | media.caption = message.caption
171 | aynav, vnay = await save_file(media)
172 | if aynav:
173 | total_files += 1
174 | elif vnay == 0:
175 | duplicate += 1
176 | elif vnay == 2:
177 | errors += 1
178 | except Exception as e:
179 | if "NoneType" in str(e):
180 | if message.empty:
181 | deleted += 1
182 | elif not media:
183 | no_media += 1
184 | logger.warning("Skipping deleted / Non-Media messages (if this continues for long, use /setskip to set a skip number)")
185 | else:
186 | logger.exception(e)
187 | current += 1
188 | if current % 20 == 0:
189 | can = [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]]
190 | reply = InlineKeyboardMarkup(can)
191 | await msg.edit_text(
192 | text=f"Total messages fetched: {current}\nTotal messages saved: {total_files}\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media}\nErrors Occured: {errors}",
193 | reply_markup=reply)
194 | except Exception as e:
195 | logger.exception(e)
196 | await msg.edit(f'Error: {e}')
197 | else:
198 | await msg.edit(f'Succesfully saved {total_files} to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media}\nErrors Occured: {errors}')
199 |
--------------------------------------------------------------------------------
/plugins/filters.py:
--------------------------------------------------------------------------------
1 | import io
2 | from pyrogram import filters, Client
3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
4 | from database.filters_mdb import(
5 | add_filter,
6 | get_filters,
7 | delete_filter,
8 | count_filters
9 | )
10 |
11 | from database.connections_mdb import active_connection
12 | from utils import get_file_id, parser, split_quotes
13 | from info import ADMINS
14 |
15 |
16 | @Client.on_message(filters.command(['filter', 'add']) & filters.incoming)
17 | async def addfilter(client, message):
18 | userid = message.from_user.id if message.from_user else None
19 | if not userid:
20 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
21 | chat_type = message.chat.type
22 | args = message.text.html.split(None, 1)
23 |
24 | if chat_type == "private":
25 | grpid = await active_connection(str(userid))
26 | if grpid is not None:
27 | grp_id = grpid
28 | try:
29 | chat = await client.get_chat(grpid)
30 | title = chat.title
31 | except:
32 | await message.reply_text("Make sure I'm present in your group!!", quote=True)
33 | return
34 | else:
35 | await message.reply_text("I'm not connected to any groups!", quote=True)
36 | return
37 |
38 | elif chat_type in ["group", "supergroup"]:
39 | grp_id = message.chat.id
40 | title = message.chat.title
41 |
42 | else:
43 | return
44 |
45 | st = await client.get_chat_member(grp_id, userid)
46 | if (
47 | st.status != "administrator"
48 | and st.status != "creator"
49 | and str(userid) not in ADMINS
50 | ):
51 | return
52 |
53 |
54 | if len(args) < 2:
55 | await message.reply_text("Command Incomplete :(", quote=True)
56 | return
57 |
58 | extracted = split_quotes(args[1])
59 | text = extracted[0].lower()
60 |
61 | if not message.reply_to_message and len(extracted) < 2:
62 | await message.reply_text("Add some content to save your filter!", quote=True)
63 | return
64 |
65 | if (len(extracted) >= 2) and not message.reply_to_message:
66 | reply_text, btn, alert = parser(extracted[1], text)
67 | fileid = None
68 | if not reply_text:
69 | await message.reply_text("You cannot have buttons alone, give some text to go with it!", quote=True)
70 | return
71 |
72 | elif message.reply_to_message and message.reply_to_message.reply_markup:
73 | try:
74 | rm = message.reply_to_message.reply_markup
75 | btn = rm.inline_keyboard
76 | msg = get_file_id(message.reply_to_message)
77 | if msg:
78 | fileid = msg.file_id
79 | reply_text = message.reply_to_message.caption.html
80 | else:
81 | reply_text = message.reply_to_message.text.html
82 | fileid = None
83 | alert = None
84 | except:
85 | reply_text = ""
86 | btn = "[]"
87 | fileid = None
88 | alert = None
89 |
90 | elif message.reply_to_message and message.reply_to_message.media:
91 | try:
92 | msg = get_file_id(message.reply_to_message)
93 | fileid = msg.file_id if msg else None
94 | reply_text, btn, alert = parser(extracted[1], text) if message.reply_to_message.sticker else parser(message.reply_to_message.caption.html, text)
95 | except:
96 | reply_text = ""
97 | btn = "[]"
98 | alert = None
99 | elif message.reply_to_message and message.reply_to_message.text:
100 | try:
101 | fileid = None
102 | reply_text, btn, alert = parser(message.reply_to_message.text.html, text)
103 | except:
104 | reply_text = ""
105 | btn = "[]"
106 | alert = None
107 | else:
108 | return
109 |
110 | await add_filter(grp_id, text, reply_text, btn, fileid, alert)
111 |
112 | await message.reply_text(
113 | f"Filter for `{text}` added in **{title}**",
114 | quote=True,
115 | parse_mode="md"
116 | )
117 |
118 |
119 | @Client.on_message(filters.command(['viewfilters', 'filters']) & filters.incoming)
120 | async def get_all(client, message):
121 |
122 | chat_type = message.chat.type
123 | userid = message.from_user.id if message.from_user else None
124 | if not userid:
125 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
126 | if chat_type == "private":
127 | userid = message.from_user.id
128 | grpid = await active_connection(str(userid))
129 | if grpid is not None:
130 | grp_id = grpid
131 | try:
132 | chat = await client.get_chat(grpid)
133 | title = chat.title
134 | except:
135 | await message.reply_text("Make sure I'm present in your group!!", quote=True)
136 | return
137 | else:
138 | await message.reply_text("I'm not connected to any groups!", quote=True)
139 | return
140 |
141 | elif chat_type in ["group", "supergroup"]:
142 | grp_id = message.chat.id
143 | title = message.chat.title
144 |
145 | else:
146 | return
147 |
148 | st = await client.get_chat_member(grp_id, userid)
149 | if (
150 | st.status != "administrator"
151 | and st.status != "creator"
152 | and str(userid) not in ADMINS
153 | ):
154 | return
155 |
156 | texts = await get_filters(grp_id)
157 | count = await count_filters(grp_id)
158 | if count:
159 | filterlist = f"Total number of filters in **{title}** : {count}\n\n"
160 |
161 | for text in texts:
162 | keywords = " × `{}`\n".format(text)
163 |
164 | filterlist += keywords
165 |
166 | if len(filterlist) > 4096:
167 | with io.BytesIO(str.encode(filterlist.replace("`", ""))) as keyword_file:
168 | keyword_file.name = "keywords.txt"
169 | await message.reply_document(
170 | document=keyword_file,
171 | quote=True
172 | )
173 | return
174 | else:
175 | filterlist = f"There are no active filters in **{title}**"
176 |
177 | await message.reply_text(
178 | text=filterlist,
179 | quote=True,
180 | parse_mode="md"
181 | )
182 |
183 | @Client.on_message(filters.command('del') & filters.incoming)
184 | async def deletefilter(client, message):
185 | userid = message.from_user.id if message.from_user else None
186 | if not userid:
187 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
188 | chat_type = message.chat.type
189 |
190 | if chat_type == "private":
191 | grpid = await active_connection(str(userid))
192 | if grpid is not None:
193 | grp_id = grpid
194 | try:
195 | chat = await client.get_chat(grpid)
196 | title = chat.title
197 | except:
198 | await message.reply_text("Make sure I'm present in your group!!", quote=True)
199 | return
200 | else:
201 | await message.reply_text("I'm not connected to any groups!", quote=True)
202 |
203 | elif chat_type in ["group", "supergroup"]:
204 | grp_id = message.chat.id
205 | title = message.chat.title
206 |
207 | else:
208 | return
209 |
210 | st = await client.get_chat_member(grp_id, userid)
211 | if (
212 | st.status != "administrator"
213 | and st.status != "creator"
214 | and str(userid) not in ADMINS
215 | ):
216 | return
217 |
218 | try:
219 | cmd, text = message.text.split(" ", 1)
220 | except:
221 | await message.reply_text(
222 | "Mention the filtername which you wanna delete!\n\n"
223 | "/del filtername\n\n"
224 | "Use /viewfilters to view all available filters",
225 | quote=True
226 | )
227 | return
228 |
229 | query = text.lower()
230 |
231 | await delete_filter(message, query, grp_id)
232 |
233 |
234 | @Client.on_message(filters.command('delall') & filters.incoming)
235 | async def delallconfirm(client, message):
236 | userid = message.from_user.id if message.from_user else None
237 | if not userid:
238 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM")
239 | chat_type = message.chat.type
240 |
241 | if chat_type == "private":
242 | grpid = await active_connection(str(userid))
243 | if grpid is not None:
244 | grp_id = grpid
245 | try:
246 | chat = await client.get_chat(grpid)
247 | title = chat.title
248 | except:
249 | await message.reply_text("Make sure I'm present in your group!!", quote=True)
250 | return
251 | else:
252 | await message.reply_text("I'm not connected to any groups!", quote=True)
253 | return
254 |
255 | elif chat_type in ["group", "supergroup"]:
256 | grp_id = message.chat.id
257 | title = message.chat.title
258 |
259 | else:
260 | return
261 |
262 | st = await client.get_chat_member(grp_id, userid)
263 | if (st.status == "creator") or (str(userid) in ADMINS):
264 | await message.reply_text(
265 | f"This will delete all filters from '{title}'.\nDo you want to continue??",
266 | reply_markup=InlineKeyboardMarkup([
267 | [InlineKeyboardButton(text="YES",callback_data="delallconfirm")],
268 | [InlineKeyboardButton(text="CANCEL",callback_data="delallcancel")]
269 | ]),
270 | quote=True
271 | )
272 |
273 |
--------------------------------------------------------------------------------
/plugins/commands.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | import random
4 | import asyncio
5 | from Script import script
6 | from pyrogram import Client, filters
7 | from pyrogram.errors.exceptions.bad_request_400 import ChatAdminRequired
8 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
9 | from database.ia_filterdb import Media, get_file_details, unpack_new_file_id
10 | from database.users_chats_db import db
11 | from info import CHANNELS, ADMINS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION, LOG_CHANNEL, PICS
12 | from utils import get_size, is_subscribed, temp
13 | import re
14 | logger = logging.getLogger(__name__)
15 |
16 | @Client.on_message(filters.command("start"))
17 | async def start(client, message):
18 | if message.chat.type in ['group', 'supergroup']:
19 | buttons = [
20 | [
21 | InlineKeyboardButton('𝙿𝚁𝙸𝚅𝙰𝚃𝙴 𝙱𝙾𝚃 ?', url=f"https://t.me/cyniteofficial")
22 | ]
23 | ]
24 | reply_markup = InlineKeyboardMarkup(buttons)
25 | await message.reply(script.PRIVATEBOT_TXT.format(message.from_user.mention if message.from_user else message.chat.title, temp.U_NAME, temp.B_NAME), reply_markup=reply_markup)
26 | await asyncio.sleep(2) # 😢 https://github.com/EvamariaTG/EvaMaria/blob/master/plugins/p_ttishow.py#L17 😬 wait a bit, before checking.
27 | if not await db.get_chat(message.chat.id):
28 | total=await client.get_chat_members_count(message.chat.id)
29 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, "Unknown"))
30 | await db.add_chat(message.chat.id, message.chat.title)
31 | return
32 | if not await db.is_user_exist(message.from_user.id):
33 | await db.add_user(message.from_user.id, message.from_user.first_name)
34 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_P.format(message.from_user.id, message.from_user.mention))
35 | if len(message.command) != 2:
36 | buttons = [[
37 | InlineKeyboardButton('⚚ ᴀᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ⚚', url=f'http://t.me/{temp.U_NAME}?startgroup=true')
38 | ],[
39 | InlineKeyboardButton('💠 ʙᴏᴛ ᴜᴘᴅᴀᴛᴇs 💠', url='https://t.me/Cynitebots'),
40 | InlineKeyboardButton('♻️ ʜᴇʟᴘ ♻️', callback_data='help')],[
41 | InlineKeyboardButton('♻️ ᴀʙᴏᴜᴛ ♻️', callback_data='about'),
42 | InlineKeyboardButton('🔍sᴇᴀʀᴄʜ', switch_inline_query_current_chat=''), ]]
43 | await message.reply_photo(
44 | photo=random.choice(PICS),
45 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME),
46 | reply_markup=reply_markup,
47 | parse_mode='html'
48 | )
49 | return
50 | if AUTH_CHANNEL and not await is_subscribed(client, message):
51 | try:
52 | invite_link = await client.create_chat_invite_link(int(AUTH_CHANNEL))
53 | except ChatAdminRequired:
54 | logger.error("Make sure Bot is admin in Forcesub channel")
55 | return
56 | btn = [
57 | [
58 | InlineKeyboardButton(
59 | "🔥 JOIN CHANNEL 🔥", url=invite_link.invite_link
60 | )
61 | ]
62 | ]
63 |
64 | if message.command[1] != "subscribe":
65 | btn.append([InlineKeyboardButton("🔁 𝐓𝐫𝐲 𝐀𝐠𝐚𝐢𝐧 🔁", callback_data=f"checksub#{message.command[1]}")])
66 | await client.send_message(
67 | chat_id=message.from_user.id,
68 | text="**𝑱𝒐𝒊𝒏 𝑶𝒖𝒓 𝑴𝒐𝒗𝒊𝒆 𝑼𝒑𝒅𝒂𝒕𝒆𝒔 𝑪𝒉𝒂𝒏𝒏𝒆𝒍 𝑻𝒐 𝑼𝒔𝒆 𝑶𝒖𝒓 𝑩𝒐𝒕!**",
69 | reply_markup=InlineKeyboardMarkup(btn),
70 | parse_mode="markdown"
71 | )
72 | return
73 | if len(message.command) ==2 and message.command[1] in ["subscribe", "error", "okay", "help"]:
74 | buttons = [[
75 | InlineKeyboardButton('⚚ ᴀᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ⚚', url=f'http://t.me/{temp.U_NAME}?startgroup=true')
76 | ],[
77 | InlineKeyboardButton('💠 ʙᴏᴛ ᴜᴘᴅᴀᴛᴇs 💠', url='https://t.me/Cynitebots'),
78 | InlineKeyboardButton('♻️ ʜᴇʟᴘ ♻️', callback_data='help')],[
79 | InlineKeyboardButton('♻️ ᴀʙᴏᴜᴛ ♻️', callback_data='about'),
80 | InlineKeyboardButton('🔍sᴇᴀʀᴄʜ', switch_inline_query_current_chat=''), ]]
81 | reply_markup = InlineKeyboardMarkup(buttons)
82 | await message.reply_photo(
83 | photo=random.choice(PICS),
84 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME),
85 | reply_markup=reply_markup,
86 | parse_mode='html'
87 | )
88 | return
89 | file_id = message.command[1]
90 | files_ = await get_file_details(file_id)
91 | if not files_:
92 | return await message.reply('No such file exist.')
93 | files = files_[0]
94 | title = files.file_name
95 | size=get_size(files.file_size)
96 | f_caption=files.caption
97 | if CUSTOM_FILE_CAPTION:
98 | try:
99 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption)
100 | except Exception as e:
101 | logger.exception(e)
102 | f_caption=f_caption
103 | if f_caption is None:
104 | f_caption = f"{files.file_name}"
105 | await client.send_cached_media(
106 | chat_id=message.from_user.id,
107 | file_id=file_id,
108 | caption=f_caption,
109 | )
110 |
111 |
112 | @Client.on_message(filters.command('channel') & filters.user(ADMINS))
113 | async def channel_info(bot, message):
114 |
115 | """Send basic information of channel"""
116 | if isinstance(CHANNELS, (int, str)):
117 | channels = [CHANNELS]
118 | elif isinstance(CHANNELS, list):
119 | channels = CHANNELS
120 | else:
121 | raise ValueError("Unexpected type of CHANNELS")
122 |
123 | text = '📑 **Indexed channels/groups**\n'
124 | for channel in channels:
125 | chat = await bot.get_chat(channel)
126 | if chat.username:
127 | text += '\n@' + chat.username
128 | else:
129 | text += '\n' + chat.title or chat.first_name
130 |
131 | text += f'\n\n**Total:** {len(CHANNELS)}'
132 |
133 | if len(text) < 4096:
134 | await message.reply(text)
135 | else:
136 | file = 'Indexed channels.txt'
137 | with open(file, 'w') as f:
138 | f.write(text)
139 | await message.reply_document(file)
140 | os.remove(file)
141 |
142 |
143 | @Client.on_message(filters.command('logs') & filters.user(ADMINS))
144 | async def log_file(bot, message):
145 | """Send log file"""
146 | try:
147 | await message.reply_document('TelegramBot.log')
148 | except Exception as e:
149 | await message.reply(str(e))
150 |
151 | @Client.on_message(filters.command('delete') & filters.user(ADMINS))
152 | async def delete(bot, message):
153 | """Delete file from database"""
154 | reply = message.reply_to_message
155 | if reply and reply.media:
156 | msg = await message.reply("𝗖𝗵𝗲𝗰𝗸𝗶𝗻𝗴...⏳😜", quote=True)
157 | else:
158 | await message.reply('Reply to file with /delete which you want to delete', quote=True)
159 | return
160 |
161 | for file_type in ("document", "video", "audio"):
162 | media = getattr(reply, file_type, None)
163 | if media is not None:
164 | break
165 | else:
166 | await msg.edit('This is not supported file format')
167 | return
168 |
169 | file_id, file_ref = unpack_new_file_id(media.file_id)
170 |
171 | result = await Media.collection.delete_one({
172 | '_id': file_id,
173 | })
174 | if result.deleted_count:
175 | await msg.edit('File is successfully deleted from database')
176 | else:
177 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name))
178 | result = await Media.collection.delete_one({
179 | 'file_name': file_name,
180 | 'file_size': media.file_size,
181 | 'mime_type': media.mime_type
182 | })
183 | if result.deleted_count:
184 | await msg.edit('File is successfully deleted from database')
185 | else:
186 | # files indexed before https://github.com/EvamariaTG/EvaMaria/commit/f3d2a1bcb155faf44178e5d7a685a1b533e714bf#diff-86b613edf1748372103e94cacff3b578b36b698ef9c16817bb98fe9ef22fb669R39
187 | # have original file name.
188 | result = await Media.collection.delete_one({
189 | 'file_name': media.file_name,
190 | 'file_size': media.file_size,
191 | 'mime_type': media.mime_type
192 | })
193 | if result.deleted_count:
194 | await msg.edit('File is successfully deleted from database')
195 | else:
196 | await msg.edit('File not found in database')
197 |
198 |
199 | @Client.on_message(filters.command('deleteall') & filters.user(ADMINS))
200 | async def delete_all_index(bot, message):
201 | await message.reply_text(
202 | 'This will delete all indexed files.\nDo you want to continue??',
203 | reply_markup=InlineKeyboardMarkup(
204 | [
205 | [
206 | InlineKeyboardButton(
207 | text="𝗬𝗘𝗦😘", callback_data="autofilter_delete"
208 | )
209 | ],
210 | [
211 | InlineKeyboardButton(
212 | text="𝗖𝗔𝗡𝗖𝗘𝗟☹️", callback_data="close_data"
213 | )
214 | ],
215 | ]
216 | ),
217 | quote=True,
218 | )
219 |
220 |
221 | @Client.on_callback_query(filters.regex(r'^autofilter_delete'))
222 | async def delete_all_index_confirm(bot, message):
223 | await Media.collection.drop()
224 | await message.answer()
225 | await message.message.edit('Succesfully Deleted All The Indexed Files.')
226 |
227 |
--------------------------------------------------------------------------------
/plugins/p_ttishow.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, filters
2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
3 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid
4 | from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT
5 | from database.users_chats_db import db
6 | from database.ia_filterdb import Media
7 | from utils import get_size, temp
8 | from Script import script
9 | from pyrogram.errors import ChatAdminRequired
10 |
11 | """-----------------------------------------https://t.me/GetTGLink/4179 --------------------------------------"""
12 |
13 | @Client.on_message(filters.new_chat_members & filters.group)
14 | async def save_group(bot, message):
15 | r_j_check = [u.id for u in message.new_chat_members]
16 | if temp.ME in r_j_check:
17 | if not await db.get_chat(message.chat.id):
18 | total=await bot.get_chat_members_count(message.chat.id)
19 | r_j = message.from_user.mention if message.from_user else "Anonymous"
20 | await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, r_j))
21 | await db.add_chat(message.chat.id, message.chat.title)
22 | if message.chat.id in temp.BANNED_CHATS:
23 | # Inspired from a boat of a banana tree
24 | buttons = [[
25 | InlineKeyboardButton('𝗢𝗪𝗡𝗘𝗥', url=f'https://t.me/{SUPPORT_CHAT}')
26 | ]]
27 | reply_markup=InlineKeyboardMarkup(buttons)
28 | k = await message.reply(
29 | text='CHAT NOT ALLOWED 🐞\n\𝚗𝙼𝚈 𝙰𝙳𝙼𝙸𝙽𝚂 𝙷𝙰𝚂 𝚁𝙴𝚂𝚃𝚁𝙸𝙲𝚃𝙴𝙳 𝙼𝙴 𝙵𝚁𝙾𝙼 𝚆𝙾𝚁𝙺𝙸𝙽𝙶 𝙷𝙴𝚁𝙴 !𝙸𝙵 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙺𝙽𝙾𝚆 𝙼𝙾𝚁𝙴 𝙰𝙱𝙾𝚄𝚃 𝙸𝚃 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙾𝚆𝙽𝙴𝚁..',
30 | reply_markup=reply_markup,
31 | )
32 |
33 | try:
34 | await k.pin()
35 | except:
36 | pass
37 | await bot.leave_chat(message.chat.id)
38 | return
39 | buttons = [
40 | [
41 | InlineKeyboardButton('💠 CHANNEL 💠', url='https://t.me/Imdb_updates')
42 | ],
43 | [
44 | InlineKeyboardButton('♻️ HELP ♻️', url=f"https://t.me/{temp.U_NAME}?start=help")
45 | ]
46 | ]
47 | reply_markup=InlineKeyboardMarkup(buttons)
48 | await message.reply_text(
49 | text=f"Thankyou For Adding Me In {message.chat.title} ❣️\n\nIf You Have Any Questions & Doubts About Using Me Contact Owner ›› @BKC0001.",
50 | reply_markup=reply_markup)
51 | else:
52 | for u in message.new_chat_members:
53 | if (temp.MELCOW).get('welcome') is not None:
54 | try:
55 | await (temp.MELCOW['welcome']).delete()
56 | except:
57 | pass
58 | temp.MELCOW['welcome'] = await message.reply(f"𝙷𝙴𝚈 {u.mention}⚡ 𝚆𝙴𝙻𝙲𝙾𝙼𝙴 𝚃𝙾 {message.chat.title}!")
59 |
60 |
61 | @Client.on_message(filters.command('leave') & filters.user(ADMINS))
62 | async def leave_a_chat(bot, message):
63 | if len(message.command) == 1:
64 | return await message.reply('Give 𝚖𝚎 𝚊 𝚌𝚑𝚊𝚝 id')
65 | chat = message.command[1]
66 | try:
67 | chat = int(chat)
68 | except:
69 | chat = chat
70 | try:
71 | buttons = [[
72 | InlineKeyboardButton('𝗢𝗪𝗡𝗘𝗥', url=f'https://t.me/{SUPPORT_CHAT}')
73 | ]]
74 | reply_markup=InlineKeyboardMarkup(buttons)
75 | await bot.send_message(
76 | chat_id=chat,
77 | text='Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group.',
78 | reply_markup=reply_markup,
79 | )
80 |
81 | await bot.leave_chat(chat)
82 | except Exception as e:
83 | await message.reply(f'Error - {e}')
84 |
85 | @Client.on_message(filters.command('disable') & filters.user(ADMINS))
86 | async def disable_chat(bot, message):
87 | if len(message.command) == 1:
88 | return await message.reply('Give me a chat id')
89 | r = message.text.split(None)
90 | if len(r) > 2:
91 | reason = message.text.split(None, 2)[2]
92 | chat = message.text.split(None, 2)[1]
93 | else:
94 | chat = message.command[1]
95 | reason = "No reason Provided"
96 | try:
97 | chat_ = int(chat)
98 | except:
99 | return await message.reply('Give Me A Valid Chat ID')
100 | cha_t = await db.get_chat(int(chat_))
101 | if not cha_t:
102 | return await message.reply("Chat Not Found In DB")
103 | if cha_t['is_disabled']:
104 | return await message.reply(f"This chat is already disabled:\nReason- {cha_t['reason']} ")
105 | await db.disable_chat(int(chat_), reason)
106 | temp.BANNED_CHATS.append(int(chat_))
107 | await message.reply('Chat Succesfully Disabled')
108 | try:
109 | buttons = [[
110 | InlineKeyboardButton('𝗢𝗪𝗡𝗘𝗥', url=f'https://t.me/{SUPPORT_CHAT}')
111 | ]]
112 | reply_markup=InlineKeyboardMarkup(buttons)
113 | await bot.send_message(
114 | chat_id=chat_,
115 | text=f'Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group. \nReason : {reason}',
116 | reply_markup=reply_markup)
117 | await bot.leave_chat(chat_)
118 | except Exception as e:
119 | await message.reply(f"Error - {e}")
120 |
121 |
122 | @Client.on_message(filters.command('enable') & filters.user(ADMINS))
123 | async def re_enable_chat(bot, message):
124 | if len(message.command) == 1:
125 | return await message.reply('Give me a chat id')
126 | chat = message.command[1]
127 | try:
128 | chat_ = int(chat)
129 | except:
130 | return await message.reply('Give Me A Valid Chat ID')
131 | sts = await db.get_chat(int(chat))
132 | if not sts:
133 | return await message.reply("Chat Not Found In DB !")
134 | if not sts.get('is_disabled'):
135 | return await message.reply('This chat is not yet disabled.')
136 | await db.re_enable_chat(int(chat_))
137 | temp.BANNED_CHATS.remove(int(chat_))
138 | await message.reply("Chat Succesfully re-enabled")
139 |
140 |
141 | @Client.on_message(filters.command('stats') & filters.user(ADMINS))
142 | async def get_ststs(bot, message):
143 | rju = await message.reply('𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝚂𝚃𝙰𝚃𝚄𝚂 𝙳𝙴𝚃𝙰𝙸𝙻𝚂...')
144 | total_users = await db.total_users_count()
145 | totl_chats = await db.total_chat_count()
146 | files = await Media.count_documents()
147 | size = await db.get_db_size()
148 | free = 536870912 - size
149 | size = get_size(size)
150 | free = get_size(free)
151 | await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free))
152 |
153 |
154 | # a function for trespassing into others groups, Inspired by a Vazha
155 | # Not to be used , But Just to showcase his vazhatharam.
156 | # @Client.on_message(filters.command('invite') & filters.user(ADMINS))
157 | async def gen_invite(bot, message):
158 | if len(message.command) == 1:
159 | return await message.reply('Give me a chat id')
160 | chat = message.command[1]
161 | try:
162 | chat = int(chat)
163 | except:
164 | return await message.reply('Give Me A Valid Chat ID')
165 | try:
166 | link = await bot.create_chat_invite_link(chat)
167 | except ChatAdminRequired:
168 | return await message.reply("Invite Link Generation Failed, Iam Not Having Sufficient Rights")
169 | except Exception as e:
170 | return await message.reply(f'Error {e}')
171 | await message.reply(f'Here is your Invite Link {link.invite_link}')
172 |
173 | @Client.on_message(filters.command('ban') & filters.user(ADMINS))
174 | async def ban_a_user(bot, message):
175 | # https://t.me/GetTGLink/4185
176 | if len(message.command) == 1:
177 | return await message.reply('Give me a user id / username')
178 | r = message.text.split(None)
179 | if len(r) > 2:
180 | reason = message.text.split(None, 2)[2]
181 | chat = message.text.split(None, 2)[1]
182 | else:
183 | chat = message.command[1]
184 | reason = "No reason Provided"
185 | try:
186 | chat = int(chat)
187 | except:
188 | pass
189 | try:
190 | k = await bot.get_users(chat)
191 | except PeerIdInvalid:
192 | return await message.reply("This is an invalid user, make sure ia have met him before.")
193 | except IndexError:
194 | return await message.reply("This might be a channel, make sure its a user.")
195 | except Exception as e:
196 | return await message.reply(f'Error - {e}')
197 | else:
198 | jar = await db.get_ban_status(k.id)
199 | if jar['is_banned']:
200 | return await message.reply(f"{k.mention} is already banned\nReason: {jar['ban_reason']}")
201 | await db.ban_user(k.id, reason)
202 | temp.BANNED_USERS.append(k.id)
203 | await message.reply(f"Succesfully banned {k.mention}")
204 |
205 |
206 |
207 | @Client.on_message(filters.command('unban') & filters.user(ADMINS))
208 | async def unban_a_user(bot, message):
209 | if len(message.command) == 1:
210 | return await message.reply('Give me a user id / username')
211 | r = message.text.split(None)
212 | if len(r) > 2:
213 | reason = message.text.split(None, 2)[2]
214 | chat = message.text.split(None, 2)[1]
215 | else:
216 | chat = message.command[1]
217 | reason = "No reason Provided"
218 | try:
219 | chat = int(chat)
220 | except:
221 | pass
222 | try:
223 | k = await bot.get_users(chat)
224 | except PeerIdInvalid:
225 | return await message.reply("This is an invalid user, make sure ia have met him before.")
226 | except IndexError:
227 | return await message.reply("Thismight be a channel, make sure its a user.")
228 | except Exception as e:
229 | return await message.reply(f'Error - {e}')
230 | else:
231 | jar = await db.get_ban_status(k.id)
232 | if not jar['is_banned']:
233 | return await message.reply(f"{k.mention} is not yet banned.")
234 | await db.remove_ban(k.id)
235 | temp.BANNED_USERS.remove(k.id)
236 | await message.reply(f"Succesfully unbanned {k.mention}")
237 |
238 |
239 |
240 | @Client.on_message(filters.command('users') & filters.user(ADMINS))
241 | async def list_users(bot, message):
242 | # https://t.me/GetTGLink/4184
243 | raju = await message.reply('Getting List Of Users')
244 | users = await db.get_all_users()
245 | out = "Users Saved In DB Are:\n\n"
246 | async for user in users:
247 | out += f"{user['name']}\n"
248 | try:
249 | await raju.edit_text(out)
250 | except MessageTooLong:
251 | with open('users.txt', 'w+') as outfile:
252 | outfile.write(out)
253 | await message.reply_document('users.txt', caption="List Of Users")
254 |
255 | @Client.on_message(filters.command('chats') & filters.user(ADMINS))
256 | async def list_chats(bot, message):
257 | raju = await message.reply('Getting List Of chats')
258 | chats = await db.get_all_chats()
259 | out = "Chats Saved In DB Are:\n\n"
260 | async for chat in chats:
261 | out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`\n"
262 | try:
263 | await raju.edit_text(out)
264 | except MessageTooLong:
265 | with open('chats.txt', 'w+') as outfile:
266 | outfile.write(out)
267 | await message.reply_document('chats.txt', caption="List Of Chats")
268 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from pyrogram.errors import InputUserDeactivated, UserNotParticipant, FloodWait, UserIsBlocked, PeerIdInvalid
3 | from info import AUTH_CHANNEL, LONG_IMDB_DESCRIPTION, MAX_LIST_ELM
4 | from imdb import IMDb
5 | import asyncio
6 | from pyrogram.types import Message
7 | from typing import Union
8 | import re
9 | import os
10 | from datetime import datetime
11 | from typing import List
12 | from pyrogram.types import InlineKeyboardButton
13 | from database.users_chats_db import db
14 | from bs4 import BeautifulSoup
15 | import requests
16 |
17 | logger = logging.getLogger(__name__)
18 | logger.setLevel(logging.INFO)
19 |
20 | BTN_URL_REGEX = re.compile(
21 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))"
22 | )
23 |
24 | imdb = IMDb()
25 |
26 | BANNED = {}
27 | SMART_OPEN = '“'
28 | SMART_CLOSE = '”'
29 | START_CHAR = ('\'', '"', SMART_OPEN)
30 |
31 | # temp db for banned
32 | class temp(object):
33 | BANNED_USERS = []
34 | BANNED_CHATS = []
35 | ME = None
36 | CURRENT=int(os.environ.get("SKIP", 2))
37 | CANCEL = False
38 | MELCOW = {}
39 | U_NAME = None
40 | B_NAME = None
41 |
42 | async def is_subscribed(bot, query):
43 | try:
44 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id)
45 | except UserNotParticipant:
46 | pass
47 | except Exception as e:
48 | logger.exception(e)
49 | else:
50 | if user.status != 'kicked':
51 | return True
52 |
53 | return False
54 |
55 | async def get_poster(query, bulk=False, id=False, file=None):
56 | if not id:
57 | # https://t.me/GetTGLink/4183
58 | query = (query.strip()).lower()
59 | title = query
60 | year = re.findall(r'[1-2]\d{3}$', query, re.IGNORECASE)
61 | if year:
62 | year = list_to_str(year[:1])
63 | title = (query.replace(year, "")).strip()
64 | elif file is not None:
65 | year = re.findall(r'[1-2]\d{3}', file, re.IGNORECASE)
66 | if year:
67 | year = list_to_str(year[:1])
68 | else:
69 | year = None
70 | movieid = imdb.search_movie(title.lower(), results=10)
71 | if not movieid:
72 | return None
73 | if year:
74 | filtered=list(filter(lambda k: str(k.get('year')) == str(year), movieid))
75 | if not filtered:
76 | filtered = movieid
77 | else:
78 | filtered = movieid
79 | movieid=list(filter(lambda k: k.get('kind') in ['movie', 'tv series'], filtered))
80 | if not movieid:
81 | movieid = filtered
82 | if bulk:
83 | return movieid
84 | movieid = movieid[0].movieID
85 | else:
86 | movieid = int(query)
87 | movie = imdb.get_movie(movieid)
88 | if movie.get("original air date"):
89 | date = movie["original air date"]
90 | elif movie.get("year"):
91 | date = movie.get("year")
92 | else:
93 | date = "N/A"
94 | plot = ""
95 | if not LONG_IMDB_DESCRIPTION:
96 | plot = movie.get('plot')
97 | if plot and len(plot) > 0:
98 | plot = plot[0]
99 | else:
100 | plot = movie.get('plot outline')
101 | if plot and len(plot) > 800:
102 | plot = plot[0:800] + "..."
103 |
104 | return {
105 | 'title': movie.get('title'),
106 | 'votes': movie.get('votes'),
107 | "aka": list_to_str(movie.get("akas")),
108 | "seasons": movie.get("number of seasons"),
109 | "box_office": movie.get('box office'),
110 | 'localized_title': movie.get('localized title'),
111 | 'kind': movie.get("kind"),
112 | "imdb_id": f"tt{movie.get('imdbID')}",
113 | "cast": list_to_str(movie.get("cast")),
114 | "runtime": list_to_str(movie.get("runtimes")),
115 | "countries": list_to_str(movie.get("countries")),
116 | "certificates": list_to_str(movie.get("certificates")),
117 | "languages": list_to_str(movie.get("languages")),
118 | "director": list_to_str(movie.get("director")),
119 | "writer":list_to_str(movie.get("writer")),
120 | "producer":list_to_str(movie.get("producer")),
121 | "composer":list_to_str(movie.get("composer")) ,
122 | "cinematographer":list_to_str(movie.get("cinematographer")),
123 | "music_team": list_to_str(movie.get("music department")),
124 | "distributors": list_to_str(movie.get("distributors")),
125 | 'release_date': date,
126 | 'year': movie.get('year'),
127 | 'genres': list_to_str(movie.get("genres")),
128 | 'poster': movie.get('full-size cover url'),
129 | 'plot': plot,
130 | 'rating': str(movie.get("rating")),
131 | 'url':f'https://www.imdb.com/title/tt{movieid}'
132 | }
133 | # https://github.com/odysseusmax/animated-lamp/blob/2ef4730eb2b5f0596ed6d03e7b05243d93e3415b/bot/utils/broadcast.py#L37
134 |
135 | async def broadcast_messages(user_id, message):
136 | try:
137 | await message.copy(chat_id=user_id)
138 | return True, "Succes"
139 | except FloodWait as e:
140 | await asyncio.sleep(e.x)
141 | return await broadcast_messages(user_id, message)
142 | except InputUserDeactivated:
143 | await db.delete_user(int(user_id))
144 | logging.info(f"{user_id}-Removed from Database, since deleted account.")
145 | return False, "Deleted"
146 | except UserIsBlocked:
147 | logging.info(f"{user_id} -Blocked the bot.")
148 | return False, "Blocked"
149 | except PeerIdInvalid:
150 | await db.delete_user(int(user_id))
151 | logging.info(f"{user_id} - PeerIdInvalid")
152 | return False, "Error"
153 | except Exception as e:
154 | return False, "Error"
155 |
156 | async def search_gagala(text):
157 | usr_agent = {
158 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
159 | 'Chrome/61.0.3163.100 Safari/537.36'
160 | }
161 | text = text.replace(" ", '+')
162 | url = f'https://www.google.com/search?q={text}'
163 | response = requests.get(url, headers=usr_agent)
164 | response.raise_for_status()
165 | soup = BeautifulSoup(response.text, 'html.parser')
166 | titles = soup.find_all( 'h3' )
167 | return [title.getText() for title in titles]
168 |
169 |
170 |
171 |
172 | def get_size(size):
173 | """Get size in readable format"""
174 |
175 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"]
176 | size = float(size)
177 | i = 0
178 | while size >= 1024.0 and i < len(units):
179 | i += 1
180 | size /= 1024.0
181 | return "%.2f %s" % (size, units[i])
182 |
183 | def split_list(l, n):
184 | for i in range(0, len(l), n):
185 | yield l[i:i + n]
186 |
187 | def get_file_id(msg: Message):
188 | if msg.media:
189 | for message_type in (
190 | "photo",
191 | "animation",
192 | "audio",
193 | "document",
194 | "video",
195 | "video_note",
196 | "voice",
197 | "sticker"
198 | ):
199 | obj = getattr(msg, message_type)
200 | if obj:
201 | setattr(obj, "message_type", message_type)
202 | return obj
203 |
204 | def extract_user(message: Message) -> Union[int, str]:
205 | """extracts the user from a message"""
206 | # https://github.com/SpEcHiDe/PyroGramBot/blob/f30e2cca12002121bad1982f68cd0ff9814ce027/pyrobot/helper_functions/extract_user.py#L7
207 | user_id = None
208 | user_first_name = None
209 | if message.reply_to_message:
210 | user_id = message.reply_to_message.from_user.id
211 | user_first_name = message.reply_to_message.from_user.first_name
212 |
213 | elif len(message.command) > 1:
214 | if (
215 | len(message.entities) > 1 and
216 | message.entities[1].type == "text_mention"
217 | ):
218 |
219 | required_entity = message.entities[1]
220 | user_id = required_entity.user.id
221 | user_first_name = required_entity.user.first_name
222 | else:
223 | user_id = message.command[1]
224 | # don't want to make a request -_-
225 | user_first_name = user_id
226 | try:
227 | user_id = int(user_id)
228 | except ValueError:
229 | pass
230 | else:
231 | user_id = message.from_user.id
232 | user_first_name = message.from_user.first_name
233 | return (user_id, user_first_name)
234 |
235 | def list_to_str(k):
236 | if not k:
237 | return "N/A"
238 | elif len(k) == 1:
239 | return str(k[0])
240 | elif MAX_LIST_ELM:
241 | k = k[:int(MAX_LIST_ELM)]
242 | return ' '.join(f'{elem}, ' for elem in k)
243 | else:
244 | return ' '.join(f'{elem}, ' for elem in k)
245 |
246 | def last_online(from_user):
247 | time = ""
248 | if from_user.is_bot:
249 | time += "🤖 Bot :("
250 | elif from_user.status == 'recently':
251 | time += "Recently"
252 | elif from_user.status == 'within_week':
253 | time += "Within the last week"
254 | elif from_user.status == 'within_month':
255 | time += "Within the last month"
256 | elif from_user.status == 'long_time_ago':
257 | time += "A long time ago :("
258 | elif from_user.status == 'online':
259 | time += "Currently Online"
260 | elif from_user.status == 'offline':
261 | time += datetime.fromtimestamp(from_user.last_online_date).strftime("%a, %d %b %Y, %H:%M:%S")
262 | return time
263 |
264 |
265 | def split_quotes(text: str) -> List:
266 | if not any(text.startswith(char) for char in START_CHAR):
267 | return text.split(None, 1)
268 | counter = 1 # ignore first char -> is some kind of quote
269 | while counter < len(text):
270 | if text[counter] == "\\":
271 | counter += 1
272 | elif text[counter] == text[0] or (text[0] == SMART_OPEN and text[counter] == SMART_CLOSE):
273 | break
274 | counter += 1
275 | else:
276 | return text.split(None, 1)
277 |
278 | # 1 to avoid starting quote, and counter is exclusive so avoids ending
279 | key = remove_escapes(text[1:counter].strip())
280 | # index will be in range, or `else` would have been executed and returned
281 | rest = text[counter + 1:].strip()
282 | if not key:
283 | key = text[0] + text[0]
284 | return list(filter(None, [key, rest]))
285 |
286 | def parser(text, keyword):
287 | if "buttonalert" in text:
288 | text = (text.replace("\n", "\\n").replace("\t", "\\t"))
289 | buttons = []
290 | note_data = ""
291 | prev = 0
292 | i = 0
293 | alerts = []
294 | for match in BTN_URL_REGEX.finditer(text):
295 | # Check if btnurl is escaped
296 | n_escapes = 0
297 | to_check = match.start(1) - 1
298 | while to_check > 0 and text[to_check] == "\\":
299 | n_escapes += 1
300 | to_check -= 1
301 |
302 | # if even, not escaped -> create button
303 | if n_escapes % 2 == 0:
304 | note_data += text[prev:match.start(1)]
305 | prev = match.end(1)
306 | if match.group(3) == "buttonalert":
307 | # create a thruple with button label, url, and newline status
308 | if bool(match.group(5)) and buttons:
309 | buttons[-1].append(InlineKeyboardButton(
310 | text=match.group(2),
311 | callback_data=f"alertmessage:{i}:{keyword}"
312 | ))
313 | else:
314 | buttons.append([InlineKeyboardButton(
315 | text=match.group(2),
316 | callback_data=f"alertmessage:{i}:{keyword}"
317 | )])
318 | i += 1
319 | alerts.append(match.group(4))
320 | elif bool(match.group(5)) and buttons:
321 | buttons[-1].append(InlineKeyboardButton(
322 | text=match.group(2),
323 | url=match.group(4).replace(" ", "")
324 | ))
325 | else:
326 | buttons.append([InlineKeyboardButton(
327 | text=match.group(2),
328 | url=match.group(4).replace(" ", "")
329 | )])
330 |
331 | else:
332 | note_data += text[prev:to_check]
333 | prev = match.start(1) - 1
334 | else:
335 | note_data += text[prev:]
336 |
337 | try:
338 | return note_data, buttons, alerts
339 | except:
340 | return note_data, buttons, None
341 |
342 | def remove_escapes(text: str) -> str:
343 | res = ""
344 | is_escaped = False
345 | for counter in range(len(text)):
346 | if is_escaped:
347 | res += text[counter]
348 | is_escaped = False
349 | elif text[counter] == "\\":
350 | is_escaped = True
351 | else:
352 | res += text[counter]
353 | return res
354 |
355 |
356 | def humanbytes(size):
357 | if not size:
358 | return ""
359 | power = 2**10
360 | n = 0
361 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'}
362 | while size > power:
363 | size /= power
364 | n += 1
365 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B'
366 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |