Archived
1
0
Fork 0

Merge branch 'Teahouse-Studios:master' into master

This commit is contained in:
ZoruaFox 2023-12-15 09:15:54 +08:00 committed by GitHub
commit f315a97c9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 595 additions and 213 deletions

194
LOCALES.md Normal file
View file

@ -0,0 +1,194 @@
# 目录
- [简介](#简介)
- [文件位置](#文件位置)
- [语言文件格式](#语言文件格式)
- [排版](#排版)
- [空格](#空格)
- [中英文之间需要增加空格](#中英文之间需要增加空格)
- [中文与数字之间需要增加空格](#中文与数字之间需要增加空格)
- [数字与单位之间不加空格](#数字与单位之间不加空格)
- [全角标点与其他字符之间不加空格](#全角标点与其他字符之间不加空格)
- [变量与中文之间需要增加空格](#变量与中文之间需要增加空格)
- [标点符号](#标点符号)
- [不要重复使用标点符号](#不要重复使用标点符号)
- [简体中文不要使用直角引号](#简体中文不要使用直角引号)
- [英文不要使用弯引号](#英文不要使用弯引号)
- [英文省略号使用三个点](#英文省略号使用三个点)
- [全角和半角](#全角和半角)
- [使用全角中文标点](#使用全角中文标点)
- [数字和英文使用半角字符](#数字和英文使用半角字符)
- [遇到完整的英文成句内容中使用半角标点](#遇到完整的英文成句内容中使用半角标点)
- [名词](#名词)
- [专有名词使用正确的大小写](#专有名词使用正确的大小写)
- [不要使用非正式的缩写](#不要使用非正式的缩写)
- [不同地区的中文使用对应的地区词](#不同地区的中文使用对应的地区词)
- [报告问题](#报告问题)
# 简介
本规范文件旨在确保项目中的多语言文本一致性和格式规范。请遵循以下内容以保持代码库中的多语言资源的统一性。
# 文件位置
请将语言文件放置在 `/locales` 目录中,并以语言代码命名为 JSON 文件。
根路径下的目录用于放置全局字符串,模块下的目录用于放置对应专用的模块字符串。
原则上,模块字符串和对应模块须对应,若模块之间存在关联则可以例外,否则请考虑转为全局字符串。
# 语言文件格式
请确保键名与字符串一一对应,不得嵌套。
**全局字符串的命名方式**`字符串类别.用途`
**模块字符串的命名方式**`模块名称.字符串类别.命令名称.用途`
使用 `${变量名}` 表示变量,变量名必须使用英文,不能使用空格和特殊符号,如需分隔则使用下划线代替。
# 排版
> 本文部分参照[中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines),内容可能有出入。
## 空格
### 中英文之间需要增加空格
正确:
> 在 IBM 的研究中,他们利用 AI 技术开发了一种先进的语音识别系统。
错误:
> 在IBM的研究中他们利用AI技术开发了一种先进的语音识别系统。
例外:专有名词、商品名等词语,按照约定俗成的格式书写。
### 中文与数字之间需要增加空格
正确:
> 今年的全球汽车销售量达到了 8000 万辆。
错误:
> 今年的全球汽车销售量达到了8000万辆。
### 数字与单位之间不加空格
正确:
> 我家的光纤入户宽带有 10GbpsSSD 一共有 10TB。
> 这个城市每年平均降雨量为 1200mm。
>
> 角度为 90° 的角,就是直角。
错误:
>我家的光纤入户宽带有 10 GbpsSSD 一共有 20 TB。
> 这个城市每年平均降雨量为 1200 mm。
>
> 角度为 90 ° 的角,就是直角。
### 全角标点与其他字符之间不加空格
正确:
> 刚刚买了一部 iPhone好开心
错误:
> 刚刚买了一部 iPhone ,好开心!
### 变量与中文之间需要增加空格
一般情况下,变量的输入为英文或数字,故变量与中文之间加入空格。
正确:
> 你扔了一块石头,漂了 ${count} 下。
错误:
> 你扔了一块石头,漂了${count}下。
例外:如果变量的输入一定为中文,则不加空格。
## 标点符号
### 不要重复使用标点符号
虽然重复使用标点符号是被允许的行为,但是请别这样做。
正确:
> 德国队竟然战胜了巴西队!
错误:
> 德国队竟然战胜了巴西队!!!
### 简体中文不要使用直角引号
直角引号并不符合简体中文使用者的使用习惯。
正确:
> “老师,‘有条不紊’的‘紊’是什么意思?”
错误:
> 「老师,『有条不紊』的『紊』是什么意思?」
### 英文不要使用弯引号
中文弯引号和英文弯引号属于同一个字符,如果使用弯引号反而会造成阅读问题,请使用直引号 `"`
正确:
> "Success is not final, failure is not fatal: It is the courage to continue that counts."
错误:
> “Success is not final, failure is not fatal: It is the courage to continue that counts.”
### 英文省略号使用三个点
同上,请使用三个点 `...`
正确:
> In the serene moonlit night, whispers of ancient tales lingered, echoing through the stillness of time...
错误:
> In the serene moonlit night, whispers of ancient tales lingered, echoing through the stillness of time…
## 全角和半角
### 使用全角中文标点
正确:
> 嗨!你知道嘛?今天前台的小妹跟我说“喵”了哎!
错误:
> 嗨! 你知道嘛? 今天前台的小妹跟我说 "喵" 了哎!
>
> 嗨!你知道嘛?今天前台的小妹跟我说"喵"了哎!
### 数字和英文使用半角字符
正确:
> 这件蛋糕只卖 200 元。
错误:
> 这件蛋糕只卖 元。
### 遇到完整的英文成句内容中使用半角标点
正确:
> 乔布斯那句话是怎么说的“Stay hungry, stay foolish.”
错误:
> 乔布斯那句话是怎么说的“Stay hungry, stay foolish。”
## 名词
### 专有名词使用正确的大小写
正确:
> 使用 GitHub 登录
错误:
> 使用 Github 登录
>
> 使用 gitHub 登录
>
> 使用 github 登录
>
> 使用 GITHUB 登录
### 不要使用非正式的缩写
正确:
> 我们需要一位熟悉 JavaScript、HTML5至少理解一种框架如 Backbone.js、AngularJS、React 等)的前端开发者。
错误:
> 我们需要一位熟悉 Js、h5至少理解一种框架如 backbone、angular、RJS 等)的 FED。
### 不同地区的中文使用对应的地区词
不要在繁体中文中使用“视频”等错误的地区词,认真的。
正确:
> 輸入影片編號取得對應資訊。
错误:
> 輸入視頻編號獲得相應信息。
# 报告问题
与简体中文翻译有关的问题可直接使用 [Issue](https://github.com/Teahouse-Studios/akari-bot/issues/new) 报告。
简体中文以外的所有语言由机器人 @Hldbot 维护,相关问题请移步 [Crowdin](https://crowdin.com/project/akari-bot) 报告。

View file

@ -44,7 +44,7 @@
#### QQ
~~目前 QQ 上稳定运行的小可实例为小可三号机。由于腾讯风控问题,请[在此提交](https://github.com/Teahouse-Studios/bot/issues/new?assignees=OasisAkari&labels=New&template=add_new_group.yaml&title=%5BNEW%5D%3A+)入群申请。~~
~~目前 QQ 上稳定运行的小可实例为小可三号机。由于腾讯风控问题,请[在此提交](https://github.com/Teahouse-Studios/akari-bot/issues/new?assignees=OasisAkari&labels=New&template=add_new_group.yaml&title=%5BNEW%5D%3A+)入群申请。~~
~~QQ 频道的测试版支持也请在上方链接申请。~~ 我们正在进行 QQ 频道官方机器人入驻,未来可能会成为官方认证的机器人。
@ -56,7 +56,7 @@
你可以[参考这里](./DEPLOY.md)来进行尝试搭建。
若遇到问题,可以通过 [Issue](https://github.com/Teahouse-Studios/bot/issues/new) 或其他方式咨询开发者。
若遇到问题,可以通过 [Issue](https://github.com/Teahouse-Studios/akari-bot/issues/new) 或其他方式咨询开发者。
### 多语言

View file

@ -14,7 +14,7 @@ from aiocqhttp import MessageSegment
from bots.aiocqhttp.client import bot
from bots.aiocqhttp.info import client_name
from config import Config
from core.builtins import Bot, base_superuser_list, command_prefix, ErrorMessage, Image, Plain, Temp, Voice
from core.builtins import Bot, base_superuser_list, command_prefix, ErrorMessage, Image, Plain, Temp, Voice, MessageTaskManager
from core.builtins.message import MessageSession as MessageSessionT
from core.builtins.message.chain import MessageChain
from core.exceptions import SendMessageFailed
@ -88,26 +88,30 @@ class MessageSession(MessageSessionT):
quote = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True,
callback=None) -> FinishedSession:
message_chain = MessageChain(message_chain)
message_chain_assendable = message_chain.as_sendable(self, embed=False)
if (self.target.target_from == 'QQ|Group' and Temp.data.get('lagrange_status', False) and not
self.tmp.get('enforce_send_by_master_client', False)):
self.tmp.get('enforce_send_by_master_client', False) and not callback):
lagrange_available_groups = Temp.data.get('lagrange_available_groups', [])
if int(self.session.target) in lagrange_available_groups:
choose = random.randint(0, 1)
Logger.debug(f'choose: {choose}')
if choose:
can_sends = []
cant_sends = []
for x in message_chain_assendable:
if isinstance(x, (Plain, Image)):
can_sends.append(x)
if isinstance(x, Voice):
cant_sends.append(x)
message_chain_assendable.remove(x)
if can_sends:
if message_chain_assendable:
await JobQueue.send_message('Lagrange', self.target.target_id,
MessageChain(can_sends).to_list())
if not message_chain_assendable:
MessageChain(message_chain_assendable).to_list())
if cant_sends:
self.tmp['enforce_send_by_master_client'] = True
await self.send_message(MessageChain(cant_sends))
return FinishedSession(self, 0, [{}])
else:
Logger.debug(f'Do not use lagrange since some conditions are not met.\n{self.target.target_from} '
@ -170,6 +174,8 @@ class MessageSession(MessageSessionT):
return FinishedSession(self, 0, [{}])
else:
raise e
if callback:
MessageTaskManager.add_callback(send['message_id'], callback)
return FinishedSession(self, send['message_id'], [send])
async def check_native_permission(self):

View file

@ -5,7 +5,7 @@ from typing import List, Union
from bots.aiogram.client import dp, bot, token
from bots.aiogram.info import client_name
from config import Config
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage, MessageTaskManager
from core.builtins.message.chain import MessageChain
from core.logger import Logger
from core.types import FetchTarget as FetchTargetT, \
@ -39,7 +39,7 @@ class MessageSession(MessageSessionT):
wait = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True, callback=None) -> FinishedSession:
message_chain = MessageChain(message_chain)
if not message_chain.is_safe and not disable_secret_check:
return await self.send_message(Plain(ErrorMessage(self.locale.t("error.message.chain.unsafe"))))
@ -89,6 +89,8 @@ class MessageSession(MessageSessionT):
msg_ids = []
for x in send:
msg_ids.append(x.message_id)
if callback:
MessageTaskManager.add_callback(x.message_id, callback)
return FinishedSession(self, msg_ids, send)
async def check_native_permission(self):

View file

@ -1,5 +1,7 @@
import discord
from config import Config
intents = discord.Intents.default()
intents.message_content = True
client = discord.Bot(intents=intents)
client = discord.Bot(intents=intents, proxy=Config('proxy'))

View file

@ -9,7 +9,7 @@ import filetype
from bots.discord.client import client
from bots.discord.info import client_name
from config import Config
from core.builtins import Bot, Plain, Image, MessageSession as MessageSessionT
from core.builtins import Bot, Plain, Image, MessageSession as MessageSessionT, MessageTaskManager
from core.builtins.message.chain import MessageChain
from core.builtins.message.internal import Embed, ErrorMessage, Voice
from core.logger import Logger
@ -69,7 +69,8 @@ class MessageSession(MessageSessionT):
quote = True
wait = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False, allow_split_image=True
async def send_message(self, message_chain, quote=True, disable_secret_check=False, allow_split_image=True,
callback=None
) -> FinishedSession:
message_chain = MessageChain(message_chain)
if not message_chain.is_safe and not disable_secret_check:
@ -102,13 +103,15 @@ class MessageSession(MessageSessionT):
files=files)
Logger.info(f'[Bot] -> [{self.target.target_id}]: Embed: {str(x.__dict__)}')
else:
send_ = False
send_ = None
if send_:
send.append(send_)
count += 1
msg_ids = []
for x in send:
msg_ids.append(x.id)
if callback:
MessageTaskManager.add_callback(x.id, callback)
return FinishedSession(self, msg_ids, send)

View file

@ -9,7 +9,7 @@ from khl import MessageTypes, Message
from bots.kook.client import bot
from bots.kook.info import client_name
from config import Config
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage, MessageTaskManager
from core.builtins.message.chain import MessageChain
from core.logger import Logger
from core.types import FetchTarget as FetchTargetT, \
@ -68,7 +68,7 @@ class MessageSession(MessageSessionT):
wait = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True, callback=None) -> FinishedSession:
self.session.message: Message
message_chain = MessageChain(message_chain)
if not message_chain.is_safe and not disable_secret_check:
@ -102,6 +102,8 @@ class MessageSession(MessageSessionT):
msg_ids = []
for x in send:
msg_ids.append(x['msg_id'])
if callback:
MessageTaskManager.add_callback(x['msg_id'], callback)
return FinishedSession(self, msg_ids, {self.session.message.channel_type.name: send})
async def check_native_permission(self):

View file

@ -14,7 +14,8 @@ from aiocqhttp import MessageSegment
from bots.lagrange.client import bot
from bots.lagrange.info import client_name
from config import Config
from core.builtins import Bot, base_superuser_list, command_prefix, ErrorMessage, Image, Plain, Temp, Voice
from core.builtins import Bot, base_superuser_list, command_prefix, ErrorMessage, Image, Plain, Temp, Voice, \
MessageTaskManager
from core.builtins.message import MessageSession as MessageSessionT
from core.builtins.message.chain import MessageChain
from core.exceptions import SendMessageFailed
@ -86,7 +87,8 @@ class MessageSession(MessageSessionT):
quote = False
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True,
callback=None) -> FinishedSession:
msg = []
"""
if quote and self.target.target_from == 'QQ|Group' and self.session.message:
@ -102,7 +104,7 @@ class MessageSession(MessageSessionT):
msg.append({
"type": "text",
"data": {
"text": x.text
"text": ('\n' if count != 0 else '') + x.text
}
})
elif isinstance(x, Image):
@ -122,7 +124,7 @@ class MessageSession(MessageSessionT):
self.locale.t("error.message.timeout")))
except aiocqhttp.exceptions.ActionFailed:
message_chain.insert(0, Plain(self.locale.t("error.message.limited.msg2img")))
msg2img = MessageSegment.image(Path(await msgchain2image(self, message_chain)).as_uri())
msg2img = MessageSegment.image(Path(await msgchain2image(message_chain, self)).as_uri())
try:
send = await bot.send_group_msg(group_id=int(self.session.target), message=msg2img)
except aiocqhttp.exceptions.ActionFailed as e:
@ -143,6 +145,8 @@ class MessageSession(MessageSessionT):
return FinishedSession(self, 0, [{}])
else:
raise e
if callback:
MessageTaskManager.add_callback(send['message_id'], callback)
return FinishedSession(self, send['message_id'], [send])
async def check_native_permission(self):

View file

@ -9,7 +9,7 @@ import nio
from bots.matrix.client import bot, homeserver_host
from bots.matrix.info import client_name
from config import Config
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage
from core.builtins import Bot, Plain, Image, Voice, MessageSession as MessageSessionT, ErrorMessage, MessageTaskManager
from core.builtins.message.chain import MessageChain
from core.logger import Logger
from core.types import FetchTarget as FetchedTargetT, \
@ -43,7 +43,8 @@ class MessageSession(MessageSessionT):
wait = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True,
callback=None) -> FinishedSession:
message_chain = MessageChain(message_chain)
if not message_chain.is_safe and not disable_secret_check:
return await self.send_message(Plain(ErrorMessage(self.locale.t("error.message.chain.unsafe"))))
@ -154,7 +155,9 @@ class MessageSession(MessageSessionT):
Logger.error(f"Error in sending message: {str(resp)}")
else:
send.append(resp)
if callback:
for x in send:
MessageTaskManager.add_callback(x.event_id, callback)
return FinishedSession(self, [resp.event_id for resp in send], self.session.target)
async def check_native_permission(self):

View file

@ -144,10 +144,13 @@ class MessageSession(MessageSessionT):
checkPermission = check_permission
checkSuperUser = check_super_user
def ts2strftime(self, timestamp: float, date=True, time=True, seconds=True, timezone=True):
def ts2strftime(self, timestamp: float, date=True, iso=False, time=True, seconds=True, timezone=True):
ftime_template = []
if date:
ftime_template.append(self.locale.t("time.date.format"))
if iso:
ftime_template.append(self.locale.t("time.date.iso.format"))
else:
ftime_template.append(self.locale.t("time.date.format"))
if time:
if seconds:
ftime_template.append(self.locale.t("time.time.format"))
@ -155,7 +158,7 @@ class MessageSession(MessageSessionT):
ftime_template.append(self.locale.t("time.time.nosec.format"))
if timezone:
if self._tz_offset == "+0":
ftime_template.append(f"(UTC)")
ftime_template.append("(UTC)")
else:
ftime_template.append(f"(UTC{self._tz_offset})")
return (datetime.utcfromtimestamp(timestamp) + self.timezone_offset).strftime(' '.join(ftime_template))

View file

@ -5,7 +5,7 @@ from urllib.parse import urlparse
import ujson as json
from core.builtins.message.internal import Plain, Image, Voice, Embed, Url, ErrorMessage, FormattedTime
from core.builtins.message.internal import Plain, Image, Voice, Embed, Url, ErrorMessage, FormattedTime, I18NText
from core.builtins.utils import Secret
from core.logger import Logger
from core.types.message import MessageChain as MessageChainT, MessageSession
@ -51,6 +51,13 @@ class MessageChain(MessageChainT):
e['data']['timestamp'],
e['data']['color'], Image(e['data']['image']), Image(e['data']['thumbnail']),
e['data']['author'], e['data']['footer'], e['data']['fields']))
elif e['type'] == 'url':
self.value.append(Url(e['data']['url']))
elif e['type'] == 'formatted_time':
self.value.append(FormattedTime(e['data']['time'], e['data']['date'], e['data']['seconds'],
e['data']['timezone']))
elif e['type'] == 'i18n':
self.value.append(I18NText(e['data']['key'], **e['data']['kwargs']))
elif isinstance(e, str):
if e != '':
self.value += match_kecode(e)
@ -124,6 +131,8 @@ class MessageChain(MessageChainT):
value.append(Plain(ErrorMessage('{error.message.chain.plain.empty}', locale=locale)))
elif isinstance(x, FormattedTime):
value.append(Plain(x.to_str(msg=msg)))
elif isinstance(x, I18NText):
value.append(Plain(msg.locale.t(x.key, **x.kwargs)))
else:
value.append(x)
if not value:

View file

@ -93,7 +93,23 @@ class FormattedTime:
return f'FormattedTime(time={self.timestamp})'
def to_dict(self):
return {'type': 'time', 'data': {'time': self.timestamp}}
return {'type': 'formatted_time', 'data': {'time': self.timestamp, 'date': self.date, 'seconds': self.seconds,
'timezone': self.timezone}}
class I18NText:
def __init__(self, key, **kwargs):
self.key = key
self.kwargs = kwargs
def __str__(self):
return self.key
def __repr__(self):
return f'I18NText(key="{self.key}", kwargs={self.kwargs})'
def to_dict(self):
return {'type': 'i18n', 'data': {'key': self.key, 'kwargs': self.kwargs}}
class ErrorMessage(EMsg):
@ -269,4 +285,4 @@ class Embed(EmbedT):
'fields': self.fields}}
__all__ = ["Plain", "Image", "Voice", "Embed", "EmbedField", "Url", "ErrorMessage", "FormattedTime"]
__all__ = ["Plain", "Image", "Voice", "Embed", "EmbedField", "Url", "ErrorMessage", "FormattedTime", "I18NText"]

View file

@ -6,6 +6,7 @@ from core.types import MessageSession
class MessageTaskManager:
_list = {}
_callback_list = {}
@classmethod
def add_task(cls, session: MessageSession, flag, all_=False, reply=None):
@ -22,6 +23,10 @@ class MessageTaskManager:
'flag': flag, 'active': True, 'type': task_type, 'reply': reply, 'ts': datetime.now().timestamp()}
Logger.debug(cls._list)
@classmethod
def add_callback(cls, message_id, callback):
cls._callback_list[message_id] = {'callback': callback, 'ts': datetime.now().timestamp()}
@classmethod
def get_result(cls, session: MessageSession):
if 'result' in cls._list[session.target.target_id][session.target.sender_id][session]:
@ -42,6 +47,9 @@ class MessageTaskManager:
if datetime.now().timestamp() - cls._list[target][sender][session]['ts'] > 3600:
cls._list[target][sender][session]['active'] = False
cls._list[target][sender][session]['flag'].set() # no result = cancel
for message_id in cls._callback_list:
if datetime.now().timestamp() - cls._callback_list[message_id]['ts'] > 3600:
del cls._callback_list[message_id]
@classmethod
async def check(cls, session: MessageSession):
@ -72,6 +80,8 @@ class MessageTaskManager:
get_['result'] = session
get_['active'] = False
get_['flag'].set()
if session.target.reply_id in cls._callback_list:
await cls._callback_list[session.target.reply_id]['callback'](session)
__all__ = ['MessageTaskManager']

View file

@ -30,7 +30,7 @@ class MessageSession(MessageSessionT):
wait = True
async def send_message(self, message_chain, quote=True, disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True, callback=None) -> FinishedSession:
message_chain = MessageChain(message_chain)
self.sent.append(message_chain)
msg_list = []
@ -44,7 +44,7 @@ class MessageSession(MessageSessionT):
img = Image.open(image_path)
img.show()
Logger.info(f'[Bot] -> [{self.target.target_id}]: Image: {image_path}')
return FinishedSession(self, [0], ['There should be a callable here... hmm...'])
return FinishedSession(self, [0], ['Should be a callable here... hmm...'])
async def wait_confirm(self, message_chain=None, quote=True, delete=True):
send = None

View file

@ -1,5 +1,5 @@
import asyncio
from typing import List, Union, Dict
from typing import List, Union, Dict, Coroutine
from core.exceptions import FinishedException
from .chain import MessageChain
@ -89,13 +89,15 @@ class MessageSession:
message_chain,
quote=True,
disable_secret_check=False,
allow_split_image=True) -> FinishedSession:
allow_split_image=True,
callback: Coroutine = None) -> FinishedSession:
"""
用于向消息发送者回复消息
:param message_chain: 消息链若传入str则自动创建一条带有Plain元素的消息链
:param quote: 是否引用传入dict中的消息默认为True
:param disable_secret_check: 是否禁用消息检查默认为False
:param allow_split_image: 是否允许拆分图片发送此参数作接口兼容用仅telegram平台使用了切割
:param callback: 回调函数用于在消息发送完成后回复本消息执行的函数
:return: 被发送的消息链
"""
raise NotImplementedError
@ -104,32 +106,36 @@ class MessageSession:
message_chain=None,
quote=True,
disable_secret_check=False,
allow_split_image=True):
allow_split_image=True,
callback: Coroutine = None):
"""
用于向消息发送者回复消息并终结会话模块后续代码不再执行
:param message_chain: 消息链若传入str则自动创建一条带有Plain元素的消息链
:param quote: 是否引用传入dict中的消息默认为True
:param disable_secret_check: 是否禁用消息检查默认为False
:param allow_split_image: 是否允许拆分图片发送此参数作接口兼容用仅telegram平台使用了切割
:param callback: 回调函数用于在消息发送完成后回复本消息执行的函数
:return: 被发送的消息链
"""
...
f = None
if message_chain is not None:
f = await self.send_message(message_chain, disable_secret_check=disable_secret_check, quote=quote,
allow_split_image=allow_split_image)
allow_split_image=allow_split_image, callback=callback)
raise FinishedException(f)
async def send_direct_message(self, message_chain, disable_secret_check=False, allow_split_image=True):
async def send_direct_message(self, message_chain, disable_secret_check=False, allow_split_image=True,
callback: Coroutine = None):
"""
用于向消息发送者直接发送消息
:param message_chain: 消息链若传入str则自动创建一条带有Plain元素的消息链
:param disable_secret_check: 是否禁用消息检查默认为False
:param allow_split_image: 是否允许拆分图片发送此参数作接口兼容用仅Telegram平台使用了切割
:param callback: 回调函数用于在消息发送完成后回复本消息执行的函数
:return: 被发送的消息链
"""
await self.send_message(message_chain, disable_secret_check=disable_secret_check, quote=False,
allow_split_image=allow_split_image)
allow_split_image=allow_split_image, callback=callback)
async def wait_confirm(self, message_chain=None, quote=True, delete=True, timeout=120, append_instruction=True):
"""
@ -142,7 +148,8 @@ class MessageSession:
"""
raise NotImplementedError
async def wait_next_message(self, message_chain=None, quote=True, delete=False, timeout=120, append_instruction=True):
async def wait_next_message(self, message_chain=None, quote=True, delete=False, timeout=120,
append_instruction=True):
"""
一次性模板用于等待对象的下一条消息
:param message_chain: 需要发送的确认消息可不填
@ -153,7 +160,8 @@ class MessageSession:
"""
raise NotImplementedError
async def wait_reply(self, message_chain, quote=True, delete=False, timeout=120, all_=False, append_instruction=True):
async def wait_reply(self, message_chain, quote=True, delete=False, timeout=120, all_=False,
append_instruction=True):
"""
一次性模板用于等待触发对象回复消息
:param message_chain: 需要发送的确认消息可不填

View file

@ -35,6 +35,7 @@
"game.message.stop.none": "This game is not in progress.",
"i18n.prompt.fallback.failed": "(If you're seeing this strange string, it means something we've messed up!\nPlease send the issue back to\n${url}\nso that we can fix it in time.)",
"language": "English",
"message.brackets": " (${msg})",
"message.collapse": "...show only the first ${amount} items.",
"message.cooldown": "${time} second(s) have passed since the last execution. The cooldown time of this command are ${cd_time} second(s).",
"message.delimiter": ", ",
@ -60,6 +61,7 @@
"petal.message.lost.success": "You lost ${amount} petal(s).",
"success": "Success.",
"time.date.format": "%B %d, %Y",
"time.date.iso.format": "%Y-%m-%d",
"time.time.format": "%H:%M:%S",
"time.time.nosec.format": "%H:%M",
"tos.reason": "Reason: ",

View file

@ -35,13 +35,14 @@
"game.message.stop.none": "当前此游戏未在进行。",
"i18n.prompt.fallback.failed": "(如果你看到了这条奇怪的字符串,说明我们又搞错了什么东西!\n请将问题反馈至\n${url}\n以便我们快速解决此问题。",
"language": "简体中文",
"message.brackets": "${msg}",
"message.collapse": "……仅显示前 ${amount} 条内容。",
"message.cooldown": "距离上次执行已过去 ${time} 秒,本命令的冷却时间为 ${cd_time} 秒。",
"message.delimiter": "、",
"message.end": "。",
"message.reply.prompt": "(请使用指定的词语回复本条消息)",
"message.wait.confirm.prompt.type1": "(发送“是”或符合确认条件的词语来确认)",
"message.wait.confirm.prompt.type2": "(发送符合条件的词语来确认)",
"message.collapse": "……仅显示前 ${amount} 条内容。",
"no": "否",
"none": "无",
"parser.admin.module.permission.denied": "“${module}”模块下的命令仅能被该群组的管理员所使用,请联系管理员执行此命令。",
@ -60,6 +61,7 @@
"petal.message.lost.success": "失去了 ${amount} 片花瓣。",
"success": "成功。",
"time.date.format": "%Y 年 %m 月 %d 日",
"time.date.iso.format": "%Y-%m-%d",
"time.time.format": "%H:%M:%S",
"time.time.nosec.format": "%H:%M",
"tos.reason": "具体原因:",
@ -74,4 +76,4 @@
"tos.warning.last": "这是最后一次警告。",
"unknown": "未知",
"yes": "是"
}
}

View file

@ -35,6 +35,7 @@
"game.message.stop.none": "目前此遊戲沒有在進行。",
"i18n.prompt.fallback.failed": "(如果你看到了這條奇怪的字串,說明我們又搞錯了什麼!\n請將問題回報至\n${url}\n以便我們快速解決此問題。",
"language": "繁體中文",
"message.brackets": "${msg}",
"message.collapse": "……僅顯示前 ${amount} 條內容。",
"message.cooldown": "距上次執行已過去 ${time} 秒,此指令的冷卻時間為 ${cd_time} 秒。",
"message.delimiter": "、",
@ -59,7 +60,8 @@
"petal.message.lost.limit": "(本日失去花瓣已達到每日上限。)",
"petal.message.lost.success": "失去了 ${amount} 片花瓣。",
"success": "成功。",
"time.date.format": "%Y年%m月%d日",
"time.date.format": "%Y 年 %m 月 %d 日",
"time.date.iso.format": "%Y-%m-%d",
"time.time.format": "%H:%M:%S",
"time.time.nosec.format": "%H:%M",
"tos.reason": "原因:",

View file

@ -1,6 +1,6 @@
from datetime import datetime
from core.builtins import Bot, Image, Plain
from core.builtins import Bot, Image, Plain, Url
from core.utils.http import get_url
@ -16,16 +16,13 @@ async def get_info(msg: Bot.MessageSession, url, get_detail):
stat = view['stat']
pic = view['pic']
video_url = f"https://www.bilibili.com/video/{view['bvid']}\n"
video_url = f"https://www.bilibili.com/video/{view['bvid']}"
title = view['title']
tname = view['tname']
timestamp = view['ctime']
timeobject = datetime.fromtimestamp(timestamp)
time = timeobject.strftime('%Y-%m-%d %H:%M:%S')
time = msg.ts2strftime(view['ctime'], iso=True, timezone=False)
if len(view['pages']) > 1:
pages = f" ({len(view['pages'])}P)"
pages = msg.locale.t("message.brackets", msg=f"{len(view['pages'])}P")
else:
pages = ''
@ -41,15 +38,15 @@ async def get_info(msg: Bot.MessageSession, url, get_detail):
fans = format_num(res['data']['Card']['card']['fans'])
if not get_detail:
output = video_url + msg.locale.t("bilibili.message", title=title, tname=tname, owner=owner, time=time)
output = msg.locale.t("bilibili.message", title=title, tname=tname, owner=owner, time=time)
else:
output = video_url + msg.locale.t("bilibili.message.detail", title=title, pages=pages, tname=tname,
output = msg.locale.t("bilibili.message.detail", title=title, pages=pages, tname=tname,
owner=owner, fans=fans, view=stat_view, danmaku=stat_danmaku,
reply=stat_reply,
like=stat_like, coin=stat_coin, favorite=stat_favorite, share=stat_share,
time=time)
await msg.finish([Image(pic), Plain(output)])
await msg.finish([Image(pic), Url(video_url), Plain(output)])
def format_num(number):

View file

@ -6,8 +6,8 @@
"bilibili.help.regex.bv": "发送 BV 号获取视频信息。",
"bilibili.help.regex.shorturl": "发送 b23.tv 短连接获取视频信息。",
"bilibili.help.regex.url": "发送 URL 获取视频信息。",
"bilibili.message": "标题:${title}\n类型${tname}\nUP 主:${owner}\n日期${time}",
"bilibili.message.detail": "标题:${title}${pages} | 类型:${tname}\nUP 主:${owner} | 粉丝:${fans}\n观看${view} | 弹幕:${danmaku} | 评论:${reply}\n喜欢${like} | 投币:${coin} | 收藏:${favorite} | 分享:${share}\n日期${time}",
"bilibili.message": "标题:${title}\n类型${tname}\nUP主:${owner}\n日期${time}",
"bilibili.message.detail": "标题:${title}${pages} | 类型:${tname}\nUP主:${owner} | 粉丝:${fans}\n观看${view} | 弹幕:${danmaku} | 评论:${reply}\n喜欢${like} | 投币:${coin} | 收藏:${favorite} | 分享:${share}\n日期${time}",
"bilibili.message.error.invalid": "发生错误:视频编号无效,请检查输入。",
"bilibili.message.not_found": "未找到对应的视频。"
}

View file

@ -6,7 +6,7 @@
"bilibili.help.regex.bv": "傳送 BV 號取得影片資訊。",
"bilibili.help.regex.shorturl": "傳送 b23.tv 短網址取得影片資訊。",
"bilibili.help.regex.url": "傳送 URL 取得影片資訊。",
"bilibili.message": "標題:${title}\n類型${tname}\nUP 主:${owner}\n日期${time}",
"bilibili.message": "標題:${title}\n類型${tname}\nUP主:${owner}\n日期${time}",
"bilibili.message.detail": "標題:${title}${pages} | 類型:${tname}\nUP 主:${owner} | 追隨者:${fans}\n觀看${view} | 彈幕:${danmaku} | 留言:${reply}\n喜歡${like} | 投幣:${coin} | 收藏:${favorite} | 分享:${share}\n日期${time}",
"bilibili.message.error.invalid": "發生錯誤:影片編號無效,請校對輸入。",
"bilibili.message.not_found": "未找到對應的影片。"

View file

@ -26,6 +26,6 @@
"calc.help.option.str": "转换为字符串str(1) -> \"1\"",
"calc.help.option.xor": "Bitwise xor: 1 ^ 1 -> 0",
"calc.message.invalid": "Invalid expression: ${expr}",
"calc.message.running_time": "Calculating time: ${time} ms / 10000 ms. ",
"calc.message.running_time": "Calculating time: ${time}ms / 10000ms. ",
"calc.message.time_out": "Calculation timeout."
}

View file

@ -26,6 +26,6 @@
"calc.help.option.str": "转换为字符串str(1) -> \"1\"",
"calc.help.option.xor": "按位异或1 ^ 1 -> 0",
"calc.message.invalid": "表达式无效:${expr}",
"calc.message.running_time": "计算花费时间:${time} ms / 10000 ms。",
"calc.message.running_time": "计算花费时间:${time}ms / 10000ms。",
"calc.message.time_out": "计算超时。"
}

View file

@ -26,6 +26,6 @@
"calc.help.option.str": "轉換為字串str(1) -> \"1\"",
"calc.help.option.xor": "按位元互斥或1 ^ 1 -> 0",
"calc.message.invalid": "運算式無效:${expr}",
"calc.message.running_time": "計算耗費時間:${time} ms / 10000 ms。",
"calc.message.running_time": "計算耗費時間:${time}ms / 10000ms。",
"calc.message.time_out": "計算逾時。"
}

View file

@ -24,7 +24,7 @@ async def _(msg: Bot.MessageSession):
elif 'r30' in msg.parsed_msg:
query = 'r30'
else:
raise
return
pat = msg.parsed_msg.get('<UserID>', False)
if pat:
query_id = pat
@ -39,7 +39,7 @@ async def _(msg: Bot.MessageSession):
qc = CoolDown('cytoid_rank', msg)
c = qc.check(150)
if c == 0:
img = await get_rating(query_id, query, msg)
img = await get_rating(msg, query_id, query)
if 'path' in img:
await msg.send_message([Image(path=img['path'])], allow_split_image=False)
if 'text' in img:

View file

@ -6,6 +6,7 @@
"cytoid.help.r30": "查询 Cytoid 用户的 R30 列表。",
"cytoid.help.unbind": "解绑用户。",
"cytoid.message.b30.cooldown": "(据官方人员所述,此 API 的调用十分昂贵,故手动做出此限制,请谅解。)",
"cytoid.message.b30.level": "等级",
"cytoid.message.bind.failed": "绑定失败,请检查输入。",
"cytoid.message.bind.success": "绑定成功:",
"cytoid.message.unbind.success": "解绑成功。",

View file

@ -20,7 +20,7 @@ from core.utils.http import get_url
from core.utils.html2text import html2text
async def get_rating(uid, query_type, msg: Bot.MessageSession):
async def get_rating(msg: Bot.MessageSession, uid, query_type):
try:
if query_type == 'b30':
query_type = 'bestRecords'
@ -88,7 +88,7 @@ async def get_rating(uid, query_type, msg: Bot.MessageSession):
resources = []
songcards = []
async def mkresources(x, rank):
async def mkresources(msg: Bot.MessageSession, x, rank):
thumbpath = await download_cover_thumb(x['chart']['level']['uid'])
chart_type = x['chart']['type']
difficulty = x['chart']['difficulty']
@ -98,7 +98,7 @@ async def get_rating(uid, query_type, msg: Bot.MessageSession):
rt = x['rating']
details = x['details']
_date = datetime.strptime(x['date'], "%Y-%m-%dT%H:%M:%S.%fZ")
local_time = _date + timedelta(hours=int(Config("timezone_offset", 8)))
local_time = _date + timedelta(hours=int(msg.options.get('timezone_offset', Config('timezone_offset', '+8'))))
playtime = local_time.timestamp()
nowtime = time.time()
playtime = playtime - nowtime
@ -125,7 +125,7 @@ async def get_rating(uid, query_type, msg: Bot.MessageSession):
for x in best_records:
rank += 1
resources.append(mkresources(x, rank))
resources.append(mkresources(msg, x, rank))
await asyncio.gather(*resources)
cards_ = await asyncio.gather(*songcards)

View file

@ -1,5 +1,5 @@
{
"langconv.help": "简繁转换。",
"langconv.message.unsupported_language": "不支持此语言。支持的语言zh_cn、zh_tw、zh_hk",
"langconv.message.running_time": "花费时间:${time} ms。"
"langconv.message.running_time": "花费时间:${time}ms。"
}

View file

@ -1,5 +1,5 @@
{
"langconv.help": "简繁转换。",
"langconv.message.unsupported_language": "不支持此语言。支持的语言zh_cn、zh_tw、zh_hk",
"langconv.message.running_time": "花费时间:${time} ms。"
"langconv.message.running_time": "花费时间:${time}ms。"
}

View file

@ -1,5 +1,5 @@
{
"langconv.help": "繁簡轉換。",
"langconv.message.unsupported_language": "不支援此語言。已支援的語言zh_cn、zh_tw、zh_hk",
"langconv.message.running_time": "花費時間:${time} ms。"
"langconv.message.running_time": "花費時間:${time}ms。"
}

View file

@ -14,6 +14,6 @@
"mcv.message.mclgv": "The latest version: ${version}\n(The data from Mojira may be earlier than the official release. Information is for reference purposes only).",
"mcv.message.mcv": "The latest version in the launcher is: \n${launcher_ver}\nThe latest version recorded on Mojira is: \n${jira_ver}\n(The latest version in the launcher shall prevail, Mojira is only for previewing the version)",
"mcv.message.mcv.jira.failed": "Failed to get Mojira information.",
"mcv.message.mcv.launcher": "The latest release: ${release}, the latest snapshot: ${snapshot},",
"mcv.message.mcv.launcher": "The latest release: ${release}\nRelease time: ${release_time}\nThe latest snapshot: ${snapshot}\nRelease time: ${snapshot_time}",
"mcv.message.mcv.launcher.failed": "Failed to get manifest.json."
}
}

View file

@ -14,6 +14,6 @@
"mcv.message.mclgv": "最新版:${version}\n資訊來源於 Mojira可能會比官方發布要早一段時間。資訊僅供參考。",
"mcv.message.mcv": "目前啟動器內最新版本為:\n${launcher_ver}\nMojira 上所記錄最新版本為:\n${jira_ver}\n以啟動器內最新版本為準Mojira 僅作版本號預覽用)",
"mcv.message.mcv.jira.failed": "取得 Mojira 資訊失敗。",
"mcv.message.mcv.launcher": "最新版:${release},最新快照:${snapshot}",
"mcv.message.mcv.launcher": "最新版:${release}\n發佈於${release_time}\n最新快照${snapshot}\n發佈於${snapshot_time}\n",
"mcv.message.mcv.launcher.failed": "取得 manifest.json 失敗。"
}
}

View file

@ -13,4 +13,4 @@
"mcv_rss.message.mcv_jira_rss.future": "Java Edition ${version} is added to Mojira.\n(“Future Version” only indicates that a new version is planned; you will have to wait for Mojang to release it in the Launcher.)",
"mcv_rss.message.mcv_rss.release": "${version} is now released in Minecraft Launcher.",
"mcv_rss.message.mcv_rss.snapshot": "Snapshot ${version} is now released in Minecraft Launcher."
}
}

View file

@ -11,6 +11,6 @@
"mcv_rss.message.mclgv_jira_rss": "Mojira 已更新 Minecraft Legends ${version}。\nMojira 上的信息仅作版本号预览用,不代表启动器/商店已更新此版本)",
"mcv_rss.message.mcv_jira_rss": "Mojira 已更新 Java 版 ${version}。\nMojira 上的信息仅作版本号预览用,不代表启动器已更新此版本)",
"mcv_rss.message.mcv_jira_rss.future": "Mojira 已新增 Java 版 ${version}。\nFuture Version 仅代表与此相关的版本正在规划中,不代表启动器已更新此版本)",
"mcv_rss.message.mcv_rss.release": "启动器已更新 ${version} 正式版。",
"mcv_rss.message.mcv_rss.snapshot": "启动器已更新 ${version} 快照。"
}
"mcv_rss.message.mcv_rss.release": "启动器已更新 ${version} 正式版。\n更新时间",
"mcv_rss.message.mcv_rss.snapshot": "启动器已更新 ${version} 快照。\n更新时间"
}

View file

@ -2,7 +2,7 @@
"mcv_rss.help.mcbv_jira_rss.desc": "啟用後 Mojira 更新基岩版時會自動推播訊息。",
"mcv_rss.help.mcbv_rss.desc": "啟用後商店更新 Minecraft 基岩版時會自動推播訊息。",
"mcv_rss.help.mcdv_jira_rss.desc": "啟用後 Mojira 更新 Minecraft Dungeons 時會自動推播訊息。",
"mcv_rss.help.mclgv_jira_rss.desc": "开启后 Mojira 更新 Minecraft Legends 时会自动推送消息。",
"mcv_rss.help.mclgv_jira_rss.desc": "啟用後 Mojira 更新 Minecraft Legends 時會自動推播訊息。",
"mcv_rss.help.mcv_jira_rss.desc": "啟用後 Mojira 更新 Java 版時會自動推播訊息。",
"mcv_rss.help.mcv_rss.desc": "啟用後 Minecraft 啟動器更新 MinecraftJava 版時會自動推播訊息。",
"mcv_rss.message.mcbv_jira_rss": "Mojira 已更新基岩版 ${version}。 \nMojira 上的資訊僅作版本號預覽用,不代表啟動器已更新此版本)",
@ -11,6 +11,6 @@
"mcv_rss.message.mclgv_jira_rss": "Mojira 已更新 Minecraft Legends ${version}。 \nMojira 上的資訊僅作版本號預覽用,不代表啟動器/商店已更新此版本)",
"mcv_rss.message.mcv_jira_rss": "Mojira 已更新 Java 版 ${version}。 \nMojira 上的資訊僅作版本號預覽用,不代表啟動器已更新此版本)",
"mcv_rss.message.mcv_jira_rss.future": "Mojira 已新增 Java 版 ${version}。 \nFuture Version 僅代表與此相關的版本正在規劃中,不代表啟動器已更新此版本)",
"mcv_rss.message.mcv_rss.release": "啟動器已更新 ${version} 正式版。",
"mcv_rss.message.mcv_rss.snapshot": "啟動器已更新 ${version} 快照。"
}
"mcv_rss.message.mcv_rss.release": "啟動器已更新 ${version} 正式版。\n更新時間",
"mcv_rss.message.mcv_rss.snapshot": "啟動器已更新 ${version} 快照。\n更新時間"
}

View file

@ -1,15 +1,18 @@
{
"ncmusic.help.desc": "网易云音乐相关工具。",
"ncmusic.help.info": "获取音乐详细信息。",
"ncmusic.help.search": "搜索网易云音乐。",
"ncmusic.help.search.legacy": "搜索网易云音乐。(旧版)",
"ncmusic.help.info": "获取音乐详细信息。",
"ncmusic.message.info": "歌名:${name}${id}\n歌手${artists}\n专辑名${album}${album_id}",
"ncmusic.message.info": "歌名:${name}${id}\n专辑名${album}${album_id}\n歌手${artists}",
"ncmusic.message.info.not_found": "找不到对应的音乐。",
"ncmusic.message.search.confirm": "是否查看音乐详细信息?",
"ncmusic.message.search.invalid.non_digital": "无效的编号,必须为数字。",
"ncmusic.message.search.invalid.out_of_range": "编号超出范围。",
"ncmusic.message.search.not_found": "未找到结果。",
"ncmusic.message.search.prompt": "输入对应的序号以查看歌曲信息。",
"ncmusic.message.search.result": "搜索结果:",
"ncmusic.message.search.table.header.album": "专辑名",
"ncmusic.message.search.table.header.artists": "歌手",
"ncmusic.message.search.table.header.id": "序号",
"ncmusic.message.search.table.header.name": "歌名",
"ncmusic.message.search.result": "搜索结果:"
}
"ncmusic.message.search.table.header.name": "歌名"
}

View file

@ -1,8 +1,10 @@
{
"ncmusic.help.desc": "网易云音乐相关工具。",
"ncmusic.help.info": "取得音樂詳細資訊。",
"ncmusic.help.search": "搜尋網易雲音樂。",
"ncmusic.help.search.legacy": "搜尋網易雲音樂。(舊版)",
"ncmusic.message.info": "歌名:${name}${id}\n歌手${artists}\n專輯名${album}${album_id}",
"ncmusic.message.info.not_found": "找不到对应的音乐。",
"ncmusic.message.search.confirm": "是否檢視音樂詳細資訊?",
"ncmusic.message.search.invalid.non_digital": "無效的編號,必須為數字。",
"ncmusic.message.search.invalid.out_of_range": "編號超出範圍。",

View file

@ -8,109 +8,112 @@ from modules.wiki.utils.dbutils import Audit
from modules.wiki.utils.wikilib import WikiLib
if Config('enable_urlmanager'):
aud = module('wiki_audit', required_superuser=True,
alias='wau')
aud = module('wiki_audit', required_superuser=True,
alias='wau')
@aud.command(['trust <apiLink>', 'block <apiLink>'])
async def _(msg: Bot.MessageSession):
date = msg.ts2strftime(datetime.now().timestamp(), timezone=False)
api = msg.parsed_msg['<apiLink>']
check = await WikiLib(api).check_wiki_available()
if check.available:
api = check.value.api
if msg.parsed_msg.get('trust', False):
res = Audit(api).add_to_AllowList(date)
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.allowlist')
else:
res = Audit(api).add_to_BlockList(date)
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.blocklist')
if not res:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.add.failed', list_name=list_name) + api)
else:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.add.success', list_name=list_name) + api)
else:
result = msg.locale.t('wiki.message.error.add') + \
('\n' + msg.locale.t('wiki.message.error.info') + check.message if check.message != '' else '')
await msg.finish(result)
@aud.command(['distrust <apiLink>', 'unblock <apiLink>'])
async def _(msg: Bot.MessageSession):
api = msg.parsed_msg['<apiLink>'] # 已关闭的站点无法验证有效性
if msg.parsed_msg.get('distrust', False):
res = Audit(api).remove_from_AllowList()
if res is None:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.failed.other') + api)
@aud.command(['trust <apiLink>', 'block <apiLink>'])
async def _(msg: Bot.MessageSession):
date = msg.ts2strftime(datetime.now().timestamp(), timezone=False)
api = msg.parsed_msg['<apiLink>']
check = await WikiLib(api).check_wiki_available()
if check.available:
api = check.value.api
if msg.parsed_msg.get('trust', False):
res = Audit(api).add_to_AllowList(date)
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.allowlist')
else:
res = Audit(api).remove_from_BlockList()
res = Audit(api).add_to_BlockList(date)
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.blocklist')
if not res:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.failed', list_name=list_name) + api)
await msg.finish(msg.locale.t('wiki.message.wiki_audit.add.failed', list_name=list_name) + api)
else:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.success', list_name=list_name) + api)
await msg.finish(msg.locale.t('wiki.message.wiki_audit.add.success', list_name=list_name) + api)
else:
result = msg.locale.t('wiki.message.error.add') + \
('\n' + msg.locale.t('wiki.message.error.info') + check.message if check.message != '' else '')
await msg.finish(result)
@aud.command('query <apiLink>')
async def _(msg: Bot.MessageSession):
api = msg.parsed_msg['<apiLink>']
check = await WikiLib(api).check_wiki_available()
if check.available:
api = check.value.api
audit = Audit(api)
allow = audit.inAllowList
block = audit.inBlockList
msg_list = []
if allow:
msg_list.append(api + msg.locale.t('wiki.message.wiki_audit.query.allowlist'))
if block:
msg_list.append(api + msg.locale.t('wiki.message.wiki_audit.query.blocklist'))
if msg_list:
msg_list.append(msg.locale.t('wiki.message.wiki_audit.query.conflict'))
await msg.finish('\n'.join(msg_list))
else:
await msg.finish(api + msg.locale.t('wiki.message.wiki_audit.query.none'))
@aud.command(['distrust <apiLink>', 'unblock <apiLink>'])
async def _(msg: Bot.MessageSession):
api = msg.parsed_msg['<apiLink>'] # 已关闭的站点无法验证有效性
if msg.parsed_msg.get('distrust', False):
res = Audit(api).remove_from_AllowList()
if res is None:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.failed.other') + api)
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.allowlist')
else:
res = Audit(api).remove_from_BlockList()
list_name = msg.locale.t('wiki.message.wiki_audit.list_name.blocklist')
if not res:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.failed', list_name=list_name) + api)
else:
await msg.finish(msg.locale.t('wiki.message.wiki_audit.remove.success', list_name=list_name) + api)
@aud.command('query <apiLink>')
async def _(msg: Bot.MessageSession):
api = msg.parsed_msg['<apiLink>']
check = await WikiLib(api).check_wiki_available()
if check.available:
api = check.value.api
audit = Audit(api)
allow = audit.inAllowList
block = audit.inBlockList
msg_list = []
if allow:
msg_list.append(api + msg.locale.t('wiki.message.wiki_audit.query.allowlist'))
if block:
msg_list.append(api + msg.locale.t('wiki.message.wiki_audit.query.blocklist'))
if msg_list:
msg_list.append(msg.locale.t('wiki.message.wiki_audit.query.conflict'))
await msg.finish('\n'.join(msg_list))
else:
result = msg.locale.t('wiki.message.error.query') + \
('\n' + msg.locale.t('wiki.message.error.info') + check.message if check.message != '' else '')
await msg.finish(result)
await msg.finish(api + msg.locale.t('wiki.message.wiki_audit.query.none'))
else:
result = msg.locale.t('wiki.message.error.query') + \
('\n' + msg.locale.t('wiki.message.error.info') + check.message if check.message != '' else '')
await msg.finish(result)
@aud.command(['list', 'list legacy'])
async def _(msg: Bot.MessageSession):
allow_list = Audit.get_allow_list()
block_list = Audit.get_block_list()
legacy = True
if not msg.parsed_msg.get('legacy', False) and msg.Feature.image:
send_msgs = []
allow_columns = [[x[0], x[1]] for x in allow_list]
if allow_columns:
allow_table = ImageTable(data=allow_columns, headers=[
msg.locale.t('wiki.message.wiki_audit.list.table.header.apilink'),
msg.locale.t('wiki.message.wiki_audit.list.table.header.date')
])
if allow_table:
allow_image = await image_table_render(allow_table)
if allow_image:
send_msgs.append(Plain(msg.locale.t('wiki.message.wiki_audit.list.allowlist')))
send_msgs.append(Image(allow_image))
block_columns = [[x[0], x[1]] for x in block_list]
if block_columns:
block_table = ImageTable(data=block_columns, headers=[
msg.locale.t('wiki.message.wiki_audit.list.table.header.apilink'),
msg.locale.t('wiki.message.wiki_audit.list.table.header.date')
])
if block_table:
block_image = await image_table_render(block_table)
if block_image:
send_msgs.append(Plain(msg.locale.t('wiki.message.wiki_audit.list.blocklist')))
send_msgs.append(Image(block_image))
if send_msgs:
await msg.finish(send_msgs)
legacy = False
if legacy:
wikis = [msg.locale.t('wiki.message.wiki_audit.list.allowlist')]
for al in allow_list:
wikis.append(f'{al[0]} ({al[1]})')
wikis.append(msg.locale.t('wiki.message.wiki_audit.list.blocklist'))
for bl in block_list:
wikis.append(f'{bl[0]} ({bl[1]})')
await msg.finish('\n'.join(wikis))
@aud.command(['list', 'list legacy'])
async def _(msg: Bot.MessageSession):
allow_list = Audit.get_allow_list()
block_list = Audit.get_block_list()
legacy = True
if not msg.parsed_msg.get('legacy', False) and msg.Feature.image:
send_msgs = []
allow_columns = [[x[0], x[1]] for x in allow_list]
if allow_columns:
allow_table = ImageTable(data=allow_columns, headers=[
msg.locale.t('wiki.message.wiki_audit.list.table.header.apilink'),
msg.locale.t('wiki.message.wiki_audit.list.table.header.date')
])
if allow_table:
allow_image = await image_table_render(allow_table)
if allow_image:
send_msgs.append(Plain(msg.locale.t('wiki.message.wiki_audit.list.allowlist')))
send_msgs.append(Image(allow_image))
block_columns = [[x[0], x[1]] for x in block_list]
if block_columns:
block_table = ImageTable(data=block_columns, headers=[
msg.locale.t('wiki.message.wiki_audit.list.table.header.apilink'),
msg.locale.t('wiki.message.wiki_audit.list.table.header.date')
])
if block_table:
block_image = await image_table_render(block_table)
if block_image:
send_msgs.append(Plain(msg.locale.t('wiki.message.wiki_audit.list.blocklist')))
send_msgs.append(Image(block_image))
if send_msgs:
await msg.finish(send_msgs)
legacy = False
if legacy:
wikis = [msg.locale.t('wiki.message.wiki_audit.list.allowlist')]
for al in allow_list:
wikis.append(f'{al[0]} ({al[1]})')
wikis.append(msg.locale.t('wiki.message.wiki_audit.list.blocklist'))
for bl in block_list:
wikis.append(f'{bl[0]} ({bl[1]})')
await msg.finish('\n'.join(wikis))

View file

@ -9,6 +9,7 @@ from core.component import module
from core.dirty_check import check
from core.logger import Logger
from core.utils.http import download_to_cache
from core.utils.image_table import image_table_render, ImageTable
from modules.wiki.utils.dbutils import WikiTargetInfo
from modules.wiki.utils.screenshot_image import generate_screenshot_v1, generate_screenshot_v2
from modules.wiki.utils.wikilib import WikiLib
@ -20,7 +21,7 @@ wiki_inline = module('wiki_inline',
@wiki_inline.regex(re.compile(r'\[\[(.*?)]]', flags=re.I), mode='A',
desc="{wiki.help.wiki_inline.page}")
desc="{wiki.help.wiki_inline.page}")
async def _(msg: Bot.MessageSession):
query_list = []
for x in msg.matched_msg:
@ -31,7 +32,7 @@ async def _(msg: Bot.MessageSession):
@wiki_inline.regex(re.compile(r'\{\{(.*?)}}', flags=re.I), mode='A',
desc='{wiki.help.wiki_inline.template}')
desc='{wiki.help.wiki_inline.template}')
async def _(msg: Bot.MessageSession):
query_list = []
for x in msg.matched_msg:
@ -42,7 +43,7 @@ async def _(msg: Bot.MessageSession):
@wiki_inline.regex(re.compile(r'≺(.*?)≻|⧼(.*?)⧽', flags=re.I), mode='A', show_typing=False,
desc='{wiki.help.wiki_inline.mediawiki}')
desc='{wiki.help.wiki_inline.mediawiki}')
async def _(msg: Bot.MessageSession):
query_list = []
for x in msg.matched_msg:
@ -130,6 +131,27 @@ async def _(msg: Bot.MessageSession):
get_infobox = await generate_screenshot_v1(q[qq].realurl, qq, headers)
if get_infobox:
await msg.send_message(Image(get_infobox), quote=False)
if get_page.invalid_section and wiki_.wiki_info.in_allowlist:
i_msg_lst = []
session_data = [[str(i + 1), get_page.sections[i]] for i in
range(len(get_page.sections))]
i_msg_lst.append(Plain(msg.locale.t('wiki.message.invalid_section')))
i_msg_lst.append(Image(await
image_table_render(
ImageTable(session_data,
['ID',
msg.locale.t('wiki.message.section')]))))
async def _callback(msg: Bot.MessageSession):
display = msg.as_display(text_only=True)
if display.isdigit():
display = int(display)
if display <= len(get_page.sections):
get_page.selected_section = display - 1
await query_pages(msg, title=get_page.title + '#' +
get_page.sections[display - 1])
await msg.send_message(i_msg_lst, callback=_callback)
if len(query_list) == 1 and img_send:
return
if msg.Feature.image:

View file

@ -29,6 +29,8 @@
"wiki.help.wiki_inline.page": "Enter a title within [[ ]] to automatically query the page.",
"wiki.help.wiki_inline.template": "Enter a title within {{ }} to automatically query the template.",
"wiki.help.wiki_inline.url": "Send the URL of the wiki page to generate the Infobox image.",
"wiki.message.section": "章节",
"wiki.message.section.rendering": "(章节渲染中)",
"wiki.message.ab.qq.title": "滥用过滤器日志",
"wiki.message.ab.qq.title.address": "滥用过滤器日志地址",
"wiki.message.ab.slice": "•${title} - ${user} at ${time}\n Filter description: ${filter_name}\n Actions taken: ${result}",
@ -37,6 +39,7 @@
"wiki.message.error.info": "Detail: ",
"wiki.message.error.query": "An error occurred: Unable to query this wiki.",
"wiki.message.error.set": "An error occurred: Unable to set up this wiki.",
"wiki.message.error.unable_to_render_section": "(章节渲染失败,请联系开发者检查原因)",
"wiki.message.fandom.disable": "Disabled to use Fandom global Interwiki queries.",
"wiki.message.fandom.enable": "Enabled to use Fandom global Interwiki queries.",
"wiki.message.flies": "This page includes the following files:",
@ -47,6 +50,8 @@
"wiki.message.id.error": "An error occurred: Page ID must be numeric.",
"wiki.message.id.not_found": "Page with page ID ${id} not found.",
"wiki.message.invalid_namespace": "There is no namespace named ${namespace} on this wiki. Please check your input.",
"wiki.message.invalid_section": "此章节不存在,以下是可能的章节(回复对应序号以选中):",
"wiki.message.invalid_section.prompt": "(此章节不存在)",
"wiki.message.iw.add.success": "Custom Interwiki added:\n ${iw} -> ${name}",
"wiki.message.iw.get.not_found": "Interwiki not found: ${iw}",
"wiki.message.iw.list": "Use \"${prefix}wiki iw get <Interwiki>\" to get the corresponding link to Interwiki.",

View file

@ -29,6 +29,8 @@
"wiki.help.wiki_inline.page": "在 [[ ]] 内输入标题以自动查询页面。",
"wiki.help.wiki_inline.template": "在 {{ }} 内输入标题以自动查询模板。",
"wiki.help.wiki_inline.url": "发送 Wiki 页面的 URL 以生成 Infobox 图片。",
"wiki.message.section": "章节",
"wiki.message.section.rendering": "(章节渲染中)",
"wiki.message.ab.qq.title": "滥用过滤器日志",
"wiki.message.ab.qq.title.address": "滥用过滤器日志地址",
"wiki.message.ab.slice": "•${title} - ${user} 于 ${time}\n 过滤器描述:${filter_name}\n 采取的行动:${result}",
@ -37,6 +39,7 @@
"wiki.message.error.info": "详细信息:",
"wiki.message.error.query": "发生错误:无法查询此 Wiki。",
"wiki.message.error.set": "发生错误:无法设置此 Wiki。",
"wiki.message.error.unable_to_render_section": "(章节渲染失败,请联系开发者检查原因)",
"wiki.message.fandom.disable": "已关闭 Fandom 全局 Interwiki 查询。",
"wiki.message.fandom.enable": "已开启 Fandom 全局 Interwiki 查询。",
"wiki.message.flies": "此页面包括以下文件:\n",
@ -47,6 +50,8 @@
"wiki.message.id.error": "发生错误:页面 ID 必须为数字。",
"wiki.message.id.not_found": "未找到页面 ID 为 ${id} 的页面。",
"wiki.message.invalid_namespace": "此 Wiki 上没有名为 ${namespace} 的命名空间,请检查输入。",
"wiki.message.invalid_section": "此章节不存在,以下是可能的章节(回复对应序号以选中):",
"wiki.message.invalid_section.prompt": "(此章节不存在)",
"wiki.message.iw.add.success": "已添加自定义 Interwiki\n${iw} -> ${name}",
"wiki.message.iw.get.not_found": "未找到 Interwiki${iw}",
"wiki.message.iw.list": "使用“${prefix}wiki iw get <Interwiki>”可以获取 Interwiki 对应的链接。",

View file

@ -29,6 +29,8 @@
"wiki.help.wiki_inline.page": "在 [[ ]] 內輸入標題以自動查詢頁面。",
"wiki.help.wiki_inline.template": "在 {{ }} 內輸入標題以自動查詢模板。",
"wiki.help.wiki_inline.url": "傳送 Wiki 頁面的 URL 以生成 Infobox 圖片。",
"wiki.message.section": "章節",
"wiki.message.section.rendering": "(章節成像中)",
"wiki.message.ab.qq.title": "防濫用過濾器日誌",
"wiki.message.ab.qq.title.address": "防濫用過濾器位址",
"wiki.message.ab.slice": "•${title} - ${user} 於 ${time}\n 過濾器描述:${filter_name}\n 採取的動作:${result}",
@ -37,6 +39,7 @@
"wiki.message.error.info": "詳細訊息:",
"wiki.message.error.query": "發生錯誤:無法查詢此 Wiki。",
"wiki.message.error.set": "發生錯誤:無法設定此 Wiki。",
"wiki.message.error.unable_to_render_section": "(章節成像失敗,請聯絡開發人員檢查原因)",
"wiki.message.fandom.disable": "已停用 Fandom 全域 Interwiki 查詢。",
"wiki.message.fandom.enable": "已啟用 Fandom 全域 Interwiki 查詢。",
"wiki.message.flies": "此頁面含有以下檔案:",
@ -47,6 +50,8 @@
"wiki.message.id.error": "發生錯誤:頁面 ID 必須為數字。",
"wiki.message.id.not_found": "未找到頁面 ID 為 ${id} 的頁面。",
"wiki.message.invalid_namespace": "此 Wiki 上沒有名為 ${namespace} 的命名空間,请校對輸入。",
"wiki.message.invalid_section": "此章節不存在,以下是可能的章節(回覆對應序號以選中):",
"wiki.message.invalid_section.prompt": "(此章節不存在)",
"wiki.message.iw.add.success": "已新增自訂 Interwiki\n${iw} -> ${name}",
"wiki.message.iw.get.not_found": "未找到 Interwiki${iw}",
"wiki.message.iw.list": "使用 「${prefix}wiki iw get <Interwiki>」可以取得 Interwiki 對應的連結。",

View file

@ -114,7 +114,8 @@ class PageInfo:
file: str = None,
desc: str = None,
args: str = None,
section: str = None,
selected_section: str = None,
sections: List[str] = None,
interwiki_prefix: str = '',
status: bool = True,
templates: List[str] = None,
@ -122,7 +123,7 @@ class PageInfo:
page_property: str = 'page',
has_template_doc: bool = False,
invalid_namespace: Union[str, bool] = False,
possible_research_title: List[str] = None
possible_research_title: List[str] = None,
):
self.info = info
self.id = id
@ -133,7 +134,8 @@ class PageInfo:
self.file = file
self.desc = desc
self.args = args
self.section = section
self.selected_section = selected_section
self.sections = sections
self.interwiki_prefix = interwiki_prefix
self.templates = templates
self.status = status
@ -142,6 +144,7 @@ class PageInfo:
self.has_template_doc = has_template_doc
self.invalid_namespace = invalid_namespace
self.possible_research_title = possible_research_title
self.invalid_section = False
class WikiLib:
@ -437,7 +440,7 @@ class WikiLib:
if _tried > 5:
if Config('enable_tos'):
raise WhatAreUDoingError
section = None
selected_section = None
if title is not None:
if title == '':
return PageInfo(title='', link=self.wiki_info.articlepath.replace("$1", ""), info=self.wiki_info,
@ -450,11 +453,13 @@ class WikiLib:
arg_list = []
_arg_list = []
section_list = []
used_quote = False
quote_code = False
for a in split_name[1:]:
if len(a) > 0:
if a[0] == '#':
quote_code = True
used_quote = True
if a[0] == '?':
quote_code = False
if quote_code:
@ -471,9 +476,11 @@ class WikiLib:
else:
title += _arg
if len(section_list) > 1:
section = ''.join(section_list)[1:]
selected_section = ''.join(section_list)[1:]
page_info = PageInfo(info=self.wiki_info, title=title, args=''.join(arg_list), interwiki_prefix=_prefix)
page_info.section = section
page_info.selected_section = selected_section
if not selected_section and used_quote:
page_info.invalid_section = True
query_string = {'action': 'query', 'prop': 'info|imageinfo|langlinks|templates', 'llprop': 'url',
'inprop': 'url', 'iiprop': 'url',
'redirects': 'True', 'titles': title}
@ -484,7 +491,7 @@ class WikiLib:
else:
raise ValueError('title and pageid cannot be both None')
use_textextracts = True if 'TextExtracts' in self.wiki_info.extensions else False
if use_textextracts and section is None:
if use_textextracts and selected_section is None:
query_string.update({'prop': 'info|imageinfo|langlinks|templates|extracts|pageprops',
'ppprop': 'description|displaytitle|disambiguation|infoboxes', 'explaintext': 'true',
'exsectionformat': 'plain', 'exchars': '200'})
@ -493,6 +500,7 @@ class WikiLib:
if query is None:
return PageInfo(title=title, link=None, desc=self.locale.t("wiki.message.utils.wikilib.error.empty"),
info=self.wiki_info)
redirects_: List[Dict[str, str]] = query.get('redirects')
if redirects_ is not None:
for r in redirects_:
@ -598,6 +606,17 @@ class WikiLib:
else:
page_info.status = True
templates = page_info.templates = [t['title'] for t in page_raw.get('templates', [])]
if selected_section or page_info.invalid_section:
parse_section_string = {'action': 'parse', 'page': title, 'prop': 'sections'}
parse_section = await self.get_json(**parse_section_string)
section_list = []
sections = parse_section['parse']['sections']
for s in sections:
section_list.append(s['anchor'])
page_info.sections = section_list
if selected_section:
if urllib.parse.unquote(selected_section) not in section_list:
page_info.invalid_section = True
if 'special' in page_raw:
full_url = re.sub(r'\$1',
urllib.parse.quote(title.encode('UTF-8')),
@ -675,12 +694,12 @@ class WikiLib:
page_info.has_template_doc = True
page_info.before_page_property = page_info.page_property = 'template'
if get_desc:
if use_textextracts and section is None:
if use_textextracts and (selected_section is None or page_info.invalid_section):
raw_desc = page_raw.get('extract')
if raw_desc is not None:
page_desc = self.parse_text(raw_desc)
else:
page_desc = self.parse_text(await self.get_html_to_text(title, section))
page_desc = self.parse_text(await self.get_html_to_text(title, selected_section))
full_url = page_raw['fullurl'] + page_info.args
file = None
if 'imageinfo' in page_raw:
@ -736,8 +755,8 @@ class WikiLib:
for possible_title in
page_info.possible_research_title]
if before_page_info.section is not None:
page_info.section = before_page_info.section
if before_page_info.selected_section is not None:
page_info.selected_section = before_page_info.selected_section
if not self.wiki_info.in_allowlist:
checklist = []
if page_info.title is not None:

View file

@ -5,6 +5,7 @@ from typing import Union
import filetype
from core.builtins import Bot, Plain, Image, Voice, Url, confirm_command
from core.utils.image_table import image_table_render, ImageTable
from core.component import module
from core.exceptions import AbuseWarning
from core.logger import Logger
@ -25,7 +26,7 @@ wiki = module('wiki',
@wiki.command('<PageName> [-l <lang>] {{wiki.help}}',
options_desc={'-l': '{wiki.help.option.l}'})
options_desc={'-l': '{wiki.help.option.l}'})
async def _(msg: Bot.MessageSession):
get_lang = msg.parsed_msg.get('-l', False)
if get_lang:
@ -201,8 +202,16 @@ async def query_pages(session: Union[Bot.MessageSession, QueryInfo], title: Unio
else:
plain_slice.append(session.locale.t('wiki.message.redirect', title=display_before_title,
redirected_title=display_title))
if r.desc is not None and r.desc != '':
plain_slice.append(r.desc)
if (r.link is not None and r.selected_section is not None and r.info.in_allowlist and
not r.invalid_section):
render_section_list.append(
{r.link: {'url': r.info.realurl, 'section': r.selected_section,
'in_allowlist': r.info.in_allowlist}})
plain_slice.append(session.locale.t("wiki.message.section.rendering"))
else:
if r.desc is not None and r.desc != '':
plain_slice.append(r.desc)
if r.link is not None:
plain_slice.append(
str(Url(r.link, use_mm=not r.info.in_allowlist)))
@ -211,19 +220,39 @@ async def query_pages(session: Union[Bot.MessageSession, QueryInfo], title: Unio
dl_list.append(r.file)
plain_slice.append(session.locale.t('wiki.message.flies') + r.file)
else:
if r.link is not None and r.section is None:
if r.link is not None and r.selected_section is None:
render_infobox_list.append(
{r.link: {'url': r.info.realurl, 'in_allowlist': r.info.in_allowlist,
'content_mode': r.has_template_doc or r.title.split(':')[0] in ['User'] or
(r.templates is not None and
('Template:Disambiguation' in r.templates or
'Template:Version disambiguation' in r.templates))}})
elif r.link is not None and r.section is not None and r.info.in_allowlist:
render_section_list.append(
{r.link: {'url': r.info.realurl, 'section': r.section,
'in_allowlist': r.info.in_allowlist}})
if plain_slice:
msg_list.append(Plain('\n'.join(plain_slice)))
if r.invalid_section and r.info.in_allowlist:
if isinstance(session, Bot.MessageSession):
if session.Feature.image:
i_msg_lst = []
session_data = [[str(i + 1), r.sections[i]] for i in range(len(r.sections))]
i_msg_lst.append(Plain(session.locale.t('wiki.message.invalid_section')))
i_msg_lst.append(Image(await
image_table_render(
ImageTable(session_data,
['ID',
session.locale.t('wiki.message.section')]))))
async def _callback(msg: Bot.MessageSession):
display = msg.as_display(text_only=True)
if display.isdigit():
display = int(display)
if display <= len(r.sections):
r.selected_section = display - 1
await query_pages(session, title=r.title + '#' + r.sections[display - 1])
await session.send_message(i_msg_lst, callback=_callback)
else:
msg_list.append(Plain(session.locale.t('wiki.message.invalid_section.prompt')))
else:
plain_slice = []
wait_plain_slice = []
@ -323,11 +352,17 @@ async def query_pages(session: Union[Bot.MessageSession, QueryInfo], title: Unio
get_section = await generate_screenshot_v2(ii, section=i[ii]['section'])
if get_section:
section_msg_list.append(Image(get_section))
else:
section_msg_list.append(Plain(
session.locale.t("wiki.message.error.unable_to_render_section")))
else:
get_section = await generate_screenshot_v1(i[ii]['url'], ii, headers,
section=i[ii]['section'])
if get_section:
section_msg_list.append(Image(get_section))
else:
section_msg_list.append(Plain(
session.locale.t("wiki.message.error.unable_to_render_section")))
if section_msg_list:
await session.send_message(section_msg_list, quote=False)

View file

@ -1,3 +1,4 @@
import datetime
import re
import traceback
from urllib.parse import quote
@ -7,6 +8,7 @@ from bs4 import BeautifulSoup
from google_play_scraper import app as google_play_scraper
from config import CFG, Config
from core.builtins import I18NText, FormattedTime
from core.logger import Logger
from core.queue import JobQueue
from core.scheduler import Scheduler, IntervalTrigger
@ -74,32 +76,47 @@ async def mcv_rss():
file = json.loads(await get_url(url, attempt=1))
release = file['latest']['release']
snapshot = file['latest']['snapshot']
time_release = 0
time_snapshot = 0
for v in file['versions']:
if v['id'] == release:
time_release = datetime.datetime.fromisoformat(v['releaseTime']).timestamp()
if v['id'] == snapshot:
time_snapshot = datetime.datetime.fromisoformat(v['releaseTime']).timestamp()
if release not in verlist:
Logger.info(f'huh, we find {release}.')
await JobQueue.trigger_hook_all('mcv_rss', message='mcv_rss.message.mcv_rss.release',
i18n=True, version=file['latest']['release'])
await JobQueue.trigger_hook_all('mcv_rss',
message=[I18NText('mcv_rss.message.mcv_rss.release',
version=release).to_dict(),
FormattedTime(time_release).to_dict()
])
verlist.append(release)
update_stored_list('scheduler', 'mcv_rss', verlist)
article = await get_article(release)
if article[0] != '':
get_stored_news_title = get_stored_list('scheduler', 'mcnews')
if article[1] not in get_stored_news_title:
await JobQueue.trigger_hook_all('minecraft_news', message='minecraft_news.message.update_log',
i18n=True, version=release, article=article[0])
await JobQueue.trigger_hook_all('minecraft_news',
message=[I18NText('minecraft_news.message.update_log',
version=release, article=article[0]).to_dict()])
get_stored_news_title.append(article[1])
update_stored_list('scheduler', 'mcnews', get_stored_news_title)
if snapshot not in verlist:
Logger.info(f'huh, we find {snapshot}.')
await JobQueue.trigger_hook_all('mcv_rss', message='mcv_rss.message.mcv_rss.snapshot', i18n=True,
version=file['latest']['snapshot'])
await JobQueue.trigger_hook_all('mcv_rss', message=[I18NText('mcv_rss.message.mcv_rss.snapshot',
version=file['latest']['snapshot']).to_dict(),
FormattedTime(time_snapshot).to_dict()])
verlist.append(snapshot)
update_stored_list('scheduler', 'mcv_rss', verlist)
article = await get_article(snapshot)
if article[0] != '':
get_stored_news_title = get_stored_list('scheduler', 'mcnews')
if article[1] not in get_stored_news_title:
await JobQueue.trigger_hook_all('minecraft_news', message='minecraft_news.message.update_log',
i18n=True, version=snapshot, article=article[0])
await JobQueue.trigger_hook_all('minecraft_news',
message=[I18NText('minecraft_news.message.update_log',
version=snapshot, article=article[0]).to_dict()])
get_stored_news_title.append(article[1])
update_stored_list('scheduler', 'mcnews', get_stored_news_title)
except Exception: