# <============================================== IMPORTS =========================================================> import asyncio import json import logging import os import random import re import shlex import time from datetime import datetime from os.path import basename from time import time from traceback import format_exc as err from typing import Optional, Tuple from urllib.parse import quote from uuid import uuid4 import requests import urllib3 from bs4 import BeautifulSoup from motor.core import AgnosticClient, AgnosticCollection, AgnosticDatabase from motor.motor_asyncio import AsyncIOMotorClient from pyrogram import Client, filters from pyrogram.enums import ChatMemberStatus, ChatType from pyrogram.errors import ( FloodWait, MessageNotModified, UserNotParticipant, WebpageCurlFailed, WebpageMediaEmpty, ) from pyrogram.types import ( CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, InputMediaPhoto, Message, ) from Mikobot import BOT_USERNAME, MESSAGE_DUMP, MONGO_DB_URI, app from Mikobot.utils.custom_filters import PREFIX_HANDLER # <=======================================================================================================> FILLERS = {} BOT_OWNER = list({int(x) for x in ("7480891683").split()}) _MGCLIENT: AgnosticClient = AsyncIOMotorClient(MONGO_DB_URI) _DATABASE: AgnosticDatabase = _MGCLIENT["MikobotAnime"] def get_collection(name: str) -> AgnosticCollection: """Create or Get Collection from your database""" return _DATABASE[name] def _close_db() -> None: _MGCLIENT.close() GROUPS = get_collection("GROUPS") SFW_GRPS = get_collection("SFW_GROUPS") DC = get_collection("DISABLED_CMDS") AG = get_collection("AIRING_GROUPS") CG = get_collection("CRUNCHY_GROUPS") SG = get_collection("SUBSPLEASE_GROUPS") HD = get_collection("HEADLINES_GROUPS") MHD = get_collection("MAL_HEADLINES_GROUPS") CHAT_OWNER = ChatMemberStatus.OWNER MEMBER = ChatMemberStatus.MEMBER ADMINISTRATOR = ChatMemberStatus.ADMINISTRATOR failed_pic = "https://telegra.ph/file/09733b49f3a9d5b147d21.png" no_pic = [ "https://telegra.ph/file/0d2097f442e816ba3f946.jpg", "https://telegra.ph/file/5a152016056308ef63226.jpg", "https://telegra.ph/file/d2bf913b18688c59828e9.jpg", "https://telegra.ph/file/d53083ea69e84e3b54735.jpg", "https://telegra.ph/file/b5eb1e3606b7d2f1b491f.jpg", ] DOWN_PATH = "Mikobot/downloads/" AUTH_USERS = get_collection("AUTH_USERS") IGNORE = get_collection("IGNORED_USERS") PIC_DB = get_collection("PIC_DB") GROUPS = get_collection("GROUPS") CC = get_collection("CONNECTED_CHANNELS") USER_JSON = {} USER_WC = {} LANGUAGES = { "af": "afrikaans", "sq": "albanian", "am": "amharic", "ar": "arabic", "hy": "armenian", "az": "azerbaijani", "eu": "basque", "be": "belarusian", "bn": "bengali", "bs": "bosnian", "bg": "bulgarian", "ca": "catalan", "ceb": "cebuano", "ny": "chichewa", "zh-cn": "chinese (simplified)", "zh-tw": "chinese (traditional)", "co": "corsican", "hr": "croatian", "cs": "czech", "da": "danish", "nl": "dutch", "en": "english", "eo": "esperanto", "et": "estonian", "tl": "filipino", "fi": "finnish", "fr": "french", "fy": "frisian", "gl": "galician", "ka": "georgian", "de": "german", "el": "greek", "gu": "gujarati", "ht": "haitian creole", "ha": "hausa", "haw": "hawaiian", "iw": "hebrew", "he": "hebrew", "hi": "hindi", "hmn": "hmong", "hu": "hungarian", "is": "icelandic", "ig": "igbo", "id": "indonesian", "ga": "irish", "it": "italian", "ja": "japanese", "jw": "javanese", "kn": "kannada", "kk": "kazakh", "km": "khmer", "ko": "korean", "ku": "kurdish (kurmanji)", "ky": "kyrgyz", "lo": "lao", "la": "latin", "lv": "latvian", "lt": "lithuanian", "lb": "luxembourgish", "mk": "macedonian", "mg": "malagasy", "ms": "malay", "ml": "malayalam", "mt": "maltese", "mi": "maori", "mr": "marathi", "mn": "mongolian", "my": "myanmar (burmese)", "ne": "nepali", "no": "norwegian", "or": "odia", "ps": "pashto", "fa": "persian", "pl": "polish", "pt": "portuguese", "pa": "punjabi", "ro": "romanian", "ru": "russian", "sm": "samoan", "gd": "scots gaelic", "sr": "serbian", "st": "sesotho", "sn": "shona", "sd": "sindhi", "si": "sinhala", "sk": "slovak", "sl": "slovenian", "so": "somali", "es": "spanish", "su": "sundanese", "sw": "swahili", "sv": "swedish", "tg": "tajik", "ta": "tamil", "tt": "tatar", "te": "telugu", "th": "thai", "tr": "turkish", "tk": "turkmen", "uk": "ukrainian", "ur": "urdu", "ug": "uyghur", "uz": "uzbek", "vi": "vietnamese", "cy": "welsh", "xh": "xhosa", "yi": "yiddish", "yo": "yoruba", "zu": "zulu", } DEFAULT_SERVICE_URLS = ( "translate.google.ac", "translate.google.ad", "translate.google.ae", "translate.google.al", "translate.google.am", "translate.google.as", "translate.google.at", "translate.google.az", "translate.google.ba", "translate.google.be", "translate.google.bf", "translate.google.bg", "translate.google.bi", "translate.google.bj", "translate.google.bs", "translate.google.bt", "translate.google.by", "translate.google.ca", "translate.google.cat", "translate.google.cc", "translate.google.cd", "translate.google.cf", "translate.google.cg", "translate.google.ch", "translate.google.ci", "translate.google.cl", "translate.google.cm", "translate.google.cn", "translate.google.co.ao", "translate.google.co.bw", "translate.google.co.ck", "translate.google.co.cr", "translate.google.co.id", "translate.google.co.il", "translate.google.co.in", "translate.google.co.jp", "translate.google.co.ke", "translate.google.co.kr", "translate.google.co.ls", "translate.google.co.ma", "translate.google.co.mz", "translate.google.co.nz", "translate.google.co.th", "translate.google.co.tz", "translate.google.co.ug", "translate.google.co.uk", "translate.google.co.uz", "translate.google.co.ve", "translate.google.co.vi", "translate.google.co.za", "translate.google.co.zm", "translate.google.co.zw", "translate.google.co", "translate.google.com.af", "translate.google.com.ag", "translate.google.com.ai", "translate.google.com.ar", "translate.google.com.au", "translate.google.com.bd", "translate.google.com.bh", "translate.google.com.bn", "translate.google.com.bo", "translate.google.com.br", "translate.google.com.bz", "translate.google.com.co", "translate.google.com.cu", "translate.google.com.cy", "translate.google.com.do", "translate.google.com.ec", "translate.google.com.eg", "translate.google.com.et", "translate.google.com.fj", "translate.google.com.gh", "translate.google.com.gi", "translate.google.com.gt", "translate.google.com.hk", "translate.google.com.jm", "translate.google.com.kh", "translate.google.com.kw", "translate.google.com.lb", "translate.google.com.lc", "translate.google.com.ly", "translate.google.com.mm", "translate.google.com.mt", "translate.google.com.mx", "translate.google.com.my", "translate.google.com.na", "translate.google.com.ng", "translate.google.com.ni", "translate.google.com.np", "translate.google.com.om", "translate.google.com.pa", "translate.google.com.pe", "translate.google.com.pg", "translate.google.com.ph", "translate.google.com.pk", "translate.google.com.pr", "translate.google.com.py", "translate.google.com.qa", "translate.google.com.sa", "translate.google.com.sb", "translate.google.com.sg", "translate.google.com.sl", "translate.google.com.sv", "translate.google.com.tj", "translate.google.com.tr", "translate.google.com.tw", "translate.google.com.ua", "translate.google.com.uy", "translate.google.com.vc", "translate.google.com.vn", "translate.google.com", "translate.google.cv", "translate.google.cx", "translate.google.cz", "translate.google.de", "translate.google.dj", "translate.google.dk", "translate.google.dm", "translate.google.dz", "translate.google.ee", "translate.google.es", "translate.google.eu", "translate.google.fi", "translate.google.fm", "translate.google.fr", "translate.google.ga", "translate.google.ge", "translate.google.gf", "translate.google.gg", "translate.google.gl", "translate.google.gm", "translate.google.gp", "translate.google.gr", "translate.google.gy", "translate.google.hn", "translate.google.hr", "translate.google.ht", "translate.google.hu", "translate.google.ie", "translate.google.im", "translate.google.io", "translate.google.iq", "translate.google.is", "translate.google.it", "translate.google.je", "translate.google.jo", "translate.google.kg", "translate.google.ki", "translate.google.kz", "translate.google.la", "translate.google.li", "translate.google.lk", "translate.google.lt", "translate.google.lu", "translate.google.lv", "translate.google.md", "translate.google.me", "translate.google.mg", "translate.google.mk", "translate.google.ml", "translate.google.mn", "translate.google.ms", "translate.google.mu", "translate.google.mv", "translate.google.mw", "translate.google.ne", "translate.google.nf", "translate.google.nl", "translate.google.no", "translate.google.nr", "translate.google.nu", "translate.google.pl", "translate.google.pn", "translate.google.ps", "translate.google.pt", "translate.google.ro", "translate.google.rs", "translate.google.ru", "translate.google.rw", "translate.google.sc", "translate.google.se", "translate.google.sh", "translate.google.si", "translate.google.sk", "translate.google.sm", "translate.google.sn", "translate.google.so", "translate.google.sr", "translate.google.st", "translate.google.td", "translate.google.tg", "translate.google.tk", "translate.google.tl", "translate.google.tm", "translate.google.tn", "translate.google.to", "translate.google.tt", "translate.google.us", "translate.google.vg", "translate.google.vu", "translate.google.ws", ) log = logging.getLogger(__name__) log.addHandler(logging.NullHandler()) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) URLS_SUFFIX = [ re.search("translate.google.(.*)", url.strip()).group(1) for url in DEFAULT_SERVICE_URLS ] URL_SUFFIX_DEFAULT = "cn" def rand_key(): return str(uuid4())[:8] def control_user(func): async def wrapper(_, message: Message): msg = json.loads(str(message)) gid = msg["chat"]["id"] gidtype = msg["chat"]["type"] if gidtype in [ChatType.SUPERGROUP, ChatType.GROUP] and not ( await GROUPS.find_one({"_id": gid}) ): try: gidtitle = msg["chat"]["username"] except KeyError: gidtitle = msg["chat"]["title"] await GROUPS.insert_one({"_id": gid, "grp": gidtitle}) await clog( "Mikobot", f"Bot added to a new group\n\n{gidtitle}\nID: `{gid}`", "NEW_GROUP", ) try: user = msg["from_user"]["id"] except KeyError: user = msg["chat"]["id"] if await IGNORE.find_one({"_id": user}): return nut = time() if user not in BOT_OWNER: try: out = USER_JSON[user] if nut - out < 1.2: USER_WC[user] += 1 if USER_WC[user] == 3: await message.reply_text( ("Stop spamming bot!!!" + "\nElse you will be blacklisted"), ) await clog("Mikobot", f"UserID: {user}", "SPAM") if USER_WC[user] == 5: await IGNORE.insert_one({"_id": user}) await message.reply_text( ( "You have been exempted from using this bot " + "now due to spamming 5 times consecutively!!!" + "\nTo remove restriction plead to " + "@ProjectCodeXSupport" ) ) await clog("Mikobot", f"UserID: {user}", "BAN") return await asyncio.sleep(USER_WC[user]) else: USER_WC[user] = 0 except KeyError: pass USER_JSON[user] = nut try: await func(_, message, msg) except FloodWait as e: await asyncio.sleep(e.x + 5) except MessageNotModified: pass except Exception: e = err() reply_msg = None if func.__name__ == "trace_bek": reply_msg = message.reply_to_message try: await clog( "Mikobot", "Message:\n" + msg["text"] + "\n\n" + "```" + e + "```", "COMMAND", msg=message, replied=reply_msg, ) except Exception: await clog("Mikobot", e, "FAILURE", msg=message) return wrapper def check_user(func): async def wrapper(_, c_q: CallbackQuery): cq = json.loads(str(c_q)) user = cq["from_user"]["id"] if await IGNORE.find_one({"_id": user}): return cqowner_is_ch = False cqowner = cq["data"].split("_").pop() if "-100" in cqowner: cqowner_is_ch = True ccdata = await CC.find_one({"_id": cqowner}) if ccdata and ccdata["usr"] == user: user_valid = True else: user_valid = False if user in BOT_OWNER or user == int(cqowner): if user not in BOT_OWNER: nt = time() try: ot = USER_JSON[user] if nt - ot < 1.4: await c_q.answer( ("Stop spamming bot!!!\n" + "Else you will be blacklisted"), show_alert=True, ) await clog("Mikobot", f"UserID: {user}", "SPAM") except KeyError: pass USER_JSON[user] = nt try: await func(_, c_q, cq) except FloodWait as e: await asyncio.sleep(e.x + 5) except MessageNotModified: pass except Exception: e = err() reply_msg = None if func.__name__ == "tracemoe_btn": reply_msg = c_q.message.reply_to_message try: await clog( "Mikobot", "Callback:\n" + cq["data"] + "\n\n" + "```" + e + "```", "CALLBACK", cq=c_q, replied=reply_msg, ) except Exception: await clog("Mikobot", e, "FAILURE", cq=c_q) else: if cqowner_is_ch: if user_valid: try: await func(_, c_q, cq) except FloodWait as e: await asyncio.sleep(e.x + 5) except MessageNotModified: pass except Exception: e = err() reply_msg = None if func.__name__ == "tracemoe_btn": reply_msg = c_q.message.reply_to_message try: await clog( "Mikobot", "Callback:\n" + cq["data"] + "\n\n" + "```" + e + "```", "CALLBACK_ANON", cq=c_q, replied=reply_msg, ) except Exception: await clog("Mikobot", e, "FAILURE", cq=c_q) else: await c_q.answer( ( "No one can click buttons on queries made by " + "channels unless connected with /aniconnect!!!" ), show_alert=True, ) else: await c_q.answer( "Not your query!!!", show_alert=True, ) return wrapper async def media_to_image(client: app, message: Message, x: Message, replied: Message): if not (replied.photo or replied.sticker or replied.animation or replied.video): await x.edit_text("Media Type Is Invalid !") await asyncio.sleep(5) await x.delete() return media = replied.photo or replied.sticker or replied.animation or replied.video if not os.path.isdir(DOWN_PATH): os.makedirs(DOWN_PATH) dls = await client.download_media( media, file_name=DOWN_PATH + rand_key(), ) dls_loc = os.path.join(DOWN_PATH, os.path.basename(dls)) if replied.sticker and replied.sticker.file_name.endswith(".tgs"): png_file = os.path.join(DOWN_PATH, f"{rand_key()}.png") cmd = ( f"lottie_convert.py --frame 0 -if lottie " + f"-of png {dls_loc} {png_file}" ) stdout, stderr = (await runcmd(cmd))[:2] os.remove(dls_loc) if not os.path.lexists(png_file): await x.edit_text("This sticker is Gey, Task Failed Successfully ≧ω≦") await asyncio.sleep(5) await x.delete() raise Exception(stdout + stderr) dls_loc = png_file elif replied.sticker and replied.sticker.file_name.endswith(".webp"): stkr_file = os.path.join(DOWN_PATH, f"{rand_key()}.png") os.rename(dls_loc, stkr_file) if not os.path.lexists(stkr_file): await x.edit_text("```Sticker not found...```") await asyncio.sleep(5) await x.delete() return dls_loc = stkr_file elif replied.animation or replied.video: await x.edit_text("`Converting Media To Image ...`") jpg_file = os.path.join(DOWN_PATH, f"{rand_key()}.jpg") await take_screen_shot(dls_loc, 0, jpg_file) os.remove(dls_loc) if not os.path.lexists(jpg_file): await x.edit_text("This Gif is Gey (。ì _ í。), Task Failed Successfully !") await asyncio.sleep(5) await x.delete() return dls_loc = jpg_file return dls_loc async def runcmd(cmd: str) -> Tuple[str, str, int, int]: """run command in terminal""" args = shlex.split(cmd) process = await asyncio.create_subprocess_exec( *args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) stdout, stderr = await process.communicate() return ( stdout.decode("utf-8", "replace").strip(), stderr.decode("utf-8", "replace").strip(), process.returncode, process.pid, ) async def take_screen_shot( video_file: str, duration: int, path: str = "" ) -> Optional[str]: """take a screenshot""" print( "[[[Extracting a frame from %s ||| Video duration => %s]]]", video_file, duration, ) thumb_image_path = path or os.path.join(DOWN_PATH, f"{basename(video_file)}.jpg") command = ( f"ffmpeg -ss {duration} " + f'-i "{video_file}" -vframes 1 "{thumb_image_path}"' ) err = (await runcmd(command))[1] if err: print(err) return thumb_image_path if os.path.exists(thumb_image_path) else None async def get_user_from_channel(cid): try: k = (await CC.find_one({"_id": str(cid)}))["usr"] return k except TypeError: return None async def return_json_senpai( query: str, vars_: dict, auth: bool = False, user: int = None ): url = "https://graphql.anilist.co" headers = None if auth: headers = { "Authorization": ( "Bearer " + str((await AUTH_USERS.find_one({"id": int(user)}))["token"]) ), "Content-Type": "application/json", "Accept": "application/json", } return requests.post( url, json={"query": query, "variables": vars_}, headers=headers ).json() def cflag(country): if country == "JP": return "\U0001F1EF\U0001F1F5" if country == "CN": return "\U0001F1E8\U0001F1F3" if country == "KR": return "\U0001F1F0\U0001F1F7" if country == "TW": return "\U0001F1F9\U0001F1FC" def pos_no(no): ep_ = list(str(no)) x = ep_.pop() if ep_ != [] and ep_.pop() == "1": return "th" th = "st" if x == "1" else "nd" if x == "2" else "rd" if x == "3" else "th" return th def make_it_rw(time_stamp): """Converting Time Stamp to Readable Format""" seconds, milliseconds = divmod(int(time_stamp), 1000) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) days, hours = divmod(hours, 24) tmp = ( ((str(days) + " Days, ") if days else "") + ((str(hours) + " Hours, ") if hours else "") + ((str(minutes) + " Minutes, ") if minutes else "") + ((str(seconds) + " Seconds, ") if seconds else "") + ((str(milliseconds) + " ms, ") if milliseconds else "") ) return tmp[:-2] async def clog( name: str, text: str, tag: str, msg: Message = None, cq: CallbackQuery = None, replied: Message = None, file: str = None, send_as_file: str = None, ): log = f"#{name.upper()} #{tag.upper()}\n\n{text}" data = "" if msg: data += str(msg) data += "\n\n\n\n" if cq: data += str(cq) data += "\n\n\n\n" await app.send_message(chat_id=MESSAGE_DUMP, text=log) if msg or cq: with open("query_data.txt", "x") as output: output.write(data) await app.send_document(MESSAGE_DUMP, "query_data.txt") os.remove("query_data.txt") if replied: media = replied.photo or replied.sticker or replied.animation or replied.video media_path = await app.download_media(media) await app.send_document(MESSAGE_DUMP, media_path) if file: await app.send_document(MESSAGE_DUMP, file) if send_as_file: with open("dataInQuestio.txt", "x") as text_file: text_file.write() await app.send_document(MESSAGE_DUMP, "dataInQuestio.txt") os.remove("dataInQuestio.txt") def get_btns( media, user: int, result: list, lsqry: str = None, lspage: int = None, auth: bool = False, sfw: str = "False", ): buttons = [] qry = f"_{lsqry}" if lsqry is not None else "" pg = f"_{lspage}" if lspage is not None else "" if media == "ANIME" and sfw == "False": buttons.append( [ InlineKeyboardButton( text="Characters", callback_data=( f"char_{result[2][0]}_ANI" + f"{qry}{pg}_{str(auth)}_1_{user}" ), ), InlineKeyboardButton( text="Description", callback_data=( f"desc_{result[2][0]}_ANI" + f"{qry}{pg}_{str(auth)}_{user}" ), ), InlineKeyboardButton( text="List Series", callback_data=( f"ls_{result[2][0]}_ANI" + f"{qry}{pg}_{str(auth)}_{user}" ), ), ] ) if media == "CHARACTER": buttons.append( [ InlineKeyboardButton( "Description", callback_data=( f"desc_{result[2][0]}_CHAR" + f"{qry}{pg}_{str(auth)}_{user}" ), ) ] ) buttons.append( [ InlineKeyboardButton( "List Series", callback_data=f"lsc_{result[2][0]}{qry}{pg}_{str(auth)}_{user}", ) ] ) if media == "SCHEDULED": if result[0] != 0 and result[0] != 6: buttons.append( [ InlineKeyboardButton( str(day_(result[0] - 1)), callback_data=f"sched_{result[0]-1}_{user}", ), InlineKeyboardButton( str(day_(result[0] + 1)), callback_data=f"sched_{result[0]+1}_{user}", ), ] ) if result[0] == 0: buttons.append( [ InlineKeyboardButton( str(day_(result[0] + 1)), callback_data=f"sched_{result[0]+1}_{user}", ) ] ) if result[0] == 6: buttons.append( [ InlineKeyboardButton( str(day_(result[0] - 1)), callback_data=f"sched_{result[0]-1}_{user}", ) ] ) if media == "MANGA" and sfw == "False": buttons.append([InlineKeyboardButton("More Info", url=result[1][2])]) if media == "AIRING" and sfw == "False": buttons.append([InlineKeyboardButton("More Info", url=result[1][0])]) if auth is True and media != "SCHEDULED" and sfw == "False": auth_btns = get_auth_btns(media, user, result[2], lspage=lspage, lsqry=lsqry) buttons.append(auth_btns) if len(result) > 3: if result[3] == "None": if result[4] != "None": buttons.append( [ InlineKeyboardButton( text="Sequel", callback_data=f"btn_{result[4]}_{str(auth)}_{user}", ) ] ) else: if result[4] != "None": buttons.append( [ InlineKeyboardButton( text="Prequel", callback_data=f"btn_{result[3]}_{str(auth)}_{user}", ), InlineKeyboardButton( text="Sequel", callback_data=f"btn_{result[4]}_{str(auth)}_{user}", ), ] ) else: buttons.append( [ InlineKeyboardButton( text="Prequel", callback_data=f"btn_{result[3]}_{str(auth)}_{user}", ) ] ) if (lsqry is not None) and (len(result) != 1): if lspage == 1: if result[1][1] is True: buttons.append( [ InlineKeyboardButton( text="Next", callback_data=( f"page_{media}{qry}_{int(lspage)+1}_{str(auth)}_{user}" ), ) ] ) else: pass elif lspage != 1: if result[1][1] is False: buttons.append( [ InlineKeyboardButton( text="Prev", callback_data=( f"page_{media}{qry}_{int(lspage)-1}_{str(auth)}_{user}" ), ) ] ) else: buttons.append( [ InlineKeyboardButton( text="Prev", callback_data=( f"page_{media}{qry}_{int(lspage)-1}_{str(auth)}_{user}" ), ), InlineKeyboardButton( text="Next", callback_data=( f"page_{media}{qry}_{int(lspage)+1}_{str(auth)}_{user}" ), ), ] ) return InlineKeyboardMarkup(buttons) def get_auth_btns(media, user, data, lsqry: str = None, lspage: int = None): btn = [] qry = f"_{lsqry}" if lsqry is not None else "" pg = f"_{lspage}" if lspage is not None else "" if media == "CHARACTER": btn.append( InlineKeyboardButton( text=("Add to Favs" if data[1] is not True else "Remove from Favs"), callback_data=f"fav_{media}_{data[0]}{qry}{pg}_{user}", ) ) else: btn.append( InlineKeyboardButton( text=("Add to Favs" if data[3] is not True else "Remove from Favs"), callback_data=f"fav_{media}_{data[0]}{qry}{pg}_{user}", ) ) btn.append( InlineKeyboardButton( text="Add to List" if data[1] is False else "Update in List", callback_data=( f"lsadd_{media}_{data[0]}{qry}{pg}_{user}" if data[1] is False else f"lsupdt_{media}_{data[0]}_{data[2]}{qry}{pg}_{user}" ), ) ) return btn def day_(x: int): if x == 0: return "Monday" if x == 1: return "Tuesday" if x == 2: return "Wednesday" if x == 3: return "Thursday" if x == 4: return "Friday" if x == 5: return "Saturday" if x == 6: return "Sunday" def season_(future: bool = False): k = datetime.now() m = k.month if future: m = m + 3 y = k.year if m > 12: y = y + 1 if m in [1, 2, 3] or m > 12: return "WINTER", y if m in [4, 5, 6]: return "SPRING", y if m in [7, 8, 9]: return "SUMMER", y if m in [10, 11, 12]: return "FALL", y class google_new_transError(Exception): """Exception that uses context to present a meaningful error message""" def __init__(self, msg=None, **kwargs): self.tts = kwargs.pop("tts", None) self.rsp = kwargs.pop("response", None) if msg: self.msg = msg elif self.tts is not None: self.msg = self.infer_msg(self.tts, self.rsp) else: self.msg = None super(google_new_transError, self).__init__(self.msg) def infer_msg(self, tts, rsp=None): cause = "Unknown" if rsp is None: premise = "Failed to connect" return "{}. Probable cause: {}".format(premise, "timeout") # if tts.tld != 'com': # host = _translate_url(tld=tts.tld) # cause = "Host '{}' is not reachable".format(host) else: status = rsp.status_code reason = rsp.reason premise = "{:d} ({}) from TTS API".format(status, reason) if status == 403: cause = "Bad token or upstream API changes" elif status == 200 and not tts.lang_check: cause = ( "No audio stream in response. Unsupported language '%s'" % self.tts.lang ) elif status >= 500: cause = "Uptream API error. Try again later." return "{}. Probable cause: {}".format(premise, cause) class google_translator: """ You can use 108 language in target and source,details view LANGUAGES. Target language: like 'en'、'zh'、'th'... :param url_suffix: The source text(s) to be translated. Batch translation is supported via sequence input. The value should be one of the url_suffix listed in : `DEFAULT_SERVICE_URLS` :type url_suffix: UTF-8 :class:`str`; :class:`unicode`; string sequence (list, tuple, iterator, generator) :param text: The source text(s) to be translated. :type text: UTF-8 :class:`str`; :class:`unicode`; :param lang_tgt: The language to translate the source text into. The value should be one of the language codes listed in : `LANGUAGES` :type lang_tgt: :class:`str`; :class:`unicode` :param lang_src: The language of the source text. The value should be one of the language codes listed in :const:`googletrans.LANGUAGES` If a language is not specified, the system will attempt to identify the source language automatically. :type lang_src: :class:`str`; :class:`unicode` :param timeout: Timeout Will be used for every request. :type timeout: number or a double of numbers :param proxies: proxies Will be used for every request. :type proxies: class : dict; like: {'http': 'http:171.112.169.47:19934/', 'https': 'https:171.112.169.47:19934/'} """ def __init__(self, url_suffix="cn", timeout=5, proxies=None): self.proxies = proxies if url_suffix not in URLS_SUFFIX: self.url_suffix = URL_SUFFIX_DEFAULT else: self.url_suffix = url_suffix url_base = "https://translate.google.{}".format(self.url_suffix) self.url = url_base + "/_/TranslateWebserverUi/data/batchexecute" self.timeout = timeout def _package_rpc(self, text, lang_src="auto", lang_tgt="auto"): GOOGLE_TTS_RPC = ["MkEWBc"] parameter = [[text.strip(), lang_src, lang_tgt, True], [1]] escaped_parameter = json.dumps(parameter, separators=(",", ":")) rpc = [[[random.choice(GOOGLE_TTS_RPC), escaped_parameter, None, "generic"]]] espaced_rpc = json.dumps(rpc, separators=(",", ":")) # text_urldecode = quote(text.strip()) freq_initial = "f.req={}&".format(quote(espaced_rpc)) freq = freq_initial return freq def translate(self, text, lang_tgt="auto", lang_src="auto", pronounce=False): try: lang = LANGUAGES[lang_src] except Exception: lang_src = "auto" try: lang = LANGUAGES[lang_tgt] except Exception: lang_src = "auto" text = str(text) if len(text) >= 5000: return "Warning: Can only detect less than 5000 characters" if len(text) == 0: return "" headers = { "Referer": "http://translate.google.{}/".format(self.url_suffix), "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/47.0.2526.106 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", } freq = self._package_rpc(text, lang_src, lang_tgt) response = requests.Request( method="POST", url=self.url, data=freq, headers=headers, ) try: if self.proxies is None or type(self.proxies) != dict: self.proxies = {} with requests.Session() as s: s.proxies = self.proxies r = s.send( request=response.prepare(), verify=False, timeout=self.timeout ) for line in r.iter_lines(chunk_size=1024): decoded_line = line.decode("utf-8") if "MkEWBc" in decoded_line: try: response = decoded_line response = json.loads(response) response = list(response) response = json.loads(response[0][2]) response_ = list(response) response = response_[1][0] if len(response) == 1: if len(response[0]) > 5: sentences = response[0][5] else: ## only url sentences = response[0][0] if pronounce is False: return sentences elif pronounce == True: return [sentences, None, None] translate_text = "" for sentence in sentences: sentence = sentence[0] translate_text += sentence.strip() + " " translate_text = translate_text if pronounce is False: return translate_text elif pronounce == True: pronounce_src = response_[0][0] pronounce_tgt = response_[1][0][0][1] return [translate_text, pronounce_src, pronounce_tgt] elif len(response) == 2: sentences = [] for i in response: sentences.append(i[0]) if pronounce is False: return sentences elif pronounce == True: pronounce_src = response_[0][0] pronounce_tgt = response_[1][0][0][1] return [sentences, pronounce_src, pronounce_tgt] except Exception as e: raise e r.raise_for_status() except requests.exceptions.ConnectTimeout as e: raise e except requests.exceptions.HTTPError as e: # Request successful, bad response raise google_new_transError(tts=self, response=r) except requests.exceptions.RequestException as e: # Request failed raise google_new_transError(tts=self) def detect(self, text): text = str(text) if len(text) >= 5000: return log.debug("Warning: Can only detect less than 5000 characters") if len(text) == 0: return "" headers = { "Referer": "http://translate.google.{}/".format(self.url_suffix), "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/47.0.2526.106 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", } freq = self._package_rpc(text) response = requests.Request( method="POST", url=self.url, data=freq, headers=headers ) try: if self.proxies is None or type(self.proxies) != dict: self.proxies = {} with requests.Session() as s: s.proxies = self.proxies r = s.send( request=response.prepare(), verify=False, timeout=self.timeout ) for line in r.iter_lines(chunk_size=1024): decoded_line = line.decode("utf-8") if "MkEWBc" in decoded_line: # regex_str = r"\[\[\"wrb.fr\",\"MkEWBc\",\"\[\[(.*).*?,\[\[\[" try: # data_got = re.search(regex_str,decoded_line).group(1) response = decoded_line response = json.loads(response) response = list(response) response = json.loads(response[0][2]) response = list(response) detect_lang = response[0][2] except Exception: raise Exception # data_got = data_got.split('\\\"]')[0] return [detect_lang, LANGUAGES[detect_lang.lower()]] r.raise_for_status() except requests.exceptions.HTTPError as e: # Request successful, bad response log.debug(str(e)) raise google_new_transError(tts=self, response=r) except requests.exceptions.RequestException as e: # Request failed log.debug(str(e)) raise google_new_transError(tts=self) async def uidata(id_): data = await GUI.find_one({"_id": str(id_)}) if data is not None: bullet = str(data["bl"]) + " " if data["bl"] is None: bullet = "" return bullet, data["cs"] return ["➤ ", "UPPER"] async def get_ui_text(case): if case == "UPPER": return [ "SOURCE", "TYPE", "SCORE", "DURATION", "USER DATA", "ADULT RATED", "STATUS", "GENRES", "TAGS", "SEQUEL", "PREQUEL", "NEXT AIRING", "DESCRIPTION", "VOLUMES", "CHAPTERS", ] else: return [ "Source", "Type", "Score", "Duration", "User Data", "Adult Rated", "Status", "Genres", "Tags", "Sequel", "Prequel", "Next Airing", "Description", "Volumes", "Chapters", ] tr = google_translator() ANIME_DB, MANGA_DB, CHAR_DB, STUDIO_DB, AIRING_DB = {}, {}, {}, {}, {} GUI = get_collection("GROUP_UI") #### Anilist part #### ANIME_TEMPLATE = """{name} **ID | MAL ID:** `{idm}` | `{idmal}` {bl}**{psrc}:** `{source}` {bl}**{ptype}:** `{formats}`{avscd}{dura}{user_data} {status_air}{gnrs_}{tags_} 🎬 {trailer_link} 📖 Official Site {additional}""" # GraphQL Queries. ANIME_QUERY = """ query ($id: Int, $idMal:Int, $search: String) { Media (id: $id, idMal: $idMal, search: $search, type: ANIME) { id idMal title { romaji english native } format status episodes duration countryOfOrigin source (version: 2) trailer { id site } genres tags { name } averageScore relations { edges { node { title { romaji english } id type } relationType } } nextAiringEpisode { timeUntilAiring episode } isAdult isFavourite mediaListEntry { status score id } siteUrl } } """ ISADULT = """ query ($id: Int) { Media (id: $id) { isAdult } } """ BROWSE_QUERY = """ query ($s: MediaSeason, $y: Int, $sort: [MediaSort]) { Page { media (season: $s, seasonYear: $y, sort: $sort) { title { romaji } format } } } """ FAV_ANI_QUERY = """ query ($id: Int, $page: Int) { User (id: $id) { favourites { anime (page: $page, perPage: 10) { pageInfo { lastPage hasNextPage } edges { node { title { romaji } siteUrl } } } } } } """ FAV_MANGA_QUERY = """ query ($id: Int, $page: Int) { User (id: $id) { favourites { manga (page: $page, perPage: 10) { pageInfo { lastPage hasNextPage } edges { node { title { romaji } siteUrl } } } } } } """ FAV_CHAR_QUERY = """ query ($id: Int, $page: Int) { User (id: $id) { favourites { characters (page: $page, perPage: 10) { pageInfo { lastPage hasNextPage } edges { node { name { full } siteUrl } } } } } } """ VIEWER_QRY = """ query { Viewer { id name siteUrl statistics { anime { count minutesWatched episodesWatched meanScore } manga { count chaptersRead volumesRead meanScore } } } } """ USER_QRY = """ query ($search: String) { User (name: $search) { id name siteUrl statistics { anime { count minutesWatched episodesWatched meanScore } manga { count chaptersRead volumesRead meanScore } } } } """ ANIME_MUTATION = """ mutation ($id: Int) { ToggleFavourite (animeId: $id) { anime { pageInfo { total } } } } """ MANGA_MUTATION = """ mutation ($id: Int) { ToggleFavourite (mangaId: $id) { manga { pageInfo { total } } } } """ STUDIO_MUTATION = """ mutation ($id: Int) { ToggleFavourite (studioId: $id) { studios { pageInfo { total } } } } """ CHAR_MUTATION = """ mutation ($id: Int) { ToggleFavourite (characterId: $id) { characters { pageInfo { total } } } } """ ANILIST_MUTATION = """ mutation ($id: Int, $status: MediaListStatus) { SaveMediaListEntry (mediaId: $id, status: $status) { media { title { romaji } } } } """ ANILIST_MUTATION_UP = """ mutation ($id: [Int], $status: MediaListStatus) { UpdateMediaListEntries (ids: $id, status: $status) { media { title { romaji } } } } """ ANILIST_MUTATION_DEL = """ mutation ($id: Int) { DeleteMediaListEntry (id: $id) { deleted } } """ AIR_QUERY = """ query ($search: String, $page: Int) { Page (perPage: 1, page: $page) { pageInfo { total hasNextPage } media (search: $search, type: ANIME) { id title { romaji english } status countryOfOrigin nextAiringEpisode { timeUntilAiring episode } siteUrl isFavourite isAdult mediaListEntry { status id } } } } """ DES_INFO_QUERY = """ query ($id: Int) { Media (id: $id) { id description (asHtml: false) } } """ CHA_INFO_QUERY = """ query ($id: Int, $page: Int) { Media (id: $id, type: ANIME) { id characters (page: $page, perPage: 25, sort: ROLE) { pageInfo { hasNextPage lastPage total } edges { node { name { full } } role } } } } """ REL_INFO_QUERY = """ query ($id: Int) { Media (id: $id, type: ANIME) { id relations { edges { node { title { romaji } type } relationType } } } } """ PAGE_QUERY = """ query ($search: String, $page: Int) { Page (perPage: 1, page: $page) { pageInfo { total hasNextPage } media (search: $search, type: ANIME) { id idMal title { romaji english native } format status episodes duration countryOfOrigin source (version: 2) trailer { id site } genres tags { name } averageScore relations { edges { node { title { romaji english } type } relationType } } nextAiringEpisode { timeUntilAiring episode } isAdult isFavourite mediaListEntry { status score id } siteUrl } } } """ CHARACTER_QUERY = """ query ($id: Int, $search: String, $page: Int) { Page (perPage: 1, page: $page) { pageInfo { total hasNextPage } characters (id: $id, search: $search) { id name { full native } image { large } media (type: ANIME) { edges { node { title { romaji } type } voiceActors (language: JAPANESE) { name { full } siteUrl } } } isFavourite siteUrl } } } """ MANGA_QUERY = """ query ($search: String, $page: Int) { Page (perPage: 1, page: $page) { pageInfo { total hasNextPage } media (search: $search, type: MANGA) { id title { romaji english native } format countryOfOrigin source (version: 2) status description(asHtml: true) chapters isFavourite mediaListEntry { status score id } volumes averageScore siteUrl isAdult } } } """ DESC_INFO_QUERY = """ query ($id: Int) { Character (id: $id) { image { large } description(asHtml: false) } } """ LS_INFO_QUERY = """ query ($id: Int) { Character (id: $id) { image { large } media (page: 1, perPage: 25) { nodes { title { romaji english } type } } } } """ ACTIVITY_QUERY = """ query ($id: Int) { Page (perPage: 12) { activities (userId: $id, type: MEDIA_LIST, sort: ID_DESC) { ...kek } } } fragment kek on ListActivity { type media { title { romaji } siteUrl } progress status } """ TOP_QUERY = """ query ($gnr: String, $page: Int) { Page (perPage: 15, page: $page) { pageInfo { lastPage total hasNextPage } media (genre: $gnr, sort: SCORE_DESC, type: ANIME) { title { romaji } } } } """ TOPT_QUERY = """ query ($gnr: String, $page: Int) { Page (perPage: 15, page: $page) { pageInfo { lastPage total hasNextPage } media (tag: $gnr, sort: SCORE_DESC, type: ANIME) { title { romaji } } } } """ ALLTOP_QUERY = """ query ($page: Int) { Page (perPage: 15, page: $page) { pageInfo { lastPage total hasNextPage } media (sort: SCORE_DESC, type: ANIME) { title { romaji } } } } """ GET_GENRES = """ query { GenreCollection } """ GET_TAGS = """ query{ MediaTagCollection { name isAdult } } """ RECOMMENDTIONS_QUERY = """ query ($id: Int) { Media (id: $id) { recommendations (perPage: 25) { edges { node { mediaRecommendation { title { romaji } id siteUrl } } } } } } """ STUDIO_QUERY = """ query ($search: String, $page: Int) { Page (page: $page, perPage: 1) { pageInfo { total hasNextPage } studios (search: $search) { id name siteUrl isFavourite } } } """ STUDIO_ANI_QUERY = """ query ($id: Int, $page: Int) { Studio (id: $id) { name media (page: $page) { pageInfo { total lastPage hasNextPage } edges { node { title { romaji } seasonYear } } } } } """ async def get_studios(qry, page, user, duser=None, auth: bool = False): page = int(page) vars_ = {"search": STUDIO_DB[qry], "page": int(page)} result = await return_json_senpai(STUDIO_QUERY, vars_, auth, user) if result["data"]["Page"]["studios"] == []: return ["Not Found"] data = result["data"]["Page"]["studios"][0] isFav = data["isFavourite"] msg = ( f"**{data['name']}**{', ♥️' if isFav is True else ''}" + f"\n\n**ID:** {data['id']}\n[Website]({data['siteUrl']})" ) if not duser: duser = user btns = [] btns.append( [ InlineKeyboardButton( "List Animes", callback_data=f"stuani_1_{data['id']}_{page}_{qry}_{auth}_{duser}", ) ] ) if auth: btns.append( [ InlineKeyboardButton( "Remove from Favs" if isFav else "Add To Favs", callback_data=f"fav_STUDIO_{data['id']}_{qry}_{page}_{duser}", ) ] ) pi = result["data"]["Page"]["pageInfo"]["hasNextPage"] if pi is False: if int(page) == 1: return msg, btns else: btns.append( [ InlineKeyboardButton( "Prev", callback_data=f"pgstudio_{page-1}_{qry}_{auth}_{duser}" ) ] ) else: if int(page) == 1: btns.append( [ InlineKeyboardButton( "Next", callback_data=f"pgstudio_2_{qry}_{auth}_{duser}" ) ] ) else: btns.append( [ InlineKeyboardButton( "Prev", callback_data=f"pgstudio_{page-1}_{qry}_{auth}_{duser}" ), InlineKeyboardButton( "Next", callback_data=f"pgstudio_{page+1}_{qry}_{auth}_{duser}" ), ] ) return msg, InlineKeyboardMarkup(btns) async def get_studio_animes(id_, page, qry, rp, user, duser=None, auth: bool = False): vars_ = {"id": id_, "page": int(page)} result = await return_json_senpai(STUDIO_ANI_QUERY, vars_, auth, user) data = result["data"]["Studio"]["media"]["edges"] if data == []: return ["No results found"] msg = f"List of animes by {result['data']['Studio']['name']} studio\n" for i in data: msg += ( f"\n⚬ `{i['node']['title']['romaji']}`" + f" __({i['node']['seasonYear']})__" ) btns = [] if not duser: duser = user pi = result["data"]["Studio"]["media"]["pageInfo"] if pi["hasNextPage"] is False: if int(page) == 1: btns.append( [ InlineKeyboardButton( "Back", callback_data=f"pgstudio_{rp}_{qry}_{auth}_{duser}" ) ] ) return msg, btns else: btns.append( [ InlineKeyboardButton( "Prev", callback_data=f"stuani_{int(page)-1}_{id_}_{rp}_{qry}_{auth}_{duser}", ) ] ) else: if int(page) == 1: btns.append( [ InlineKeyboardButton( "Next", callback_data=f"stuani_2_{id_}_{rp}_{qry}_{auth}_{duser}", ) ] ) else: btns.append( [ InlineKeyboardButton( "Prev", callback_data=f"stuani_{int(page)-1}_{id_}_{rp}_{qry}_{auth}_{duser}", ), InlineKeyboardButton( "Next", callback_data=f"stuani_{int(page)+1}_{id_}_{rp}_{qry}_{auth}_{duser}", ), ] ) btns.append( [ InlineKeyboardButton( "Back", callback_data=f"pgstudio_{rp}_{qry}_{auth}_{duser}" ) ] ) return msg, InlineKeyboardMarkup(btns) async def get_all_tags(text: str = None): vars_ = {} result = await return_json_senpai(GET_TAGS, vars_, auth=False, user=None) msg = "**Tags List:**\n\n`" kek = [] for i in result["data"]["MediaTagCollection"]: if text is not None and "nsfw" in text: if str(i["isAdult"]) != "False": kek.append(i["name"]) else: if str(i["isAdult"]) == "False": kek.append(i["name"]) msg += ", ".join(kek) msg += "`" return msg async def get_all_genres(): vars_ = {} result = await return_json_senpai(GET_GENRES, vars_, auth=False) msg = "**Genres List:**\n\n" for i in result["data"]["GenreCollection"]: msg += f"`{i}`\n" return msg async def get_user_activity(id_, user, duser=None): vars_ = {"id": id_} result = await return_json_senpai(ACTIVITY_QUERY, vars_, auth=True, user=user) data = result["data"]["Page"]["activities"] msg = "" for i in data: try: name = f"[{i['media']['title']['romaji']}]" + f"({i['media']['siteUrl']})" if i["status"] in ["watched episode", "read chapter"]: msg += ( f"⚬ {str(i['status']).capitalize()} " + f"{i['progress']} of {name}\n" ) else: progress = i["progress"] of = "of" if i["status"] == "dropped": of = "at" msg += ( f"⚬ {str(i['status']).capitalize()}" + f"{f'{progress} {of} ' if progress is not None else ' '}" + f"{name}\n" ) except KeyError: pass if duser is None: duser = user btn = [[InlineKeyboardButton("Back", callback_data=f"getusrbc_{duser}")]] return [ f"https://img.anili.st/user/{id_}?a={time.time()}", msg, InlineKeyboardMarkup(btn), ] async def get_recommendations(id_): vars_ = {"id": int(id_)} result = await return_json_senpai(RECOMMENDTIONS_QUERY, vars_) data = result["data"]["Media"]["recommendations"]["edges"] rc_ls = [] for i in data: ii = i["node"]["mediaRecommendation"] rc_ls.append([ii["title"]["romaji"], ii["id"], ii["siteUrl"]]) if rc_ls == []: return "No Recommendations available related to given anime!!!" outstr = "Recommended animes:\n\n" for i in rc_ls: outstr += ( f"**{i[0]}**\n ➥[Synopsis]" + f"(https://t.me/{BOT_USERNAME}?astart=anime_{i[1]})" + f"\n ➥[Official Site]({i[2]})\n\n" ) return outstr async def get_top_animes(gnr: str, page, user): vars_ = {"gnr": gnr.lower(), "page": int(page)} query = TOP_QUERY msg = f"Top animes for genre `{gnr.capitalize()}`:\n\n" if gnr == "None": query = ALLTOP_QUERY vars_ = {"page": int(page)} msg = f"Top animes:\n\n" nsfw = False result = await return_json_senpai(query, vars_, auth=False, user=user) if len(result["data"]["Page"]["media"]) == 0: query = TOPT_QUERY msg = f"Top animes for tag `{gnr.capitalize()}`:\n\n" result = await return_json_senpai(query, vars_, auth=False, user=user) if len(result["data"]["Page"]["media"]) == 0: return [f"No results Found"] nsls = await get_all_tags("nsfw") nsfw = True if gnr.lower() in nsls.lower() else False data = result["data"]["Page"] for i in data["media"]: msg += f"⚬ `{i['title']['romaji']}`\n" msg += f"\nTotal available animes: `{data['pageInfo']['total']}`" btn = [] if int(page) == 1: if int(data["pageInfo"]["lastPage"]) != 1: btn.append( [ InlineKeyboardButton( "Next", callback_data=f"topanimu_{gnr}_{int(page)+1}_{user}" ) ] ) elif int(page) == int(data["pageInfo"]["lastPage"]): btn.append( [ InlineKeyboardButton( "Prev", callback_data=f"topanimu_{gnr}_{int(page)-1}_{user}" ) ] ) else: btn.append( [ InlineKeyboardButton( "Prev", callback_data=f"topanimu_{gnr}_{int(page)-1}_{user}" ), InlineKeyboardButton( "Next", callback_data=f"topanimu_{gnr}_{int(page)+1}_{user}" ), ] ) return [msg, nsfw], InlineKeyboardMarkup(btn) if len(btn) != 0 else "" async def get_user_favourites(id_, user, req, page, sighs, duser=None): vars_ = {"id": int(id_), "page": int(page)} result = await return_json_senpai( ( FAV_ANI_QUERY if req == "ANIME" else FAV_CHAR_QUERY if req == "CHAR" else FAV_MANGA_QUERY ), vars_, auth=True, user=int(user), ) data = result["data"]["User"]["favourites"][ "anime" if req == "ANIME" else "characters" if req == "CHAR" else "manga" ] msg = ( "Favourite Animes:\n\n" if req == "ANIME" else "Favourite Characters:\n\n" if req == "CHAR" else "Favourite Manga:\n\n" ) for i in data["edges"]: node_name = ( i["node"]["title"]["romaji"] if req != "CHAR" else i["node"]["name"]["full"] ) msg += f"⚬ [{node_name}]({i['node']['siteUrl']})\n" btn = [] if duser is None: duser = user if int(page) == 1: if int(data["pageInfo"]["lastPage"]) != 1: btn.append( [ InlineKeyboardButton( "Next", callback_data=( f"myfavqry_{req}_{id_}_{str(int(page)+1)}" + f"_{sighs}_{duser}" ), ) ] ) elif int(page) == int(data["pageInfo"]["lastPage"]): btn.append( [ InlineKeyboardButton( "Prev", callback_data=( f"myfavqry_{req}_{id_}_{str(int(page)-1)}_{sighs}_{duser}" ), ) ] ) else: btn.append( [ InlineKeyboardButton( "Prev", callback_data=( f"myfavqry_{req}_{id_}_{str(int(page)-1)}_{sighs}_{duser}" ), ), InlineKeyboardButton( "Next", callback_data=( f"myfavqry_{req}_{id_}_{str(int(page)+1)}_{sighs}_{duser}" ), ), ] ) btn.append( [InlineKeyboardButton("Back", callback_data=f"myfavs_{id_}_{sighs}_{user}")] ) return [ f"https://img.anili.st/user/{id_}?a=({time.time()})", msg, InlineKeyboardMarkup(btn), ] async def get_featured_in_lists( idm, req, auth: bool = False, user: int = None, page: int = 0 ): vars_ = {"id": int(idm)} result = await return_json_senpai(LS_INFO_QUERY, vars_, auth=auth, user=user) data = result["data"]["Character"]["media"]["nodes"] if req == "ANI": out = "ANIMES:\n\n" out_ = [] for ani in data: k = ani["title"]["english"] or ani["title"]["romaji"] kk = ani["type"] if kk == "ANIME": out_.append(f"• __{k}__\n") else: out = "MANGAS:\n\n" out_ = [] for ani in data: k = ani["title"]["english"] or ani["title"]["romaji"] kk = ani["type"] if kk == "MANGA": out_.append(f"• __{k}__\n") total = len(out_) for _ in range(15 * page): out_.pop(0) out_ = "".join(out_[:15]) return ([out + out_, total] if len(out_) != 0 else False), result["data"][ "Character" ]["image"]["large"] async def get_additional_info( idm, ctgry, req=None, auth: bool = False, user: int = None, page: int = 0 ): vars_ = {"id": int(idm)} if req == "char": vars_["page"] = page result = await return_json_senpai( ( ( DES_INFO_QUERY if req == "desc" else CHA_INFO_QUERY if req == "char" else REL_INFO_QUERY ) if ctgry == "ANI" else DESC_INFO_QUERY ), vars_, ) data = result["data"]["Media"] if ctgry == "ANI" else result["data"]["Character"] pic = f"https://img.anili.st/media/{idm}" if req == "desc": synopsis = data.get("description") if os.environ.get("PREFERRED_LANGUAGE"): synopsis = tr.translate( synopsis, lang_tgt=os.environ.get("PREFERRED_LANGUAGE") ) return (pic if ctgry == "ANI" else data["image"]["large"]), synopsis elif req == "char": charlist = [] for char in data["characters"]["edges"]: charlist.append(f"• `{char['node']['name']['full']}` ({char['role']})") chrctrs = ("\n").join(charlist) charls = f"{chrctrs}" if len(charlist) != 0 else "" return pic, charls, data["characters"]["pageInfo"] else: prqlsql = data.get("relations").get("edges") ps = "" for i in prqlsql: ps += ( f'• {i["node"]["title"]["romaji"]} ' + f'({i["node"]["type"]}) `{i["relationType"]}`\n' ) return pic, ps async def get_anime(vars_, auth: bool = False, user: int = None, cid: int = None): result = await return_json_senpai(ANIME_QUERY, vars_, auth=auth, user=user) error = result.get("errors") if error: error_sts = error[0].get("message") return [f"[{error_sts}]"] data = result["data"]["Media"] # Data of all fields in returned json # pylint: disable=possibly-unused-variable idm = data.get("id") idmal = data.get("idMal") romaji = data["title"]["romaji"] english = data["title"]["english"] native = data["title"]["native"] formats = data.get("format") status = data.get("status") episodes = data.get("episodes") duration = data.get("duration") country = data.get("countryOfOrigin") c_flag = cflag(country) source = data.get("source") prqlsql = data.get("relations").get("edges") adult = data.get("isAdult") url = data.get("siteUrl") trailer_link = "N/A" gnrs = ", ".join(data["genres"]) score = data["averageScore"] bl, cs = await uidata(cid) text = await get_ui_text(cs) psrc, ptype = text[0], text[1] avscd = f"\n{bl}**{text[2]}:** `{score}%` 🌟" if score is not None else "" tags = [] for i in data["tags"]: tags.append(i["name"]) tags_ = f"\n{bl}**{text[8]}:** `{', '.join(tags[:5])}`" if tags != [] else "" bot = BOT_USERNAME.replace("@", "") gnrs_ = "" if len(gnrs) != 0: gnrs_ = f"\n{bl}**{text[7]}:** `{gnrs}`" isfav = data.get("isFavourite") fav = ", in Favourites" if isfav is True else "" user_data = "" in_ls = False in_ls_id = "" if auth is True: in_list = data.get("mediaListEntry") if in_list is not None: in_ls = True in_ls_id = in_list["id"] in_ls_stts = in_list["status"] in_ls_score = ( f" and scored {in_list['score']}" if in_list["score"] != 0 else "" ) user_data = f"\n{bl}**{text[4]}:** `{in_ls_stts}{fav}{in_ls_score}`" if data["title"]["english"] is not None: name = f"""[{c_flag}]**{romaji}** | {native}""" else: name = f"""[{c_flag}]**{romaji}** | {native}""" prql, prql_id, sql, sql_id = "", "None", "", "None" for i in prqlsql: if i["relationType"] == "PREQUEL" and i["node"]["type"] == "ANIME": pname = ( i["node"]["title"]["english"] if i["node"]["title"]["english"] is not None else i["node"]["title"]["romaji"] ) prql += f"**{text[10]}:** `{pname}`\n" prql_id = i["node"]["id"] break for i in prqlsql: if i["relationType"] == "SEQUEL" and i["node"]["type"] == "ANIME": sname = ( i["node"]["title"]["english"] if i["node"]["title"]["english"] is not None else i["node"]["title"]["romaji"] ) sql += f"**{text[9]}:** `{sname}`\n" sql_id = i["node"]["id"] break additional = f"{prql}{sql}" surl = f"https://t.me/{bot}/?astart=des_ANI_{idm}_desc" dura = f"\n{bl}**{text[3]}:** `{duration} min/ep`" if duration is not None else "" air_on = None if data["nextAiringEpisode"]: nextAir = data["nextAiringEpisode"]["timeUntilAiring"] air_on = make_it_rw(nextAir * 1000) eps = data["nextAiringEpisode"]["episode"] th = pos_no(str(eps)) air_on += f" | {eps}{th} eps" if air_on is None: eps_ = f"` | `{episodes} eps" if episodes is not None else "" status_air = f"{bl}**{text[6]}:** `{status}{eps_}`" else: status_air = f"{bl}**{text[6]}:** `{status}`\n{bl}**{text[11]}:** `{air_on}`" if data["trailer"] and data["trailer"]["site"] == "youtube": trailer_link = f"Trailer" title_img = f"https://img.anili.st/media/{idm}" try: finals_ = ANIME_TEMPLATE.format(**locals()) except KeyError as kys: return [f"{kys}"] return ( title_img, finals_, [idm, in_ls, in_ls_id, isfav, str(adult)], prql_id, sql_id, ) async def get_anilist(qdb, page, auth: bool = False, user: int = None, cid: int = None): vars_ = {"search": ANIME_DB[qdb], "page": page} result = await return_json_senpai(PAGE_QUERY, vars_, auth=auth, user=user) if len(result["data"]["Page"]["media"]) == 0: return [f"No results Found"] data = result["data"]["Page"]["media"][0] # Data of all fields in returned json # pylint: disable=possibly-unused-variable idm = data.get("id") bot = BOT_USERNAME.replace("@", "") idmal = data.get("idMal") romaji = data["title"]["romaji"] english = data["title"]["english"] native = data["title"]["native"] formats = data.get("format") status = data.get("status") episodes = data.get("episodes") duration = data.get("duration") country = data.get("countryOfOrigin") c_flag = cflag(country) source = data.get("source") prqlsql = data.get("relations").get("edges") adult = data.get("isAdult") trailer_link = "N/A" isfav = data.get("isFavourite") gnrs = ", ".join(data["genres"]) gnrs_ = "" bl, cs = await uidata(cid) text = await get_ui_text(cs) psrc, ptype = text[0], text[1] if len(gnrs) != 0: gnrs_ = f"\n{bl}**{text[7]}:** `{gnrs}`" fav = ", in Favourites" if isfav is True else "" score = data["averageScore"] avscd = f"\n{bl}**{text[2]}:** `{score}%` 🌟" if score is not None else "" tags = [] for i in data["tags"]: tags.append(i["name"]) tags_ = f"\n{bl}**{text[8]}:** `{', '.join(tags[:5])}`" if tags != [] else "" in_ls = False in_ls_id = "" user_data = "" if auth is True: in_list = data.get("mediaListEntry") if in_list is not None: in_ls = True in_ls_id = in_list["id"] in_ls_stts = in_list["status"] in_ls_score = ( f" and scored {in_list['score']}" if in_list["score"] != 0 else "" ) user_data = f"\n{bl}**{text[4]}:** `{in_ls_stts}{fav}{in_ls_score}`" if data["title"]["english"] is not None: name = f"[{c_flag}]**{english}** (`{native}`)" else: name = f"[{c_flag}]**{romaji}** (`{native}`)" prql, sql = "", "" for i in prqlsql: if i["relationType"] == "PREQUEL" and i["node"]["type"] == "ANIME": pname = ( i["node"]["title"]["english"] if i["node"]["title"]["english"] is not None else i["node"]["title"]["romaji"] ) prql += f"**{text[10]}:** `{pname}`\n" break for i in prqlsql: if i["relationType"] == "SEQUEL" and i["node"]["type"] == "ANIME": sname = ( i["node"]["title"]["english"] if i["node"]["title"]["english"] is not None else i["node"]["title"]["romaji"] ) sql += f"**{text[9]}:** `{sname}`\n" break additional = f"{prql}{sql}" additional.replace("-", "") dura = f"\n{bl}**{text[3]}:** `{duration} min/ep`" if duration is not None else "" air_on = None if data["nextAiringEpisode"]: nextAir = data["nextAiringEpisode"]["timeUntilAiring"] air_on = make_it_rw(nextAir * 1000) eps = data["nextAiringEpisode"]["episode"] th = pos_no(str(eps)) air_on += f" | {eps}{th} eps" if air_on is None: eps_ = f"` | `{episodes} eps" if episodes is not None else "" status_air = f"{bl}**{text[6]}:** `{status}{eps_}`" else: status_air = f"{bl}**{text[6]}:** `{status}`\n{bl}**{text[11]}:** `{air_on}`" if data["trailer"] and data["trailer"]["site"] == "youtube": trailer_link = f"Trailer" url = data.get("siteUrl") title_img = f"https://img.anili.st/media/{idm}" surl = f"https://t.me/{bot}/?astart=des_ANI_{idm}_desc" hasNextPage = result["data"]["Page"]["pageInfo"]["hasNextPage"] try: finals_ = ANIME_TEMPLATE.format(**locals()) except KeyError as kys: return [f"{kys}"] return title_img, [finals_, hasNextPage], [idm, in_ls, in_ls_id, isfav, str(adult)] async def get_character(query, page, auth: bool = False, user: int = None): var = {"search": CHAR_DB[query], "page": int(page)} result = await return_json_senpai(CHARACTER_QUERY, var, auth=auth, user=user) if len(result["data"]["Page"]["characters"]) == 0: return [f"No results Found"] data = result["data"]["Page"]["characters"][0] # Character Data id_ = data["id"] name = data["name"]["full"] native = data["name"]["native"] img = data["image"]["large"] site_url = data["siteUrl"] isfav = data.get("isFavourite") va = [] for i in data["media"]["edges"]: for ii in i["voiceActors"]: if f"[{ii['name']['full']}]({ii['siteUrl']})" not in va: va.append(f"[{ii['name']['full']}]({ii['siteUrl']})") lva = None if len(va) > 1: lva = va.pop() sva = ( f"\n**Voice Actors:** {', '.join(va)}" + f"{' and '+lva if lva is not None else ''}\n" if va != [] else "" ) cap_text = f""" __{native}__ (`{name}`) **ID:** {id_} {sva} Visit Website""" hasNextPage = result["data"]["Page"]["pageInfo"]["hasNextPage"] return img, [cap_text, hasNextPage], [id_, isfav] async def browse_(qry: str): s, y = season_() sort = "POPULARITY_DESC" if qry == "upcoming": s, y = season_(True) if qry == "trending": sort = "TRENDING_DESC" vars_ = {"s": s, "y": y, "sort": sort} result = await return_json_senpai(BROWSE_QUERY, vars_) data = result["data"]["Page"]["media"] ls = [] for i in data: if i["format"] in ["TV", "MOVIE", "ONA"]: ls.append("• `" + i["title"]["romaji"] + "`") out = f"{qry.capitalize()} animes in {s} {y}:\n\n" return out + "\n".join(ls[:20]) async def get_manga(qdb, page, auth: bool = False, user: int = None, cid: int = None): vars_ = {"search": MANGA_DB[qdb], "asHtml": True, "page": page} result = await return_json_senpai(MANGA_QUERY, vars_, auth=auth, user=user) if len(result["data"]["Page"]["media"]) == 0: return [f"No results Found"] data = result["data"]["Page"]["media"][0] # Data of all fields in returned json # pylint: disable=possibly-unused-variable idm = data.get("id") romaji = data["title"]["romaji"] english = data["title"]["english"] native = data["title"]["native"] status = data.get("status") synopsis = data.get("description") description = synopsis[:500] description_s = "" if len(synopsis) > 500: description += f"..." description_s = ( f"[Click for more info](https://t.me/{BOT_USERNAME}" + f"/?astart=des_ANI_{idm}_desc)" ) volumes = data.get("volumes") chapters = data.get("chapters") score = data.get("averageScore") url = data.get("siteUrl") format_ = data.get("format") country = data.get("countryOfOrigin") source = data.get("source") c_flag = cflag(country) isfav = data.get("isFavourite") adult = data.get("isAdult") fav = ", in Favourites" if isfav is True else "" in_ls = False in_ls_id = "" bl, cs = await uidata(cid) text = await get_ui_text(cs) user_data = "" if auth is True: in_list = data.get("mediaListEntry") if in_list is not None: in_ls = True in_ls_id = in_list["id"] in_ls_stts = in_list["status"] in_ls_score = ( f" and scored {in_list['score']}" if in_list["score"] != 0 else "" ) user_data = f"{bl}**{text[4]}:** `{in_ls_stts}{fav}{in_ls_score}`\n" name = f"""[{c_flag}]**{romaji}** __{english}__ {native}""" if english is None: name = f"""[{c_flag}]**{romaji}** {native}""" finals_ = f"{name}\n\n" finals_ += f"{bl}**ID:** `{idm}`\n" finals_ += f"{bl}**{text[6]}:** `{status}`\n" finals_ += f"{bl}**{text[13]}:** `{volumes}`\n" finals_ += f"{bl}**{text[14]}:** `{chapters}`\n" finals_ += f"{bl}**{text[2]}:** `{score}`\n" finals_ += f"{bl}**{text[1]}:** `{format_}`\n" finals_ += f"{bl}**{text[0]}:** `{source}`\n" finals_ += user_data if os.environ.get("PREFERRED_LANGUAGE"): description = tr.translate( description, lang_tgt=os.environ.get("PREFERRED_LANGUAGE") ) findesc = "" if description == "" else f"`{description}`" finals_ += f"\n**{text[12]}**: {findesc}\n\n{description_s}" pic = f"https://img.anili.st/media/{idm}" return ( pic, [finals_, result["data"]["Page"]["pageInfo"]["hasNextPage"], url], [idm, in_ls, in_ls_id, isfav, str(adult)], ) async def get_airing(qry, ind: int, auth: bool = False, user: int = None): vars_ = {"search": AIRING_DB[qry], "page": int(ind)} result = await return_json_senpai(AIR_QUERY, vars_, auth=auth, user=user) error = result.get("errors") if error: error_sts = error[0].get("message") return [f"{error_sts}"] try: data = result["data"]["Page"]["media"][0] except IndexError: return ["No results Found"] # Airing Details mid = data.get("id") romaji = data["title"]["romaji"] english = data["title"]["english"] status = data.get("status") country = data.get("countryOfOrigin") c_flag = cflag(country) coverImg = f"https://img.anili.st/media/{mid}" isfav = data.get("isFavourite") adult = data.get("isAdult") in_ls = False in_ls_id = "" user_data = "" if auth is True: in_list = data.get("mediaListEntry") if in_list is not None: in_ls = True in_ls_id = in_list["id"] in_ls_stts = in_list["status"] user_data = f"**USER DATA:** `{in_ls_stts}`\n" air_on = None if data["nextAiringEpisode"]: nextAir = data["nextAiringEpisode"]["timeUntilAiring"] episode = data["nextAiringEpisode"]["episode"] th = pos_no(episode) air_on = make_it_rw(nextAir * 1000) title_ = english or romaji out = f"[{c_flag}] **{title_}**" out += f"\n\n**ID:** `{mid}`" out += f"\n**Status:** `{status}`\n" out += user_data if air_on: out += f"Airing Episode `{episode}{th}` in `{air_on}`" site = data["siteUrl"] return ( [coverImg, out], [site, result["data"]["Page"]["pageInfo"]["hasNextPage"]], [mid, in_ls, in_ls_id, isfav, str(adult)], ) async def toggle_favourites(id_: int, media: str, user: int): vars_ = {"id": int(id_)} query = ( ANIME_MUTATION if media == "ANIME" or media == "AIRING" else ( CHAR_MUTATION if media == "CHARACTER" else MANGA_MUTATION if media == "MANGA" else STUDIO_MUTATION ) ) k = await return_json_senpai(query=query, vars_=vars_, auth=True, user=int(user)) try: kek = k["data"]["ToggleFavourite"] return "ok" except KeyError: return "failed" async def get_user(vars_, req, user, display_user=None): query = USER_QRY if "user" in req else VIEWER_QRY k = await return_json_senpai( query=query, vars_=vars_, auth=False if "user" in req else True, user=int(user) ) error = k.get("errors") if error: error_sts = error[0].get("message") return [f"{error_sts}"] data = k["data"]["User" if "user" in req else "Viewer"] anime = data["statistics"]["anime"] manga = data["statistics"]["manga"] stats = f""" **Anime Stats**: Total Anime Watched: `{anime['count']}` Total Episode Watched: `{anime['episodesWatched']}` Total Time Spent: `{anime['minutesWatched']}` Average Score: `{anime['meanScore']}` **Manga Stats**: Total Manga Read: `{manga['count']}` Total Chapters Read: `{manga['chaptersRead']}` Total Volumes Read: `{manga['volumesRead']}` Average Score: `{manga['meanScore']}` """ btn = [] if not "user" in req: btn.append( [ InlineKeyboardButton( "Favourites", callback_data=f"myfavs_{data['id']}_yes_{display_user}", ), InlineKeyboardButton( "Activity", callback_data=f"myacc_{data['id']}_{display_user}" ), ] ) btn.append([InlineKeyboardButton("Profile", url=str(data["siteUrl"]))]) return [ f'https://img.anili.st/user/{data["id"]}?a={time.time()}', stats, InlineKeyboardMarkup(btn), ] async def update_anilist(id_, req, user, eid: int = None, status: str = None): vars_ = {"id": int(id_), "status": status} if req == "lsus": vars_ = {"id": int(eid), "status": status} if req == "dlt": vars_ = {"id": int(eid)} k = await return_json_senpai( query=( ANILIST_MUTATION if req == "lsas" else ANILIST_MUTATION_UP if req == "lsus" else ANILIST_MUTATION_DEL ), vars_=vars_, auth=True, user=int(user), ) try: ( k["data"]["SaveMediaListEntry"] if req == "lsas" else ( k["data"]["UpdateMediaListEntries"] if req == "lsus" else k["data"]["DeleteMediaListEntry"] ) ) return "ok" except KeyError: return "failed" async def check_if_adult(id_): vars_ = {"id": int(id_)} k = await return_json_senpai(query=ISADULT, vars_=vars_, auth=False) if str(k["data"]["Media"]["isAdult"]) == "True": return "True" else: return "False" #### END #### #### Jikanpy part #### async def get_scheduled(x: int = 9): base_url = "https://api.jikan.moe/v4/schedules/" day = str(day_(x if x != 9 else datetime.now().weekday())).lower() out = f"Scheduled animes for {day.capitalize()}\n\n" data = requests.get(base_url + day).json() sched_ls = data["data"] for i in sched_ls: try: title = i["titles"][0]["title"] except IndexError: title = i["title"] out += f"• `{title}`\n" return out, x if x != 9 else datetime.now().weekday() #### END #### #### chiaki part #### def get_wols(x: str): data = requests.get(f"https://chiaki.vercel.app/search2?query={x}").json() ls = [] for i in data: sls = [data[i], i] ls.append(sls) return ls def get_wo(x: int, page: int): data = requests.get(f"https://chiaki.vercel.app/get2?group_id={x}").json() msg = "Watch order for the given query is:\n\n" out = [] for i in data: out.append(f"{i['index']}. `{i['name']}`\n") total = len(out) for _ in range(50 * page): out.pop(0) out_ = "".join(out[:50]) return msg + out_, total #### END #### ##### Anime Fillers Part ##### def search_filler(query): html = requests.get("https://www.animefillerlist.com/shows").text soup = BeautifulSoup(html, "html.parser") div = soup.findAll("div", attrs={"class": "Group"}) index = {} for i in div: li = i.findAll("li") for jk in li: yum = jk.a["href"].split("/")[-1] cum = jk.text index[cum] = yum ret = {} keys = list(index.keys()) for i in range(len(keys)): if query.lower() in keys[i].lower(): ret[keys[i]] = index[keys[i]] return ret def parse_filler(filler_id): url = "https://www.animefillerlist.com/shows/" + filler_id html = requests.get(url).text soup = BeautifulSoup(html, "html.parser") div = soup.find("div", attrs={"id": "Condensed"}) all_ep = div.find_all("span", attrs={"class": "Episodes"}) if len(all_ep) == 1: ttl_ep = all_ep[0].findAll("a") total_ep = [] mix_ep = None filler_ep = None ac_ep = None for tol in ttl_ep: total_ep.append(tol.text) dict_ = { "filler_id": filler_id, "total_ep": ", ".join(total_ep), "mixed_ep": mix_ep, "filler_ep": filler_ep, "ac_ep": ac_ep, } return dict_ if len(all_ep) == 2: ttl_ep = all_ep[0].findAll("a") fl_ep = all_ep[1].findAll("a") total_ep = [] mix_ep = None ac_ep = None filler_ep = [] for tol in ttl_ep: total_ep.append(tol.text) for fol in fl_ep: filler_ep.append(fol.text) dict_ = { "filler_id": filler_id, "total_ep": ", ".join(total_ep), "mixed_ep": mix_ep, "filler_ep": ", ".join(filler_ep), "ac_ep": ac_ep, } return dict_ if len(all_ep) == 3: ttl_ep = all_ep[0].findAll("a") mxl_ep = all_ep[1].findAll("a") fl_ep = all_ep[2].findAll("a") total_ep = [] mix_ep = [] filler_ep = [] ac_ep = None for tol in ttl_ep: total_ep.append(tol.text) for fol in fl_ep: filler_ep.append(fol.text) for mol in mxl_ep: mix_ep.append(mol.text) dict_ = { "filler_id": filler_id, "total_ep": ", ".join(total_ep), "mixed_ep": ", ".join(mix_ep), "filler_ep": ", ".join(filler_ep), "ac_ep": ac_ep, } return dict_ if len(all_ep) == 4: ttl_ep = all_ep[0].findAll("a") mxl_ep = all_ep[1].findAll("a") fl_ep = all_ep[2].findAll("a") al_ep = all_ep[3].findAll("a") total_ep = [] mix_ep = [] filler_ep = [] ac_ep = [] for tol in ttl_ep: total_ep.append(tol.text) for fol in fl_ep: filler_ep.append(fol.text) for mol in mxl_ep: mix_ep.append(mol.text) for aol in al_ep: ac_ep.append(aol.text) dict_ = { "filler_id": filler_id, "total_ep": ", ".join(total_ep), "mixed_ep": ", ".join(mix_ep), "filler_ep": ", ".join(filler_ep), "ac_ep": ", ".join(ac_ep), } return dict_ @app.on_message( filters.command(["anime", f"anime{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def anime_cmd(client: Client, message: Message, mdata: dict): """Search Anime Info""" text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "anime" in find_gc["cmd_list"].split(): return if len(text) == 1: k = await message.reply_text( """Please give a query to search about example: /anime Sword Art Online""" ) await asyncio.sleep(5) return await k.delete() query = text[1] auth = False vars_ = {"search": query} if query.isdigit(): vars_ = {"id": int(query)} if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_anime( vars_, user=auser, auth=auth, cid=gid if gid != user else None ) if len(result) != 1: title_img, finals_ = result[0], result[1] else: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() buttons = get_btns("ANIME", result=result, user=user, auth=auth) if await SFW_GRPS.find_one({"id": gid}) and result[2].pop() == "True": await client.send_photo( gid, no_pic[random.randint(0, 4)], caption="This anime is marked 18+ and not allowed in this group", ) return try: await client.send_photo(gid, title_img, caption=finals_, reply_markup=buttons) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", title_img, "LINK", msg=message) await client.send_photo(gid, failed_pic, caption=finals_, reply_markup=buttons) @app.on_message( filters.command(["manga", f"manga{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def manga_cmd(client: Client, message: Message, mdata: dict): """Search Manga Info""" text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "manga" in find_gc["cmd_list"].split(): return if len(text) == 1: k = await message.reply_text( """Please give a query to search about example: /manga Sword Art Online""" ) await asyncio.sleep(5) return await k.delete() query = text[1] qdb = rand_key() MANGA_DB[qdb] = query auth = False if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_manga( qdb, 1, auth=auth, user=auser, cid=gid if gid != user else None ) if len(result) == 1: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() pic, finals_ = result[0], result[1][0] buttons = get_btns( "MANGA", lsqry=qdb, lspage=1, user=user, result=result, auth=auth ) if await SFW_GRPS.find_one({"id": gid}) and result[2].pop() == "True": buttons = get_btns( "MANGA", lsqry=qdb, lspage=1, user=user, result=result, auth=auth, sfw="True", ) await client.send_photo( gid, no_pic[random.randint(0, 4)], caption="This manga is marked 18+ and not allowed in this group", reply_markup=buttons, ) return try: await client.send_photo(gid, pic, caption=finals_, reply_markup=buttons) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=message) await client.send_photo(gid, failed_pic, caption=finals_, reply_markup=buttons) @app.on_message( filters.command(["character", f"character{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def character_cmd(client: Client, message: Message, mdata: dict): """Get Info about a Character""" text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "character" in find_gc["cmd_list"].split(): return if len(text) == 1: k = await message.reply_text( "Please give a query to search about\nexample: /character Luffy" ) await asyncio.sleep(5) return await k.delete() query = text[1] qdb = rand_key() CHAR_DB[qdb] = query auth = False if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_character(qdb, 1, auth=auth, user=auser) if len(result) == 1: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() img = result[0] cap_text = result[1][0] buttons = get_btns( "CHARACTER", user=user, lsqry=qdb, lspage=1, result=result, auth=auth ) try: await client.send_photo(gid, img, caption=cap_text, reply_markup=buttons) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", img, "LINK", msg=message) await client.send_photo(gid, failed_pic, caption=cap_text, reply_markup=buttons) @app.on_message( filters.command(["anilist", f"anilist{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def anilist_cmd(client: Client, message: Message, mdata: dict): text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "anilist" in find_gc["cmd_list"].split(): return if len(text) == 1: k = await message.reply_text( "Please give a query to search about\nexample: /anilist Sword Art Online" ) await asyncio.sleep(5) return await k.delete() query = text[1] qdb = rand_key() ANIME_DB[qdb] = query auth = False if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_anilist( qdb, 1, auth=auth, user=auser, cid=gid if gid != user else None ) if len(result) == 1: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() pic, msg = result[0], result[1][0] buttons = get_btns( "ANIME", lsqry=qdb, lspage=1, result=result, user=user, auth=auth ) if await SFW_GRPS.find_one({"id": gid}) and result[2].pop() == "True": buttons = get_btns( "ANIME", lsqry=qdb, lspage=1, result=result, user=user, auth=auth, sfw="True", ) await client.send_photo( gid, no_pic[random.randint(0, 4)], caption="This anime is marked 18+ and not allowed in this group", reply_markup=buttons, ) return try: await client.send_photo(gid, pic, caption=msg, reply_markup=buttons) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=message) await client.send_photo(gid, failed_pic, caption=msg, reply_markup=buttons) @app.on_message(filters.command(["top", f"top{BOT_USERNAME}"], prefixes=PREFIX_HANDLER)) @control_user async def top_tags_cmd(client: Client, message: Message, mdata: dict): query = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "top" in find_gc["cmd_list"].split(): return get_tag = "None" if len(query) == 2: get_tag = query[1] try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] result = await get_top_animes(get_tag, 1, user) if len(result) == 1: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() if await SFW_GRPS.find_one({"id": gid}) and str(result[0][1]) == "True": return await message.reply_text("No nsfw stuff allowed in this group!!!") msg, buttons = result await client.send_message( gid, msg[0], reply_markup=buttons if buttons != "" else None ) @app.on_message( filters.command(["studio", f"studio{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def studio_cmd(client: Client, message: Message, mdata: dict): text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "studio" in find_gc["cmd_list"].split(): return if len(text) == 1: x = await message.reply_text( "Please give a query to search about!!!\nExample: /studio ufotable" ) await asyncio.sleep(5) await x.delete() return query = text[1] qdb = rand_key() STUDIO_DB[qdb] = query auth = False try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_studios(qdb, 1, user=auser, duser=user, auth=auth) if len(result) == 1: x = await message.reply_text("No results found!!!") await asyncio.sleep(5) return await x.delete() msg, buttons = result[0], result[1] await client.send_message(gid, msg, reply_markup=buttons if buttons != "" else None) @app.on_message( filters.command(["airing", f"airing{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def airing_cmd(client: Client, message: Message, mdata: dict): """Get Airing Detail of Anime""" text = mdata["text"].split(" ", 1) gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "airing" in find_gc["cmd_list"].split(): return if len(text) == 1: k = await message.reply_text( """Please give a query to search about example: /airing Sword Art Online""" ) await asyncio.sleep(5) return await k.delete() query = text[1] qdb = rand_key() AIRING_DB[qdb] = query auth = False try: user = mdata["from_user"]["id"] auser = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] ufc = await gcc(user) if ufc is not None: auser = ufc else: auser = user if await AUTH_USERS.find_one({"id": auser}): auth = True result = await get_airing(qdb, 1, auth=auth, user=auser) if len(result) == 1: k = await message.reply_text(result[0]) await asyncio.sleep(5) return await k.delete() coverImg, out = result[0] btn = get_btns("AIRING", user=user, result=result, auth=auth, lsqry=qdb, lspage=1) if await SFW_GRPS.find_one({"id": gid}) and result[2].pop() == "True": btn = get_btns( "AIRING", user=user, result=result, auth=auth, lsqry=qdb, lspage=1, sfw="True", ) await client.send_photo( gid, no_pic[random.randint(0, 4)], caption="This anime is marked 18+ and not allowed in this group", reply_markup=btn, ) return try: await client.send_photo(gid, coverImg, caption=out, reply_markup=btn) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", coverImg, "LINK", msg=message) await client.send_photo(gid, failed_pic, caption=out, reply_markup=btn) setting_text = """ This allows you to change group settings NSFW toggle switches on filtering of 18+ marked content Airing notifications notifies about airing of anime in recent Crunchyroll updates will toggle notifications about release of animes on crunchyroll site Subsplease updates will toggle notifications about release of animes on subsplease site Click Headlines button to enable headlines. You can choose from given sources""" @app.on_message( ~filters.private & filters.command( ["anisettings", f"anisettings{BOT_USERNAME}"], prefixes=PREFIX_HANDLER ) ) @control_user async def settings_cmd(client: Client, message: Message, mdata: dict): cid = mdata["chat"]["id"] try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] type_ = mdata["chat"]["type"] try: status = (await app.get_chat_member(cid, user)).status except UserNotParticipant: status = None if ( user in BOT_OWNER or status in [ADMINISTRATOR, CHAT_OWNER] or type_ == ChatType.CHANNEL or user == cid ): sfw = "NSFW: Allowed" if await SFW_GRPS.find_one({"id": cid}): sfw = "NSFW: Not Allowed" notif = "Airing notifications: OFF" if await AG.find_one({"_id": cid}): notif = "Airing notifications: ON" cr = "Crunchyroll Updates: OFF" if await CG.find_one({"_id": cid}): cr = "Crunchyroll Updates: ON" sp = "Subsplease Updates: OFF" if await SG.find_one({"_id": cid}): sp = "Subsplease Updates: ON" await message.reply_text( text=setting_text, reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton( text=sfw, callback_data=f"settogl_sfw_{cid}" ) ], [ InlineKeyboardButton( text=notif, callback_data=f"settogl_notif_{cid}" ) ], [InlineKeyboardButton(text=cr, callback_data=f"settogl_cr_{cid}")], [InlineKeyboardButton(text=sp, callback_data=f"settogl_sp_{cid}")], [ InlineKeyboardButton( text="Headlines", callback_data=f"headlines_call_{cid}" ) ], [ InlineKeyboardButton( text="Change UI", callback_data=f"cui_call_{cid}" ) ], ] ), ) @app.on_message( filters.command(["browse", f"browse{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def browse_cmd(client: Client, message: Message, mdata: dict): try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "browse" in find_gc["cmd_list"].split(): return up = "Upcoming" tr = "• Trending •" pp = "Popular" btns = [ [ InlineKeyboardButton(tr, callback_data=f"browse_{tr.lower()}_{user}"), InlineKeyboardButton(pp, callback_data=f"browse_{pp.lower()}_{user}"), InlineKeyboardButton(up, callback_data=f"browse_{up.lower()}_{user}"), ] ] msg = await browse_("trending") await client.send_message(gid, msg, reply_markup=InlineKeyboardMarkup(btns)) @app.on_message( filters.command( ["gettags", f"gettags{BOT_USERNAME}", "getgenres", f"getgenres{BOT_USERNAME}"], prefixes=PREFIX_HANDLER, ) ) @control_user async def list_tags_genres_cmd(client, message: Message, mdata: dict): gid = mdata["chat"]["id"] text = mdata["text"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "gettags" in ( text.split()[0] and find_gc["cmd_list"].split() ): return if find_gc is not None and "getgenres" in ( text.split()[0] and find_gc["cmd_list"].split() ): return if await SFW_GRPS.find_one({"id": gid}) and "nsfw" in text: return await message.reply_text("No nsfw allowed here!!!") msg = ( (await get_all_tags(text)) if "gettags" in text.split()[0] else (await get_all_genres()) ) await message.reply_text(msg) @app.on_callback_query(filters.regex(pattern=r"page_(.*)")) @check_user async def page_btn(client: Client, cq: CallbackQuery, cdata: dict): kek, media, query, page, auth, user = cq.data.split("_") gid = cdata["message"]["chat"]["id"] if media == "ANIME": try: ANIME_DB[query] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if media == "MANGA": try: MANGA_DB[query] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if media == "CHARACTER": try: CHAR_DB[query] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if media == "AIRING": try: AIRING_DB[query] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) authbool = bool(1) if auth == "True" else bool(0) if "-100" in str(user): auser = await gcc(user) else: auser = user if media in ["ANIME", "MANGA"]: result = await (get_anilist if media == "ANIME" else get_manga)( query, int(page), auth=authbool, user=int(auser), cid=gid if gid != user else None, ) else: result = await (get_character if media == "CHARACTER" else get_airing)( query, int(page), auth=authbool, user=int(auser) ) if "No results Found" in result: await cq.answer("No more results available!!!", show_alert=True) return pic, msg = result[0], result[1][0] if media == "AIRING": pic, msg = result[0][0], result[0][1] button = get_btns( media, lsqry=query, lspage=int(page), result=result, user=user, auth=authbool ) if ( await SFW_GRPS.find_one({"id": gid}) and media != "CHARACTER" and result[2].pop() == "True" ): button = get_btns( media, lsqry=query, lspage=int(page), result=result, user=user, auth=authbool, sfw="True", ) await cq.edit_message_media( InputMediaPhoto( no_pic[random.randint(0, 4)], caption=""" This material is marked 18+ and not allowed in this group""", ), reply_markup=button, ) return try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=button ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=button ) await cq.answer() @app.on_callback_query(filters.regex(pattern=r"pgstudio_(.*)")) @check_user async def studio_pg_btn(client: Client, cq: CallbackQuery, cdata: dict): kek, page, qry, auth, user = cdata["data"].split("_") authbool = bool(1) if auth == "True" else bool(0) try: STUDIO_DB[qry] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if "-100" in str(user): auser = await gcc(user) else: auser = user result = await get_studios(qry, page=page, user=auser, duser=user, auth=authbool) if len(result) == 1: return await cq.answer("No more results available!!!", show_alert=True) msg, buttons = result[0], result[1] await cq.edit_message_text(msg, reply_markup=buttons) @app.on_callback_query(filters.regex(pattern=r"stuani_(.*)")) @check_user async def studio_ani_btn(client: Client, cq: CallbackQuery, cdata: dict): kek, page, id_, rp, qry, auth, user = cdata["data"].split("_") authbool = bool(1) if auth == "True" else bool(0) if "-100" in str(user): auser = await gcc(user) else: auser = user result = await get_studio_animes(id_, page, qry, rp, auser, user, authbool) if len(result) == 1: return await cq.answer("No results available!!!", show_alert=True) msg, buttons = result[0], result[1] await cq.edit_message_text(msg, reply_markup=buttons) @app.on_callback_query(filters.regex(pattern=r"btn_(.*)")) @check_user async def anime_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() query = cdata["data"].split("_") idm = query[1] user = int(query.pop()) if "-100" in str(user): auser = await gcc(user) else: auser = user authbool = bool(1) if query[2] == "True" else bool(0) vars_ = {"id": int(idm)} cid = cdata["message"]["chat"]["id"] result = await get_anime( vars_, auth=authbool, user=auser, cid=cid if cid != user else None ) pic, msg = result[0], result[1] btns = get_btns("ANIME", result=result, user=user, auth=authbool) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"topanimu_(.*)")) @check_user async def top_tags_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() kek, gnr, page, user = cdata["data"].split("_") result = await get_top_animes(gnr, page=page, user=user) msg, buttons = result[0][0], result[1] await cq.edit_message_text(msg, reply_markup=buttons) @app.on_callback_query(filters.regex(pattern=r"settogl_(.*)")) async def nsfw_toggle_btn(client: Client, cq: CallbackQuery): cus = cq.from_user.id gid = cq.data.split("_").pop() try: k = (await client.get_chat_member(gid, cus)).status except UserNotParticipant: await cq.answer() return if cus not in BOT_OWNER and k == MEMBER: await cq.answer( "You don't have enough permissions to change this!!!", show_alert=True ) return query = cq.data.split("_") if await SFW_GRPS.find_one({"id": int(query[2])}): sfw = "NSFW: Not Allowed" else: sfw = "NSFW: Allowed" if await AG.find_one({"_id": int(query[2])}): notif = "Airing notifications: ON" else: notif = "Airing notifications: OFF" if await CG.find_one({"_id": int(query[2])}): cr = "Crunchyroll Updates: ON" else: cr = "Crunchyroll Updates: OFF" if await SG.find_one({"_id": int(query[2])}): sp = "Subsplease Updates: ON" else: sp = "Subsplease Updates: OFF" if query[1] == "sfw": if await SFW_GRPS.find_one({"id": int(query[2])}): await SFW_GRPS.find_one_and_delete({"id": int(query[2])}) sfw = "NSFW: Allowed" else: await SFW_GRPS.insert_one({"id": int(query[2])}) sfw = "NSFW: Not Allowed" if query[1] == "notif": if await AG.find_one({"_id": int(query[2])}): await AG.find_one_and_delete({"_id": int(query[2])}) notif = "Airing notifications: OFF" else: await AG.insert_one({"_id": int(query[2])}) notif = "Airing notifications: ON" if query[1] == "cr": if await CG.find_one({"_id": int(query[2])}): await CG.find_one_and_delete({"_id": int(query[2])}) cr = "Crunchyroll Updates: OFF" else: await CG.insert_one({"_id": int(query[2])}) cr = "Crunchyroll Updates: ON" if query[1] == "sp": if await SG.find_one({"_id": int(query[2])}): await SG.find_one_and_delete({"_id": int(query[2])}) sp = "Subsplease Updates: OFF" else: await SG.insert_one({"_id": int(query[2])}) sp = "Subsplease Updates: ON" btns = InlineKeyboardMarkup( [ [InlineKeyboardButton(text=sfw, callback_data=f"settogl_sfw_{query[2]}")], [ InlineKeyboardButton( text=notif, callback_data=f"settogl_notif_{query[2]}" ) ], [InlineKeyboardButton(text=cr, callback_data=f"settogl_cr_{query[2]}")], [InlineKeyboardButton(text=sp, callback_data=f"settogl_sp_{query[2]}")], [ InlineKeyboardButton( text="Headlines", callback_data=f"headlines_call_{query[2]}" ) ], [ InlineKeyboardButton( text="Change UI", callback_data=f"cui_call_{query[2]}" ) ], ] ) await cq.answer() if query[1] == "call": await cq.edit_message_text(text=setting_text, reply_markup=btns) await cq.edit_message_reply_markup(reply_markup=btns) @app.on_callback_query(filters.regex(pattern=r"myacc_(.*)")) @check_user async def flex_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() query = cdata["data"].split("_")[1] user = cdata["data"].split("_").pop() if "-100" in str(user): auser = await gcc(user) else: auser = user result = await get_user_activity(int(query), user=int(auser), duser=int(user)) pic, msg, btns = result try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"myfavs_(.*)")) @check_user async def list_favourites_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() q = cdata["data"].split("_") btn = [ [ InlineKeyboardButton( "ANIME", callback_data=f"myfavqry_ANIME_{q[1]}_1_{q[2]}_{q[3]}" ), InlineKeyboardButton( "CHARACTER", callback_data=f"myfavqry_CHAR_{q[1]}_1_{q[2]}_{q[3]}" ), InlineKeyboardButton( "MANGA", callback_data=f"myfavqry_MANGA_{q[1]}_1_{q[2]}_{q[3]}" ), ] ] if q[2] == "yes": btn.append([InlineKeyboardButton("BACK", callback_data=f"getusrbc_{q[3]}")]) else: btn.append( [InlineKeyboardButton("PROFILE", url=f"https://anilist.co/user/{q[1]}")] ) try: await cq.edit_message_media( InputMediaPhoto( f"https://img.anili.st/user/{q[1]}?a={time.time()}", caption="Choose one of the below options", ), reply_markup=InlineKeyboardMarkup(btn), ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog( "Mikobot", f"https://img.anili.st/user/{q[1]}?a={time.time()}", "LINK", msg=cq, ) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption="Choose one of the below options"), reply_markup=InlineKeyboardMarkup(btn), ) @app.on_callback_query(filters.regex(pattern=r"myfavqry_(.*)")) @check_user async def favourites_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() q = cdata["data"].split("_") if "-100" in str(q[5]): auser = await gcc(q[5]) else: auser = q[5] pic, msg, btns = await get_user_favourites( q[2], int(auser), q[1], q[3], q[4], duser=int(q[5]) ) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"getusrbc_(.*)")) @check_user async def get_user_back_btn(client: Client, cq: CallbackQuery, cdata: dict): await cq.answer() query = cdata["data"].split("_")[1] if "-100" in str(query): auser = await gcc(query) else: auser = query result = await get_user(None, "flex", user=int(auser), display_user=query) pic, msg, btns = result try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), creply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"fav_(.*)")) @check_user async def toggle_favourites_btn(client: Client, cq: CallbackQuery, cdata: dict): query = cdata["data"].split("_") if query[1] == "ANIME" and len(query) > 4: try: ANIME_DB[query[3]] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if query[1] == "MANGA": try: MANGA_DB[query[3]] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if query[1] == "CHARACTER": try: CHAR_DB[query[3]] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) if query[1] == "STUDIO": try: STUDIO_DB[query[3]] except KeyError: return await cq.answer("Query Expired!!!\nCreate new one", show_alert=True) idm = int(query[2]) user = int(query.pop()) if "-100" in str(user): auser = await gcc(user) else: auser = user gid = cdata["message"]["chat"]["id"] rslt = await toggle_favourites(id_=idm, media=query[1], user=auser) if rslt == "ok": await cq.answer("Updated", show_alert=True) else: return await cq.answer("Failed to update!!!", show_alert=True) result = ( ( await get_anime( {"id": idm}, auth=True, user=auser, cid=gid if gid != user else None ) ) if query[1] == "ANIME" and len(query) == 3 else ( ( await get_anilist( query[3], page=int(query[4]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[1] == "ANIME" and len(query) != 3 else ( ( await get_manga( query[3], page=int(query[4]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[1] == "MANGA" else ( ( await get_airing( query[3], auth=True, user=auser, ind=int(query[4]) ) ) if query[1] == "AIRING" else ( ( await get_character( query[3], int(query[4]), auth=True, user=auser ) ) if query[1] == "CHARACTER" else ( await get_studios( query[3], int(query[4]), user=auser, auth=True, duser=user, ) ) ) ) ) ) ) if query[1] == "STUDIO": return await cq.edit_message_text(result[0], reply_markup=result[1]) pic, msg = ( (result[0], result[1]) if query[1] == "ANIME" and len(query) == 3 else (result[0]) if query[1] == "AIRING" else (result[0], result[1][0]) ) btns = get_btns( query[1], result=result, user=user, auth=True, lsqry=query[3] if len(query) != 3 else None, lspage=int(query[4]) if len(query) != 3 else None, ) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"(lsadd|lsupdt)_(.*)")) @check_user async def list_update_anilist_btn(client: Client, cq: CallbackQuery, cdata: dict): stts_ls = ["COMPLETED", "CURRENT", "PLANNING", "DROPPED", "PAUSED", "REPEATING"] query = cdata["data"].split("_") btns = [] row = [] for i in stts_ls: row.append( InlineKeyboardButton( text=i, callback_data=( cq.data.replace("lsadd", f"lsas_{i}") if query[0] == "lsadd" else cq.data.replace("lsupdt", f"lsus_{i}") ), ) ) if len(row) == 3: btns.append(row) row = [] if query[0] == "lsupdt": btns.append( [ InlineKeyboardButton( "DELETE", callback_data=cq.data.replace("lsupdt", f"dlt_{i}") ) ] ) await cq.edit_message_reply_markup(reply_markup=InlineKeyboardMarkup(btns)) @app.on_callback_query( filters.regex(pattern=r"browse_(upcoming|trending|popular)_(.*)") ) @check_user async def browse_btn(client: Client, cq: CallbackQuery, cdata: dict): query = cdata["data"].split("_") if "•" in query[1]: return msg = await browse_(query[1]) up = "Upcoming" if query[1] != "upcoming" else "• Upcoming •" tr = "Trending" if query[1] != "trending" else "• Trending •" pp = "Popular" if query[1] != "popular" else "• Popular •" btns = [ [ InlineKeyboardButton(tr, callback_data=f"browse_{tr.lower()}_{query[2]}"), InlineKeyboardButton(pp, callback_data=f"browse_{pp.lower()}_{query[2]}"), InlineKeyboardButton(up, callback_data=f"browse_{up.lower()}_{query[2]}"), ] ] await cq.edit_message_text(msg, reply_markup=InlineKeyboardMarkup(btns)) @app.on_callback_query(filters.regex(pattern=r"(lsas|lsus|dlt)_(.*)")) @check_user async def update_anilist_btn(client: Client, cq: CallbackQuery, cdata: dict): query = cdata["data"].split("_") if query[2] == "ANIME": if len(query) == 7: try: ANIME_DB[query[4]] except KeyError: return await cq.answer( "Query Expired!!!\nCreate new one", show_alert=True ) if len(query) == 8: try: ANIME_DB[query[5]] except KeyError: return await cq.answer( "Query Expired!!!\nCreate new one", show_alert=True ) if query[2] == "MANGA": if len(query) == 7: try: MANGA_DB[query[4]] except KeyError: return await cq.answer( "Query Expired!!!\nCreate new one", show_alert=True ) if len(query) == 8: try: MANGA_DB[query[5]] except KeyError: return await cq.answer( "Query Expired!!!\nCreate new one", show_alert=True ) idm = int(query[3]) user = int(query.pop()) if "-100" in str(user): auser = await gcc(user) else: auser = user gid = cdata["message"]["chat"]["id"] eid = None if query[0] != "lsas": eid = int(query[4]) rslt = await update_anilist( id_=idm, req=query[0], status=query[1], user=auser, eid=eid ) if rslt == "ok": await cq.answer("Updated", show_alert=True) else: await cq.answer( "Something unexpected happened and operation failed successfully", show_alert=True, ) return result = ( ( await get_anime( {"id": idm}, auth=True, user=auser, cid=gid if gid != user else None ) ) if query[2] == "ANIME" and (len(query) == 4 or len(query) == 5) else ( ( await get_anilist( query[4], page=int(query[5]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[2] == "ANIME" and len(query) == 6 else ( ( await get_anilist( query[5], page=int(query[6]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[2] == "ANIME" and len(query) == 7 else ( ( await get_manga( query[4], page=int(query[5]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[2] == "MANGA" and len(query) == 6 else ( ( await get_manga( query[5], page=int(query[6]), auth=True, user=auser, cid=gid if gid != user else None, ) ) if query[2] == "MANGA" and len(query) == 7 else ( await get_airing( query[4] if eid is None else query[5], auth=True, user=auser, ind=int(query[5] if eid is None else query[6]), ) ) ) ) ) ) ) pic, msg = ( (result[0], result[1]) if query[2] == "ANIME" and (len(query) == 4 or len(query) == 5) else (result[0]) if query[2] == "AIRING" else (result[0], result[1][0]) ) btns = get_btns( query[2], result=result, user=user, auth=True, lsqry=query[4] if len(query) == 6 else query[5] if len(query) == 7 else None, lspage=( int(query[5]) if len(query) == 6 else int(query[6]) if len(query) == 7 else None ), ) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=btns ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=btns ) @app.on_callback_query(filters.regex(pattern=r"(desc|ls|char)_(.*)")) @check_user async def additional_info_btn(client: Client, cq: CallbackQuery, cdata: dict): q = cdata["data"].split("_") kek, qry, ctgry = q[0], q[1], q[2] info = ( "Description" if kek == "desc" else "Series List" if kek == "ls" else "Characters List" ) page = 0 lsqry = f"_{q[3]}" if len(q) > 6 else "" lspg = f"_{q[4]}" if len(q) > 6 else "" if kek == "char": page = q[6] if len(q) > 6 else q[4] rjsdata = await get_additional_info(qry, ctgry, kek, page=int(page)) pic, result = rjsdata[0], rjsdata[1] button = [] spoiler = False bot = BOT_USERNAME if result is None: await cq.answer("No description available!!!", show_alert=True) return if "~!" in result and "!~" in result: result = re.sub(r"~!.*!~", "[Spoiler]", result) spoiler = True button.append( [ InlineKeyboardButton( text="VIEW SPOILER", url=f"https://t.me/{bot}/?astart=des_{ctgry}_{qry}_desc", ) ] ) if len(result) > 1000: result = result[:940] + "..." if spoiler is False: result += "\n\nFor more info click below given button" button.append( [ InlineKeyboardButton( text="MORE INFO", url=f"https://t.me/{bot}/?astart=des_{ctgry}_{qry}_{kek}", ) ] ) add_ = "" user = q.pop() if kek == "char": btndata = rjsdata[2] if btndata["lastPage"] != 1: qs = q[5] if len(q) != 5 else q[3] pre = f"{kek}_{qry}_{ctgry}{lsqry}{lspg}_{qs}_{int(page)-1}_{user}" nex = f"{kek}_{qry}_{ctgry}{lsqry}{lspg}_{qs}_{int(page)+1}_{user}" if page == "1": button.append([InlineKeyboardButton(text="NEXT", callback_data=nex)]) elif btndata["lastPage"] == int(page): button.append([InlineKeyboardButton(text="PREV", callback_data=pre)]) else: button.append( [ InlineKeyboardButton(text="PREV", callback_data=pre), InlineKeyboardButton(text="NEXT", callback_data=nex), ] ) add_ = f"\n\nTotal Characters: {btndata['total']}" msg = f"{info}:\n\n{result+add_}" cbd = ( f"btn_{qry}_{q[3]}_{user}" if len(q) <= 5 else ( f"page_ANIME{lsqry}{lspg}_{q[5]}_{user}" if ctgry == "ANI" else f"page_CHARACTER{lsqry}{lspg}_{q[5]}_{user}" ) ) button.append([InlineKeyboardButton(text="BACK", callback_data=cbd)]) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=InlineKeyboardMarkup(button) ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=InlineKeyboardMarkup(button), ) await cq.answer() @app.on_callback_query(filters.regex(pattern=r"lsc_(.*)")) @check_user async def featured_in_btn(client: Client, cq: CallbackQuery, cdata: dict): kek, idm, qry, pg, auth, usr = cdata["data"].split("_") result = await get_featured_in_lists(int(idm), "ANI") req = "lscm" if result[0] is False: result = await get_featured_in_lists(int(idm), "MAN") req = None if result[0] is False: await cq.answer("No Data Available!!!", show_alert=True) return [msg, total], pic = result button = [] totalpg, kek = divmod(total, 15) if kek != 0: totalpg + 1 if total > 15: button.append( [ InlineKeyboardButton( text="NEXT", callback_data=f"lsca_{idm}_1_{qry}_{pg}_{auth}_{usr}" ) ] ) if req is not None: button.append( [ InlineKeyboardButton( text="MANGA", callback_data=f"lscm_{idm}_0_{qry}_{pg}_{auth}_{usr}" ) ] ) button.append( [ InlineKeyboardButton( text="BACK", callback_data=f"page_CHARACTER_{qry}_{pg}_{auth}_{usr}" ) ] ) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=InlineKeyboardMarkup(button) ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=InlineKeyboardMarkup(button), ) @app.on_callback_query(filters.regex(pattern=r"lsc(a|m)_(.*)")) @check_user async def featured_in_switch_btn(client: Client, cq: CallbackQuery, cdata: dict): req, idm, reqpg, qry, pg, auth, user = cdata["data"].split("_") result = await get_featured_in_lists( int(idm), "MAN" if req == "lscm" else "ANI", page=int(reqpg) ) reqb = "lsca" if req == "lscm" else "lscm" bt = "Anime" if req == "lscm" else "Manga" if result[0] is False: await cq.answer("No Data Available!!!", show_alert=True) return [msg, total], pic = result totalpg, kek = divmod(total, 15) if kek != 0: totalpg + 1 button = [] if total > 15: nex = f"{req}_{idm}_{int(reqpg)+1}_{qry}_{pg}_{auth}_{user}" bac = f"{req}_{idm}_{int(reqpg)-1}_{qry}_{pg}_{auth}_{user}" if int(reqpg) == 0: button.append([InlineKeyboardButton(text="NEXT", callback_data=nex)]) elif int(reqpg) == totalpg: button.append([InlineKeyboardButton(text="BACK", callback_data=bac)]) else: button.append( [ InlineKeyboardButton(text="BACK", callback_data=bac), InlineKeyboardButton(text="NEXT", callback_data=nex), ] ) button.append( [ InlineKeyboardButton( text=f"{bt}", callback_data=f"{reqb}_{idm}_0_{qry}_{pg}_{auth}_{user}" ) ] ) button.append( [ InlineKeyboardButton( text="BACK", callback_data=f"page_CHARACTER_{qry}_{pg}_{auth}_{user}" ) ] ) try: await cq.edit_message_media( InputMediaPhoto(pic, caption=msg), reply_markup=InlineKeyboardMarkup(button) ) except (WebpageMediaEmpty, WebpageCurlFailed): await clog("Mikobot", pic, "LINK", msg=cq) await cq.edit_message_media( InputMediaPhoto(failed_pic, caption=msg), reply_markup=InlineKeyboardMarkup(button), ) headlines_text = """ Turn LiveChart option on to get news feeds from livechart.me Turn MyAnimeList option on to get news feeds from myanimelist.net For Auto Pin and Auto Unpin features, give the bot "Pin Message" and "Delete Message" perms Auto Unpin can be customized, click on the button to see available options """ @app.on_callback_query(filters.regex(pattern=r"headlines_(.*)")) async def headlines_btn(client: Client, cq: CallbackQuery): cus = cq.from_user.id qry = cq.data.split("_")[1] gid = int(cq.data.split("_")[2]) try: k = (await client.get_chat_member(gid, cus)).status except UserNotParticipant: await cq.answer() return if cus not in BOT_OWNER and k == MEMBER: await cq.answer( "You don't have enough permissions to change this!!!", show_alert=True ) return lcdata = await HD.find_one({"_id": gid}) maldata = await MHD.find_one({"_id": gid}) lchd = "LiveChart: OFF" malhd = "MyAnimeList: OFF" malhdpin = lchdpin = "Auto Pin: OFF" malpin = lcpin = None if lcdata: lchd = "LiveChart: ON" try: lcpin = lcdata["pin"] lchdpin = f"Auto Pin: {lcpin}" except KeyError: pass if maldata: malhd = "MyAnimeList: ON" try: malpin = maldata["pin"] malhdpin = f"Auto Pin: {malpin}" except KeyError: pass if "mal" in qry: data = maldata pin = malpin pin_msg = malhdpin collection = MHD src_status = malhd srcname = "MyAnimeList" else: data = lcdata pin = lcpin pin_msg = lchdpin collection = HD src_status = lchd srcname = "LiveChart" if re.match(r"^(mal|lc)hd$", qry): if data: await collection.find_one_and_delete(data) src_status = f"{srcname}: OFF" pin_msg = f"Auto Pin: OFF" else: await collection.insert_one({"_id": gid}) src_status = f"{srcname}: ON" pin_msg = f"Auto Pin: OFF" if re.match(r"^(mal|lc)hdpin$", qry): if data: if pin: switch = "ON" if pin == "OFF" else "OFF" await collection.find_one_and_update( data, {"$set": {"pin": switch, "unpin": None}}, upsert=True ) pin_msg = f"Auto Pin: {switch}" else: await collection.find_one_and_update( data, {"$set": {"pin": "ON"}}, upsert=True ) pin_msg = f"Auto Pin: ON" else: await cq.answer(f"Please enable {srcname} first!!!", show_alert=True) if "mal" in qry: malhdpin = pin_msg malhd = src_status else: lchdpin = pin_msg lchd = src_status btn = InlineKeyboardMarkup( [ [InlineKeyboardButton(text=lchd, callback_data=f"headlines_lchd_{gid}")], [ InlineKeyboardButton( text=lchdpin, callback_data=f"headlines_lchdpin_{gid}" ), InlineKeyboardButton( text="Auto Unpin (LC)", callback_data=f"anpin_call_lc_{gid}" ), ], [InlineKeyboardButton(text=malhd, callback_data=f"headlines_malhd_{gid}")], [ InlineKeyboardButton( text=malhdpin, callback_data=f"headlines_malhdpin_{gid}" ), InlineKeyboardButton( text="Auto Unpin (MAL)", callback_data=f"anpin_call_mal_{gid}" ), ], [InlineKeyboardButton(text="BACK", callback_data=f"settogl_call_{gid}")], ] ) await cq.edit_message_text(headlines_text, reply_markup=btn) await cq.answer() TIMES = { "1 day": 86400, "5 days": 432000, "1 week": 604800, "2 week": 1209600, "1 month": 2592000, "New Feed": 0, "OFF": None, } @app.on_callback_query(filters.regex(pattern=r"anpin_(.*)")) async def auto_unpin(client: Client, cq: CallbackQuery): cus = cq.from_user.id qry = cq.data.split("_")[1] src = cq.data.split("_")[2] gid = int(cq.data.split("_")[3]) try: k = (await client.get_chat_member(gid, cus)).status except UserNotParticipant: await cq.answer() return if cus not in BOT_OWNER and k == MEMBER: await cq.answer( "You don't have enough permissions to change this!!!", show_alert=True ) return cancel = False if src == "lc": srcname = "LiveChart" collection = HD else: srcname = "MyAnimeList" collection = MHD data = await collection.find_one({"_id": gid}) if data: try: data["pin"] try: unpin = data["unpin"] except KeyError: unpin = None except KeyError: cancel = True else: cancel = True if cancel: return await cq.answer( f"Please enable {srcname} and Auto Pin option for them!!!", show_alert=True ) setting = None if qry == "call": pass elif qry == "None": setting = {"unpin": None} elif qry.isdigit(): if int(qry) == 0: unpin = int(qry) setting = {"unpin": 0} else: now = round(time.time(), -2) unpin = int(qry) setting = {"unpin": int(qry), "next_unpin": int(qry) + int(now)} if setting: await collection.find_one_and_update(data, {"$set": setting}) btn = [] row = [] count = 0 for i in TIMES.keys(): count = count + 1 row.append( InlineKeyboardButton(i, callback_data=f"unpin_{TIMES[i]}_{src}_{gid}") ) if count == 3: btn.append(row) count = 0 row = [] if len(row) != 0: btn.append(row) btn.append([InlineKeyboardButton("BACK", callback_data=f"headlines_call_{gid}")]) if type(unpin) is int: if unpin == 0: unpindata = "after Next Feed" else: unpindata = "after " + list(TIMES.keys())[list(TIMES.values()).index(unpin)] else: unpindata = "OFF" await cq.edit_message_text( f"Auto Unpin options for {srcname}\nCurrently set to: {unpindata}", reply_markup=InlineKeyboardMarkup(btn), ) await cq.answer() BULLETS = ["➤", "•", "⚬", "▲", "▸", "△", "⋟", "»", "None"] @app.on_callback_query(filters.regex(pattern=r"cui_(.*)")) async def change_ui_btn(client: Client, cq: CallbackQuery): cus = cq.from_user.id qry = cq.data.split("_")[1] gid = cq.data.split("_")[2] try: k = (await client.get_chat_member(gid, cus)).status except UserNotParticipant: await cq.answer() return if cus not in BOT_OWNER and k == MEMBER: await cq.answer( "You don't have enough permissions to change this!!!", show_alert=True ) return await cq.answer() row, btn = [], [] for i in BULLETS: row.append(InlineKeyboardButton(text=i, callback_data=f"cui_{i}_{gid}")) if len(row) == 3: btn.append(row) row = [] btn.append(row) btn.append( [ InlineKeyboardButton(text="CAPS", callback_data=f"cui_Caps_{gid}"), InlineKeyboardButton(text="UPPER", callback_data=f"cui_UPPER_{gid}"), ] ) btn.append([InlineKeyboardButton(text="BACK", callback_data=f"settogl_call_{gid}")]) if qry in ["Caps", "UPPER"]: if await GUI.find_one({"_id": gid}): await GUI.update_one({"_id": gid}, {"$set": {"cs": qry}}) else: await GUI.insert_one({"_id": gid, "bl": "➤", "cs": qry}) elif qry != "call": bullet = qry if qry == "None": bullet = None if await GUI.find_one({"_id": gid}): await GUI.update_one({"_id": gid}, {"$set": {"bl": bullet}}) else: await GUI.insert_one({"_id": gid, "bl": bullet, "cs": "UPPER"}) bl = "➤" cs = "UPPER" if await GUI.find_one({"_id": gid}): data = await GUI.find_one({"_id": gid}) bl = data["bl"] cs = data["cs"] text = f"""Selected bullet in this group: {bl} Selected text case in this group: {cs}""" await cq.edit_message_text(text, reply_markup=InlineKeyboardMarkup(btn)) ## For accepting commands from edited messages @app.on_edited_message( filters.command(["anime", f"anime{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def anime_edit_cmd(client: app, message: Message): await anime_cmd(client, message) @app.on_edited_message( filters.command(["manga", f"manga{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def manga_edit_cmd(client: app, message: Message): await manga_cmd(client, message) @app.on_edited_message( filters.command(["character", f"character{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def character_edit_cmd(client: app, message: Message): await character_cmd(client, message) @app.on_edited_message( filters.command(["anilist", f"anilist{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def anilist_edit_cmd(client: app, message: Message): await anilist_cmd(client, message) @app.on_edited_message( filters.command(["top", f"top{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def top_edit_cmd(client: app, message: Message): await top_tags_cmd(client, message) @app.on_edited_message( filters.command(["airing", f"airing{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def airing_edit_cmd(client: app, message: Message): await airing_cmd(client, message) @app.on_edited_message( ~filters.private & filters.command( ["anisettings", f"anisettings{BOT_USERNAME}"], prefixes=PREFIX_HANDLER ) ) async def settings_edit_cmd(client: app, message: Message): await settings_cmd(client, message) @app.on_edited_message( filters.command(["browse", f"browse{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def browse_edit_cmd(client: app, message: Message): await browse_cmd(client, message) @app.on_edited_message( filters.command( ["gettags", f"gettags{BOT_USERNAME}", "getgenres", f"getgenres{BOT_USERNAME}"], prefixes=PREFIX_HANDLER, ) ) async def tags_genres_edit_cmd(client: app, message: Message): await list_tags_genres_cmd(client, message) @app.on_message( filters.command(["studio", f"studio{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def studio_edit_cmd(client: Client, message: Message): await studio_cmd(client, message) @app.on_message( filters.command(["schedule", f"schedule{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def get_schuled(client: Client, message: Message, mdata: dict): """Get List of Scheduled Anime""" gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "schedule" in find_gc["cmd_list"].split(): return x = await client.send_message(gid, "Fetching Scheduled Animes") try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] msg = await get_scheduled() buttons = get_btns("SCHEDULED", result=[msg[1]], user=user) await x.edit_text(msg[0], reply_markup=buttons) @app.on_callback_query(filters.regex(pattern=r"sched_(.*)")) @check_user async def ns_(client: app, cq: CallbackQuery, cdata: dict): kek, day, user = cdata["data"].split("_") msg = await get_scheduled(int(day)) buttons = get_btns("SCHEDULED", result=[int(day)], user=user) await cq.edit_message_text(msg[0], reply_markup=buttons) @app.on_edited_message( filters.command(["schedule", f"schedule{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def get_schuled_edit(client: Client, message: Message): await get_schuled(client, message) @app.on_message( filters.command(["watch", f"watch{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def get_watch_order(client: Client, message: Message, mdata: dict): """Get List of Scheduled Anime""" gid = mdata["chat"]["id"] find_gc = await DC.find_one({"_id": gid}) if find_gc is not None and "watch" in find_gc["cmd_list"].split(): return x = message.text.split(" ", 1) if len(x) == 1: await message.reply_text("Nothing given to search for!!!") return try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] data = get_wols(x[1]) msg = f"Found related animes for the query {x[1]}" buttons = [] if data == []: await client.send_message(gid, "No results found!!!") return for i in data: buttons.append( [ InlineKeyboardButton( str(i[1]), callback_data=f"watch_{i[0]}_{x[1]}_0_{user}" ) ] ) await client.send_message(gid, msg, reply_markup=InlineKeyboardMarkup(buttons)) @app.on_callback_query(filters.regex(pattern=r"watch_(.*)")) @check_user async def watch_(client: app, cq: CallbackQuery, cdata: dict): kek, id_, qry, req, user = cdata["data"].split("_") msg, total = get_wo(int(id_), int(req)) totalpg, lol = divmod(total, 50) button = [] if lol != 0: totalpg + 1 if total > 50: if int(req) == 0: button.append( [ InlineKeyboardButton( text="NEXT", callback_data=f"{kek}_{id_}_{qry}_{int(req)+1}_{user}", ) ] ) elif int(req) == totalpg: button.append( [ InlineKeyboardButton( text="PREV", callback_data=f"{kek}_{id_}_{qry}_{int(req)-1}_{user}", ) ] ) else: button.append( [ InlineKeyboardButton( text="PREV", callback_data=f"{kek}_{id_}_{qry}_{int(req)-1}_{user}", ), InlineKeyboardButton( text="NEXT", callback_data=f"{kek}_{id_}_{qry}_{int(req)+1}_{user}", ), ] ) button.append([InlineKeyboardButton("Back", callback_data=f"wol_{qry}_{user}")]) await cq.edit_message_text(msg, reply_markup=InlineKeyboardMarkup(button)) @app.on_callback_query(filters.regex(pattern=r"wol_(.*)")) @check_user async def wls(client: app, cq: CallbackQuery, cdata: dict): kek, qry, user = cdata["data"].split("_") data = get_wols(qry) msg = f"Found related animes for the query {qry}" buttons = [] for i in data: buttons.append( [ InlineKeyboardButton( str(i[1]), callback_data=f"watch_{i[0]}_{qry}_0_{user}" ) ] ) await cq.edit_message_text(msg, reply_markup=InlineKeyboardMarkup(buttons)) @app.on_edited_message( filters.command(["watch", f"watch{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def get_watch_order_edit(client: Client, message: Message): await get_watch_order(client, message) @app.on_message( filters.command(["fillers", f"fillers{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) @control_user async def fillers_cmd(client: app, message: Message, mdata: dict): find_gc = await DC.find_one({"_id": mdata["chat"]["id"]}) try: user = mdata["from_user"]["id"] except KeyError: user = mdata["sender_chat"]["id"] if find_gc is not None and "watch" in find_gc["cmd_list"].split(): return qry = mdata["text"].split(" ", 1) if len(qry) == 1: return await message.reply_text( """Give some anime name to search fillers for example: /fillers Detective Conan""" ) k = search_filler(qry[1]) if k == {}: await message.reply_text("No fillers found for the given anime...") return button = [] list_ = list(k.keys()) if len(list_) == 1: result = parse_filler(k.get(list_[0])) msg = "" msg += f"Fillers for anime `{list_[0]}`\n\nManga Canon episodes:\n" msg += str(result.get("total_ep")) msg += "\n\nMixed/Canon fillers:\n" msg += str(result.get("mixed_ep")) msg += "\n\nFillers:\n" msg += str(result.get("filler_ep")) if result.get("ac_ep") is not None: msg += "\n\nAnime Canon episodes:\n" msg += str(result.get("ac_ep")) await message.reply_text(msg) return for i in list_: fl_js = rand_key() FILLERS[fl_js] = [k.get(i), i] button.append([InlineKeyboardButton(i, callback_data=f"fill_{fl_js}_{user}")]) await message.reply_text( "Pick anime you want to see fillers list for:", reply_markup=InlineKeyboardMarkup(button), ) @app.on_callback_query(filters.regex(pattern=r"fill_(.*)")) @check_user async def filler_btn(client: app, cq: CallbackQuery, cdata: dict): kek, req, user = cdata["data"].split("_") result = parse_filler((FILLERS.get(req))[0]) msg = "" msg += f"**Fillers for anime** `{(FILLERS.get(req))[1]}`" msg += "\n\n**Manga Canon episodes:**\n" msg += str(result.get("total_ep")) msg += "\n\n**Mixed/Canon fillers:**\n" msg += str(result.get("mixed_ep")) msg += "\n\n**Fillers:**\n" msg += str(result.get("filler_ep")) if result.get("ac_ep") is not None: msg += "\n\n**Anime Canon episodes:**\n" msg += str(result.get("ac_ep")) await cq.edit_message_text(msg) @app.on_message( filters.command(["fillers", f"fillers{BOT_USERNAME}"], prefixes=PREFIX_HANDLER) ) async def fillers_cmd(client: app, message: Message): await fillers_cmd(client, message) @app.on_message(filters.command("animequotes")) async def animequotes(client, message): name = ( message.reply_to_message.from_user.first_name if message.reply_to_message else message.from_user.first_name ) keyboard = [[InlineKeyboardButton(text="CHANGE", callback_data="changek_quote")]] await message.reply_photo( photo=random.choice(QUOTES_IMG), reply_markup=InlineKeyboardMarkup(keyboard), ) @app.on_callback_query(filters.regex("changek_quote")) async def changek_quote(client, callback_query): keyboard = [[InlineKeyboardButton(text="CHANGE", callback_data="changek_quote")]] await callback_query.edit_message_media( media=InputMediaPhoto(media=random.choice(QUOTES_IMG)), reply_markup=InlineKeyboardMarkup(keyboard), ) QUOTES_IMG = [ "https://i.imgur.com/Iub4RYj.jpg", "https://i.imgur.com/uvNMdIl.jpg", "https://i.imgur.com/YOBOntg.jpg", "https://i.imgur.com/fFpO2ZQ.jpg", "https://i.imgur.com/f0xZceK.jpg", "https://i.imgur.com/RlVcCip.jpg", "https://i.imgur.com/CjpqLRF.jpg", "https://i.imgur.com/8BHZDk6.jpg", "https://i.imgur.com/8bHeMgy.jpg", "https://i.imgur.com/5K3lMvr.jpg", "https://i.imgur.com/NTzw4RN.jpg", "https://i.imgur.com/wJxryAn.jpg", "https://i.imgur.com/9L0DWzC.jpg", "https://i.imgur.com/sBe8TTs.jpg", "https://i.imgur.com/1Au8gdf.jpg", "https://i.imgur.com/28hFQeU.jpg", "https://i.imgur.com/Qvc03JY.jpg", "https://i.imgur.com/gSX6Xlf.jpg", "https://i.imgur.com/iP26Hwa.jpg", "https://i.imgur.com/uSsJoX8.jpg", "https://i.imgur.com/OvX3oHB.jpg", "https://i.imgur.com/JMWuksm.jpg", "https://i.imgur.com/lhM3fib.jpg", "https://i.imgur.com/64IYKkw.jpg", "https://i.imgur.com/nMbyA3J.jpg", "https://i.imgur.com/7KFQhY3.jpg", "https://i.imgur.com/mlKb7zt.jpg", "https://i.imgur.com/JCQGJVw.jpg", "https://i.imgur.com/hSFYDEz.jpg", "https://i.imgur.com/PQRjAgl.jpg", "https://i.imgur.com/ot9624U.jpg", "https://i.imgur.com/iXmqN9y.jpg", "https://i.imgur.com/RhNBeGr.jpg", "https://i.imgur.com/tcMVNa8.jpg", "https://i.imgur.com/LrVg810.jpg", "https://i.imgur.com/TcWfQlz.jpg", "https://i.imgur.com/muAUdvJ.jpg", "https://i.imgur.com/AtC7ZRV.jpg", "https://i.imgur.com/sCObQCQ.jpg", "https://i.imgur.com/AJFDI1r.jpg", "https://i.imgur.com/TCgmRrH.jpg", "https://i.imgur.com/LMdmhJU.jpg", "https://i.imgur.com/eyyax0N.jpg", "https://i.imgur.com/YtYxV66.jpg", "https://i.imgur.com/292w4ye.jpg", "https://i.imgur.com/6Fm1vdw.jpg", "https://i.imgur.com/2vnBOZd.jpg", "https://i.imgur.com/j5hI9Eb.jpg", "https://i.imgur.com/cAv7pJB.jpg", "https://i.imgur.com/jvI7Vil.jpg", "https://i.imgur.com/fANpjsg.jpg", "https://i.imgur.com/5o1SJyo.jpg", "https://i.imgur.com/dSVxmh8.jpg", "https://i.imgur.com/02dXlAD.jpg", "https://i.imgur.com/htvIoGY.jpg", "https://i.imgur.com/hy6BXOj.jpg", "https://i.imgur.com/OuwzNYu.jpg", "https://i.imgur.com/L8vwvc2.jpg", "https://i.imgur.com/3VMVF9y.jpg", "https://i.imgur.com/yzjq2n2.jpg", "https://i.imgur.com/0qK7TAN.jpg", "https://i.imgur.com/zvcxSOX.jpg", "https://i.imgur.com/FO7bApW.jpg", "https://i.imgur.com/KK06gwg.jpg", "https://i.imgur.com/6lG4tsO.jpg", ] # <================================================= HELP ======================================================> __help__ = """ ⛩ *Anime:* ➠ *Dazai provides you the best anime-based commands including anime news and much more!* ➠ *Commands:* » /anime: fetches info on single anime (includes buttons to look up for prequels and sequels) » /character: fetches info on multiple possible characters related to query » /manga: fetches info on multiple possible mangas related to query » /airing: fetches info on airing data for anime » /studio: fetches info on multiple possible studios related to query » /schedule: fetches scheduled animes » /browse: get popular, trending or upcoming animes ➠ /animequotes: get random anime quotes » /anisettings: to toggle NSFW lock and airing notifications and other settings in groups (anime news) » /top: to retrieve top animes for a genre or tag » /watch: fetches watch order for anime series » /fillers: to get a list of anime fillers » /gettags: get a list of available tags » /getgenres - Get list of available Genres """ __mod_name__ = "ANIME" # <================================================== END =====================================================>