diff --git "a/Mikobot/plugins/anime.py" "b/Mikobot/plugins/anime.py" deleted file mode 100644--- "a/Mikobot/plugins/anime.py" +++ /dev/null @@ -1,5138 +0,0 @@ -# <============================================== 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 ("5907205317").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:* - -➠ *Mikobot 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 =====================================================>