2022-07-14 05:31:47 +00:00
|
|
|
|
import re
|
2023-04-08 16:50:15 +00:00
|
|
|
|
import asyncio
|
2023-04-12 06:11:44 +00:00
|
|
|
|
import traceback
|
2022-07-14 05:31:47 +00:00
|
|
|
|
|
2023-02-05 14:33:33 +00:00
|
|
|
|
from core.builtins import Bot
|
2023-03-04 08:51:56 +00:00
|
|
|
|
from core.component import module
|
2023-02-05 14:33:33 +00:00
|
|
|
|
from core.utils.http import get_url
|
2023-04-08 16:50:15 +00:00
|
|
|
|
from config import Config
|
2022-01-19 15:28:46 +00:00
|
|
|
|
|
2023-03-04 08:51:56 +00:00
|
|
|
|
mod_dl = module(
|
2022-01-19 15:28:46 +00:00
|
|
|
|
bind_prefix='mod_dl',
|
2023-04-09 04:38:22 +00:00
|
|
|
|
desc='下载 CurseForge 和 Modrinth 上的 Mod。',
|
2023-04-08 16:50:15 +00:00
|
|
|
|
developers=['HornCopper', 'OasisAkari', 'z0z0r4'],
|
2022-01-21 11:42:02 +00:00
|
|
|
|
recommend_modules=['mcmod'],
|
|
|
|
|
alias='moddl')
|
2022-01-19 15:28:46 +00:00
|
|
|
|
|
2023-04-08 16:50:15 +00:00
|
|
|
|
x_api_key = Config("curseforge_api_key")
|
2022-01-21 11:40:12 +00:00
|
|
|
|
|
2022-07-14 05:31:47 +00:00
|
|
|
|
def cn_chk(string: str):
|
|
|
|
|
for word in string:
|
|
|
|
|
if u'\u4e00' <= word <= u'\u9fff':
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2023-04-08 16:50:15 +00:00
|
|
|
|
@mod_dl.handle('<mod_name> [<version>] {通过模组名获取模组下载链接}')
|
2023-02-05 14:33:33 +00:00
|
|
|
|
async def main(msg: Bot.MessageSession):
|
2022-07-14 05:31:47 +00:00
|
|
|
|
mod_name = msg.parsed_msg['<mod_name>']
|
2023-04-08 16:50:15 +00:00
|
|
|
|
ver = msg.parsed_msg.get('<version>', None)
|
2022-07-14 05:31:47 +00:00
|
|
|
|
if ver:
|
|
|
|
|
match_ver = re.match(r'^\d+\.\d+\.\d+$|^\d+\.\d+$|\d+w\d+[abcd]', ver)
|
|
|
|
|
if match_ver is None:
|
|
|
|
|
mod_name += ' ' + ver
|
|
|
|
|
ver = False
|
|
|
|
|
if cn_chk(mod_name):
|
2023-04-08 16:50:15 +00:00
|
|
|
|
return {'msg': '暂不支持中文搜索。', 'success': False}
|
|
|
|
|
|
|
|
|
|
async def search_modrinth(name: str, ver: str):
|
|
|
|
|
url = f'https://api.modrinth.com/v2/search?query={name}&limit=10'
|
|
|
|
|
if ver:
|
|
|
|
|
url += f'&facets=[["versions:{ver}"],["project_type:mod"]]'
|
2022-07-14 05:31:47 +00:00
|
|
|
|
else:
|
2023-04-08 16:50:15 +00:00
|
|
|
|
url += f'&facets=[["project_type:mod"]]'
|
|
|
|
|
resp = await get_url(url, 200, fmt="json", timeout=5, attempt=3)
|
|
|
|
|
if resp is not None:
|
|
|
|
|
results = []
|
|
|
|
|
if len(resp["hits"]) == 0:
|
|
|
|
|
return None
|
|
|
|
|
for project in resp['hits']:
|
|
|
|
|
results.append(("modrinth", project["title"], project["project_id"], project["versions"]))
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
async def search_curseforge(name: str, ver: str):
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'x-api-key': x_api_key
|
|
|
|
|
}
|
|
|
|
|
url = f'https://api.curseforge.com/v1/mods/search?gameId=432&searchFilter={name}&sortField=2&sortOrder=desc&pageSize=10&classId=6'
|
2022-07-14 05:31:47 +00:00
|
|
|
|
if ver:
|
2023-04-08 16:50:15 +00:00
|
|
|
|
url += f'&gameVersion={ver}'
|
2023-04-12 06:11:44 +00:00
|
|
|
|
results = []
|
|
|
|
|
try:
|
|
|
|
|
resp = await get_url(url, 200, fmt="json", timeout=5, attempt=3, headers=headers)
|
|
|
|
|
if resp is not None:
|
|
|
|
|
if resp["pagination"]["resultCount"] == 0:
|
|
|
|
|
return None
|
|
|
|
|
for mod in resp["data"]:
|
|
|
|
|
results.append(("curseforge", mod["name"], mod["id"], None))
|
|
|
|
|
except Exception:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
return results
|
2023-04-08 16:50:15 +00:00
|
|
|
|
|
|
|
|
|
async def get_modrinth_project_version(project_id: str, ver: str):
|
|
|
|
|
url = f'https://api.modrinth.com/v2/project/{project_id}/version?game_versions=["{ver}"]&featured=true'
|
|
|
|
|
resp = (await get_url(url, 200, fmt="json", timeout=5, attempt=3))[0]
|
|
|
|
|
if resp is not None:
|
|
|
|
|
return resp
|
|
|
|
|
|
|
|
|
|
async def get_curseforge_mod_version_index(modid: str):
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'x-api-key': x_api_key
|
|
|
|
|
}
|
|
|
|
|
url = f'https://api.curseforge.com/v1/mods/{modid}'
|
|
|
|
|
resp = await get_url(url, 200, fmt="json", timeout=5, attempt=3, headers=headers)
|
|
|
|
|
if resp is not None:
|
|
|
|
|
return resp["data"]['latestFilesIndexes']
|
|
|
|
|
|
|
|
|
|
async def get_curseforge_mod_file(modid: str, ver: str):
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'x-api-key': x_api_key
|
|
|
|
|
}
|
|
|
|
|
url = f'https://api.curseforge.com/v1/mods/{modid}/files?gameVersion={ver}'
|
2023-04-12 06:11:44 +00:00
|
|
|
|
try:
|
|
|
|
|
resp = await get_url(url, 200, fmt="json", timeout=5, attempt=3, headers=headers)
|
|
|
|
|
if resp is not None:
|
|
|
|
|
return resp["data"][0]
|
|
|
|
|
except Exception:
|
|
|
|
|
traceback.print_exc()
|
2023-04-08 16:50:15 +00:00
|
|
|
|
|
|
|
|
|
# 搜索 Mod
|
|
|
|
|
result = await asyncio.gather(*(search_modrinth(mod_name, ver), search_curseforge(mod_name, ver)))
|
|
|
|
|
cache_result = []
|
|
|
|
|
if result[0] is None and result[1] is None:
|
|
|
|
|
await msg.finish("搜索失败,无结果。")
|
|
|
|
|
else:
|
|
|
|
|
# 合并搜索结果
|
|
|
|
|
reply_text, count = [], 0
|
|
|
|
|
if result[0] is None:
|
|
|
|
|
reply_text.append("Modrinth 结果:无")
|
|
|
|
|
reply_text.append("Modrinth 结果:")
|
|
|
|
|
for mod in result[0]:
|
|
|
|
|
count += 1
|
|
|
|
|
reply_text.append(f"{count}. {mod[1]}")
|
|
|
|
|
cache_result.append(mod)
|
|
|
|
|
|
|
|
|
|
if result[1] is None:
|
|
|
|
|
reply_text.append("CurseForge 结果:无")
|
2022-07-14 05:31:47 +00:00
|
|
|
|
else:
|
2023-04-08 16:50:15 +00:00
|
|
|
|
reply_text.append("CurseForge 结果:")
|
|
|
|
|
for mod in result[1]:
|
|
|
|
|
count += 1
|
|
|
|
|
reply_text.append(f"{count}. {mod[1]}")
|
|
|
|
|
cache_result.append(mod)
|
|
|
|
|
|
|
|
|
|
reply = await msg.waitReply('\n'.join(reply_text) + '\n请回复编号来选择mod。')
|
|
|
|
|
replied = reply.asDisplay(text_only=True)
|
|
|
|
|
|
|
|
|
|
# 查找 Mod
|
|
|
|
|
if replied.isdigit():
|
|
|
|
|
replied = int(replied)
|
|
|
|
|
if replied > len(cache_result):
|
|
|
|
|
return await msg.finish('编号超出范围。')
|
2022-07-14 05:31:47 +00:00
|
|
|
|
else:
|
2023-04-08 16:50:15 +00:00
|
|
|
|
mod_info = cache_result[replied - 1]
|
|
|
|
|
else:
|
|
|
|
|
return await msg.finish('无效的编号,必须为纯数字。')
|
|
|
|
|
|
|
|
|
|
if mod_info[0] == "modrinth": # modrinth mod
|
|
|
|
|
if ver is None:
|
|
|
|
|
reply2 = await msg.waitReply('此mod拥有如下版本:\n' + '\n'.join(mod_info[3]) + '\n请回复版本号来选择版本。')
|
|
|
|
|
replied2 = reply2.asDisplay(text_only=True)
|
|
|
|
|
if replied2 in mod_info[3]:
|
|
|
|
|
version_info = await get_modrinth_project_version(mod_info[2], replied2)
|
|
|
|
|
if version_info is not None:
|
|
|
|
|
await msg.finish(f'{" ".join(version_info["loaders"])}\n下载链接:{version_info["files"][0]["url"]}\n文件名:{version_info["files"][0]["filename"]}')
|
|
|
|
|
elif ver not in mod_info[3]:
|
|
|
|
|
await msg.finish("未找到指定版本。")
|
|
|
|
|
elif ver in mod_info[3]:
|
|
|
|
|
version_info = await get_modrinth_project_version(mod_info[2], ver)
|
|
|
|
|
if version_info is not None:
|
|
|
|
|
await msg.finish(f'{" ".join(version_info["loaders"])}\n下载链接:{version_info["files"][0]["url"]}\n文件名:{version_info["files"][0]["filename"]}')
|
|
|
|
|
else: # curseforge mod
|
|
|
|
|
version_index = await get_curseforge_mod_version_index(mod_info[2])
|
|
|
|
|
if version_index is not None:
|
|
|
|
|
if ver is None:
|
|
|
|
|
reply_text = []
|
|
|
|
|
for version in version_index:
|
|
|
|
|
reply_text.append(version["gameVersion"])
|
2023-04-09 04:38:22 +00:00
|
|
|
|
reply2 = await msg.waitReply('此mod拥有如下版本:\n' +
|
|
|
|
|
'\n'.join(reply_text) +
|
|
|
|
|
'\n请回复版本号来选择版本。')
|
2023-04-08 16:50:15 +00:00
|
|
|
|
ver = reply2.asDisplay(text_only=True)
|
|
|
|
|
elif ver not in version_index:
|
|
|
|
|
await msg.finish("未找到指定版本。")
|
2022-07-14 05:31:47 +00:00
|
|
|
|
|
2023-04-08 16:50:15 +00:00
|
|
|
|
if ver in version_index:
|
|
|
|
|
file_info = await get_curseforge_mod_file(mod_info[2], ver)
|
|
|
|
|
if file_info is not None:
|
2023-04-09 04:38:22 +00:00
|
|
|
|
await msg.finish(f'{" ".join(file_info["gameVersions"])} \
|
|
|
|
|
\n下载链接:{file_info["downloadUrl"]} \
|
|
|
|
|
\n文件名:{file_info["fileName"]}')
|
2023-04-08 16:50:15 +00:00
|
|
|
|
else:
|
2023-04-12 06:11:44 +00:00
|
|
|
|
await msg.finish("未找到指定版本。")
|