Spaces:
Running
Running
File size: 7,283 Bytes
1a1e2eb 2fe1440 1a1e2eb 3a67739 1a1e2eb 1fa270a 9a92ff5 746a920 1a1e2eb 9a92ff5 1a1e2eb 9a92ff5 2fe1440 3a67739 1fa270a 3a67739 1fa270a 29b5c59 1fa270a 29b5c59 1a1e2eb 3a67739 1fa270a 1a1e2eb 3a67739 658e097 3a67739 29b5c59 1fa270a 3a67739 2fe1440 1a1e2eb 3a67739 1fa270a 3a67739 1fa270a 3a67739 1fa270a 29b5c59 1a1e2eb 3a67739 1fa270a e7261d3 3a67739 9a92ff5 1fa270a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | # Thunder/utils/bot_utils.py
import asyncio
from typing import Any, Dict, Optional
from urllib.parse import quote
from pyrogram import Client
from pyrogram.enums import ChatMemberStatus
from pyrogram.errors import FloodWait
from pyrogram.types import (InlineKeyboardButton, InlineKeyboardMarkup,
Message, User)
from Thunder.utils.database import db
from Thunder.utils.file_properties import get_fname, get_fsize, get_hash
from Thunder.utils.human_readable import humanbytes
from Thunder.utils.logger import logger
from Thunder.utils.messages import (MSG_BUTTON_GET_HELP, MSG_DC_UNKNOWN,
MSG_DC_USER_INFO, MSG_NEW_USER)
from Thunder.utils.shortener import shorten
from Thunder.vars import Var
def quote_media_name(file_name: str) -> str:
return quote(str(file_name).replace("/", "_"), safe="")
async def _build_links(
*,
download_path: str,
stream_path: str,
media_name: str,
media_size: str,
shortener: bool = True
) -> Dict[str, str]:
base_url = Var.URL.rstrip("/")
slink = f"{base_url}{stream_path}"
olink = f"{base_url}{download_path}"
if shortener and getattr(Var, "SHORTEN_MEDIA_LINKS", False):
try:
s_results = await asyncio.gather(shorten(slink), shorten(olink), return_exceptions=True)
if not isinstance(s_results[0], Exception):
slink = s_results[0]
else:
logger.warning(f"Failed to shorten stream_link: {s_results[0]}")
if not isinstance(s_results[1], Exception):
olink = s_results[1]
else:
logger.warning(f"Failed to shorten online_link: {s_results[1]}")
except Exception as e:
logger.error(f"Error during link shortening: {e}")
return {"stream_link": slink, "online_link": olink, "media_name": media_name, "media_size": media_size}
async def gen_canonical_links(
*,
file_name: str,
file_size: int,
public_hash: str,
shortener: bool = True
) -> Dict[str, str]:
media_name = str(file_name)
media_size = humanbytes(file_size)
encoded_name = quote_media_name(media_name)
return await _build_links(
download_path=f"/f/{public_hash}/{encoded_name}",
stream_path=f"/watch/f/{public_hash}/{encoded_name}",
media_name=media_name,
media_size=media_size,
shortener=shortener
)
async def notify_ch(cli: Client, txt: str):
if not (hasattr(Var, 'BIN_CHANNEL') and isinstance(Var.BIN_CHANNEL, int) and Var.BIN_CHANNEL != 0):
return
try:
await cli.send_message(chat_id=Var.BIN_CHANNEL, text=txt)
except FloodWait as e:
await asyncio.sleep(e.value)
await cli.send_message(chat_id=Var.BIN_CHANNEL, text=txt)
async def notify_own(cli: Client, txt: str):
o_ids = Var.OWNER_ID if isinstance(Var.OWNER_ID, (list, tuple, set)) else [Var.OWNER_ID]
async def send_with_flood_wait(chat_id: int):
try:
await cli.send_message(chat_id=chat_id, text=txt)
except FloodWait as e:
await asyncio.sleep(e.value)
await cli.send_message(chat_id=chat_id, text=txt)
tasks = [send_with_flood_wait(oid) for oid in o_ids]
if hasattr(Var, 'BIN_CHANNEL') and isinstance(Var.BIN_CHANNEL, int) and Var.BIN_CHANNEL != 0:
tasks.append(send_with_flood_wait(Var.BIN_CHANNEL))
await asyncio.gather(*tasks, return_exceptions=True)
async def reply_user_err(msg: Message, err_txt: str):
try:
await msg.reply_text(
text=err_txt,
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(MSG_BUTTON_GET_HELP, callback_data="help_command")]]),
disable_web_page_preview=True
)
except FloodWait as e:
await asyncio.sleep(e.value)
await msg.reply_text(
text=err_txt,
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(MSG_BUTTON_GET_HELP, callback_data="help_command")]]),
disable_web_page_preview=True
)
async def log_newusr(cli: Client, uid: int, fname: str):
try:
is_new = await db.add_user(uid)
if not is_new:
return
if hasattr(Var, 'BIN_CHANNEL') and isinstance(Var.BIN_CHANNEL, int) and Var.BIN_CHANNEL != 0:
try:
await cli.send_message(chat_id=Var.BIN_CHANNEL, text=MSG_NEW_USER.format(first_name=fname, user_id=uid))
except FloodWait as e:
await asyncio.sleep(e.value)
await cli.send_message(chat_id=Var.BIN_CHANNEL, text=MSG_NEW_USER.format(first_name=fname, user_id=uid))
except Exception as e:
logger.error(f"Database error in log_newusr for user {uid}: {e}")
async def gen_links(fwd_msg: Message, shortener: bool = True) -> Dict[str, str]:
fid = fwd_msg.id
m_name_raw = get_fname(fwd_msg)
m_name = m_name_raw.decode('utf-8', errors='replace') if isinstance(m_name_raw, bytes) else str(m_name_raw)
m_size_hr = humanbytes(get_fsize(fwd_msg))
enc_fname = quote_media_name(m_name)
f_hash = get_hash(fwd_msg)
return await _build_links(
download_path=f"/{f_hash}{fid}/{enc_fname}",
stream_path=f"/watch/{f_hash}{fid}/{enc_fname}",
media_name=m_name,
media_size=m_size_hr,
shortener=shortener
)
async def gen_dc_txt(usr: User) -> str:
dc_id_val = usr.dc_id if usr.dc_id is not None else MSG_DC_UNKNOWN
return MSG_DC_USER_INFO.format(user_name=usr.first_name or 'User', user_id=usr.id, dc_id=dc_id_val)
async def get_user(cli: Client, qry: Any) -> Optional[User]:
if isinstance(qry, str):
if qry.startswith('@'):
try:
return await cli.get_users(qry)
except FloodWait as e:
await asyncio.sleep(e.value)
return await cli.get_users(qry)
elif qry.isdigit():
try:
return await cli.get_users(int(qry))
except FloodWait as e:
await asyncio.sleep(e.value)
return await cli.get_users(int(qry))
elif isinstance(qry, int):
try:
return await cli.get_users(qry)
except FloodWait as e:
await asyncio.sleep(e.value)
return await cli.get_users(qry)
return None
async def is_admin(cli: Client, chat_id_val: int) -> bool:
try:
member = await cli.get_chat_member(chat_id_val, cli.me.id)
except FloodWait as e:
await asyncio.sleep(e.value)
try:
member = await cli.get_chat_member(chat_id_val, cli.me.id)
except Exception:
return False
except Exception:
return False
if member is None:
return False
return member.status in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER]
async def reply(msg: Message, **kwargs):
try:
return await msg.reply_text(**kwargs, quote=True, disable_web_page_preview=True)
except FloodWait as e:
await asyncio.sleep(e.value)
return await msg.reply_text(**kwargs, quote=True, disable_web_page_preview=True)
|