├── shivu
├── modules
│ ├── dev_cmd.py
│ ├── ping.py
│ ├── broadcast.py
│ ├── changetime.py
│ ├── __init__.py
│ ├── inlinequery.py
│ ├── eval.py
│ ├── harem.py
│ ├── start.py
│ ├── leaderboard.py
│ ├── upload.py
│ └── trade.py
├── config.py
├── __init__.py
└── __main__.py
├── runtime.txt
├── Procfile
├── Git_Pull.bat
├── requirements.txt
├── Git_Push.bat
├── LICENSE
├── Dockerfile
├── README.md
└── .gitignore
/shivu/modules/dev_cmd.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.11.0
2 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python3 -m shivu
2 |
--------------------------------------------------------------------------------
/Git_Pull.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | TITLE Github Quick-Pull
3 |
4 | :: Print the branch cause ..oooooo fancy!
5 | echo Pulling from branch:
6 | git branch
7 | echo.
8 | git pull
9 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | motor
2 | aiohttp
3 | requests
4 | python-telegram-bot==20.6
5 | pymongo
6 | pyrate-limiter==3.1.0
7 | apscheduler==3.6.3
8 | pyrogram
9 | tgcrypto
10 | python-dotenv
11 | cachetools
12 |
--------------------------------------------------------------------------------
/Git_Push.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | TITLE Github Quick-pushing
3 |
4 | :: Print the branch cause people like me push to wrong branches and cry about it later.
5 | echo Pushing to branch:
6 | git branch
7 | echo.
8 | :: Take input for comment and thats about it
9 | set /p commit_title="Enter Commit title (pushes with you as author): "
10 |
11 | :: If you are reading comments to understand this part then you can go back stab yourself.
12 | echo.
13 | git pull
14 | git add *
15 | git commit -m "%commit_title%"
16 | git push
17 |
--------------------------------------------------------------------------------
/shivu/modules/ping.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from telegram import Update
4 | from telegram.ext import CommandHandler, CallbackContext
5 |
6 | from shivu import application, sudo_users
7 |
8 | async def ping(update: Update, context: CallbackContext) -> None:
9 | if str(update.effective_user.id) not in sudo_users:
10 | update.message.reply_text("Nouu.. its Sudo user's Command..")
11 | return
12 | start_time = time.time()
13 | message = await update.message.reply_text('Pong!')
14 | end_time = time.time()
15 | elapsed_time = round((end_time - start_time) * 1000, 3)
16 | await message.edit_text(f'Pong! {elapsed_time}ms')
17 |
18 | application.add_handler(CommandHandler("ping", ping))
19 |
--------------------------------------------------------------------------------
/shivu/config.py:
--------------------------------------------------------------------------------
1 | class Config(object):
2 | LOGGER = True
3 |
4 | # Get this value from my.telegram.org/apps
5 | OWNER_ID = "6765826972"
6 | sudo_users = "6845325416", "6765826972"
7 | GROUP_ID = -1002133191051
8 | TOKEN = "6707490163:AAHZzqjm3rbEZsObRiNaT7DMtw_i5WPo_0o"
9 | mongo_url = "mongodb+srv://HaremDBBot:ThisIsPasswordForHaremDB@haremdb.swzjngj.mongodb.net/?retryWrites=true&w=majority"
10 | PHOTO_URL = ["https://telegra.ph/file/b925c3985f0f325e62e17.jpg", "https://telegra.ph/file/4211fb191383d895dab9d.jpg"]
11 | SUPPORT_CHAT = "Collect_em_support"
12 | UPDATE_CHAT = "Collect_em_support"
13 | BOT_USERNAME = "Collect_Em_AllBot"
14 | CHARA_CHANNEL_ID = "-1002133191051"
15 | api_id = 26626068
16 | api_hash = "bf423698bcbe33cfd58b11c78c42caa2"
17 |
18 |
19 | class Production(Config):
20 | LOGGER = True
21 |
22 |
23 | class Development(Config):
24 | LOGGER = True
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Shuyaa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/shivu/modules/broadcast.py:
--------------------------------------------------------------------------------
1 | from telegram import Update
2 | from telegram.ext import CallbackContext, CommandHandler
3 |
4 | from shivu import application, top_global_groups_collection, pm_users, OWNER_ID
5 |
6 | async def broadcast(update: Update, context: CallbackContext) -> None:
7 |
8 | if update.effective_user.id != OWNER_ID:
9 | await update.message.reply_text("You are not authorized to use this command.")
10 | return
11 |
12 | message_to_broadcast = update.message.reply_to_message
13 |
14 | if message_to_broadcast is None:
15 | await update.message.reply_text("Please reply to a message to broadcast.")
16 | return
17 |
18 | all_chats = await top_global_groups_collection.distinct("group_id")
19 | all_users = await pm_users.distinct("_id")
20 |
21 | shuyaa = list(set(all_chats + all_users))
22 |
23 | failed_sends = 0
24 |
25 | for chat_id in shuyaa:
26 | try:
27 | await context.bot.forward_message(chat_id=chat_id,
28 | from_chat_id=message_to_broadcast.chat_id,
29 | message_id=message_to_broadcast.message_id)
30 | except Exception as e:
31 | print(f"Failed to send message to {chat_id}: {e}")
32 | failed_sends += 1
33 |
34 | await update.message.reply_text(f"Broadcast complete. Failed to send to {failed_sends} chats/users.")
35 |
36 | application.add_handler(CommandHandler("broadcast", broadcast, block=False))
37 |
--------------------------------------------------------------------------------
/shivu/modules/changetime.py:
--------------------------------------------------------------------------------
1 | from pymongo import ReturnDocument
2 | from pyrogram.enums import ChatMemberStatus, ChatType
3 | from shivu import user_totals_collection, shivuu
4 | from pyrogram import Client, filters
5 | from pyrogram.types import Message
6 |
7 | ADMINS = [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER]
8 |
9 |
10 | @shivuu.on_message(filters.command("changetime"))
11 | async def change_time(client: Client, message: Message):
12 |
13 | user_id = message.from_user.id
14 | chat_id = message.chat.id
15 | member = await shivuu.get_chat_member(chat_id,user_id)
16 |
17 |
18 | if member.status not in ADMINS :
19 | await message.reply_text('You are not an Admin.')
20 | return
21 |
22 | try:
23 | args = message.command
24 | if len(args) != 2:
25 | await message.reply_text('Please use: /changetime NUMBER')
26 | return
27 |
28 | new_frequency = int(args[1])
29 | if new_frequency < 100:
30 | await message.reply_text('The message frequency must be greater than or equal to 100.')
31 | return
32 |
33 |
34 | chat_frequency = await user_totals_collection.find_one_and_update(
35 | {'chat_id': str(chat_id)},
36 | {'$set': {'message_frequency': new_frequency}},
37 | upsert=True,
38 | return_document=ReturnDocument.AFTER
39 | )
40 |
41 | await message.reply_text(f'Successfully changed {new_frequency}')
42 | except Exception as e:
43 | await message.reply_text(f'Failed to change {str(e)}')
44 |
--------------------------------------------------------------------------------
/shivu/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | from pyrogram import Client
4 | from telegram.ext import Application
5 | from motor.motor_asyncio import AsyncIOMotorClient
6 |
7 | logging.basicConfig(
8 | format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
9 | handlers=[logging.FileHandler("log.txt"), logging.StreamHandler()],
10 | level=logging.INFO,
11 | )
12 |
13 | logging.getLogger("apscheduler").setLevel(logging.ERROR)
14 | logging.getLogger('httpx').setLevel(logging.WARNING)
15 | logging.getLogger("pyrate_limiter").setLevel(logging.ERROR)
16 | LOGGER = logging.getLogger(__name__)
17 |
18 | from shivu.config import Development as Config
19 |
20 |
21 | api_id = Config.api_id
22 | api_hash = Config.api_hash
23 | TOKEN = Config.TOKEN
24 | GROUP_ID = Config.GROUP_ID
25 | CHARA_CHANNEL_ID = Config.CHARA_CHANNEL_ID
26 | mongo_url = Config.mongo_url
27 | PHOTO_URL = Config.PHOTO_URL
28 | SUPPORT_CHAT = Config.SUPPORT_CHAT
29 | UPDATE_CHAT = Config.UPDATE_CHAT
30 | BOT_USERNAME = Config.BOT_USERNAME
31 | sudo_users = Config.sudo_users
32 | OWNER_ID = Config.OWNER_ID
33 |
34 | application = Application.builder().token(TOKEN).build()
35 | shivuu = Client("Shivu", api_id, api_hash, bot_token=TOKEN)
36 | lol = AsyncIOMotorClient(mongo_url)
37 | db = lol['Character_catcher']
38 | collection = db['anime_characters_lol']
39 | user_totals_collection = db['user_totals_lmaoooo']
40 | user_collection = db["user_collection_lmaoooo"]
41 | group_user_totals_collection = db['group_user_totalsssssss']
42 | top_global_groups_collection = db['top_global_groups']
43 | pm_users = db['total_pm_users']
44 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8.5-slim-buster
2 |
3 | ENV PIP_NO_CACHE_DIR 1
4 |
5 | RUN sed -i.bak 's/us-west-2\.ec2\.//' /etc/apt/sources.list
6 |
7 | # Installing Required Packages
8 | RUN apt update && apt upgrade -y && \
9 | apt install --no-install-recommends -y \
10 | debian-keyring \
11 | debian-archive-keyring \
12 | bash \
13 | bzip2 \
14 | curl \
15 | figlet \
16 | git \
17 | util-linux \
18 | libffi-dev \
19 | libjpeg-dev \
20 | libjpeg62-turbo-dev \
21 | libwebp-dev \
22 | linux-headers-amd64 \
23 | musl-dev \
24 | musl \
25 | neofetch \
26 | php-pgsql \
27 | python3-lxml \
28 | postgresql \
29 | postgresql-client \
30 | python3-psycopg2 \
31 | libpq-dev \
32 | libcurl4-openssl-dev \
33 | libxml2-dev \
34 | libxslt1-dev \
35 | python3-pip \
36 | python3-requests \
37 | python3-sqlalchemy \
38 | python3-tz \
39 | python3-aiohttp \
40 | openssl \
41 | pv \
42 | jq \
43 | wget \
44 | python3 \
45 | python3-dev \
46 | libreadline-dev \
47 | libyaml-dev \
48 | gcc \
49 | sqlite3 \
50 | libsqlite3-dev \
51 | sudo \
52 | zlib1g \
53 | ffmpeg \
54 | libssl-dev \
55 | libgconf-2-4 \
56 | libxi6 \
57 | xvfb \
58 | unzip \
59 | libopus0 \
60 | libopus-dev \
61 | && rm -rf /var/lib/apt/lists /var/cache/apt/archives /tmp
62 |
63 | # Pypi package Repo upgrade
64 | RUN pip3 install --upgrade pip setuptools
65 |
66 | # Copy Python Requirements to /root/FallenRobot
67 | RUN git clone https://github.com/Mynameishekhar/ptb /root/ptb
68 | WORKDIR /root/ptb
69 |
70 |
71 | ENV PATH="/home/bot/bin:$PATH"
72 |
73 | # Install requirements
74 | RUN pip3 install -U -r requirements.txt
75 |
76 | # Starting Worker
77 | CMD ["python3","-m", "shivu"]
78 |
--------------------------------------------------------------------------------
/shivu/modules/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import sys
3 | import time
4 |
5 | StartTime = time.time()
6 |
7 | # enable logging
8 | logging.basicConfig(
9 | format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
10 | handlers=[logging.FileHandler("log.txt"), logging.StreamHandler()],
11 | level=logging.INFO,
12 | )
13 |
14 | logging.getLogger("apscheduler").setLevel(logging.ERROR)
15 |
16 | logging.getLogger("pyrate_limiter").setLevel(logging.ERROR)
17 | LOGGER = logging.getLogger(__name__)
18 |
19 | # if version < 3.6, stop bot.
20 | if sys.version_info[0] < 3 or sys.version_info[1] < 6:
21 | LOGGER.error(
22 | "You MUST have a python version of at least 3.6! Multiple features depend on this. Bot quitting."
23 | )
24 | quit(1)
25 |
26 | LOAD = []
27 | NO_LOAD = []
28 |
29 | def __list_all_modules():
30 | import glob
31 | from os.path import basename, dirname, isfile
32 |
33 | # This generates a list of modules in this folder for the * in __main__ to work.
34 | mod_paths = glob.glob(dirname(__file__) + "/*.py")
35 | all_modules = [
36 | basename(f)[:-3]
37 | for f in mod_paths
38 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py")
39 | ]
40 |
41 | if LOAD or NO_LOAD:
42 | to_load = LOAD
43 | if to_load:
44 | if not all(
45 | any(mod == module_name for module_name in all_modules)
46 | for mod in to_load
47 | ):
48 | LOGGER.error("Invalid loadorder names, Quitting...")
49 | quit(1)
50 |
51 | all_modules = sorted(set(all_modules) - set(to_load))
52 | to_load = list(all_modules) + to_load
53 |
54 | else:
55 | to_load = all_modules
56 |
57 | if NO_LOAD:
58 | LOGGER.info("Not loading: {}".format(NO_LOAD))
59 | return [item for item in to_load if item not in NO_LOAD]
60 |
61 | return to_load
62 |
63 | return all_modules
64 |
65 |
66 | ALL_MODULES = __list_all_modules()
67 | LOGGER.info("Modules to load: %s", str(ALL_MODULES))
68 | __all__ = ALL_MODULES + ["ALL_MODULES"]
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## WAIFU & HUSBANDO CATCHER
4 |
5 |
6 | 
[](https://github.com/ellerbrock/open-source-badges/) [](https://makeapullrequest.com)
7 | [](https://t.me/collect_em_support)
8 |
9 |
10 | _**Available On Telegram As
11 | [Collect Em all](https://t.me/Collect_em_AllBot) and**_
12 | _Ask for Help in our [Support Chat](https://t.me/Collect_em_support)_
13 |
14 | ## About The Repository
15 | ● This is an Open Source Implementation of Character Catcher Bot for Telegram
16 | - For Example, Grab/Hunt/Protecc/Collect etc.. These Types of Bot You must have seen it on your telegram groups..
17 | - This bot sends characters in group after every 100 Messages Of Groups Then any user can Guess that character's Name Using /guess Command.
18 |
19 | - Now you can also deploy this type of bot. Using our source, we've used Python-Telegram-Bot V20.6 and Also lil bit Pyrogram. Enjoy!
20 |
21 | ## HOW TO UPLOAD CHARACTERS?
22 |
23 | Format:
24 | ```
25 | /upload img_url character-name anime-name rarity-number
26 | ```
27 | #### Example:
28 | ```
29 | /upload Img_url muzan-kibutsuji Demon-slayer 3
30 | ```
31 |
32 |
33 |
34 | use Rarity Number accordingly rarity Map
35 |
36 | | Number | Rarity |
37 | | ------ | -----------|
38 | | 1 | ⚪️ Common |
39 | | 2 | 🟣 Rare |
40 | | 3 | 🟡 Legendary|
41 | | 4 | 🟢 Medium |
42 |
43 |
44 | ## USER COMMANDS
45 | - `/guess` - Guess the character
46 | - `/fav` - Add a character to favorites
47 | - `/trade` - Trade a character with another user
48 | - `/gift` - Gift a character to another user
49 | - `/collection` - Boast your harem collection
50 | - `/topgroups` - List the groups with biggest harem (globally)
51 | - `/top` - List the users with biggest harem (globally)
52 | - `/ctop` - List the users with biggest harem (current chat)
53 | - `/changetime` - Change the frequency of character spawn
54 |
55 | ## SUDO USER COMMANDS..
56 | - `/upload` - Add a new character to the database
57 | - `/delete` - Delete a character from the database
58 | - `/update` - Update stats of a character in the database
59 |
60 | ## OWNER COMMANDS
61 | - `/ping` - Pings the bot and sends a response
62 | - `/stats` - Lists number or groups and users
63 | - `/list` - Sends a document with list of all users that used the bot
64 | - `/groups` - Sends a document with list of all groups that the bot has been in
65 |
66 | ## DEPLOYMENT METHODS
67 |
68 | ### Heroku
69 | - Fork The Repository
70 | - Go to [`config.py`](./shivu/config.py)
71 | - Fill the All variables and Go to heroku. and deploy Your forked Repository
72 |
73 | ### Local Deploy/VPS
74 | - Fill variables in [`config.py`](./shivu/config.py)
75 | - Open your VPS terminal (we're using Debian based) and run the following:
76 | ```bash
77 | sudo apt-get update && sudo apt-get upgrade -y
78 |
79 | sudo apt-get install python3-pip -y
80 | sudo pip3 install -U pip
81 |
82 | git clone https://github.com//WAIFU-HUSBANDO-CATCHER && cd WAIFU-HUSBANDO-CATCHER
83 |
84 | pip3 install -U -r requirements.txt
85 |
86 | sudo apt install tmux && tmux
87 | python3 -m shivu
88 | ```
89 |
90 | ## License
91 | The Source is licensed under MIT, and hence comes with no Warranty whatsoever.
92 |
93 | ## Appreciation
94 | If you appreciate this Code, make sure to star ✨ the repository.
95 |
96 | ## Developer Suggestions
97 | - Don't Use heroku. Deploy on Heroku is just for testing. Otherwise Bot's Inline will Work Too Slow.
98 | - Use a reliable VPS provider
99 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Added by IzumiCypherX for local tesing purposes
2 | test/
3 | *test.py
4 | .vscode/
5 | *.old
6 | .vim/
7 | *.session
8 | log.txt
9 |
10 |
11 | # Byte-compiled / optimized / DLL files
12 | __pycache__/
13 | *.py[cod]
14 | *$py.class
15 |
16 | # C extensions
17 | *.so
18 |
19 | # Distribution / packaging
20 | .Python
21 | build/
22 | develop-eggs/
23 | dist/
24 | downloads/
25 | eggs/
26 | .eggs/
27 | lib/
28 | lib64/
29 | parts/
30 | sdist/
31 | var/
32 | wheels/
33 | share/python-wheels/
34 | *.egg-info/
35 | .installed.cfg
36 | *.egg
37 | MANIFEST
38 |
39 | # PyInstaller
40 | # Usually these files are written by a python script from a template
41 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
42 | *.manifest
43 | *.spec
44 |
45 | # Installer logs
46 | pip-log.txt
47 | pip-delete-this-directory.txt
48 |
49 | # Unit test / coverage reports
50 | htmlcov/
51 | .tox/
52 | .nox/
53 | .coverage
54 | .coverage.*
55 | .cache
56 | nosetests.xml
57 | coverage.xml
58 | *.cover
59 | *.py,cover
60 | .hypothesis/
61 | .pytest_cache/
62 | cover/
63 |
64 | # Translations
65 | *.mo
66 | *.pot
67 |
68 | # Django stuff:
69 | *.log
70 | local_settings.py
71 | db.sqlite3
72 | db.sqlite3-journal
73 |
74 | # Flask stuff:
75 | instance/
76 | .webassets-cache
77 |
78 | # Scrapy stuff:
79 | .scrapy
80 |
81 | # Sphinx documentation
82 | docs/_build/
83 |
84 | # PyBuilder
85 | .pybuilder/
86 | target/
87 |
88 | # Jupyter Notebook
89 | .ipynb_checkpoints
90 |
91 | # IPython
92 | profile_default/
93 | ipython_config.py
94 |
95 | # pyenv
96 | # For a library or package, you might want to ignore these files since the code is
97 | # intended to run in multiple environments; otherwise, check them in:
98 | # .python-version
99 |
100 | # pipenv
101 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
102 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
103 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
104 | # install all needed dependencies.
105 | #Pipfile.lock
106 |
107 | # poetry
108 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
109 | # This is especially recommended for binary packages to ensure reproducibility, and is more
110 | # commonly ignored for libraries.
111 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
112 | #poetry.lock
113 |
114 | # pdm
115 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
116 | #pdm.lock
117 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
118 | # in version control.
119 | # https://pdm.fming.dev/#use-with-ide
120 | .pdm.toml
121 |
122 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
123 | __pypackages__/
124 |
125 | # Celery stuff
126 | celerybeat-schedule
127 | celerybeat.pid
128 |
129 | # SageMath parsed files
130 | *.sage.py
131 |
132 | # Environments
133 | .env
134 | .venv
135 | env/
136 | venv/
137 | ENV/
138 | env.bak/
139 | venv.bak/
140 |
141 | # Spyder project settings
142 | .spyderproject
143 | .spyproject
144 |
145 | # Rope project settings
146 | .ropeproject
147 |
148 | # mkdocs documentation
149 | /site
150 |
151 | # mypy
152 | .mypy_cache/
153 | .dmypy.json
154 | dmypy.json
155 |
156 | # Pyre type checker
157 | .pyre/
158 |
159 | # pytype static type analyzer
160 | .pytype/
161 |
162 | # Cython debug symbols
163 | cython_debug/
164 |
165 | # PyCharm
166 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
167 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
168 | # and can be added to the global gitignore or merged into this file. For a more nuclear
169 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
170 | #.idea/
--------------------------------------------------------------------------------
/shivu/modules/inlinequery.py:
--------------------------------------------------------------------------------
1 | import re
2 | import time
3 | from html import escape
4 | from cachetools import TTLCache
5 | from pymongo import MongoClient, ASCENDING
6 |
7 | from telegram import Update, InlineQueryResultPhoto
8 | from telegram.ext import InlineQueryHandler, CallbackContext, CommandHandler
9 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup
10 |
11 | from shivu import user_collection, collection, application, db
12 |
13 |
14 | # collection
15 | db.characters.create_index([('id', ASCENDING)])
16 | db.characters.create_index([('anime', ASCENDING)])
17 | db.characters.create_index([('img_url', ASCENDING)])
18 |
19 | # user_collection
20 | db.user_collection.create_index([('characters.id', ASCENDING)])
21 | db.user_collection.create_index([('characters.name', ASCENDING)])
22 | db.user_collection.create_index([('characters.img_url', ASCENDING)])
23 |
24 | all_characters_cache = TTLCache(maxsize=10000, ttl=36000)
25 | user_collection_cache = TTLCache(maxsize=10000, ttl=60)
26 |
27 | async def inlinequery(update: Update, context: CallbackContext) -> None:
28 | query = update.inline_query.query
29 | offset = int(update.inline_query.offset) if update.inline_query.offset else 0
30 |
31 | if query.startswith('collection.'):
32 | user_id, *search_terms = query.split(' ')[0].split('.')[1], ' '.join(query.split(' ')[1:])
33 | if user_id.isdigit():
34 | if user_id in user_collection_cache:
35 | user = user_collection_cache[user_id]
36 | else:
37 | user = await user_collection.find_one({'id': int(user_id)})
38 | user_collection_cache[user_id] = user
39 |
40 | if user:
41 | all_characters = list({v['id']:v for v in user['characters']}.values())
42 | if search_terms:
43 | regex = re.compile(' '.join(search_terms), re.IGNORECASE)
44 | all_characters = [character for character in all_characters if regex.search(character['name']) or regex.search(character['anime'])]
45 | else:
46 | all_characters = []
47 | else:
48 | all_characters = []
49 | else:
50 | if query:
51 | regex = re.compile(query, re.IGNORECASE)
52 | all_characters = list(await collection.find({"$or": [{"name": regex}, {"anime": regex}]}).to_list(length=None))
53 | else:
54 | if 'all_characters' in all_characters_cache:
55 | all_characters = all_characters_cache['all_characters']
56 | else:
57 | all_characters = list(await collection.find({}).to_list(length=None))
58 | all_characters_cache['all_characters'] = all_characters
59 |
60 | characters = all_characters[offset:offset+50]
61 | if len(characters) > 50:
62 | characters = characters[:50]
63 | next_offset = str(offset + 50)
64 | else:
65 | next_offset = str(offset + len(characters))
66 |
67 | results = []
68 | for character in characters:
69 | global_count = await user_collection.count_documents({'characters.id': character['id']})
70 | anime_characters = await collection.count_documents({'anime': character['anime']})
71 |
72 | if query.startswith('collection.'):
73 | user_character_count = sum(c['id'] == character['id'] for c in user['characters'])
74 | user_anime_characters = sum(c['anime'] == character['anime'] for c in user['characters'])
75 | caption = f" Look At {(escape(user.get('first_name', user['id'])))}'s Character\n\n🌸: {character['name']} (x{user_character_count})\n🏖️: {character['anime']} ({user_anime_characters}/{anime_characters})\n{character['rarity']}\n\n🆔️: {character['id']}"
76 | else:
77 | caption = f"Look At This Character !!\n\n🌸: {character['name']}\n🏖️: {character['anime']}\n{character['rarity']}\n🆔️: {character['id']}\n\nGlobally Guessed {global_count} Times..."
78 | results.append(
79 | InlineQueryResultPhoto(
80 | thumbnail_url=character['img_url'],
81 | id=f"{character['id']}_{time.time()}",
82 | photo_url=character['img_url'],
83 | caption=caption,
84 | parse_mode='HTML'
85 | )
86 | )
87 |
88 | await update.inline_query.answer(results, next_offset=next_offset, cache_time=5)
89 |
90 | application.add_handler(InlineQueryHandler(inlinequery, block=False))
91 |
--------------------------------------------------------------------------------
/shivu/modules/eval.py:
--------------------------------------------------------------------------------
1 | #credit @ishikki_Akabane
2 |
3 | import io
4 | import os
5 | import textwrap
6 | import traceback
7 | from contextlib import redirect_stdout
8 |
9 | from shivu import application, LOGGER
10 | from telegram import Update
11 | from telegram.constants import ChatID, ParseMode
12 | from telegram.ext import ContextTypes, CommandHandler
13 | from telegram.ext import CallbackContext
14 |
15 | namespaces = {}
16 | DEV_LIST = [6404226395]
17 |
18 | def namespace_of(chat, update, bot):
19 | if chat not in namespaces:
20 | namespaces[chat] = {
21 | "__builtins__": globals()["__builtins__"],
22 | "bot": bot,
23 | "effective_message": update.effective_message,
24 | "effective_user": update.effective_user,
25 | "effective_chat": update.effective_chat,
26 | "update": update,
27 | }
28 |
29 | return namespaces[chat]
30 |
31 |
32 | def log_input(update):
33 | user = update.effective_user.id
34 | chat = update.effective_chat.id
35 | LOGGER.info(f"IN: {update.effective_message.text} (user={user}, chat={chat})")
36 |
37 |
38 | async def send(msg, bot, update):
39 | if len(str(msg)) > 2000:
40 | with io.BytesIO(str.encode(msg)) as out_file:
41 | out_file.name = "output.txt"
42 | await bot.send_document(
43 | chat_id=update.effective_chat.id,
44 | document=out_file,
45 | message_thread_id=update.effective_message.message_thread_id if update.effective_chat.is_forum else None
46 | )
47 | else:
48 | LOGGER.info(f"OUT: '{msg}'")
49 | await bot.send_message(
50 | chat_id=update.effective_chat.id,
51 | text=f"`{msg}`",
52 | parse_mode=ParseMode.MARKDOWN,
53 | message_thread_id=update.effective_message.message_thread_id if update.effective_chat.is_forum else None
54 | )
55 |
56 |
57 | async def evaluate(update: Update, context: ContextTypes.DEFAULT_TYPE):
58 | if update.effective_message.from_user.id not in DEV_LIST:
59 | return
60 |
61 | bot = context.bot
62 | await send(await do(eval, bot, update), bot, update)
63 |
64 |
65 | async def execute(update: Update, context: ContextTypes.DEFAULT_TYPE):
66 | if update.effective_message.from_user.id not in DEV_LIST:
67 | return
68 |
69 | bot = context.bot
70 | await send(await do(exec, bot, update), bot, update)
71 |
72 |
73 | def cleanup_code(code):
74 | if code.startswith("```") and code.endswith("```"):
75 | return "\n".join(code.split("\n")[1:-1])
76 | return code.strip("` \n")
77 |
78 |
79 | async def do(func, bot, update):
80 | log_input(update)
81 | content = update.message.text.split(" ", 1)[-1]
82 | body = cleanup_code(content)
83 | env = namespace_of(update.message.chat_id, update, bot)
84 |
85 | os.chdir(os.getcwd())
86 | with open(
87 | "temp.txt", "w",
88 | ) as temp:
89 | temp.write(body)
90 |
91 | stdout = io.StringIO()
92 |
93 | to_compile = f'async def func():\n{textwrap.indent(body, " ")}'
94 |
95 | try:
96 | exec(to_compile, env)
97 | except Exception as e:
98 | return f"{e.__class__.__name__}: {e}"
99 |
100 | func = env["func"]
101 |
102 | try:
103 | with redirect_stdout(stdout):
104 | func_return = await func()
105 | except Exception as e:
106 | value = stdout.getvalue()
107 | return f"{value}{traceback.format_exc()}"
108 | else:
109 | value = stdout.getvalue()
110 | result = None
111 | if func_return is None:
112 | if value:
113 | result = f"{value}"
114 | else:
115 | try:
116 | result = f"{repr(eval(body, env))}"
117 | except:
118 | pass
119 | else:
120 | result = f"{value}{func_return}"
121 | if result:
122 | return result
123 |
124 |
125 | async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE):
126 | if update.effective_message.from_user.id not in DEV_LIST:
127 | return
128 |
129 | bot = context.bot
130 | log_input(update)
131 | global namespaces
132 | if update.message.chat_id in namespaces:
133 | del namespaces[update.message.chat_id]
134 | await send("Cleared locals.", bot, update)
135 |
136 |
137 | EVAL_HANDLER = CommandHandler(("e", "ev", "eva", "eval"), evaluate, block=False)
138 | EXEC_HANDLER = CommandHandler(("x", "ex", "exe", "exec", "py"), execute, block=False)
139 | CLEAR_HANDLER = CommandHandler("clearlocals", clear, block=False)
140 |
141 | application.add_handler(EVAL_HANDLER)
142 | application.add_handler(EXEC_HANDLER)
143 | application.add_handler(CLEAR_HANDLER)
144 |
--------------------------------------------------------------------------------
/shivu/modules/harem.py:
--------------------------------------------------------------------------------
1 | from telegram import Update
2 | from itertools import groupby
3 | import math
4 | from html import escape
5 | import random
6 |
7 | from telegram.ext import CommandHandler, CallbackContext, CallbackQueryHandler
8 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup
9 |
10 | from shivu import collection, user_collection, application
11 |
12 | async def harem(update: Update, context: CallbackContext, page=0) -> None:
13 | user_id = update.effective_user.id
14 |
15 | user = await user_collection.find_one({'id': user_id})
16 | if not user:
17 | if update.message:
18 | await update.message.reply_text('You Have Not Guessed any Characters Yet..')
19 | else:
20 | await update.callback_query.edit_message_text('You Have Not Guessed any Characters Yet..')
21 | return
22 |
23 | characters = sorted(user['characters'], key=lambda x: (x['anime'], x['id']))
24 |
25 | character_counts = {k: len(list(v)) for k, v in groupby(characters, key=lambda x: x['id'])}
26 |
27 |
28 | unique_characters = list({character['id']: character for character in characters}.values())
29 |
30 |
31 | total_pages = math.ceil(len(unique_characters) / 15)
32 |
33 | if page < 0 or page >= total_pages:
34 | page = 0
35 |
36 | harem_message = f"{escape(update.effective_user.first_name)}'s Harem - Page {page+1}/{total_pages}\n"
37 |
38 |
39 | current_characters = unique_characters[page*15:(page+1)*15]
40 |
41 |
42 | current_grouped_characters = {k: list(v) for k, v in groupby(current_characters, key=lambda x: x['anime'])}
43 |
44 | for anime, characters in current_grouped_characters.items():
45 | harem_message += f'\n{anime} {len(characters)}/{await collection.count_documents({"anime": anime})}\n'
46 |
47 | for character in characters:
48 |
49 | count = character_counts[character['id']]
50 | harem_message += f'{character["id"]} {character["name"]} ×{count}\n'
51 |
52 |
53 | total_count = len(user['characters'])
54 |
55 | keyboard = [[InlineKeyboardButton(f"See Collection ({total_count})", switch_inline_query_current_chat=f"collection.{user_id}")]]
56 |
57 |
58 | if total_pages > 1:
59 |
60 | nav_buttons = []
61 | if page > 0:
62 | nav_buttons.append(InlineKeyboardButton("⬅️", callback_data=f"harem:{page-1}:{user_id}"))
63 | if page < total_pages - 1:
64 | nav_buttons.append(InlineKeyboardButton("➡️", callback_data=f"harem:{page+1}:{user_id}"))
65 | keyboard.append(nav_buttons)
66 |
67 | reply_markup = InlineKeyboardMarkup(keyboard)
68 |
69 | if 'favorites' in user and user['favorites']:
70 |
71 | fav_character_id = user['favorites'][0]
72 | fav_character = next((c for c in user['characters'] if c['id'] == fav_character_id), None)
73 |
74 | if fav_character and 'img_url' in fav_character:
75 | if update.message:
76 | await update.message.reply_photo(photo=fav_character['img_url'], parse_mode='HTML', caption=harem_message, reply_markup=reply_markup)
77 | else:
78 |
79 | if update.callback_query.message.caption != harem_message:
80 | await update.callback_query.edit_message_caption(caption=harem_message, reply_markup=reply_markup, parse_mode='HTML')
81 | else:
82 | if update.message:
83 | await update.message.reply_text(harem_message, parse_mode='HTML', reply_markup=reply_markup)
84 | else:
85 |
86 | if update.callback_query.message.text != harem_message:
87 | await update.callback_query.edit_message_text(harem_message, parse_mode='HTML', reply_markup=reply_markup)
88 | else:
89 |
90 | if user['characters']:
91 |
92 | random_character = random.choice(user['characters'])
93 |
94 | if 'img_url' in random_character:
95 | if update.message:
96 | await update.message.reply_photo(photo=random_character['img_url'], parse_mode='HTML', caption=harem_message, reply_markup=reply_markup)
97 | else:
98 |
99 | if update.callback_query.message.caption != harem_message:
100 | await update.callback_query.edit_message_caption(caption=harem_message, reply_markup=reply_markup, parse_mode='HTML')
101 | else:
102 | if update.message:
103 | await update.message.reply_text(harem_message, parse_mode='HTML', reply_markup=reply_markup)
104 | else:
105 |
106 | if update.callback_query.message.text != harem_message:
107 | await update.callback_query.edit_message_text(harem_message, parse_mode='HTML', reply_markup=reply_markup)
108 | else:
109 | if update.message:
110 | await update.message.reply_text("Your List is Empty :)")
111 |
112 |
113 | async def harem_callback(update: Update, context: CallbackContext) -> None:
114 | query = update.callback_query
115 | data = query.data
116 |
117 |
118 | _, page, user_id = data.split(':')
119 |
120 |
121 | page = int(page)
122 | user_id = int(user_id)
123 |
124 |
125 | if query.from_user.id != user_id:
126 | await query.answer("its Not Your Harem", show_alert=True)
127 | return
128 |
129 |
130 | await harem(update, context, page)
131 |
132 |
133 |
134 |
135 | application.add_handler(CommandHandler(["harem", "collection"], harem,block=False))
136 | harem_handler = CallbackQueryHandler(harem_callback, pattern='^harem', block=False)
137 | application.add_handler(harem_handler)
138 |
139 |
--------------------------------------------------------------------------------
/shivu/modules/start.py:
--------------------------------------------------------------------------------
1 | import random
2 | from html import escape
3 |
4 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
5 | from telegram.ext import CallbackContext, CallbackQueryHandler, CommandHandler
6 |
7 | from shivu import application, PHOTO_URL, SUPPORT_CHAT, UPDATE_CHAT, BOT_USERNAME, db, GROUP_ID
8 | from shivu import pm_users as collection
9 |
10 |
11 | async def start(update: Update, context: CallbackContext) -> None:
12 | user_id = update.effective_user.id
13 | first_name = update.effective_user.first_name
14 | username = update.effective_user.username
15 |
16 | user_data = await collection.find_one({"_id": user_id})
17 |
18 | if user_data is None:
19 |
20 | await collection.insert_one({"_id": user_id, "first_name": first_name, "username": username})
21 |
22 | await context.bot.send_message(chat_id=GROUP_ID,
23 | text=f"New user Started The Bot..\n User: {escape(first_name)})",
24 | parse_mode='HTML')
25 | else:
26 |
27 | if user_data['first_name'] != first_name or user_data['username'] != username:
28 |
29 | await collection.update_one({"_id": user_id}, {"$set": {"first_name": first_name, "username": username}})
30 |
31 |
32 |
33 | if update.effective_chat.type== "private":
34 |
35 |
36 | caption = f"""
37 | ***Heyyyy...***
38 |
39 | ***I am An Open Source Character Catcher Bot...Add Me in Your group.. And I will send Random Characters After.. every 100 messages in Group... Use /guess to.. Collect that Characters in Your Collection.. and see Collection by using /Harem... So add in Your groups and Collect Your harem***
40 | """
41 |
42 | keyboard = [
43 | [InlineKeyboardButton("ADD ME", url=f'http://t.me/{BOT_USERNAME}?startgroup=new')],
44 | [InlineKeyboardButton("SUPPORT", url=f'https://t.me/{SUPPORT_CHAT}'),
45 | InlineKeyboardButton("UPDATES", url=f'https://t.me/{UPDATE_CHAT}')],
46 | [InlineKeyboardButton("HELP", callback_data='help')],
47 | [InlineKeyboardButton("SOURCE", url=f'https://github.com/MyNameIsShekhar/WAIFU-HUSBANDO-CATCHER')]
48 | ]
49 | reply_markup = InlineKeyboardMarkup(keyboard)
50 | photo_url = random.choice(PHOTO_URL)
51 |
52 | await context.bot.send_photo(chat_id=update.effective_chat.id, photo=photo_url, caption=caption, reply_markup=reply_markup, parse_mode='markdown')
53 |
54 | else:
55 | photo_url = random.choice(PHOTO_URL)
56 | keyboard = [
57 | [InlineKeyboardButton("ADD ME", url=f'http://t.me/{BOT_USERNAME}?startgroup=new')],
58 | [InlineKeyboardButton("SUPPORT", url=f'https://t.me/{SUPPORT_CHAT}'),
59 | InlineKeyboardButton("UPDATES", url=f'https://t.me/{UPDATE_CHAT}')],
60 | [InlineKeyboardButton("HELP", callback_data='help')],
61 | [InlineKeyboardButton("SOURCE", url=f'https://github.com/MyNameIsShekhar/WAIFU-HUSBANDO-CATCHER')]
62 | ]
63 |
64 | reply_markup = InlineKeyboardMarkup(keyboard)
65 | await context.bot.send_photo(chat_id=update.effective_chat.id, photo=photo_url, caption="🎴Alive!?... \n connect to me in PM For more information ",reply_markup=reply_markup )
66 |
67 | async def button(update: Update, context: CallbackContext) -> None:
68 | query = update.callback_query
69 | await query.answer()
70 |
71 | if query.data == 'help':
72 | help_text = """
73 | ***Help Section:***
74 |
75 | ***/guess: To Guess character (only works in group)***
76 | ***/fav: Add Your fav***
77 | ***/trade : To trade Characters***
78 | ***/gift: Give any Character from Your Collection to another user.. (only works in groups)***
79 | ***/collection: To see Your Collection***
80 | ***/topgroups : See Top Groups.. Ppl Guesses Most in that Groups***
81 | ***/top: Too See Top Users***
82 | ***/ctop : Your ChatTop***
83 | ***/changetime: Change Character appear time (only works in Groups)***
84 | """
85 | help_keyboard = [[InlineKeyboardButton("⤾ Bᴀᴄᴋ", callback_data='back')]]
86 | reply_markup = InlineKeyboardMarkup(help_keyboard)
87 |
88 | await context.bot.edit_message_caption(chat_id=update.effective_chat.id, message_id=query.message.message_id, caption=help_text, reply_markup=reply_markup, parse_mode='markdown')
89 |
90 | elif query.data == 'back':
91 |
92 | caption = f"""
93 | ***Hoyyyy...*** ✨
94 |
95 | ***I am An Open Source Character Catcher Bot..Add Me in Your group.. And I will send Random Characters After.. every 100 messages in Group... Use /guess to.. Collect that Characters in Your Collection.. and see Collection by using /Harem... So add in Your groups and Collect Your harem***
96 | """
97 |
98 |
99 | keyboard = [
100 | [InlineKeyboardButton("ADD ME", url=f'http://t.me/{BOT_USERNAME}?startgroup=new')],
101 | [InlineKeyboardButton("SUPPORT", url=f'https://t.me/{SUPPORT_CHAT}'),
102 | InlineKeyboardButton("UPDATES", url=f'https://t.me/{UPDATE_CHAT}')],
103 | [InlineKeyboardButton("HELP", callback_data='help')],
104 | [InlineKeyboardButton("SOURCE", url=f'https://github.com/MyNameIsShekhar/WAIFU-HUSBANDO-CATCHER')]
105 | ]
106 | reply_markup = InlineKeyboardMarkup(keyboard)
107 |
108 | await context.bot.edit_message_caption(chat_id=update.effective_chat.id, message_id=query.message.message_id, caption=caption, reply_markup=reply_markup, parse_mode='markdown')
109 |
110 |
111 | application.add_handler(CallbackQueryHandler(button, pattern='^help$|^back$', block=False))
112 | start_handler = CommandHandler('start', start, block=False)
113 | application.add_handler(start_handler)
114 |
--------------------------------------------------------------------------------
/shivu/modules/leaderboard.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | import html
4 |
5 | from telegram import Update
6 | from telegram.ext import CommandHandler, CallbackContext
7 |
8 | from shivu import (application, PHOTO_URL, OWNER_ID,
9 | user_collection, top_global_groups_collection, top_global_groups_collection,
10 | group_user_totals_collection)
11 |
12 | from shivu import sudo_users as SUDO_USERS
13 |
14 |
15 | async def global_leaderboard(update: Update, context: CallbackContext) -> None:
16 |
17 | cursor = top_global_groups_collection.aggregate([
18 | {"$project": {"group_name": 1, "count": 1}},
19 | {"$sort": {"count": -1}},
20 | {"$limit": 10}
21 | ])
22 | leaderboard_data = await cursor.to_list(length=10)
23 |
24 | leaderboard_message = "TOP 10 GROUPS WHO GUESSED MOST CHARACTERS\n\n"
25 |
26 | for i, group in enumerate(leaderboard_data, start=1):
27 | group_name = html.escape(group.get('group_name', 'Unknown'))
28 |
29 | if len(group_name) > 10:
30 | group_name = group_name[:15] + '...'
31 | count = group['count']
32 | leaderboard_message += f'{i}. {group_name} ➾ {count}\n'
33 |
34 |
35 | photo_url = random.choice(PHOTO_URL)
36 |
37 | await update.message.reply_photo(photo=photo_url, caption=leaderboard_message, parse_mode='HTML')
38 |
39 | async def ctop(update: Update, context: CallbackContext) -> None:
40 | chat_id = update.effective_chat.id
41 |
42 | cursor = group_user_totals_collection.aggregate([
43 | {"$match": {"group_id": chat_id}},
44 | {"$project": {"username": 1, "first_name": 1, "character_count": "$count"}},
45 | {"$sort": {"character_count": -1}},
46 | {"$limit": 10}
47 | ])
48 | leaderboard_data = await cursor.to_list(length=10)
49 |
50 | leaderboard_message = "TOP 10 USERS WHO GUESSED CHARACTERS MOST TIME IN THIS GROUP..\n\n"
51 |
52 | for i, user in enumerate(leaderboard_data, start=1):
53 | username = user.get('username', 'Unknown')
54 | first_name = html.escape(user.get('first_name', 'Unknown'))
55 |
56 | if len(first_name) > 10:
57 | first_name = first_name[:15] + '...'
58 | character_count = user['character_count']
59 | leaderboard_message += f'{i}. {first_name} ➾ {character_count}\n'
60 |
61 | photo_url = random.choice(PHOTO_URL)
62 |
63 | await update.message.reply_photo(photo=photo_url, caption=leaderboard_message, parse_mode='HTML')
64 |
65 |
66 | async def leaderboard(update: Update, context: CallbackContext) -> None:
67 |
68 | cursor = user_collection.aggregate([
69 | {"$project": {"username": 1, "first_name": 1, "character_count": {"$size": "$characters"}}},
70 | {"$sort": {"character_count": -1}},
71 | {"$limit": 10}
72 | ])
73 | leaderboard_data = await cursor.to_list(length=10)
74 |
75 | leaderboard_message = "TOP 10 USERS WITH MOST CHARACTERS\n\n"
76 |
77 | for i, user in enumerate(leaderboard_data, start=1):
78 | username = user.get('username', 'Unknown')
79 | first_name = html.escape(user.get('first_name', 'Unknown'))
80 |
81 | if len(first_name) > 10:
82 | first_name = first_name[:15] + '...'
83 | character_count = user['character_count']
84 | leaderboard_message += f'{i}. {first_name} ➾ {character_count}\n'
85 |
86 | photo_url = random.choice(PHOTO_URL)
87 |
88 | await update.message.reply_photo(photo=photo_url, caption=leaderboard_message, parse_mode='HTML')
89 |
90 |
91 |
92 |
93 | async def stats(update: Update, context: CallbackContext) -> None:
94 |
95 | if update.effective_user.id != OWNER_ID:
96 | await update.message.reply_text("You are not authorized to use this command.")
97 | return
98 |
99 |
100 | user_count = await user_collection.count_documents({})
101 |
102 |
103 | group_count = await group_user_totals_collection.distinct('group_id')
104 |
105 |
106 | await update.message.reply_text(f'Total Users: {user_count}\nTotal groups: {len(group_count)}')
107 |
108 |
109 |
110 |
111 | async def send_users_document(update: Update, context: CallbackContext) -> None:
112 | if str(update.effective_user.id) not in SUDO_USERS:
113 | update.message.reply_text('only For Sudo users...')
114 | return
115 | cursor = user_collection.find({})
116 | users = []
117 | async for document in cursor:
118 | users.append(document)
119 | user_list = ""
120 | for user in users:
121 | user_list += f"{user['first_name']}\n"
122 | with open('users.txt', 'w') as f:
123 | f.write(user_list)
124 | with open('users.txt', 'rb') as f:
125 | await context.bot.send_document(chat_id=update.effective_chat.id, document=f)
126 | os.remove('users.txt')
127 |
128 | async def send_groups_document(update: Update, context: CallbackContext) -> None:
129 | if str(update.effective_user.id) not in SUDO_USERS:
130 | update.message.reply_text('Only For Sudo users...')
131 | return
132 | cursor = top_global_groups_collection.find({})
133 | groups = []
134 | async for document in cursor:
135 | groups.append(document)
136 | group_list = ""
137 | for group in groups:
138 | group_list += f"{group['group_name']}\n"
139 | group_list += "\n"
140 | with open('groups.txt', 'w') as f:
141 | f.write(group_list)
142 | with open('groups.txt', 'rb') as f:
143 | await context.bot.send_document(chat_id=update.effective_chat.id, document=f)
144 | os.remove('groups.txt')
145 |
146 |
147 | application.add_handler(CommandHandler('ctop', ctop, block=False))
148 | application.add_handler(CommandHandler('stats', stats, block=False))
149 | application.add_handler(CommandHandler('TopGroups', global_leaderboard, block=False))
150 |
151 | application.add_handler(CommandHandler('list', send_users_document, block=False))
152 | application.add_handler(CommandHandler('groups', send_groups_document, block=False))
153 |
154 |
155 | application.add_handler(CommandHandler('top', leaderboard, block=False))
156 |
157 |
--------------------------------------------------------------------------------
/shivu/modules/upload.py:
--------------------------------------------------------------------------------
1 | import urllib.request
2 | from pymongo import ReturnDocument
3 |
4 | from telegram import Update
5 | from telegram.ext import CommandHandler, CallbackContext
6 |
7 | from shivu import application, sudo_users, collection, db, CHARA_CHANNEL_ID, SUPPORT_CHAT
8 |
9 | WRONG_FORMAT_TEXT = """Wrong ❌️ format... eg. /upload Img_url muzan-kibutsuji Demon-slayer 3
10 |
11 | img_url character-name anime-name rarity-number
12 |
13 | use rarity number accordingly rarity Map
14 |
15 | rarity_map = 1 (⚪️ Common), 2 (🟣 Rare) , 3 (🟡 Legendary), 4 (🟢 Medium)"""
16 |
17 |
18 |
19 | async def get_next_sequence_number(sequence_name):
20 | sequence_collection = db.sequences
21 | sequence_document = await sequence_collection.find_one_and_update(
22 | {'_id': sequence_name},
23 | {'$inc': {'sequence_value': 1}},
24 | return_document=ReturnDocument.AFTER
25 | )
26 | if not sequence_document:
27 | await sequence_collection.insert_one({'_id': sequence_name, 'sequence_value': 0})
28 | return 0
29 | return sequence_document['sequence_value']
30 |
31 | async def upload(update: Update, context: CallbackContext) -> None:
32 | if str(update.effective_user.id) not in sudo_users:
33 | await update.message.reply_text('Ask My Owner...')
34 | return
35 |
36 | try:
37 | args = context.args
38 | if len(args) != 4:
39 | await update.message.reply_text(WRONG_FORMAT_TEXT)
40 | return
41 |
42 | character_name = args[1].replace('-', ' ').title()
43 | anime = args[2].replace('-', ' ').title()
44 |
45 | try:
46 | urllib.request.urlopen(args[0])
47 | except:
48 | await update.message.reply_text('Invalid URL.')
49 | return
50 |
51 | rarity_map = {1: "⚪ Common", 2: "🟣 Rare", 3: "🟡 Legendary", 4: "🟢 Medium"}
52 | try:
53 | rarity = rarity_map[int(args[3])]
54 | except KeyError:
55 | await update.message.reply_text('Invalid rarity. Please use 1, 2, 3, 4, or 5.')
56 | return
57 |
58 | id = str(await get_next_sequence_number('character_id')).zfill(2)
59 |
60 | character = {
61 | 'img_url': args[0],
62 | 'name': character_name,
63 | 'anime': anime,
64 | 'rarity': rarity,
65 | 'id': id
66 | }
67 |
68 | try:
69 | message = await context.bot.send_photo(
70 | chat_id=CHARA_CHANNEL_ID,
71 | photo=args[0],
72 | caption=f'Character Name: {character_name}\nAnime Name: {anime}\nRarity: {rarity}\nID: {id}\nAdded by {update.effective_user.first_name}',
73 | parse_mode='HTML'
74 | )
75 | character['message_id'] = message.message_id
76 | await collection.insert_one(character)
77 | await update.message.reply_text('CHARACTER ADDED....')
78 | except:
79 | await collection.insert_one(character)
80 | update.effective_message.reply_text("Character Added but no Database Channel Found, Consider adding one.")
81 |
82 | except Exception as e:
83 | await update.message.reply_text(f'Character Upload Unsuccessful. Error: {str(e)}\nIf you think this is a source error, forward to: {SUPPORT_CHAT}')
84 |
85 | async def delete(update: Update, context: CallbackContext) -> None:
86 | if str(update.effective_user.id) not in sudo_users:
87 | await update.message.reply_text('Ask my Owner to use this Command...')
88 | return
89 |
90 | try:
91 | args = context.args
92 | if len(args) != 1:
93 | await update.message.reply_text('Incorrect format... Please use: /delete ID')
94 | return
95 |
96 |
97 | character = await collection.find_one_and_delete({'id': args[0]})
98 |
99 | if character:
100 |
101 | await context.bot.delete_message(chat_id=CHARA_CHANNEL_ID, message_id=character['message_id'])
102 | await update.message.reply_text('DONE')
103 | else:
104 | await update.message.reply_text('Deleted Successfully from db, but character not found In Channel')
105 | except Exception as e:
106 | await update.message.reply_text(f'{str(e)}')
107 |
108 | async def update(update: Update, context: CallbackContext) -> None:
109 | if str(update.effective_user.id) not in sudo_users:
110 | await update.message.reply_text('You do not have permission to use this command.')
111 | return
112 |
113 | try:
114 | args = context.args
115 | if len(args) != 3:
116 | await update.message.reply_text('Incorrect format. Please use: /update id field new_value')
117 | return
118 |
119 | # Get character by ID
120 | character = await collection.find_one({'id': args[0]})
121 | if not character:
122 | await update.message.reply_text('Character not found.')
123 | return
124 |
125 | # Check if field is valid
126 | valid_fields = ['img_url', 'name', 'anime', 'rarity']
127 | if args[1] not in valid_fields:
128 | await update.message.reply_text(f'Invalid field. Please use one of the following: {", ".join(valid_fields)}')
129 | return
130 |
131 | # Update field
132 | if args[1] in ['name', 'anime']:
133 | new_value = args[2].replace('-', ' ').title()
134 | elif args[1] == 'rarity':
135 | rarity_map = {1: "⚪ Common", 2: "🟣 Rare", 3: "🟡 Legendary", 4: "🟢 Medium", 5: "💮 Special edition"}
136 | try:
137 | new_value = rarity_map[int(args[2])]
138 | except KeyError:
139 | await update.message.reply_text('Invalid rarity. Please use 1, 2, 3, 4, or 5.')
140 | return
141 | else:
142 | new_value = args[2]
143 |
144 | await collection.find_one_and_update({'id': args[0]}, {'$set': {args[1]: new_value}})
145 |
146 |
147 | if args[1] == 'img_url':
148 | await context.bot.delete_message(chat_id=CHARA_CHANNEL_ID, message_id=character['message_id'])
149 | message = await context.bot.send_photo(
150 | chat_id=CHARA_CHANNEL_ID,
151 | photo=new_value,
152 | caption=f'Character Name: {character["name"]}\nAnime Name: {character["anime"]}\nRarity: {character["rarity"]}\nID: {character["id"]}\nUpdated by {update.effective_user.first_name}',
153 | parse_mode='HTML'
154 | )
155 | character['message_id'] = message.message_id
156 | await collection.find_one_and_update({'id': args[0]}, {'$set': {'message_id': message.message_id}})
157 | else:
158 |
159 | await context.bot.edit_message_caption(
160 | chat_id=CHARA_CHANNEL_ID,
161 | message_id=character['message_id'],
162 | caption=f'Character Name: {character["name"]}\nAnime Name: {character["anime"]}\nRarity: {character["rarity"]}\nID: {character["id"]}\nUpdated by {update.effective_user.first_name}',
163 | parse_mode='HTML'
164 | )
165 |
166 | await update.message.reply_text('Updated Done in Database.... But sometimes it Takes Time to edit Caption in Your Channel..So wait..')
167 | except Exception as e:
168 | await update.message.reply_text(f'I guess did not added bot in channel.. or character uploaded Long time ago.. Or character not exits.. orr Wrong id')
169 |
170 | UPLOAD_HANDLER = CommandHandler('upload', upload, block=False)
171 | application.add_handler(UPLOAD_HANDLER)
172 | DELETE_HANDLER = CommandHandler('delete', delete, block=False)
173 | application.add_handler(DELETE_HANDLER)
174 | UPDATE_HANDLER = CommandHandler('update', update, block=False)
175 | application.add_handler(UPDATE_HANDLER)
176 |
--------------------------------------------------------------------------------
/shivu/modules/trade.py:
--------------------------------------------------------------------------------
1 | from pyrogram import filters
2 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
3 |
4 | from shivu import user_collection, shivuu
5 |
6 | pending_trades = {}
7 |
8 |
9 | @shivuu.on_message(filters.command("trade"))
10 | async def trade(client, message):
11 | sender_id = message.from_user.id
12 |
13 | if not message.reply_to_message:
14 | await message.reply_text("You need to reply to a user's message to trade a character!")
15 | return
16 |
17 | receiver_id = message.reply_to_message.from_user.id
18 |
19 | if sender_id == receiver_id:
20 | await message.reply_text("You can't trade a character with yourself!")
21 | return
22 |
23 | if len(message.command) != 3:
24 | await message.reply_text("You need to provide two character IDs!")
25 | return
26 |
27 | sender_character_id, receiver_character_id = message.command[1], message.command[2]
28 |
29 | sender = await user_collection.find_one({'id': sender_id})
30 | receiver = await user_collection.find_one({'id': receiver_id})
31 |
32 | sender_character = next((character for character in sender['characters'] if character['id'] == sender_character_id), None)
33 | receiver_character = next((character for character in receiver['characters'] if character['id'] == receiver_character_id), None)
34 |
35 | if not sender_character:
36 | await message.reply_text("You don't have the character you're trying to trade!")
37 | return
38 |
39 | if not receiver_character:
40 | await message.reply_text("The other user doesn't have the character they're trying to trade!")
41 | return
42 |
43 |
44 |
45 |
46 |
47 |
48 | if len(message.command) != 3:
49 | await message.reply_text("/trade [Your Character ID] [Other User Character ID]!")
50 | return
51 |
52 | sender_character_id, receiver_character_id = message.command[1], message.command[2]
53 |
54 |
55 | pending_trades[(sender_id, receiver_id)] = (sender_character_id, receiver_character_id)
56 |
57 |
58 | keyboard = InlineKeyboardMarkup(
59 | [
60 | [InlineKeyboardButton("Confirm Trade", callback_data="confirm_trade")],
61 | [InlineKeyboardButton("Cancel Trade", callback_data="cancel_trade")]
62 | ]
63 | )
64 |
65 | await message.reply_text(f"{message.reply_to_message.from_user.mention}, do you accept this trade?", reply_markup=keyboard)
66 |
67 |
68 | @shivuu.on_callback_query(filters.create(lambda _, __, query: query.data in ["confirm_trade", "cancel_trade"]))
69 | async def on_callback_query(client, callback_query):
70 | receiver_id = callback_query.from_user.id
71 |
72 |
73 | for (sender_id, _receiver_id), (sender_character_id, receiver_character_id) in pending_trades.items():
74 | if _receiver_id == receiver_id:
75 | break
76 | else:
77 | await callback_query.answer("This is not for you!", show_alert=True)
78 | return
79 |
80 | if callback_query.data == "confirm_trade":
81 |
82 | sender = await user_collection.find_one({'id': sender_id})
83 | receiver = await user_collection.find_one({'id': receiver_id})
84 |
85 | sender_character = next((character for character in sender['characters'] if character['id'] == sender_character_id), None)
86 | receiver_character = next((character for character in receiver['characters'] if character['id'] == receiver_character_id), None)
87 |
88 |
89 |
90 | sender['characters'].remove(sender_character)
91 | receiver['characters'].remove(receiver_character)
92 |
93 |
94 | await user_collection.update_one({'id': sender_id}, {'$set': {'characters': sender['characters']}})
95 | await user_collection.update_one({'id': receiver_id}, {'$set': {'characters': receiver['characters']}})
96 |
97 |
98 | sender['characters'].append(receiver_character)
99 | receiver['characters'].append(sender_character)
100 |
101 |
102 | await user_collection.update_one({'id': sender_id}, {'$set': {'characters': sender['characters']}})
103 | await user_collection.update_one({'id': receiver_id}, {'$set': {'characters': receiver['characters']}})
104 |
105 |
106 | del pending_trades[(sender_id, receiver_id)]
107 |
108 | await callback_query.message.edit_text(f"You have successfully traded your character with {callback_query.message.reply_to_message.from_user.mention}!")
109 |
110 | elif callback_query.data == "cancel_trade":
111 |
112 | del pending_trades[(sender_id, receiver_id)]
113 |
114 | await callback_query.message.edit_text("❌️ Sad Cancelled....")
115 |
116 |
117 |
118 |
119 | pending_gifts = {}
120 |
121 |
122 | @shivuu.on_message(filters.command("gift"))
123 | async def gift(client, message):
124 | sender_id = message.from_user.id
125 |
126 | if not message.reply_to_message:
127 | await message.reply_text("You need to reply to a user's message to gift a character!")
128 | return
129 |
130 | receiver_id = message.reply_to_message.from_user.id
131 | receiver_username = message.reply_to_message.from_user.username
132 | receiver_first_name = message.reply_to_message.from_user.first_name
133 |
134 | if sender_id == receiver_id:
135 | await message.reply_text("You can't gift a character to yourself!")
136 | return
137 |
138 | if len(message.command) != 2:
139 | await message.reply_text("You need to provide a character ID!")
140 | return
141 |
142 | character_id = message.command[1]
143 |
144 | sender = await user_collection.find_one({'id': sender_id})
145 |
146 | character = next((character for character in sender['characters'] if character['id'] == character_id), None)
147 |
148 | if not character:
149 | await message.reply_text("You don't have this character in your collection!")
150 | return
151 |
152 |
153 | pending_gifts[(sender_id, receiver_id)] = {
154 | 'character': character,
155 | 'receiver_username': receiver_username,
156 | 'receiver_first_name': receiver_first_name
157 | }
158 |
159 |
160 | keyboard = InlineKeyboardMarkup(
161 | [
162 | [InlineKeyboardButton("Confirm Gift", callback_data="confirm_gift")],
163 | [InlineKeyboardButton("Cancel Gift", callback_data="cancel_gift")]
164 | ]
165 | )
166 |
167 | await message.reply_text(f"do You Really Wanns To Gift {message.reply_to_message.from_user.mention} ?", reply_markup=keyboard)
168 |
169 | @shivuu.on_callback_query(filters.create(lambda _, __, query: query.data in ["confirm_gift", "cancel_gift"]))
170 | async def on_callback_query(client, callback_query):
171 | sender_id = callback_query.from_user.id
172 |
173 |
174 | for (_sender_id, receiver_id), gift in pending_gifts.items():
175 | if _sender_id == sender_id:
176 | break
177 | else:
178 | await callback_query.answer("This is not for you!", show_alert=True)
179 | return
180 |
181 | if callback_query.data == "confirm_gift":
182 |
183 | sender = await user_collection.find_one({'id': sender_id})
184 | receiver = await user_collection.find_one({'id': receiver_id})
185 |
186 |
187 | sender['characters'].remove(gift['character'])
188 | await user_collection.update_one({'id': sender_id}, {'$set': {'characters': sender['characters']}})
189 |
190 |
191 | if receiver:
192 | await user_collection.update_one({'id': receiver_id}, {'$push': {'characters': gift['character']}})
193 | else:
194 |
195 | await user_collection.insert_one({
196 | 'id': receiver_id,
197 | 'username': gift['receiver_username'],
198 | 'first_name': gift['receiver_first_name'],
199 | 'characters': [gift['character']],
200 | })
201 |
202 |
203 | del pending_gifts[(sender_id, receiver_id)]
204 |
205 | await callback_query.message.edit_text(f"You have successfully gifted your character to [{gift['receiver_first_name']}](tg://user?id={receiver_id})!")
206 |
207 |
208 |
--------------------------------------------------------------------------------
/shivu/__main__.py:
--------------------------------------------------------------------------------
1 | import importlib
2 | import time
3 | import random
4 | import re
5 | import asyncio
6 | from html import escape
7 |
8 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup
9 | from telegram import InlineKeyboardMarkup, InlineKeyboardButton
10 | from telegram import Update
11 | from telegram.ext import CommandHandler, CallbackContext, MessageHandler, filters
12 |
13 | from shivu import collection, top_global_groups_collection, group_user_totals_collection, user_collection, user_totals_collection, shivuu
14 | from shivu import application, SUPPORT_CHAT, UPDATE_CHAT, db, LOGGER
15 | from shivu.modules import ALL_MODULES
16 |
17 |
18 | locks = {}
19 | message_counters = {}
20 | spam_counters = {}
21 | last_characters = {}
22 | sent_characters = {}
23 | first_correct_guesses = {}
24 | message_counts = {}
25 |
26 |
27 | for module_name in ALL_MODULES:
28 | imported_module = importlib.import_module("shivu.modules." + module_name)
29 |
30 |
31 | last_user = {}
32 | warned_users = {}
33 | def escape_markdown(text):
34 | escape_chars = r'\*_`\\~>#+-=|{}.!'
35 | return re.sub(r'([%s])' % re.escape(escape_chars), r'\\\1', text)
36 |
37 |
38 | async def message_counter(update: Update, context: CallbackContext) -> None:
39 | chat_id = str(update.effective_chat.id)
40 | user_id = update.effective_user.id
41 |
42 | if chat_id not in locks:
43 | locks[chat_id] = asyncio.Lock()
44 | lock = locks[chat_id]
45 |
46 | async with lock:
47 |
48 | chat_frequency = await user_totals_collection.find_one({'chat_id': chat_id})
49 | if chat_frequency:
50 | message_frequency = chat_frequency.get('message_frequency', 100)
51 | else:
52 | message_frequency = 100
53 |
54 |
55 | if chat_id in last_user and last_user[chat_id]['user_id'] == user_id:
56 | last_user[chat_id]['count'] += 1
57 | if last_user[chat_id]['count'] >= 10:
58 |
59 | if user_id in warned_users and time.time() - warned_users[user_id] < 600:
60 | return
61 | else:
62 |
63 | await update.message.reply_text(f"⚠️ Don't Spam {update.effective_user.first_name}...\nYour Messages Will be ignored for 10 Minutes...")
64 | warned_users[user_id] = time.time()
65 | return
66 | else:
67 | last_user[chat_id] = {'user_id': user_id, 'count': 1}
68 |
69 |
70 | if chat_id in message_counts:
71 | message_counts[chat_id] += 1
72 | else:
73 | message_counts[chat_id] = 1
74 |
75 |
76 | if message_counts[chat_id] % message_frequency == 0:
77 | await send_image(update, context)
78 |
79 | message_counts[chat_id] = 0
80 |
81 | async def send_image(update: Update, context: CallbackContext) -> None:
82 | chat_id = update.effective_chat.id
83 |
84 | all_characters = list(await collection.find({}).to_list(length=None))
85 |
86 | if chat_id not in sent_characters:
87 | sent_characters[chat_id] = []
88 |
89 | if len(sent_characters[chat_id]) == len(all_characters):
90 | sent_characters[chat_id] = []
91 |
92 | character = random.choice([c for c in all_characters if c['id'] not in sent_characters[chat_id]])
93 |
94 | sent_characters[chat_id].append(character['id'])
95 | last_characters[chat_id] = character
96 |
97 | if chat_id in first_correct_guesses:
98 | del first_correct_guesses[chat_id]
99 |
100 | await context.bot.send_photo(
101 | chat_id=chat_id,
102 | photo=character['img_url'],
103 | caption=f"""A New {character['rarity']} Character Appeared...\n/guess Character Name and add in Your Harem""",
104 | parse_mode='Markdown')
105 |
106 |
107 | async def guess(update: Update, context: CallbackContext) -> None:
108 | chat_id = update.effective_chat.id
109 | user_id = update.effective_user.id
110 |
111 | if chat_id not in last_characters:
112 | return
113 |
114 | if chat_id in first_correct_guesses:
115 | await update.message.reply_text(f'❌️ Already Guessed By Someone.. Try Next Time Bruhh ')
116 | return
117 |
118 | guess = ' '.join(context.args).lower() if context.args else ''
119 |
120 | if "()" in guess or "&" in guess.lower():
121 | await update.message.reply_text("Nahh You Can't use This Types of words in your guess..❌️")
122 | return
123 |
124 |
125 | name_parts = last_characters[chat_id]['name'].lower().split()
126 |
127 | if sorted(name_parts) == sorted(guess.split()) or any(part == guess for part in name_parts):
128 |
129 |
130 | first_correct_guesses[chat_id] = user_id
131 |
132 | user = await user_collection.find_one({'id': user_id})
133 | if user:
134 | update_fields = {}
135 | if hasattr(update.effective_user, 'username') and update.effective_user.username != user.get('username'):
136 | update_fields['username'] = update.effective_user.username
137 | if update.effective_user.first_name != user.get('first_name'):
138 | update_fields['first_name'] = update.effective_user.first_name
139 | if update_fields:
140 | await user_collection.update_one({'id': user_id}, {'$set': update_fields})
141 |
142 | await user_collection.update_one({'id': user_id}, {'$push': {'characters': last_characters[chat_id]}})
143 |
144 | elif hasattr(update.effective_user, 'username'):
145 | await user_collection.insert_one({
146 | 'id': user_id,
147 | 'username': update.effective_user.username,
148 | 'first_name': update.effective_user.first_name,
149 | 'characters': [last_characters[chat_id]],
150 | })
151 |
152 |
153 | group_user_total = await group_user_totals_collection.find_one({'user_id': user_id, 'group_id': chat_id})
154 | if group_user_total:
155 | update_fields = {}
156 | if hasattr(update.effective_user, 'username') and update.effective_user.username != group_user_total.get('username'):
157 | update_fields['username'] = update.effective_user.username
158 | if update.effective_user.first_name != group_user_total.get('first_name'):
159 | update_fields['first_name'] = update.effective_user.first_name
160 | if update_fields:
161 | await group_user_totals_collection.update_one({'user_id': user_id, 'group_id': chat_id}, {'$set': update_fields})
162 |
163 | await group_user_totals_collection.update_one({'user_id': user_id, 'group_id': chat_id}, {'$inc': {'count': 1}})
164 |
165 | else:
166 | await group_user_totals_collection.insert_one({
167 | 'user_id': user_id,
168 | 'group_id': chat_id,
169 | 'username': update.effective_user.username,
170 | 'first_name': update.effective_user.first_name,
171 | 'count': 1,
172 | })
173 |
174 |
175 |
176 | group_info = await top_global_groups_collection.find_one({'group_id': chat_id})
177 | if group_info:
178 | update_fields = {}
179 | if update.effective_chat.title != group_info.get('group_name'):
180 | update_fields['group_name'] = update.effective_chat.title
181 | if update_fields:
182 | await top_global_groups_collection.update_one({'group_id': chat_id}, {'$set': update_fields})
183 |
184 | await top_global_groups_collection.update_one({'group_id': chat_id}, {'$inc': {'count': 1}})
185 |
186 | else:
187 | await top_global_groups_collection.insert_one({
188 | 'group_id': chat_id,
189 | 'group_name': update.effective_chat.title,
190 | 'count': 1,
191 | })
192 |
193 |
194 |
195 | keyboard = [[InlineKeyboardButton(f"See Harem", switch_inline_query_current_chat=f"collection.{user_id}")]]
196 |
197 |
198 | await update.message.reply_text(f'{escape(update.effective_user.first_name)} You Guessed a New Character ✅️ \n\n𝗡𝗔𝗠𝗘: {last_characters[chat_id]["name"]} \n𝗔𝗡𝗜𝗠𝗘: {last_characters[chat_id]["anime"]} \n𝗥𝗔𝗜𝗥𝗧𝗬: {last_characters[chat_id]["rarity"]}\n\nThis Character added in Your harem.. use /harem To see your harem', parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard))
199 |
200 | else:
201 | await update.message.reply_text('Please Write Correct Character Name... ❌️')
202 |
203 |
204 | async def fav(update: Update, context: CallbackContext) -> None:
205 | user_id = update.effective_user.id
206 |
207 |
208 | if not context.args:
209 | await update.message.reply_text('Please provide Character id...')
210 | return
211 |
212 | character_id = context.args[0]
213 |
214 |
215 | user = await user_collection.find_one({'id': user_id})
216 | if not user:
217 | await update.message.reply_text('You have not Guessed any characters yet....')
218 | return
219 |
220 |
221 | character = next((c for c in user['characters'] if c['id'] == character_id), None)
222 | if not character:
223 | await update.message.reply_text('This Character is Not In your collection')
224 | return
225 |
226 |
227 | user['favorites'] = [character_id]
228 |
229 |
230 | await user_collection.update_one({'id': user_id}, {'$set': {'favorites': user['favorites']}})
231 |
232 | await update.message.reply_text(f'Character {character["name"]} has been added to your favorite...')
233 |
234 |
235 |
236 |
237 | def main() -> None:
238 | """Run bot."""
239 |
240 | application.add_handler(CommandHandler(["guess", "protecc", "collect", "grab", "hunt"], guess, block=False))
241 | application.add_handler(CommandHandler("fav", fav, block=False))
242 | application.add_handler(MessageHandler(filters.ALL, message_counter, block=False))
243 |
244 | application.run_polling(drop_pending_updates=True)
245 |
246 | if __name__ == "__main__":
247 | shivuu.start()
248 | LOGGER.info("Bot started")
249 | main()
250 |
251 |
--------------------------------------------------------------------------------