Change httpx variable

This commit is contained in:
yasirarism 2023-08-19 22:04:22 +07:00 committed by GitHub
parent cfc3a0afc9
commit 67a16e8773
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 91 additions and 129 deletions

View file

@ -7,7 +7,7 @@ from aiohttp import ClientSession
session = ClientSession() session = ClientSession()
# HTTPx Async Client # HTTPx Async Client
http = httpx.AsyncClient( fetch = httpx.AsyncClient(
http2=True, http2=True,
verify=False, verify=False,
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edge/107.0.1418.42"}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edge/107.0.1418.42"},

View file

@ -7,7 +7,7 @@ from bs4 import BeautifulSoup
from telegraph.aio import Telegraph from telegraph.aio import Telegraph
from misskaty import BOT_USERNAME from misskaty import BOT_USERNAME
from misskaty.helper.http import http from misskaty.helper.http import fetch
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@ -24,7 +24,7 @@ async def kusonimeBypass(url: str, slug=None):
noslug_url = "https://kusonime.com/{slug}" noslug_url = "https://kusonime.com/{slug}"
_url = noslug_url.format({"slug": slug}) _url = noslug_url.format({"slug": slug})
try: try:
page = await http.get(_url, headers=headers) page = await fetch.get(_url, headers=headers)
soup = BeautifulSoup(page.text, "lxml") soup = BeautifulSoup(page.text, "lxml")
thumb = soup.find("div", {"class": "post-thumb"}).find("img").get("src") thumb = soup.find("div", {"class": "post-thumb"}).find("img").get("src")
data = [] data = []

View file

@ -149,7 +149,7 @@ padding-top: 0.25rem;
import json import json
import re import re
from .http import http from .http import fetch
def html_builder(title: str, text: str) -> str: def html_builder(title: str, text: str) -> str:
@ -220,7 +220,7 @@ def html_builder(title: str, text: str) -> str:
async def mediainfo_paste(text: str, title: str) -> str: async def mediainfo_paste(text: str, title: str) -> str:
html_content = html_builder(title, text) html_content = html_builder(title, text)
URL = "https://mediainfo-1-y5870653.deta.app/api" URL = "https://mediainfo-1-y5870653.deta.app/api"
response = await http.post(URL, json={"content": html_content}) response = await fetch.post(URL, json={"content": html_content})
return ( return (
f"https://mediainfo-1-y5870653.deta.app/{json.loads(response.content)['key']}" f"https://mediainfo-1-y5870653.deta.app/{json.loads(response.content)['key']}"
) )

View file

@ -10,7 +10,7 @@ from urllib.parse import urlparse
import psutil import psutil
from misskaty import BOT_NAME, UBOT_NAME, botStartTime from misskaty import BOT_NAME, UBOT_NAME, botStartTime
from misskaty.helper.http import http from misskaty.helper.http import fetch
from misskaty.helper.human_read import get_readable_time from misskaty.helper.human_read import get_readable_time
from misskaty.plugins import ALL_MODULES from misskaty.plugins import ALL_MODULES
@ -87,7 +87,7 @@ def get_random_string(length: int = 5):
async def rentry(teks): async def rentry(teks):
# buat dapetin cookie # buat dapetin cookie
cookie = SimpleCookie() cookie = SimpleCookie()
kuki = (await http.get("https://rentry.co")).cookies kuki = (await fetch.get("https://rentry.co")).cookies
cookie.load(kuki) cookie.load(kuki)
kukidict = {key: value.value for key, value in cookie.items()} kukidict = {key: value.value for key, value in cookie.items()}
# headernya # headernya
@ -95,7 +95,7 @@ async def rentry(teks):
payload = {"csrfmiddlewaretoken": kukidict["csrftoken"], "text": teks} payload = {"csrfmiddlewaretoken": kukidict["csrftoken"], "text": teks}
return ( return (
( (
await http.post( await fetch.post(
"https://rentry.co/api/new", "https://rentry.co/api/new",
data=payload, data=payload,
headers=header, headers=header,
@ -128,7 +128,7 @@ async def search_jw(movie_name: str, locale: str):
m_t_ = "" m_t_ = ""
try: try:
response = ( response = (
await http.get( await fetch.get(
f"https://yasirapi.eu.org/justwatch?q={movie_name}&locale={locale}" f"https://yasirapi.eu.org/justwatch?q={movie_name}&locale={locale}"
) )
).json() ).json()

View file

@ -17,7 +17,7 @@ from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.errors import capture_err from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import get_readable_file_size, http, rentry from misskaty.helper import get_readable_file_size, fetch, rentry
from misskaty.vars import COMMAND_HANDLER from misskaty.vars import COMMAND_HANDLER
LIST_LINK = """ LIST_LINK = """
@ -43,7 +43,7 @@ async def pling_bypass(url):
try: try:
id_url = re.search(r"https?://(store.kde.org|www.pling.com)\/p\/(\d+)", url)[2] id_url = re.search(r"https?://(store.kde.org|www.pling.com)\/p\/(\d+)", url)[2]
link = f"https://www.pling.com/p/{id_url}/loadFiles" link = f"https://www.pling.com/p/{id_url}/loadFiles"
res = await http.get(link) res = await fetch.get(link)
json_dic_files = res.json().pop("files") json_dic_files = res.json().pop("files")
msg = f"\n**Source Link** :\n`{url}`\n**Direct Link :**\n" msg = f"\n**Source Link** :\n`{url}`\n**Direct Link :**\n"
msg += "\n".join( msg += "\n".join(

View file

@ -15,7 +15,7 @@ from pyrogram.types import Message
from misskaty import app from misskaty import app
from misskaty.core import pyro_cooldown from misskaty.core import pyro_cooldown
from misskaty.helper import check_time_gap, post_to_telegraph from misskaty.helper import check_time_gap, post_to_telegraph
from misskaty.helper.http import http from misskaty.helper.http import fetch
from misskaty.helper.localization import use_chat_lang from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, OPENAI_API, SUDO from misskaty.vars import COMMAND_HANDLER, OPENAI_API, SUDO
@ -32,7 +32,7 @@ async def bard_chatbot(_, ctx: Message, strings):
) )
msg = await ctx.reply_msg(strings("find_answers_str"), quote=True) msg = await ctx.reply_msg(strings("find_answers_str"), quote=True)
try: try:
req = await http.get( req = await fetch.get(
f"https://yasirapi.eu.org/bard?input={ctx.text.split(' ', 1)[1]}" f"https://yasirapi.eu.org/bard?input={ctx.text.split(' ', 1)[1]}"
) )
random_choice = random.choice(req.json().get("choices")) random_choice = random.choice(req.json().get("choices"))

View file

@ -8,7 +8,7 @@ from pyrogram.types import Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch
from misskaty.vars import CURRENCY_API from misskaty.vars import CURRENCY_API
__MODULE__ = "Currency" __MODULE__ = "Currency"
@ -42,7 +42,7 @@ async def currency(_, ctx: Message):
f"pair/{currency_from}/{currency_to}/{amount}" f"pair/{currency_from}/{currency_to}/{amount}"
) )
try: try:
res = await http.get(url) res = await fetch.get(url)
data = res.json() data = res.json()
try: try:
conversion_rate = data["conversion_rate"] conversion_rate = data["conversion_rate"]

View file

@ -18,7 +18,7 @@ from pySmartDL import SmartDL
from misskaty import app from misskaty import app
from misskaty.core.decorator import capture_err, new_task from misskaty.core.decorator import capture_err, new_task
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch
from misskaty.helper.pyro_progress import humanbytes, progress_for_pyrogram from misskaty.helper.pyro_progress import humanbytes, progress_for_pyrogram
from misskaty.vars import COMMAND_HANDLER, SUDO from misskaty.vars import COMMAND_HANDLER, SUDO
@ -60,7 +60,7 @@ async def upload(bot, message):
try: try:
files = {"file": open(fileku, "rb")} files = {"file": open(fileku, "rb")}
await m.edit("Uploading to Anonfile, Please Wait||") await m.edit("Uploading to Anonfile, Please Wait||")
callapi = await http.post("https://api.anonfiles.com/upload", files=files) callapi = await fetch.post("https://api.anonfiles.com/upload", files=files)
text = callapi.json() text = callapi.json()
output = f'<u>File Uploaded to Anonfile</u>\n\n📂 File Name: {text["data"]["file"]["metadata"]["name"]}\n\n📦 File Size: {text["data"]["file"]["metadata"]["size"]["readable"]}\n\n📥 Download Link: {text["data"]["file"]["url"]["full"]}' output = f'<u>File Uploaded to Anonfile</u>\n\n📂 File Name: {text["data"]["file"]["metadata"]["name"]}\n\n📦 File Size: {text["data"]["file"]["metadata"]["size"]["readable"]}\n\n📥 Download Link: {text["data"]["file"]["url"]["full"]}'
@ -180,7 +180,7 @@ async def tiktokdl(_, message):
msg = await message.reply("Trying download...") msg = await message.reply("Trying download...")
try: try:
r = ( r = (
await http.get(f"https://apimu.my.id/downloader/tiktok3?link={link}") await fetch.get(f"https://apimu.my.id/downloader/tiktok3?link={link}")
).json() ).json()
await message.reply_video( await message.reply_video(
r["hasil"]["download_mp4_hd"], r["hasil"]["download_mp4_hd"],
@ -202,7 +202,7 @@ async def fbdl(_, message):
link = message.command[1] link = message.command[1]
msg = await message.reply("Trying download...") msg = await message.reply("Trying download...")
try: try:
resjson = (await http.get(f"https://yasirapi.eu.org/fbdl?link={link}")).json() resjson = (await fetch.get(f"https://yasirapi.eu.org/fbdl?link={link}")).json()
try: try:
url = resjson["result"]["links"]["hd"].replace("&amp;", "&") url = resjson["result"]["links"]["hd"].replace("&amp;", "&")
except: except:

View file

@ -13,8 +13,7 @@ from database.users_chats_db import db
from misskaty import BOT_USERNAME, app from misskaty import BOT_USERNAME, app
from misskaty.core.decorator import asyncify, capture_err from misskaty.core.decorator import asyncify, capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch, use_chat_lang
from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, SUDO, SUPPORT_CHAT from misskaty.vars import COMMAND_HANDLER, SUDO, SUPPORT_CHAT
from utils import temp from utils import temp
@ -139,7 +138,7 @@ async def member_has_joined(c: app, member: ChatMemberUpdated, strings):
# Combot API Detection # Combot API Detection
try: try:
apicombot = ( apicombot = (
await http.get(f"https://api.cas.chat/check?user_id={user.id}") await fetch.get(f"https://api.cas.chat/check?user_id={user.id}")
).json() ).json()
if apicombot.get("ok") == "true": if apicombot.get("ok") == "true":
await app.ban_chat_member( await app.ban_chat_member(
@ -189,7 +188,7 @@ async def greet_group(bot, message, strings):
# Combot API Detection # Combot API Detection
try: try:
apicombot = ( apicombot = (
await http.get(f"https://api.cas.chat/check?user_id={u.id}") await fetch.get(f"https://api.cas.chat/check?user_id={u.id}")
).json() ).json()
if apicombot.get("ok") == "true": if apicombot.get("ok") == "true":
await app.ban_chat_member( await app.ban_chat_member(

View file

@ -31,14 +31,11 @@ from pyrogram.types import (
from database.imdb_db import add_imdbset, is_imdbset, remove_imdbset from database.imdb_db import add_imdbset, is_imdbset, remove_imdbset
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import GENRES_EMOJI, Cache, get_random_string, http, search_jw from misskaty.helper import GENRES_EMOJI, Cache, get_random_string, fetch, search_jw
from utils import demoji from utils import demoji
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
LIST_CARI = Cache(filename="imdb_cache.db", path="cache", in_memory=False) LIST_CARI = Cache(filename="imdb_cache.db", path="cache", in_memory=False)
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.1.17 (KHTML, like Gecko) Version/7.1 Safari/537.85.10"
}
# IMDB Choose Language # IMDB Choose Language
@ -136,9 +133,8 @@ async def imdb_search_id(kueri, message):
msg = "" msg = ""
buttons = InlineKeyboard(row_width=4) buttons = InlineKeyboard(row_width=4)
try: try:
r = await http.get( r = await fetch.get(
f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json", f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json"
headers=headers,
) )
res = r.json().get("d") res = r.json().get("d")
if not res: if not res:
@ -193,9 +189,8 @@ async def imdb_search_en(kueri, message):
msg = "" msg = ""
buttons = InlineKeyboard(row_width=4) buttons = InlineKeyboard(row_width=4)
try: try:
r = await http.get( r = await fetch.get(
f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json", f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json"
headers=headers,
) )
res = r.json().get("d") res = r.json().get("d")
if not res: if not res:
@ -257,9 +252,8 @@ async def imdbcari(_, query: CallbackQuery):
msg = "" msg = ""
buttons = InlineKeyboard(row_width=4) buttons = InlineKeyboard(row_width=4)
try: try:
r = await http.get( r = await fetch.get(
f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json", f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json"
headers=headers,
) )
res = r.json().get("d") res = r.json().get("d")
if not res: if not res:
@ -309,9 +303,8 @@ async def imdbcari(_, query: CallbackQuery):
msg = "" msg = ""
buttons = InlineKeyboard(row_width=4) buttons = InlineKeyboard(row_width=4)
try: try:
r = await http.get( r = await fetch.get(
f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json", f"https://v3.sg.media-imdb.com/suggestion/titles/x/{quote_plus(kueri)}.json"
headers=headers,
) )
res = r.json().get("d") res = r.json().get("d")
if not res: if not res:
@ -360,7 +353,7 @@ async def imdb_id_callback(self: Client, query: CallbackQuery):
try: try:
await query.message.edit_caption("⏳ Permintaan kamu sedang diproses.. ") await query.message.edit_caption("⏳ Permintaan kamu sedang diproses.. ")
imdb_url = f"https://www.imdb.com/title/tt{movie}/" imdb_url = f"https://www.imdb.com/title/tt{movie}/"
resp = await http.get(imdb_url, headers=headers) resp = await fetch.get(imdb_url)
sop = BeautifulSoup(resp, "lxml") sop = BeautifulSoup(resp, "lxml")
r_json = json.loads( r_json = json.loads(
sop.find("script", attrs={"type": "application/ld+json"}).contents[0] sop.find("script", attrs={"type": "application/ld+json"}).contents[0]
@ -519,7 +512,7 @@ async def imdb_en_callback(self: Client, query: CallbackQuery):
try: try:
await query.message.edit_caption("<i>⏳ Getting IMDb source..</i>") await query.message.edit_caption("<i>⏳ Getting IMDb source..</i>")
imdb_url = f"https://www.imdb.com/title/tt{movie}/" imdb_url = f"https://www.imdb.com/title/tt{movie}/"
resp = await http.get(imdb_url, headers=headers) resp = await fetch.get(imdb_url)
sop = BeautifulSoup(resp, "lxml") sop = BeautifulSoup(resp, "lxml")
r_json = json.loads( r_json = json.loads(
sop.find("script", attrs={"type": "application/ld+json"}).contents[0] sop.find("script", attrs={"type": "application/ld+json"}).contents[0]

View file

@ -26,9 +26,8 @@ from pyrogram.types import (
from misskaty import BOT_USERNAME, app, user from misskaty import BOT_USERNAME, app, user
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import GENRES_EMOJI, http, post_to_telegraph, search_jw from misskaty.helper import GENRES_EMOJI, fetch, post_to_telegraph, search_jw
from misskaty.plugins.dev import shell_exec from misskaty.plugins.dev import shell_exec
from misskaty.plugins.misc_tools import get_content
from misskaty.vars import USER_SESSION from misskaty.vars import USER_SESSION
from utils import demoji from utils import demoji
@ -117,13 +116,8 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
kueri = inline_query.query.split(None, 1)[1].strip() kueri = inline_query.query.split(None, 1)[1].strip()
headers = { jsonapi = await fetch.get(
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/61.0.3163.100 Safari/537.36"
}
jsonapi = await http.get(
"https://github.com/PaulSonOfLars/telegram-bot-api-spec/raw/main/api.json", "https://github.com/PaulSonOfLars/telegram-bot-api-spec/raw/main/api.json",
headers=headers,
follow_redirects=True, follow_redirects=True,
) )
parsemethod = jsonapi.json().get("methods") parsemethod = jsonapi.json().get("methods")
@ -229,7 +223,7 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
judul = inline_query.query.split(None, 1)[1].strip() judul = inline_query.query.split(None, 1)[1].strip()
search_results = await http.get( search_results = await fetch.get(
f"https://www.google.com/search?q={judul}&num=20" f"https://www.google.com/search?q={judul}&num=20"
) )
soup = BeautifulSoup(search_results.text, "lxml") soup = BeautifulSoup(search_results.text, "lxml")
@ -375,7 +369,7 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
query = inline_query.query.split(None, 1)[1].strip() query = inline_query.query.split(None, 1)[1].strip()
search_results = await http.get( search_results = await fetch.get(
f"https://api.github.com/search/repositories?q={query}" f"https://api.github.com/search/repositories?q={query}"
) )
srch_results = json.loads(search_results.text) srch_results = json.loads(search_results.text)
@ -421,7 +415,7 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
query = inline_query.query.split(None, 1)[1].strip() query = inline_query.query.split(None, 1)[1].strip()
search_results = await http.get(f"https://yasirapi.eu.org/pypi?q={query}") search_results = await fetch.get(f"https://yasirapi.eu.org/pypi?q={query}")
srch_results = search_results.json() srch_results = search_results.json()
data = [] data = []
for sraeo in srch_results["result"]: for sraeo in srch_results["result"]:
@ -463,7 +457,7 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
judul = inline_query.query.split(None, 1)[1].strip() judul = inline_query.query.split(None, 1)[1].strip()
search_results = await http.get( search_results = await fetch.get(
f"https://api.abir-hasan.tk/youtube?query={judul}" f"https://api.abir-hasan.tk/youtube?query={judul}"
) )
srch_results = json.loads(search_results.text) srch_results = json.loads(search_results.text)
@ -519,7 +513,7 @@ async def inline_menu(_, inline_query: InlineQuery):
switch_pm_parameter="inline", switch_pm_parameter="inline",
) )
movie_name = inline_query.query.split(None, 1)[1].strip() movie_name = inline_query.query.split(None, 1)[1].strip()
search_results = await http.get( search_results = await fetch.get(
f"https://yasirapi.eu.org/imdb-search?q={movie_name}" f"https://yasirapi.eu.org/imdb-search?q={movie_name}"
) )
res = json.loads(search_results.text).get("result") res = json.loads(search_results.text).get("result")
@ -612,7 +606,7 @@ async def imdb_inl(_, query):
"⏳ <i>Permintaan kamu sedang diproses.. </i>" "⏳ <i>Permintaan kamu sedang diproses.. </i>"
) )
url = f"https://www.imdb.com/title/{movie}/" url = f"https://www.imdb.com/title/{movie}/"
resp = await get_content(url) resp = await fetch.get(url)
sop = BeautifulSoup(resp, "lxml") sop = BeautifulSoup(resp, "lxml")
r_json = json.loads( r_json = json.loads(
sop.find("script", attrs={"type": "application/ld+json"}).contents[0] sop.find("script", attrs={"type": "application/ld+json"}).contents[0]

View file

@ -35,7 +35,7 @@ from pyrogram.types import (
from misskaty import BOT_USERNAME, app from misskaty import BOT_USERNAME, app
from misskaty.core.decorator.errors import capture_err from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch
from misskaty.helper.tools import rentry from misskaty.helper.tools import rentry
from misskaty.vars import COMMAND_HANDLER from misskaty.vars import COMMAND_HANDLER
from utils import extract_user, get_file_id from utils import extract_user, get_file_id
@ -67,22 +67,11 @@ def remove_html_tags(text):
return re.sub(clean, "", text) return re.sub(clean, "", text)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edge/107.0.1418.42"
}
async def get_content(url):
async with aiohttp.ClientSession() as session:
r = await session.get(url, headers=headers)
return await r.read()
@app.on_cmd("kbbi") @app.on_cmd("kbbi")
async def kbbi_search(_, ctx: Client): async def kbbi_search(_, ctx: Client):
if len(ctx.command) == 1: if len(ctx.command) == 1:
return await ctx.reply_msg("Please add keyword to search definition in kbbi") return await ctx.reply_msg("Please add keyword to search definition in kbbi")
r = (await http.get(f"https://yasirapi.eu.org/kbbi?kata={ctx.input}")).json() r = (await fetch.get(f"https://yasirapi.eu.org/kbbi?kata={ctx.input}")).json()
if nomsg := r.get("detail"): if nomsg := r.get("detail"):
return await ctx.reply_msg(nomsg) return await ctx.reply_msg(nomsg)
kbbi_btn = InlineKeyboardMarkup( kbbi_btn = InlineKeyboardMarkup(
@ -115,7 +104,7 @@ async def carbon_make(self: Client, ctx: Message):
"backgroundColor": "#1F816D", "backgroundColor": "#1F816D",
} }
try: try:
response = await http.post( response = await fetch.post(
"https://carbon.yasirapi.eu.org/api/cook", json=json_data "https://carbon.yasirapi.eu.org/api/cook", json=json_data
) )
except httpx.HTTPError as exc: except httpx.HTTPError as exc:
@ -144,7 +133,7 @@ async def readqr(c, m):
foto = await m.reply_to_message.download() foto = await m.reply_to_message.download()
myfile = {"file": (foto, open(foto, "rb"), "application/octet-stream")} myfile = {"file": (foto, open(foto, "rb"), "application/octet-stream")}
url = "http://api.qrserver.com/v1/read-qr-code/" url = "http://api.qrserver.com/v1/read-qr-code/"
r = await http.post(url, files=myfile) r = await fetch.post(url, files=myfile)
os.remove(foto) os.remove(foto)
if res := r.json()[0]["symbol"][0]["data"] is None: if res := r.json()[0]["symbol"][0]["data"] is None:
return await m.reply_msg(res) return await m.reply_msg(res)
@ -177,7 +166,7 @@ async def stackoverflow(_, message):
if len(message.command) == 1: if len(message.command) == 1:
return await message.reply("Give a query to search in StackOverflow!") return await message.reply("Give a query to search in StackOverflow!")
r = ( r = (
await http.get( await fetch.get(
f"https://api.stackexchange.com/2.3/search/excerpts?order=asc&sort=relevance&q={message.command[1]}&accepted=True&migrated=False¬ice=False&wiki=False&site=stackoverflow" f"https://api.stackexchange.com/2.3/search/excerpts?order=asc&sort=relevance&q={message.command[1]}&accepted=True&migrated=False¬ice=False&wiki=False&site=stackoverflow"
) )
).json() ).json()
@ -210,9 +199,8 @@ async def gsearch(_, message):
query = message.text.split(" ", maxsplit=1)[1] query = message.text.split(" ", maxsplit=1)[1]
msg = await message.reply_text(f"**Googling** for `{query}` ...") msg = await message.reply_text(f"**Googling** for `{query}` ...")
try: try:
html = await http.get( html = await fetch.get(
f"https://www.google.com/search?q={query}&gl=id&hl=id&num=17", f"https://www.google.com/search?q={query}&gl=id&hl=id&num=17",
headers=headers,
) )
soup = BeautifulSoup(html.text, "lxml") soup = BeautifulSoup(html.text, "lxml")
@ -536,7 +524,7 @@ async def mdl_callback(_, query: CallbackQuery):
await query.message.edit_text("Permintaan kamu sedang diproses.. ") await query.message.edit_text("Permintaan kamu sedang diproses.. ")
result = "" result = ""
try: try:
res = (await http.get(f"https://kuryana.vercel.app/id/{slug}")).json() res = (await fetch.get(f"https://kuryana.vercel.app/id/{slug}")).json()
result += f"<b>Title:</b> <a href='{res['data']['link']}'>{res['data']['title']}</a>\n" result += f"<b>Title:</b> <a href='{res['data']['link']}'>{res['data']['title']}</a>\n"
result += ( result += (
f"<b>AKA:</b> <code>{res['data']['others']['also_known_as']}</code>\n\n" f"<b>AKA:</b> <code>{res['data']['others']['also_known_as']}</code>\n\n"

View file

@ -15,8 +15,7 @@ from telegraph.aio import Telegraph
from misskaty import app from misskaty import app
from misskaty.core.decorator.errors import capture_err from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch, use_chat_lang
from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER from misskaty.vars import COMMAND_HANDLER
__MODULE__ = "OCR" __MODULE__ = "OCR"
@ -48,7 +47,7 @@ async def ocr(_, ctx: Message, strings):
response = await Telegraph().upload_file(file_path) response = await Telegraph().upload_file(file_path)
url = f"https://telegra.ph{response[0]['src']}" url = f"https://telegra.ph{response[0]['src']}"
req = ( req = (
await http.get( await fetch.get(
f"https://script.google.com/macros/s/AKfycbwURISN0wjazeJTMHTPAtxkrZTWTpsWIef5kxqVGoXqnrzdLdIQIfLO7jsR5OQ5GO16/exec?url={url}", f"https://script.google.com/macros/s/AKfycbwURISN0wjazeJTMHTPAtxkrZTWTpsWIef5kxqVGoXqnrzdLdIQIfLO7jsR5OQ5GO16/exec?url={url}",
follow_redirects=True, follow_redirects=True,
) )

View file

@ -13,7 +13,7 @@ from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import http, post_to_telegraph, rentry from misskaty.helper import fetch, post_to_telegraph, rentry
from misskaty.vars import COMMAND_HANDLER from misskaty.vars import COMMAND_HANDLER
__MODULE__ = "Paste" __MODULE__ = "Paste"
@ -217,7 +217,7 @@ async def wastepaste(_, message):
"expire_at": 0, "expire_at": 0,
"expire_in": 0, "expire_in": 0,
} }
response = await http.post("https://paste.yasir.eu.org/api/new", json=json_data) response = await fetch.post("https://paste.yasir.eu.org/api/new", json=json_data)
url = f"https://paste.yasir.eu.org/{response.json()['id']}" url = f"https://paste.yasir.eu.org/{response.json()['id']}"
except Exception as e: except Exception as e:
return await msg.edit_msg(f"ERROR: {e}") return await msg.edit_msg(f"ERROR: {e}")
@ -286,7 +286,7 @@ async def nekopaste(_, message):
try: try:
x = ( x = (
await http.post("https://nekobin.com/api/documents", json={"content": data}) await fetch.post("https://nekobin.com/api/documents", json={"content": data})
).json() ).json()
url = f"https://nekobin.com/{x['result']['key']}" url = f"https://nekobin.com/{x['result']['key']}"
except Exception as e: except Exception as e:
@ -356,7 +356,7 @@ async def spacebinn(_, message):
try: try:
siteurl = "https://spaceb.in/api/v1/documents/" siteurl = "https://spaceb.in/api/v1/documents/"
response = await http.post(siteurl, data={"content": data, "extension": "txt"}) response = await fetch.post(siteurl, data={"content": data, "extension": "txt"})
response = response.json() response = response.json()
url = "https://spaceb.in/" + response["payload"]["id"] url = "https://spaceb.in/" + response["payload"]["id"]
except Exception as e: except Exception as e:
@ -492,7 +492,7 @@ async def tempaste(_, message):
uname = message.sender_chat.title uname = message.sender_chat.title
try: try:
req = await http.post( req = await fetch.post(
"https://tempaste.com/api/v1/create-paste/", "https://tempaste.com/api/v1/create-paste/",
data={ data={
"api_key": "xnwuzXubxk3kCUz9Q2pjMVR8xeTO4t", "api_key": "xnwuzXubxk3kCUz9Q2pjMVR8xeTO4t",

View file

@ -11,8 +11,8 @@ from pyrogram.types import CallbackQuery, Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import Cache, http from misskaty.helper import Cache, fetch
from misskaty.plugins.web_scraper import headers, split_arr from misskaty.plugins.web_scraper import split_arr
from misskaty.vars import COMMAND_HANDLER from misskaty.vars import COMMAND_HANDLER
PYPI_DICT = Cache(filename="pypi_cache.db", path="cache", in_memory=False) PYPI_DICT = Cache(filename="pypi_cache.db", path="cache", in_memory=False)
@ -20,7 +20,7 @@ PYPI_DICT = Cache(filename="pypi_cache.db", path="cache", in_memory=False)
async def getDataPypi(msg, kueri, CurrentPage, user): async def getDataPypi(msg, kueri, CurrentPage, user):
if not PYPI_DICT.get(msg.id): if not PYPI_DICT.get(msg.id):
pypijson = (await http.get(f"https://yasirapi.eu.org/pypi?q={kueri}")).json() pypijson = (await fetch.get(f"https://yasirapi.eu.org/pypi?q={kueri}")).json()
if not pypijson.get("result"): if not pypijson.get("result"):
await msg.edit_msg("Sorry could not find any matching results!", del_in=6) await msg.edit_msg("Sorry could not find any matching results!", del_in=6)
return None, 0, None return None, 0, None
@ -126,7 +126,7 @@ async def pypi_getdata(_, callback_query: CallbackQuery):
InlineButton("❌ Close", f"close#{callback_query.from_user.id}"), InlineButton("❌ Close", f"close#{callback_query.from_user.id}"),
) )
try: try:
html = await http.get(f"https://pypi.org/pypi/{pkgname}/json", headers=headers) html = await fetch.get(f"https://pypi.org/pypi/{pkgname}/json")
res = html.json() res = html.json()
requirement = ( requirement = (
"".join(f"{i}, " for i in res["info"].get("requires_dist")) "".join(f"{i}, " for i in res["info"].get("requires_dist"))

View file

@ -9,7 +9,7 @@ from pyrogram.types import Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch
__MODULE__ = "Fun" __MODULE__ = "Fun"
__HELP__ = """ __HELP__ = """
@ -234,7 +234,7 @@ async def pyrogram_to_quotly(messages, is_reply):
else: else:
the_message_dict_to_append["replyMessage"] = {} the_message_dict_to_append["replyMessage"] = {}
payload["messages"].append(the_message_dict_to_append) payload["messages"].append(the_message_dict_to_append)
r = await http.post("https://bot.lyo.su/quote/generate.png", json=payload) r = await fetch.post("https://bot.lyo.su/quote/generate.png", json=payload)
if not r.is_error: if not r.is_error:
return r.read() return r.read()
else: else:

View file

@ -29,8 +29,7 @@ from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch, use_chat_lang
from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL
__MODULE__ = "Stickers" __MODULE__ = "Stickers"
@ -217,7 +216,7 @@ async def kang_sticker(self: Client, ctx: Message, strings):
await prog_msg.delete() await prog_msg.delete()
return return
try: try:
r = await http.get(img_url) r = await fetch.get(img_url)
if r.status_code == 200: if r.status_code == 200:
with open(filename, mode="wb") as f: with open(filename, mode="wb") as f:
f.write(r.read()) f.write(r.read())

View file

@ -3,12 +3,12 @@ from pyrogram.types import CallbackQuery, Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch
async def getData(chat_id, message_id, GetWord, CurrentPage): async def getData(chat_id, message_id, GetWord, CurrentPage):
UDJson = ( UDJson = (
await http.get(f"https://api.urbandictionary.com/v0/define?term={GetWord}") await fetch.get(f"https://api.urbandictionary.com/v0/define?term={GetWord}")
).json() ).json()
if "list" not in UDJson: if "list" not in UDJson:

View file

@ -17,9 +17,7 @@ from pyrogram.types import Message
from database import dbname from database import dbname
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import Cache, http from misskaty.helper import Cache, fetch, Kusonime, use_chat_lang
from misskaty.helper.kuso_utils import Kusonime
from misskaty.helper.localization import use_chat_lang
__MODULE__ = "WebScraper" __MODULE__ = "WebScraper"
__HELP__ = """ __HELP__ = """
@ -35,10 +33,6 @@ __HELP__ = """
/samehadaku [query <optional>] - Scrape website data from Samehadaku. /samehadaku [query <optional>] - Scrape website data from Samehadaku.
""" """
headers = {
"User-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582"
}
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
SCRAP_DICT = Cache(filename="scraper_cache.db", path="cache", in_memory=False) SCRAP_DICT = Cache(filename="scraper_cache.db", path="cache", in_memory=False)
data_kuso = Cache(filename="kuso_cache.db", path="cache", in_memory=False) data_kuso = Cache(filename="kuso_cache.db", path="cache", in_memory=False)
@ -75,9 +69,9 @@ async def getDataTerbit21(msg, kueri, CurrentPage, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
terbitjson = ( terbitjson = (
(await http.get(f"{web['yasirapi']}/terbit21?q={kueri}")).json() (await fetch.get(f"{web['yasirapi']}/terbit21?q={kueri}")).json()
if kueri if kueri
else (await http.get("https://yasirapi.eu.org/terbit21")).json() else (await fetch.get("https://yasirapi.eu.org/terbit21")).json()
) )
except: except:
await msg.edit_msg(strings("err_getapi")) await msg.edit_msg(strings("err_getapi"))
@ -117,9 +111,9 @@ async def getDatalk21(msg, kueri, CurrentPage, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
lk21json = ( lk21json = (
(await http.get(f"{web['yasirapi']}/lk21?q={kueri}")).json() (await fetch.get(f"{web['yasirapi']}/lk21?q={kueri}")).json()
if kueri if kueri
else (await http.get("https://yasirapi.eu.org/lk21")).json() else (await fetch.get("https://yasirapi.eu.org/lk21")).json()
) )
except: except:
await msg.edit_msg(strings("err_getapi")) await msg.edit_msg(strings("err_getapi"))
@ -156,7 +150,7 @@ async def getDatalk21(msg, kueri, CurrentPage, strings):
async def getDataPahe(msg, kueri, CurrentPage, strings): async def getDataPahe(msg, kueri, CurrentPage, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
pahejson = (await http.get(f"{web['yasirapi']}/pahe?q={kueri}")).json() pahejson = (await fetch.get(f"{web['yasirapi']}/pahe?q={kueri}")).json()
except: except:
await msg.edit_msg(strings("err_getapi")) await msg.edit_msg(strings("err_getapi"))
return None, None return None, None
@ -189,8 +183,8 @@ async def getDataKuso(msg, kueri, CurrentPage, user, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
kusodata = [] kusodata = []
try: try:
data = await http.get( data = await fetch.get(
f"{web['kusonime']}/?s={kueri}", headers=headers, follow_redirects=True f"{web['kusonime']}/?s={kueri}", follow_redirects=True
) )
except Exception as err: except Exception as err:
await msg.edit_msg(strings("err_getweb").format(err=err)) await msg.edit_msg(strings("err_getweb").format(err=err))
@ -242,8 +236,8 @@ async def getDataMovieku(msg, kueri, CurrentPage, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
moviekudata = [] moviekudata = []
try: try:
data = await http.get( data = await fetch.get(
f"{web['movieku']}/?s={kueri}", headers=headers, follow_redirects=True f"{web['movieku']}/?s={kueri}", follow_redirects=True
) )
except Exception as err: except Exception as err:
await msg.edit_msg(strings("err_getweb").format(err=err)) await msg.edit_msg(strings("err_getweb").format(err=err))
@ -283,9 +277,8 @@ async def getDataSavefilm21(msg, kueri, CurrentPage, user, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
sfdata = [] sfdata = []
try: try:
data = await http.get( data = await fetch.get(
f"{web['savefilm21']}/?s={kueri}", f"{web['savefilm21']}/?s={kueri}",
headers=headers,
follow_redirects=True, follow_redirects=True,
) )
except Exception as err: except Exception as err:
@ -336,14 +329,13 @@ async def getDataLendrive(msg, kueri, CurrentPage, user, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
if query: if query:
data = await http.get( data = await fetch.get(
f"{web['lendrive']}/?s={kueri}", f"{web['lendrive']}/?s={kueri}",
headers=headers,
follow_redirects=True, follow_redirects=True,
) )
else: else:
data = await http.get( data = await fetch.get(
web["lendrive"], headers=headers, follow_redirects=True web["lendrive"], follow_redirects=True
) )
except Exception as err: except Exception as err:
await msg.edit_msg(strings("err_getweb").format(err=err)) await msg.edit_msg(strings("err_getweb").format(err=err))
@ -398,9 +390,8 @@ async def getDataLendrive(msg, kueri, CurrentPage, user, strings):
async def getDataMelong(msg, kueri, CurrentPage, user, strings): async def getDataMelong(msg, kueri, CurrentPage, user, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
data = await http.get( data = await fetch.get(
f"{web['melongmovie']}/?s={kueri}", f"{web['melongmovie']}/?s={kueri}",
headers=headers,
follow_redirects=True, follow_redirects=True,
) )
except Exception as err: except Exception as err:
@ -449,8 +440,8 @@ async def getDataMelong(msg, kueri, CurrentPage, user, strings):
async def getDataGomov(msg, kueri, CurrentPage, user, strings): async def getDataGomov(msg, kueri, CurrentPage, user, strings):
if not SCRAP_DICT.get(msg.id): if not SCRAP_DICT.get(msg.id):
try: try:
gomovv = await http.get( gomovv = await fetch.get(
f"{web['gomov']}/?s={kueri}", headers=headers, follow_redirects=True f"{web['gomov']}/?s={kueri}", follow_redirects=True
) )
except Exception as err: except Exception as err:
await msg.edit_msg(strings("err_getweb").format(err=err)) await msg.edit_msg(strings("err_getweb").format(err=err))
@ -505,9 +496,9 @@ async def getSame(msg, query, current_page, strings):
cfse = cloudscraper.create_scraper() cfse = cloudscraper.create_scraper()
try: try:
if query: if query:
data = cfse.get(f"{web['samehadaku']}/?s={query}", headers=headers) data = cfse.get(f"{web['samehadaku']}/?s={query}")
else: else:
data = cfse.get(web["samehadaku"], headers=headers) data = cfse.get(web["samehadaku"])
except Exception as err: except Exception as err:
await msg.edit_msg(strings("err_getweb").format(err=err)) await msg.edit_msg(strings("err_getweb").format(err=err))
return None, None return None, None
@ -1278,7 +1269,7 @@ async def savefilm21_scrap(_, callback_query, strings):
InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"),
) )
try: try:
html = await http.get(link, headers=headers) html = await fetch.get(link)
soup = BeautifulSoup(html.text, "lxml") soup = BeautifulSoup(html.text, "lxml")
res = soup.find_all(class_="button button-shadow") res = soup.find_all(class_="button button-shadow")
res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res) res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res)
@ -1296,7 +1287,7 @@ async def savefilm21_scrap(_, callback_query, strings):
async def muviku_scrap(_, message, strings): async def muviku_scrap(_, message, strings):
try: try:
link = message.text.split(" ", maxsplit=1)[1] link = message.text.split(" ", maxsplit=1)[1]
html = await http.get(link, headers=headers) html = await fetch.get(link)
soup = BeautifulSoup(html.text, "lxml") soup = BeautifulSoup(html.text, "lxml")
res = soup.find_all(class_="smokeurl") res = soup.find_all(class_="smokeurl")
data = [] data = []
@ -1344,7 +1335,7 @@ async def melong_scrap(_, callback_query, strings):
InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"),
) )
try: try:
html = await http.get(link, headers=headers) html = await fetch.get(link)
soup = BeautifulSoup(html.text, "lxml") soup = BeautifulSoup(html.text, "lxml")
rep = "" rep = ""
for ep in soup.findAll(text=re.compile(r"(?i)episode\s+\d+|LINK DOWNLOAD")): for ep in soup.findAll(text=re.compile(r"(?i)episode\s+\d+|LINK DOWNLOAD")):
@ -1384,7 +1375,7 @@ async def gomov_dl(_, callback_query, strings):
InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"),
) )
try: try:
html = await http.get(link, headers=headers) html = await fetch.get(link)
soup = BeautifulSoup(html.text, "lxml") soup = BeautifulSoup(html.text, "lxml")
entry = soup.find(class_="gmr-download-wrap clearfix") entry = soup.find(class_="gmr-download-wrap clearfix")
hasil = soup.find(class_="title-download").text hasil = soup.find(class_="title-download").text
@ -1422,7 +1413,7 @@ async def lendrive_dl(_, callback_query, strings):
InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"),
) )
try: try:
hmm = await http.get(link, headers=headers) hmm = await fetch.get(link)
q = BeautifulSoup(hmm.text, "lxml") q = BeautifulSoup(hmm.text, "lxml")
j = q.findAll("div", class_="soraurlx") j = q.findAll("div", class_="soraurlx")
kl = "" kl = ""

View file

@ -27,8 +27,7 @@ from pyrogram.types import (
from misskaty import app from misskaty import app
from misskaty.core import pyro_cooldown from misskaty.core import pyro_cooldown
from misskaty.core.decorator import capture_err, new_task, ratelimiter from misskaty.core.decorator import capture_err, new_task, ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import fetch, use_chat_lang
from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL, SUDO from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL, SUDO
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
@ -318,7 +317,7 @@ async def get_ytthumb(videoid: str):
thumb_link = "https://i.imgur.com/4LwPLai.png" thumb_link = "https://i.imgur.com/4LwPLai.png"
for qualiy in thumb_quality: for qualiy in thumb_quality:
link = f"https://i.ytimg.com/vi/{videoid}/{qualiy}" link = f"https://i.ytimg.com/vi/{videoid}/{qualiy}"
if (await http.get(link)).status_code == 200: if (await fetch.get(link)).status_code == 200:
thumb_link = link thumb_link = link
break break
return thumb_link return thumb_link