Path: blob/master/bot/modules/search.py
1628 views
from httpx import AsyncClient1from html import escape2from urllib.parse import quote34from .. import LOGGER5from ..core.config_manager import Config6from ..core.torrent_manager import TorrentManager7from ..helper.ext_utils.bot_utils import new_task8from ..helper.ext_utils.status_utils import get_readable_file_size9from ..helper.ext_utils.telegraph_helper import telegraph10from ..helper.telegram_helper.button_build import ButtonMaker11from ..helper.telegram_helper.message_utils import edit_message, send_message1213PLUGINS = []14SITES = None15TELEGRAPH_LIMIT = 300161718async def initiate_search_tools():19qb_plugins = await TorrentManager.qbittorrent.search.plugins()20if qb_plugins:21names = [plugin.name for plugin in qb_plugins]22await TorrentManager.qbittorrent.search.uninstall_plugin(names)23PLUGINS.clear()24if Config.SEARCH_PLUGINS:25await TorrentManager.qbittorrent.search.install_plugin(Config.SEARCH_PLUGINS)2627if Config.SEARCH_API_LINK:28global SITES29try:30async with AsyncClient() as client:31response = await client.get(f"{Config.SEARCH_API_LINK}/api/v1/sites")32data = response.json()33SITES = {34str(site): str(site).capitalize() for site in data["supported_sites"]35}36SITES["all"] = "All"37except Exception as e:38LOGGER.error(39f"{e} Can't fetching sites from SEARCH_API_LINK make sure use latest version of API"40)41SITES = None424344async def search(key, site, message, method):45if method.startswith("api"):46if method == "apisearch":47LOGGER.info(f"API Searching: {key} from {site}")48if site == "all":49api = f"{Config.SEARCH_API_LINK}/api/v1/all/search?query={key}&limit={Config.SEARCH_LIMIT}"50else:51api = f"{Config.SEARCH_API_LINK}/api/v1/search?site={site}&query={key}&limit={Config.SEARCH_LIMIT}"52elif method == "apitrend":53LOGGER.info(f"API Trending from {site}")54if site == "all":55api = f"{Config.SEARCH_API_LINK}/api/v1/all/trending?limit={Config.SEARCH_LIMIT}"56else:57api = f"{Config.SEARCH_API_LINK}/api/v1/trending?site={site}&limit={Config.SEARCH_LIMIT}"58elif method == "apirecent":59LOGGER.info(f"API Recent from {site}")60if site == "all":61api = f"{Config.SEARCH_API_LINK}/api/v1/all/recent?limit={Config.SEARCH_LIMIT}"62else:63api = f"{Config.SEARCH_API_LINK}/api/v1/recent?site={site}&limit={Config.SEARCH_LIMIT}"64try:65async with AsyncClient() as client:66response = await client.get(api)67search_results = response.json()68if "error" in search_results or search_results["total"] == 0:69await edit_message(70message,71f"No result found for <i>{key}</i>\nTorrent Site:- <i>{SITES.get(site)}</i>",72)73return74msg = f"<b>Found {min(search_results['total'], TELEGRAPH_LIMIT)}</b>"75if method == "apitrend":76msg += f" <b>trending result(s)\nTorrent Site:- <i>{SITES.get(site)}</i></b>"77elif method == "apirecent":78msg += (79f" <b>recent result(s)\nTorrent Site:- <i>{SITES.get(site)}</i></b>"80)81else:82msg += f" <b>result(s) for <i>{key}</i>\nTorrent Site:- <i>{SITES.get(site)}</i></b>"83search_results = search_results["data"]84except Exception as e:85await edit_message(message, str(e))86return87else:88LOGGER.info(f"PLUGINS Searching: {key} from {site}")89search = await TorrentManager.qbittorrent.search.start(90pattern=key, plugins=[site], category="all"91)92search_id = search.id93while True:94result_status = await TorrentManager.qbittorrent.search.status(search_id)95status = result_status[0].status96if status != "Running":97break98dict_search_results = await TorrentManager.qbittorrent.search.results(99id=search_id, limit=TELEGRAPH_LIMIT100)101search_results = dict_search_results.results102total_results = dict_search_results.total103if total_results == 0:104await edit_message(105message,106f"No result found for <i>{key}</i>\nTorrent Site:- <i>{site.capitalize()}</i>",107)108return109msg = f"<b>Found {min(total_results, TELEGRAPH_LIMIT)}</b>"110msg += f" <b>result(s) for <i>{key}</i>\nTorrent Site:- <i>{site.capitalize()}</i></b>"111await TorrentManager.qbittorrent.search.delete(search_id)112link = await get_result(search_results, key, message, method)113buttons = ButtonMaker()114buttons.url_button("🔎 VIEW", link)115button = buttons.build_menu(1)116await edit_message(message, msg, button)117118119async def get_result(search_results, key, message, method):120telegraph_content = []121if method == "apirecent":122msg = "<h4>API Recent Results</h4>"123elif method == "apisearch":124msg = f"<h4>API Search Result(s) For {key}</h4>"125elif method == "apitrend":126msg = "<h4>API Trending Results</h4>"127else:128msg = f"<h4>PLUGINS Search Result(s) For {key}</h4>"129for index, result in enumerate(search_results, start=1):130if method.startswith("api"):131try:132if "name" in result.keys():133msg += f"<code><a href='{result['url']}'>{escape(result['name'])}</a></code><br>"134if "torrents" in result.keys():135for subres in result["torrents"]:136msg += f"<b>Quality: </b>{subres['quality']} | <b>Type: </b>{subres['type']} | "137msg += f"<b>Size: </b>{subres['size']}<br>"138if "torrent" in subres.keys():139msg += f"<a href='{subres['torrent']}'>Direct Link</a><br>"140elif "magnet" in subres.keys():141msg += "<b>Share Magnet to</b> "142msg += f"<a href='http://t.me/share/url?url={subres['magnet']}'>Telegram</a><br>"143msg += "<br>"144else:145msg += f"<b>Size: </b>{result['size']}<br>"146try:147msg += f"<b>Seeders: </b>{result['seeders']} | <b>Leechers: </b>{result['leechers']}<br>"148except:149pass150if "torrent" in result.keys():151msg += f"<a href='{result['torrent']}'>Direct Link</a><br><br>"152elif "magnet" in result.keys():153msg += "<b>Share Magnet to</b> "154msg += f"<a href='http://t.me/share/url?url={quote(result['magnet'])}'>Telegram</a><br><br>"155else:156msg += "<br>"157except:158continue159else:160msg += f"<a href='{result.descrLink}'>{escape(result.fileName)}</a><br>"161msg += f"<b>Size: </b>{get_readable_file_size(result.fileSize)}<br>"162msg += f"<b>Seeders: </b>{result.nbSeeders} | <b>Leechers: </b>{result.nbLeechers}<br>"163link = result.fileUrl164if link.startswith("magnet:"):165msg += f"<b>Share Magnet to</b> <a href='http://t.me/share/url?url={quote(link)}'>Telegram</a><br><br>"166else:167msg += f"<a href='{link}'>Direct Link</a><br><br>"168169if len(msg.encode("utf-8")) > 39000:170telegraph_content.append(msg)171msg = ""172173if index == TELEGRAPH_LIMIT:174break175176if msg != "":177telegraph_content.append(msg)178179await edit_message(180message, f"<b>Creating</b> {len(telegraph_content)} <b>Telegraph pages.</b>"181)182path = [183(184await telegraph.create_page(185title="Mirror-leech-bot Torrent Search", content=content186)187)["path"]188for content in telegraph_content189]190if len(path) > 1:191await edit_message(192message, f"<b>Editing</b> {len(telegraph_content)} <b>Telegraph pages.</b>"193)194await telegraph.edit_telegraph(path, telegraph_content)195return f"https://telegra.ph/{path[0]}"196197198def api_buttons(user_id, method):199buttons = ButtonMaker()200for data, name in SITES.items():201buttons.data_button(name, f"torser {user_id} {data} {method}")202buttons.data_button("Cancel", f"torser {user_id} cancel")203return buttons.build_menu(2)204205206async def plugin_buttons(user_id):207buttons = ButtonMaker()208if not PLUGINS:209pl = await TorrentManager.qbittorrent.search.plugins()210for i in pl:211PLUGINS.append(i.name)212for siteName in PLUGINS:213buttons.data_button(214siteName.capitalize(), f"torser {user_id} {siteName} plugin"215)216buttons.data_button("All", f"torser {user_id} all plugin")217buttons.data_button("Cancel", f"torser {user_id} cancel")218return buttons.build_menu(2)219220221@new_task222async def torrent_search(_, message):223user_id = message.from_user.id224buttons = ButtonMaker()225key = message.text.split()226if SITES is None and not Config.SEARCH_PLUGINS:227await send_message(228message, "No API link or search PLUGINS added for this function"229)230elif len(key) == 1 and SITES is None:231await send_message(message, "Send a search key along with command")232elif len(key) == 1:233buttons.data_button("Trending", f"torser {user_id} apitrend")234buttons.data_button("Recent", f"torser {user_id} apirecent")235buttons.data_button("Cancel", f"torser {user_id} cancel")236button = buttons.build_menu(2)237await send_message(message, "Send a search key along with command", button)238elif SITES is not None and Config.SEARCH_PLUGINS:239buttons.data_button("Api", f"torser {user_id} apisearch")240buttons.data_button("Plugins", f"torser {user_id} plugin")241buttons.data_button("Cancel", f"torser {user_id} cancel")242button = buttons.build_menu(2)243await send_message(message, "Choose tool to search:", button)244elif SITES is not None:245button = api_buttons(user_id, "apisearch")246await send_message(message, "Choose site to search | API:", button)247else:248button = await plugin_buttons(user_id)249await send_message(message, "Choose site to search | Plugins:", button)250251252@new_task253async def torrent_search_update(_, query):254user_id = query.from_user.id255message = query.message256key = message.reply_to_message.text.split(maxsplit=1)257key = key[1].strip() if len(key) > 1 else None258data = query.data.split()259if user_id != int(data[1]):260await query.answer("Not Yours!", show_alert=True)261elif data[2].startswith("api"):262await query.answer()263button = api_buttons(user_id, data[2])264await edit_message(message, "Choose site:", button)265elif data[2] == "plugin":266await query.answer()267button = await plugin_buttons(user_id)268await edit_message(message, "Choose site:", button)269elif data[2] != "cancel":270await query.answer()271site = data[2]272method = data[3]273if method.startswith("api"):274if key is None:275if method == "apirecent":276endpoint = "Recent"277elif method == "apitrend":278endpoint = "Trending"279await edit_message(280message,281f"<b>Listing {endpoint} Items...\nTorrent Site:- <i>{SITES.get(site)}</i></b>",282)283else:284await edit_message(285message,286f"<b>Searching for <i>{key}</i>\nTorrent Site:- <i>{SITES.get(site)}</i></b>",287)288else:289await edit_message(290message,291f"<b>Searching for <i>{key}</i>\nTorrent Site:- <i>{site.capitalize()}</i></b>",292)293await search(key, site, message, method)294else:295await query.answer()296await edit_message(message, "Search has been canceled!")297298299