Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #192

Merged
merged 10 commits into from
Jun 14, 2024
Merged

Dev #192

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ FullTClash名字来源于 Full Test base on Clash 。后端部分使用[Clash项
1. Netflix
2. Youtube
3. DisneyPlus
4. steam货币
4. Bilibili解锁
5. OpenAI(ChatGPT)
6. 落地ip风险(IP欺诈度)
7. 维基百科
8. TVBAnyware
9. Viu
8. 微软Copilot
9. Claude
10. 落地DNS区域检测
11. Spotify
12. SSH 22端口封禁检测
13. Tiktok

此外还有:

Expand Down Expand Up @@ -152,7 +156,7 @@ pip install -r requirements.txt
Windows系统名字后缀名.exe要加上,其他类Unix系统不需要加后缀名。
- 管理员配置(可选)

从3.6.10版本开始,bot在首次启动时会将接收到的第一条消息的发送者作为管理员,一般无需手动配置,除非您想设置多个管理员:
从3.6.11版本开始,bot在首次启动时会将接收到的第一条消息的发送者作为管理员,一般无需手动配置,除非您想设置多个管理员:
```yaml
admin:
- 12345678 # 改成自己的telegram uid
Expand Down
13 changes: 9 additions & 4 deletions addons/builtin/copilot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import aiohttp
from loguru import logger

# 解锁判定方式;目前Copilot除了极少数地区未提供支持,其他的几乎都支持。和节点质量关系并不大。
UNS_REGION = ["MY", "CV", "CN", "CU", "SR", "TL", "IR", 'CI', 'KP', 'PS', 'RU', 'SH', 'SY']
try:
from utils import retry
Expand Down Expand Up @@ -31,7 +32,7 @@ async def fetch_copilot(collector, session: aiohttp.ClientSession, proxy=None):
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0'
}
url = 'https://www.bing.com/search?q=bing'
url = 'https://www.bing.com/chat?toWww=1'
async with session.get(url, headers=headers, proxy=proxy, timeout=5) as resp:
if resp.history:
for i in resp.history:
Expand All @@ -40,8 +41,10 @@ async def fetch_copilot(collector, session: aiohttp.ClientSession, proxy=None):
return True
if resp.status == 200:
text = await resp.text()
# index = text.find("Copilot")
index = text.find("b-scopeListItem-conv")
index = text.find("b_wlcmPersLogo.copilot")
# print("b_wlcmPersLogo.copilot:", index)
collector.info['copilot'] = str(index)
# return True
try:
region = re.search(r'Region:"(\w\w)"', text).group(1)
# region2 = re.search(r'Region:"(.*)"', text).group(1)
Expand Down Expand Up @@ -91,4 +94,6 @@ async def demo():


if __name__ == "__main__":
asyncio.run(demo())
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(demo())
20 changes: 14 additions & 6 deletions botmodule/command/authority.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
'slaveid': {}, # 记录后端id选择
}
task_type = ['testurl', 'analyzeurl', 'speedurl']
temp_queue = asyncio.Queue(maxsize=1)
# temp_queue = {}
QUEUE_MAP = {}


def generate_random_string(length: int):
Expand Down Expand Up @@ -123,6 +124,9 @@ async def get_url_from_invite(_, message2: "Message"):
exclude_text = texts_li[2]
url_li = geturl(text_li, True)
if url_li:
temp_queue: Union[asyncio.Queue, None] = QUEUE_MAP.get(ID, None)
if temp_queue is None:
await message2.reply("❌此任务队列已被销毁,请重试")
await temp_queue.put((url_li, include_text, exclude_text))
else:
await message2.reply("无效的URL")
Expand Down Expand Up @@ -176,24 +180,28 @@ async def invite_pass(client: Client, message: Message):
return
try:
async with timeout(timeout_value):
suburl, in_text, ex_text = await temp_queue.get()
iq = asyncio.Queue(1)
QUEUE_MAP[start_uid] = iq
suburl, in_text, ex_text = await iq.get()
except asyncio.TimeoutError:
logger.info(f"验证过期: {key}")
await bot_mes.edit_text("❌任务已取消\n\n原因: 接收订阅链接超时")
finally:
QUEUE_MAP.pop(start_uid, None)
INVITE_CACHE.pop(key, '')
if suburl:
from botmodule.bot import bot_put
await message.reply("✨提交成功,请返回群组查看测试结果。")
await asyncio.sleep(3)
await asyncio.sleep(1)
await bot_mes.delete()
# await bot_put(app, originmsg, put_type, None, sort=sort_str, coreindex=1, slaveid=slaveid)
print(
logger.info(
f"invite提交的任务项: {subtext[1]}\n测试项:{test_items}\n过滤器: {in_text}<->{ex_text}\n排序: {sort_str}\n"
f"coreindex: {coreindex}\n后端id: {slaveid}")
await bot_put(client, mes, subtext[1], test_items=test_items,
include_text=in_text, exclude_text=ex_text, url=suburl,
sort=sort_str, coreindex=coreindex, slaveid=slaveid)
else:
INVITE_CACHE.pop(key, '')

success_message_list.pop(start_uid, None)


Expand Down
6 changes: 4 additions & 2 deletions botmodule/command/setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,10 @@ async def select_slave_page(_: Client, call: Union[CallbackQuery, Message], cont
if "default-slave" in slaveconfig:
slaveconfig.pop("default-slave")
usermsg = call.message.reply_to_message if isinstance(call, CallbackQuery) else call
user_ranking = get_slave_ranking(getID(usermsg))
slaveconfig = get_ranked_slave_list(slaveconfig, user_ranking)
uconf = config.getUserconfig()
if "usage-ranking" in uconf and bool(uconf.get("usage-ranking", {}).get("enable", True)):
user_ranking = get_slave_ranking(getID(usermsg))
slaveconfig = get_ranked_slave_list(slaveconfig, user_ranking)
comment = [i.get('comment', None) for k, i in slaveconfig.items() if i.get('comment', None)]

page = int(kwargs.get('page', 1))
Expand Down
9 changes: 6 additions & 3 deletions botmodule/command/submanage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import pyrogram.types
from pyrogram.errors import RPCError
from loguru import logger
from pyrogram.types import Message
from pyrogram.enums import ParseMode

from utils import check, cleaner
from botmodule.init_bot import config, admin
from utils.check import check_user, get_telegram_id_from_message
Expand Down Expand Up @@ -74,7 +77,7 @@ async def sub_invite(_, message: pyrogram.types.Message):
# print(r)


async def sub(_, message):
async def sub(_, message: "Message"):
ID = get_telegram_id_from_message(message)
arg = cleaner.ArgCleaner().getall(str(message.text))
try:
Expand All @@ -90,11 +93,11 @@ async def sub(_, message):
subowner = subinfo.get('owner', '')
if await check_user(message, admin, isalert=False):
# 管理员至高权限
await message.reply(str(subinfo.get('url', '')))
await message.reply(str(subinfo.get('url', '')), parse_mode=ParseMode.DISABLED)
return
if subowner and subowner == ID:
if hashlib.sha256(pwd.encode("utf-8")).hexdigest() == subpwd:
await message.reply(str(subinfo.get('url', '')))
await message.reply(str(subinfo.get('url', '')), )
else:
m2 = await message.reply("❌密码错误,请检查后重试")
await asyncio.sleep(5)
Expand Down
50 changes: 19 additions & 31 deletions botmodule/subinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@
from loguru import logger
from pyrogram.enums import ParseMode
from pyrogram.errors import RPCError
from utils.cleaner import geturl
from utils.cleaner import geturl, ArgCleaner
from utils.collector import SubCollector
from utils.check import get_telegram_id_from_message as get_id
from utils.check import check_user
from utils import message_delete_queue as mdq
from botmodule.init_bot import config, admin
from utils import cleaner


async def getSubInfo(_, message):
ID = get_id(message)
arg = cleaner.ArgCleaner().getall(str(message.text))
arg = ArgCleaner.getarg(str(message.text))
call_time = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime())
try:
back_message = await message.reply("正在查询流量信息...") # 发送提示
text = str(message.text)
url = geturl(text)
arglen = len(arg)
status = False
subname = arg[1]
if not url:
if arglen == 1:
await back_message.edit_text("使用方法: /traffic & /subinfo & /流量查询 + <订阅链接> & <订阅名>")
await asyncio.sleep(5)
await back_message.delete()
mdq.put(back_message)
return
else:
pwd = arg[2] if len(arg) > 2 else arg[1]
Expand Down Expand Up @@ -54,38 +54,26 @@ async def getSubInfo(_, message):
subcl = SubCollector(url)
subcl.cvt_enable = False
subinfo = await subcl.getSubTraffic()
if status:
if subinfo:
rs = subinfo[3] - subinfo[2] # 剩余流量
subname = arg[1]
subinfo_text = f"""
☁️订阅名称:{subname}
if not subinfo:
await back_message.edit_text("此订阅无法获取流量信息")
return
days_diff = subinfo[5] if len(subinfo) > 5 else ""
if days_diff:
days_diff = f"({days_diff}天)"
rs = subinfo[3] - subinfo[2] # 剩余流量
subinfo_text = f"""
⬆️已用上行:{round(subinfo[0], 3)} GB
⬇️已用下行:{round(subinfo[1], 3)} GB
🚗总共使用:{round(subinfo[2], 3)} GB
⏳剩余流量:{round(rs, 3)} GB
💧总流量:{round(subinfo[3], 3)} GB
⏱️过期时间:{subinfo[4]}
⏱️过期时间:{subinfo[4]} {days_diff}
🔍查询时间:{call_time}
"""
await back_message.edit_text(subinfo_text, parse_mode=ParseMode.DISABLED)
else:
await back_message.edit_text("此订阅无法获取流量信息")
"""
if status:
subinfo_text = f"☁️订阅名称:{subname}" + subinfo_text
else:
if subinfo:
rs = subinfo[3] - subinfo[2] # 剩余流量
subinfo_text = f"""
☁️订阅链接:{url}
⬆️已用上行:{round(subinfo[0], 3)} GB
⬇️已用下行:{round(subinfo[1], 3)} GB
🚗总共使用:{round(subinfo[2], 3)} GB
⏳剩余流量:{round(rs, 3)} GB
💧总流量:{round(subinfo[3], 3)} GB
⏱️过期时间:{subinfo[4]}
🔍查询时间:{call_time}
"""
await back_message.edit_text(subinfo_text, parse_mode=ParseMode.DISABLED)
else:
await back_message.edit_text("此订阅无法获取流量信息")
subinfo_text = f"☁️订阅链接:{url}" + subinfo_text
await back_message.edit_text(subinfo_text, parse_mode=ParseMode.DISABLED)
except RPCError as r:
logger.error(str(r))
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
aiohttp>=3.8.5
aiohttp>=3.9.2
async_timeout>=4.0.2
Pillow==10.1
Pillow==10.2.0
pilmoji>=2.0.4
Pyrogram==2.0.106
PyYAML>=6.0
Expand All @@ -12,5 +12,5 @@ loguru>=0.6.0
aiohttp_socks>=0.8.4
tzlocal==4.1
geoip2==4.6.0
cryptography==40.0.2
google-re2==1.0
cryptography==42.0.4
google-re2>=1.0
17 changes: 9 additions & 8 deletions resources/config.yaml.example
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# 注意,yaml配置文件对缩进敏感,请不要强迫症删掉#号之间的空格。
admin:
- 12345678 #管理员,此处写你的账户id或用户名,必须配置该项,否则程序会自动退出
clash:
path: './bin/FullTCore' # 代理客户端的路径,默认为 ./bin/ 下。下载地址: https://github.com/AirportR/FullTCore/releases
# allow-caching: false #是否缓存测试过程产生的订阅,若否,则测试完成后会自动删除测试订阅,以免造成空间浪费。(此配置暂不生效)
# core: 4 # 核心数,数量越多测试速度越快,但代价是内存会大量占用(每个核心大概10M),自己的机子多少内存自己平衡。默认值为1.
# branch: origin #clash内核上游分支,仅有两个有效值: [origin, meta], meta分支支持更多协议,比如vless、tuic等,但是使用上较为不可控,默认为origin原生内核。
bot:
api_id: 123456 # Telegram的api_id
api_hash: ABCDEFG # Telegram的api_hash
Expand All @@ -21,6 +14,12 @@ bot:
# bright: "]" #右括号自定义文本
# bspace: " " #空格自定义文本,默认为2个
# command: ['mycommand1', 'mycommand2'] #自定义指令,用于适配权限回调。高级用法,不会无需配置。
#admin:
#- 12345678 #管理员,此处写你的账户id或用户名,必须配置该项,否则程序会自动退出
#clash:
# path: './bin/FullTCore' # 代理客户端的路径,默认为 ./bin/ 下。下载地址: https://github.com/AirportR/FullTCore/releases
# core: 4 # 单批次中同时测试的节点数量,数量越多测试速度越快,但代价是运行内存会相应变大,自己的机子多少内存自己平衡。默认值为4.
# branch: origin #clash内核上游分支,仅有两个有效值: [origin, meta], meta分支支持更多协议,比如vless、tuic等,但是使用上较为不可控,默认为meta原生内核。
#以下是fulltclash的buildtoken,可以用默认的,但是安全性得不到保障,具体原因详见文档
#buildtoken: c7004ded9db897e538405c67e50e0ef0c3dbad717e67a92d02f6ebcfd1022a5ad1d2c4419541f538ff623051759ec000d2f426e03f9709a6608570c5b9141a6b
#proxy: "host:端口" # http配置代理(非socks5),括号内可选用于下载获取订阅链接,订阅链接国内打不开可尝试开启(可选配置),本机提供的代理可以这样填: '127.0.0.1:7890'
Expand All @@ -33,6 +32,7 @@ bot:
# host: '127.0.0.1:25500' #域名或者ip加端口
# tls: false #是否启用了tls,决定拼接的转换地址URL前缀是http还是https,默认false
# remoteconfig: "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini" #远程配置
#ua: "ClashMetaForAndroid/2.8.9.Meta Mihomo/0.16 Clash.Meta" #获取订阅时请求UA(user-agent)覆写,此配置仅会影响获取订阅时的UA,默认值如当前所示。
#pingurl: http://www.gstatic.com/generate_204 #自定义延迟测试URL
#netflixurl: "https://www.netflix.com/title/80113701" #自定义奈飞非自制剧检测网页,注意在更换此链接时请确保是非自制的链接。
#speedfile: #自定义测速文件,可以添加多个诸如以下格式或者[https://1.com, https://2.com]
Expand Down Expand Up @@ -75,7 +75,8 @@ bot:
# slaveid: local #slaveid的有效值参照配置里的 slaveconfig下的所有键。
# script: ["Netflix", "Youtube", "Disney+", "维基百科"] #script的有效值参照连通性测试绘图结果中显示的名称(大小写敏感)。
# sort: "HTTP升序"
# usage-ranking: #后端使用排行,这里记录者用户使用的后端次数,以便测试选择后端时把最常用的后端显示在第一页,这个配置是bot自动生成的,不用手动修改,你也不需要去管它。
# usage-ranking: #后端使用排行,这里记录者用户使用的后端次数,以便测试选择后端时把最常用的后端显示在第一页。
# enable: True #是否启用
# 查看你的机器人的所有可用测试项的python变量:
# from utils.cleaner import addon
# print(addon.global_test_item)
Expand Down
5 changes: 3 additions & 2 deletions utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
from utils.cron import *
from typing import Callable, Any, Union, Coroutine, Optional

__version__ = "3.6.11" # 项目版本号
__version__ = "3.6.12" # 项目版本号
HOME_DIR = getcwd()
DEFAULT_UA = f"fulltclash/{__version__}" # 默认请求头
__all__ = [
"cron_delete_message",
"cron_edit_message",
"message_delete_queue",
"message_edit_queue",
"__version__",
"DEFAULT_UA",
"retry",
"script_demo",
"HOME_DIR",
Expand Down Expand Up @@ -90,7 +92,6 @@ def async_runtime(loop: Optional[asyncio.AbstractEventLoop] = None):
"""
临时的异步运行时,适用于只有一两个异步函数的情况
:param: loop: 事件循环
:param: break_func: 触发的回调中止函数,参数为调用函数的返回值,返回值为bool,
"""
if loop is None:
loop = asyncio.new_event_loop()
Expand Down
4 changes: 2 additions & 2 deletions utils/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from loguru import logger
from utils.collector import proxies
from libs import pynat
from utils import message_edit_queue, cleaner, collector, ipstack, proxy, sorter, geoip
from utils import message_edit_queue, cleaner, collector, ipstack, proxy, sorter, geoip, __version__

# 重写整个测试核心,技术栈分离。

Expand Down Expand Up @@ -255,7 +255,7 @@ def nat_type_test(proxyaddr=None, proxyport=None):
async def fetch(self: Speedtest, urls: list, host: str, port: int, buffer: int):
try:
async with aiohttp.ClientSession(
headers={"User-Agent": "FullTClash"},
headers={"User-Agent": f"fulltclash/{__version__}"},
connector=ProxyConnector(host=host, port=port),
) as session:
flag = 0
Expand Down
9 changes: 9 additions & 0 deletions utils/cleaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,15 @@ def get_slave_ranking(self, ID: Union[str, int] = None):
sorted_ranking = {item: c for item, c in sorted_ranking}
return sorted_ranking

def get_ua(self):
"""
获取自定义ua
"""
try:
return str(self.config['ua'])
except KeyError:
return ""

def getConcurrency(self) -> int:
clashconf = self.config.get('clash', {})
max_workers = min(32, (os.cpu_count() or 1) + 14)
Expand Down
Loading