diff --git a/defs/chat.py b/defs/chat.py
index 04469e0..4fbe36d 100644
--- a/defs/chat.py
+++ b/defs/chat.py
@@ -5,28 +5,27 @@ from mipac.models.lite import LiteUser
from pyrogram.errors import MediaEmpty
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
-from glover import misskey_host
from init import bot, request
from models.services.scheduler import add_delete_file_job, delete_file
-def get_user_link(user: LiteUser) -> str:
+def get_user_link(host: str, user: LiteUser) -> str:
if user.host:
- return f"https://{user.host}/@{user.username}"
- return f"{misskey_host}/@{user.username}"
+ return f"https://{host}/@{user.username}@{user.host}"
+ return f"https://{host}/@{user.username}"
-def get_source_link(message: ChatMessage) -> str:
+def get_source_link(host: str, message: ChatMessage) -> str:
return (
- f"{misskey_host}/my/messaging/{message.user.username}?cid={message.user.id}"
+ f"https://{host}/my/messaging/{message.user.username}?cid={message.user.id}"
if not message.group and message.user
- else f"{misskey_host}/my/messaging/group/{message.group.id}"
+ else f"https://{host}/my/messaging/group/{message.group.id}"
)
-def gen_button(message: ChatMessage):
- author = get_user_link(message.user)
- source = get_source_link(message)
+def gen_button(host: str, message: ChatMessage):
+ author = get_user_link(host, message.user)
+ source = get_source_link(host, message)
first_line = [
InlineKeyboardButton(text="Chat", url=source),
InlineKeyboardButton(text="Author", url=author),
@@ -34,24 +33,26 @@ def gen_button(message: ChatMessage):
return InlineKeyboardMarkup([first_line])
-def get_content(message: ChatMessage) -> str:
+def get_content(host: str, message: ChatMessage) -> str:
content = message.text or ""
content = content[:768]
- user = f'{message.user.nickname}'
+ user = f'{message.user.nickname}'
if message.group:
- group = f'{message.group.name}'
+ group = f'{message.group.name}'
user += f" ( {group} )"
return f"""Misskey Message
{user}: {content}
"""
-async def send_text(cid: int, message: ChatMessage, reply_to_message_id: int):
+async def send_text(
+ host: str, cid: int, message: ChatMessage, reply_to_message_id: int
+):
await bot.send_message(
cid,
- get_content(message),
+ get_content(host, message),
reply_to_message_id=reply_to_message_id,
- reply_markup=gen_button(message),
+ reply_markup=gen_button(host, message),
disable_web_page_preview=True,
)
@@ -61,53 +62,53 @@ def deprecated_to_text(func):
try:
return await func(*args, **kwargs)
except MediaEmpty:
- return await send_text(args[0], args[2], args[3])
+ return await send_text(args[0], args[1], args[3], args[4])
return wrapper
@deprecated_to_text
async def send_photo(
- cid: int, url: str, message: ChatMessage, reply_to_message_id: int
+ host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
):
if not url:
- return await send_text(cid, message, reply_to_message_id)
+ return await send_text(host, cid, message, reply_to_message_id)
await bot.send_photo(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(message),
- reply_markup=gen_button(message),
+ caption=get_content(host, message),
+ reply_markup=gen_button(host, message),
)
@deprecated_to_text
async def send_video(
- cid: int, url: str, message: ChatMessage, reply_to_message_id: int
+ host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
):
if not url:
- return await send_text(cid, message, reply_to_message_id)
+ return await send_text(host, cid, message, reply_to_message_id)
await bot.send_video(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(message),
- reply_markup=gen_button(message),
+ caption=get_content(host, message),
+ reply_markup=gen_button(host, message),
)
@deprecated_to_text
async def send_audio(
- cid: int, url: str, message: ChatMessage, reply_to_message_id: int
+ host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
):
if not url:
- return await send_text(cid, message, reply_to_message_id)
+ return await send_text(host, cid, message, reply_to_message_id)
await bot.send_audio(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(message),
- reply_markup=gen_button(message),
+ caption=get_content(host, message),
+ reply_markup=gen_button(host, message),
)
@@ -129,31 +130,31 @@ async def fetch_document(file: File) -> Optional[str]:
@deprecated_to_text
async def send_document(
- cid: int, file: File, message: ChatMessage, reply_to_message_id: int
+ host: str, cid: int, file: File, message: ChatMessage, reply_to_message_id: int
):
file = await fetch_document(file)
if not file:
- return await send_text(cid, message, reply_to_message_id)
+ return await send_text(host, cid, message, reply_to_message_id)
await bot.send_document(
cid,
file,
reply_to_message_id=reply_to_message_id,
- caption=get_content(message),
- reply_markup=gen_button(message),
+ caption=get_content(host, message),
+ reply_markup=gen_button(host, message),
)
await delete_file(file)
-async def send_chat_message(cid: int, message: ChatMessage, topic_id: int):
+async def send_chat_message(host: str, cid: int, message: ChatMessage, topic_id: int):
if not message.file:
- return await send_text(cid, message, topic_id)
+ return await send_text(host, cid, message, topic_id)
file_url = message.file.url
file_type = message.file.type
if file_type.startswith("image"):
- await send_photo(cid, file_url, message, topic_id)
+ await send_photo(host, cid, file_url, message, topic_id)
elif file_type.startswith("video"):
- await send_video(cid, file_url, message, topic_id)
+ await send_video(host, cid, file_url, message, topic_id)
elif file_type.startswith("audio"):
- await send_audio(cid, file_url, message, topic_id)
+ await send_audio(host, cid, file_url, message, topic_id)
else:
- await send_document(cid, message.file, message, topic_id)
+ await send_document(host, cid, message.file, message, topic_id)
diff --git a/defs/check_node.py b/defs/check_node.py
new file mode 100644
index 0000000..de6abfd
--- /dev/null
+++ b/defs/check_node.py
@@ -0,0 +1,30 @@
+from httpx import URL, InvalidURL
+
+from init import request
+
+
+def get_host(url: str) -> str:
+ try:
+ url = URL(url)
+ except InvalidURL:
+ return ""
+ return url.host
+
+
+async def check_host(host: str) -> bool:
+ if not host:
+ return False
+ try:
+ req = await request.get(f"https://{host}/.well-known/nodeinfo")
+ req.raise_for_status()
+ node_url = req.json()["links"][0]["href"]
+ req = await request.get(node_url)
+ req.raise_for_status()
+ data = req.json()
+ if data["software"]["name"] != "misskey":
+ raise ValueError
+ if not data["software"]["version"].startswith("13."):
+ raise ValueError
+ return True
+ except Exception:
+ return False
diff --git a/defs/misskey.py b/defs/misskey.py
index a88b85e..c427799 100644
--- a/defs/misskey.py
+++ b/defs/misskey.py
@@ -6,7 +6,6 @@ from mipac.models.lite import LiteUser
from mipac.types import IDriveFile
from pyrogram.enums import ParseMode
from pyrogram.errors import MediaEmpty
-
from pyrogram.types import (
InlineKeyboardMarkup,
InlineKeyboardButton,
@@ -16,18 +15,17 @@ from pyrogram.types import (
InputMediaAudio,
)
-from glover import misskey_host
from init import bot, request
from models.services.scheduler import add_delete_file_job, delete_file
-def get_note_url(note: Note) -> str:
- return f"{misskey_host}/notes/{note.id}"
+def get_note_url(host: str, note: Note) -> str:
+ return f"https://{host}/notes/{note.id}"
-def gen_button(note: Note, author: str):
- source = get_note_url(note)
- reply_source = get_note_url(note.reply) if note.reply else None
+def gen_button(host: str, note: Note, author: str):
+ source = get_note_url(host, note)
+ reply_source = get_note_url(host, note.reply) if note.reply else None
renote_id = note.renote_id if note.reply else note.id
if reply_source:
first_line = [
@@ -48,14 +46,16 @@ def gen_button(note: Note, author: str):
return InlineKeyboardMarkup([first_line, second_line])
-def get_user_link(user: LiteUser) -> str:
+def get_user_link(host: str, user: LiteUser) -> str:
if user.host:
- return f"https://{user.host}/@{user.username}"
- return f"{misskey_host}/@{user.username}"
+ return f"https://{host}/@{user.username}@{user.host}"
+ return f"https://{host}/@{user.username}"
-def get_user_alink(user: LiteUser) -> str:
- return "{}".format(get_user_link(user), user.nickname or f"@{user.username}")
+def get_user_alink(host: str, user: LiteUser) -> str:
+ return '{}'.format(
+ get_user_link(host, user), user.nickname or f"@{user.username}"
+ )
def get_post_time(date: datetime) -> str:
@@ -66,7 +66,7 @@ def get_post_time(date: datetime) -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
-def get_content(note: Note) -> str:
+def get_content(host: str, note: Note) -> str:
content = note.content or ""
action = "发表"
origin = ""
@@ -76,7 +76,7 @@ def get_content(note: Note) -> str:
action = "转推"
content = note.renote.content or content
origin = (
- f'\n{get_user_alink(note.renote.author)} '
+ f"\n{get_user_alink(host, note.renote.author)} "
f"发表于 {get_post_time(note.renote.created_at)}"
)
content = content[:768]
@@ -84,16 +84,16 @@ def get_content(note: Note) -> str:
{content}
-{get_user_alink(note.author)} {action}于 {get_post_time(note.created_at)}{origin}
+{get_user_alink(host, note.author)} {action}于 {get_post_time(note.created_at)}{origin}
点赞: {sum(show_note.reactions.values())} | 回复: {show_note.replies_count} | 转发: {show_note.renote_count}"""
-async def send_text(cid: int, note: Note, reply_to_message_id: int):
+async def send_text(host: str, cid: int, note: Note, reply_to_message_id: int):
await bot.send_message(
cid,
- get_content(note),
+ get_content(host, note),
reply_to_message_id=reply_to_message_id,
- reply_markup=gen_button(note, get_user_link(note.author)),
+ reply_markup=gen_button(host, note, get_user_link(host, note.author)),
disable_web_page_preview=True,
)
@@ -103,47 +103,53 @@ def deprecated_to_text(func):
try:
return await func(*args, **kwargs)
except MediaEmpty:
- return await send_text(args[0], args[2], args[3])
+ return await send_text(args[0], args[1], args[3], args[4])
return wrapper
@deprecated_to_text
-async def send_photo(cid: int, url: str, note: Note, reply_to_message_id: int):
+async def send_photo(
+ host: str, cid: int, url: str, note: Note, reply_to_message_id: int
+):
if not url:
- return await send_text(cid, note, reply_to_message_id)
+ return await send_text(host, cid, note, reply_to_message_id)
await bot.send_photo(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(note),
- reply_markup=gen_button(note, get_user_link(note.author)),
+ caption=get_content(host, note),
+ reply_markup=gen_button(host, note, get_user_link(host, note.author)),
)
@deprecated_to_text
-async def send_video(cid: int, url: str, note: Note, reply_to_message_id: int):
+async def send_video(
+ host: str, cid: int, url: str, note: Note, reply_to_message_id: int
+):
if not url:
- return await send_text(cid, note, reply_to_message_id)
+ return await send_text(host, cid, note, reply_to_message_id)
await bot.send_video(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(note),
- reply_markup=gen_button(note, get_user_link(note.author)),
+ caption=get_content(host, note),
+ reply_markup=gen_button(host, note, get_user_link(host, note.author)),
)
@deprecated_to_text
-async def send_audio(cid: int, url: str, note: Note, reply_to_message_id: int):
+async def send_audio(
+ host: str, cid: int, url: str, note: Note, reply_to_message_id: int
+):
if not url:
- return await send_text(cid, note, reply_to_message_id)
+ return await send_text(host, cid, note, reply_to_message_id)
await bot.send_audio(
cid,
url,
reply_to_message_id=reply_to_message_id,
- caption=get_content(note),
- reply_markup=gen_button(note, get_user_link(note.author)),
+ caption=get_content(host, note),
+ reply_markup=gen_button(host, note, get_user_link(host, note.author)),
)
@@ -165,17 +171,17 @@ async def fetch_document(file: IDriveFile) -> Optional[str]:
@deprecated_to_text
async def send_document(
- cid: int, file: IDriveFile, note: Note, reply_to_message_id: int
+ host: str, cid: int, file: IDriveFile, note: Note, reply_to_message_id: int
):
file = await fetch_document(file)
if not file:
- return await send_text(cid, note, reply_to_message_id)
+ return await send_text(host, cid, note, reply_to_message_id)
await bot.send_document(
cid,
file,
reply_to_message_id=reply_to_message_id,
- caption=get_content(note),
- reply_markup=gen_button(note, get_user_link(note.author)),
+ caption=get_content(host, note),
+ reply_markup=gen_button(host, note, get_user_link(host, note.author)),
)
await delete_file(file)
@@ -219,11 +225,11 @@ async def get_media_group(files: list[IDriveFile]) -> list:
async def send_group(
- cid: int, files: list[IDriveFile], note: Note, reply_to_message_id: int
+ host: str, cid: int, files: list[IDriveFile], note: Note, reply_to_message_id: int
):
groups = await get_media_group(files)
if len(groups) == 0:
- return await send_text(cid, note, reply_to_message_id)
+ return await send_text(host, cid, note, reply_to_message_id)
photo, video, audio, document, msg = [], [], [], [], None
for i in groups:
if isinstance(i, InputMediaPhoto):
@@ -278,10 +284,10 @@ async def send_group(
)
if msg and isinstance(msg, list):
msg = msg[0]
- await send_text(cid, note, msg.id if msg else None)
+ await send_text(host, cid, note, msg.id if msg else None)
-async def send_update(cid: int, note: Note, topic_id: int):
+async def send_update(host: str, cid: int, note: Note, topic_id: int):
files = list(note.files)
if note.reply:
files.extend(iter(note.reply.files))
@@ -290,18 +296,18 @@ async def send_update(cid: int, note: Note, topic_id: int):
files = list({f.get("id"): f for f in files}.values())
match len(files):
case 0:
- await send_text(cid, note, topic_id)
+ await send_text(host, cid, note, topic_id)
case 1:
file = files[0]
file_url = file.get("url", None)
file_type = file.get("type", "")
if file_type.startswith("image"):
- await send_photo(cid, file_url, note, topic_id)
+ await send_photo(host, cid, file_url, note, topic_id)
elif file_type.startswith("video"):
- await send_video(cid, file_url, note, topic_id)
+ await send_video(host, cid, file_url, note, topic_id)
elif file_type.startswith("audio"):
- await send_audio(cid, file_url, note, topic_id)
+ await send_audio(host, cid, file_url, note, topic_id)
else:
- await send_document(cid, file, note, topic_id)
+ await send_document(host, cid, file, note, topic_id)
case _:
- await send_group(cid, files, note, topic_id)
+ await send_group(host, cid, files, note, topic_id)
diff --git a/defs/notice.py b/defs/notice.py
index 0e56ca0..cb12cd7 100644
--- a/defs/notice.py
+++ b/defs/notice.py
@@ -1,10 +1,11 @@
from json import load
+
+from mipac.models.lite.user import LiteUser
from mipac.models.notification import (
NotificationFollow,
NotificationFollowRequest,
NotificationAchievement,
)
-from mipac.models.lite.user import LiteUser
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from init import bot
diff --git a/defs/search_user.py b/defs/search_user.py
index c8482ec..3d20d8a 100644
--- a/defs/search_user.py
+++ b/defs/search_user.py
@@ -1,6 +1,6 @@
+from datetime import datetime, timedelta
from typing import Optional
-from datetime import datetime, timedelta
from mipac import UserDetailed
from mipac.errors import FailedToResolveRemoteUserError
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
diff --git a/gen/achievement.json b/gen/achievement.json
index 60468d6..c069481 100644
--- a/gen/achievement.json
+++ b/gen/achievement.json
@@ -2,157 +2,157 @@
"notes1": [
"初来乍到",
"第一次发帖",
- "祝您在Misskey玩的愉快~"
+ "祝您在 Misskey 玩的愉快~"
],
"notes10": [
"一些帖子",
- "发布了10篇帖子",
+ "发布了 10 篇帖子",
""
],
"notes100": [
"很多帖子",
- "发布了100篇帖子",
+ "发布了 100 篇帖子",
""
],
"notes500": [
"满是帖子",
- "发布了500篇帖子",
+ "发布了 500 篇帖子",
""
],
"notes1000": [
"积帖成山",
- "发布了1,000篇帖子",
+ "发布了 1,000 篇帖子",
""
],
"notes5000": [
"帖如泉涌",
- "发布了5,000篇帖子",
+ "发布了 5,000 篇帖子",
""
],
"notes10000": [
"超级帖",
- "发布了10,000篇帖子",
+ "发布了 10,000 篇帖子",
""
],
"notes20000": [
"还想要更多帖子",
- "发布了20,000篇帖子",
+ "发布了 20,000 篇帖子",
""
],
"notes30000": [
"帖子帖子帖子",
- "发布了30,000篇帖子",
+ "发布了 30,000 篇帖子",
""
],
"notes40000": [
"帖子工厂",
- "发布了40,000篇帖子",
+ "发布了 40,000 篇帖子",
""
],
"notes50000": [
"帖子星球",
- "发布了50,000篇帖子",
+ "发布了 50,000 篇帖子",
""
],
"notes60000": [
"帖子类星体",
- "发布了60,000篇帖子",
+ "发布了 60,000 篇帖子",
""
],
"notes70000": [
"帖子黑洞",
- "发布了70,000篇帖子",
+ "发布了 70,000 篇帖子",
""
],
"notes80000": [
"帖子星系",
- "发布了80,000篇帖子",
+ "发布了 80,000 篇帖子",
""
],
"notes90000": [
"帖子起源",
- "发布了90,000篇帖子",
+ "发布了 90,000 篇帖子",
""
],
"notes100000": [
"ALL YOUR NOTE ARE BELONG TO US",
- "发布了100,000篇帖子",
+ "发布了 100,000 篇帖子",
"真的有那么多可以写的东西吗?"
],
"login3": [
"初学者 I",
- "连续登录3天",
- "今天开始我就是Misskist!"
+ "累计登录 3 天",
+ "今天开始我就是 Misskist!"
],
"login7": [
"初学者 II",
- "连续登录7天",
+ "累计登录 7 天",
"您开始习惯了吗?"
],
"login15": [
"初学者 III",
- "连续登录15天",
+ "累计登录 15 天",
""
],
"login30": [
"Misskist Ⅰ",
- "连续登录30天",
+ "累计登录 30 天",
""
],
"login60": [
"Misskist Ⅱ",
- "连续登录60天",
+ "累计登录 60 天",
""
],
"login100": [
"Misskist Ⅲ",
- "总登入100天",
- "那个用户,是Misskist喔"
+ "累计登入 100 天",
+ "那个用户,是 Misskist 喔"
],
"login200": [
"定期联系Ⅰ",
- "总登录天数200天",
+ "累计登录 200 天",
""
],
"login300": [
"定期联系Ⅱ",
- "总登录天数300天",
+ "累计登录 300 天",
""
],
"login400": [
"定期联系Ⅲ",
- "总登录天数400天",
+ "累计登录 400 天",
""
],
"login500": [
"老熟人Ⅰ",
- "总登录天数500天",
+ "累计登录 500 天",
"诸君,我喜欢贴文"
],
"login600": [
"老熟人Ⅱ",
- "总登录天数600天",
+ "累计登录 600 天",
""
],
"login700": [
"老熟人Ⅲ",
- "总登录天数700天",
+ "累计登录 700 天",
""
],
"login800": [
- "帖子大师Ⅰ",
- "总登录天数800天",
+ "帖子大师 Ⅰ",
+ "累计登录 800 天",
""
],
"login900": [
- "帖子大师Ⅱ",
- "总登录天数900天",
+ "帖子大师 Ⅱ",
+ "累计登录 900 天",
""
],
"login1000": [
- "帖子大师Ⅲ",
- "总登录天数1000天",
- "感谢您使用Misskey!"
+ "帖子大师 Ⅲ",
+ "累计登录 1000 天",
+ "感谢您使用 Misskey!"
],
"noteClipped1": [
"忍不住要收藏到便签",
@@ -186,22 +186,22 @@
],
"following10": [
"关注,跟随",
- "关注超过10人",
+ "关注超过 10 人",
""
],
"following50": [
"我的朋友很多",
- "关注超过50人",
+ "关注超过 50 人",
""
],
"following100": [
- "我的朋友很多",
- "关注超过100人",
+ "胜友如云",
+ "关注超过 100 人",
""
],
"following300": [
"朋友成群",
- "关注数超过300",
+ "关注数超过 300",
""
],
"followers1": [
@@ -211,37 +211,37 @@
],
"followers10": [
"关注我吧!",
- "拥有超过10名关注者",
+ "拥有超过 10 名关注者",
""
],
"followers50": [
"三五成群",
- "拥有超过50名关注者",
+ "拥有超过 50 名关注者",
""
],
"followers100": [
"胜友如云",
- "拥有超过100名关注者",
+ "拥有超过 100 名关注者",
""
],
"followers300": [
"排列成行",
- "拥有超过300名关注者",
+ "拥有超过 300 名关注者",
""
],
"followers500": [
"信号塔",
- "拥有超过500名关注者",
+ "拥有超过 500 名关注者",
""
],
"followers1000": [
"大影响家",
- "拥有超过1000名关注者",
+ "拥有超过 1000 名关注者",
""
],
"collectAchievements30": [
"成就收藏家",
- "获得超过30个成就",
+ "获得超过 30 个成就",
""
],
"viewAchievements3min": [
@@ -251,7 +251,7 @@
],
"iLoveMisskey": [
"I Love Misskey",
- "发布\"I ❤ #Misskey\"帖子",
+ "发布 \"I ❤ #Misskey\" 帖子",
"感谢您使用 Misskey ! by 开发团队"
],
"foundTreasure": [
@@ -261,12 +261,12 @@
],
"client30min": [
"休息一下!",
- "启动客户端超过30分钟",
+ "启动客户端超过 30 分钟",
""
],
"client60min": [
- "Misskey重度依赖",
- "启动客户端超过60分钟",
+ "Misskey 重度依赖",
+ "启动客户端超过 60 分钟",
""
],
"noteDeletedWithin1min": [
@@ -281,7 +281,7 @@
],
"postedAt0min0sec": [
"报时",
- "在0点发布一篇帖子",
+ "在 0 点发布一篇帖子",
"嘣 嘣 嘣 Biu——!"
],
"selfQuote": [
@@ -291,7 +291,7 @@
],
"htl20npm": [
"流动的时间线",
- "在首页时间线的流速超过20npm",
+ "在首页时间线的流速超过 20npm",
""
],
"viewInstanceChart": [
@@ -301,7 +301,7 @@
],
"outputHelloWorldOnScratchpad": [
"Hello, world!",
- "在AiScript控制台中输出 hello world",
+ "在 AiScript 控制台中输出 hello world",
""
],
"open3windows": [
@@ -316,7 +316,7 @@
],
"reactWithoutRead": [
"有好好读过吗?",
- "在含有100字以上的帖子被发出三秒内做出回应",
+ "在含有 100 字以上的帖子被发出三秒内做出回应",
""
],
"clickedClickHere": [
@@ -326,27 +326,27 @@
],
"justPlainLucky": [
"超高校级的幸运",
- "每10秒有0.01的概率自动获得",
+ "每 10 秒有 0.01 的概率自动获得",
""
],
"setNameToSyuilo": [
"像神一样呐",
- "将名称设定为syuilo",
+ "将名称设定为 syuilo",
""
],
"passedSinceAccountCreated1": [
"一周年",
- "账户创建时间超过1年",
+ "账户创建时间超过 1 年",
""
],
"passedSinceAccountCreated2": [
"二周年",
- "账户创建时间超过2年",
+ "账户创建时间超过 2 年",
""
],
"passedSinceAccountCreated3": [
"三周年",
- "账户创建时间超过3年",
+ "账户创建时间超过 3 年",
""
],
"loggedInOnBirthday": [
@@ -366,7 +366,7 @@
],
"brainDiver": [
"Brain Diver",
- "发布了包含Brain Diver链接的帖子",
+ "发布了包含 Brain Diver 链接的帖子",
"Misskey-Misskey La-Tu-Ma"
]
}
\ No newline at end of file
diff --git a/gen/achievement.py b/gen/achievement.py
index 6d12efb..fbda7a0 100644
--- a/gen/achievement.py
+++ b/gen/achievement.py
@@ -1,7 +1,8 @@
-import yaml
-from pathlib import Path
-from httpx import get
from json import dump
+from pathlib import Path
+
+import yaml
+from httpx import get
json_path = Path(__file__).parent / "achievement.json"
diff --git a/glover.py b/glover.py
index c701ac4..d096991 100644
--- a/glover.py
+++ b/glover.py
@@ -1,4 +1,3 @@
-import re
from configparser import RawConfigParser
from typing import Union
from distutils.util import strtobool
@@ -9,9 +8,6 @@ api_hash: str = ""
# [Basic]
ipv6: Union[bool, str] = "False"
# [misskey]
-misskey_url: str = ""
-misskey_host: str = ""
-misskey_domain: str = ""
web_domain: str = ""
admin: int = 0
@@ -20,20 +16,9 @@ config.read("config.ini")
api_id = config.getint("pyrogram", "api_id", fallback=api_id)
api_hash = config.get("pyrogram", "api_hash", fallback=api_hash)
ipv6 = config.get("basic", "ipv6", fallback=ipv6)
-misskey_url = config.get("misskey", "url", fallback=misskey_url)
-if origin_url := re.search(r"wss?://(.*)/streaming", misskey_url):
- misskey_host = (
- origin_url[0]
- .replace("wss", "https")
- .replace("ws", "http")
- .replace("/streaming", "")
- )
-else:
- misskey_host = misskey_url
-misskey_domain = re.search(r"https?://(.*)", misskey_host)[1]
web_domain = config.get("misskey", "web_domain", fallback=web_domain)
admin = config.getint("misskey", "admin", fallback=admin)
try:
- ipv6 = strtobool(ipv6)
+ ipv6 = bool(strtobool(ipv6))
except ValueError:
ipv6 = False
diff --git a/misskey_init.py b/misskey_init.py
index 6152a46..f182a71 100644
--- a/misskey_init.py
+++ b/misskey_init.py
@@ -23,7 +23,6 @@ from defs.notice import (
send_follow_request_accept,
send_achievement_earned,
)
-from glover import misskey_url, misskey_host
from models.models.user import User, TokenStatusEnum
from models.services.user import UserAction
@@ -45,41 +44,37 @@ class MisskeyBot(commands.Bot):
await Router(ws).connect_channel(["main", "home"])
async def on_note(self, note: Note):
- if self.tg_user:
- await send_update(self.tg_user.chat_id, note, self.tg_user.timeline_topic)
+ await send_update(
+ self.tg_user.host, self.tg_user.chat_id, note, self.tg_user.timeline_topic
+ )
async def on_user_followed(self, notice: NotificationFollow):
- if self.tg_user:
- await send_user_followed(
- self.tg_user.chat_id, notice, self.tg_user.notice_topic
- )
+ await send_user_followed(
+ self.tg_user.chat_id, notice, self.tg_user.notice_topic
+ )
async def on_follow_request(self, notice: NotificationFollowRequest):
- if self.tg_user:
- await send_follow_request(
- self.tg_user.chat_id, notice, self.tg_user.notice_topic
- )
+ await send_follow_request(
+ self.tg_user.chat_id, notice, self.tg_user.notice_topic
+ )
async def on_follow_request_accept(self, notice: NotificationFollowRequest):
- if self.tg_user:
- await send_follow_request_accept(
- self.tg_user.chat_id, notice, self.tg_user.notice_topic
- )
+ await send_follow_request_accept(
+ self.tg_user.chat_id, notice, self.tg_user.notice_topic
+ )
async def on_chat(self, message: ChatMessage):
- if self.tg_user:
- await send_chat_message(
- self.tg_user.chat_id, message, self.tg_user.notice_topic
- )
+ await send_chat_message(
+ self.tg_user.host, self.tg_user.chat_id, message, self.tg_user.notice_topic
+ )
async def on_chat_unread_message(self, message: ChatMessage):
await message.api.read()
async def on_achievement_earned(self, notice: NotificationAchievement):
- if self.tg_user:
- await send_achievement_earned(
- self.tg_user.chat_id, notice, self.tg_user.notice_topic
- )
+ await send_achievement_earned(
+ self.tg_user.chat_id, notice, self.tg_user.notice_topic
+ )
misskey_bot_map: dict[int, MisskeyBot] = {}
@@ -99,16 +94,16 @@ async def run(user: User):
misskey = await create_or_get_misskey_bot(user)
try:
logs.info(f"尝试启动 Misskey Bot WS 任务 {user.user_id}")
- await misskey.start(misskey_url, user.token)
+ await misskey.start(f"wss://{user.host}", user.token)
except ClientConnectorError:
await sleep(3)
await run(user)
-async def test_token(token: str) -> bool:
+async def test_token(host: str, token: str) -> bool:
try:
- logs.info(f"验证 Token {token}")
- client = MisskeyClient(misskey_host, token)
+ logs.info(f"验证 Token {host} {token}")
+ client = MisskeyClient(f"https://{host}", token)
await client.http.login()
await client.http.close_session()
return True
@@ -124,7 +119,7 @@ async def rerun_misskey_bot(user_id: int) -> bool:
user = await UserAction.get_user_if_ok(user_id)
if not user:
return False
- if not await test_token(user.token):
+ if not await test_token(user.host, user.token):
await UserAction.set_user_status(user_id, TokenStatusEnum.INVALID_TOKEN)
return False
bot.loop.create_task(run(user))
@@ -135,7 +130,7 @@ async def init_misskey_bot():
await sqlite.create_db_and_tables()
count = 0
for user in await UserAction.get_all_token_ok_users():
- if not await test_token(user.token):
+ if not await test_token(user.host, user.token):
user.status = TokenStatusEnum.INVALID_TOKEN
await UserAction.update_user(user)
continue
diff --git a/models/models/user.py b/models/models/user.py
index 4cdd2d5..8a07c9e 100644
--- a/models/models/user.py
+++ b/models/models/user.py
@@ -12,8 +12,9 @@ class User(SQLModel, table=True):
__table_args__ = dict(mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci")
user_id: int = Field(primary_key=True)
+ host: str = Field(default="")
token: str = Field(default="")
status: TokenStatusEnum = Field(sa_column=Column(Enum(TokenStatusEnum)))
- chat_id: int = Field(default=0)
+ chat_id: int = Field(default=0, primary_key=True)
timeline_topic: int = Field(default=0)
notice_topic: int = Field(default=0)
diff --git a/models/services/user.py b/models/services/user.py
index 6bd3a9f..a73efce 100644
--- a/models/services/user.py
+++ b/models/services/user.py
@@ -35,6 +35,7 @@ class UserAction:
.where(User.timeline_topic != 0)
.where(User.notice_topic != 0)
.where(User.token != "")
+ .where(User.host != "")
)
results = await session.exec(statement)
return user[0] if (user := results.first()) else None
@@ -80,12 +81,22 @@ class UserAction:
return True
@staticmethod
- async def change_user_token(user_id: int, token: str) -> bool:
+ async def change_user_host(user_id: int, host: str) -> bool:
user = await UserAction.get_user_by_id(user_id)
if not user:
user = User(
- user_id=user_id, token=token, status=TokenStatusEnum.STATUS_SUCCESS
+ user_id=user_id, host=host, status=TokenStatusEnum.INVALID_TOKEN
)
+ user.host = host
+ user.status = TokenStatusEnum.INVALID_TOKEN
+ await UserAction.update_user(user)
+ return True
+
+ @staticmethod
+ async def change_user_token(user_id: int, token: str) -> bool:
+ user = await UserAction.get_user_by_id(user_id)
+ if not user:
+ return False
user.token = token
user.status = TokenStatusEnum.STATUS_SUCCESS
await UserAction.update_user(user)
diff --git a/models/sqlite.py b/models/sqlite.py
index 6b05f9f..a17791d 100644
--- a/models/sqlite.py
+++ b/models/sqlite.py
@@ -1,7 +1,8 @@
+from pathlib import Path
+
from sqlmodel import SQLModel
from models.models.user import User
-from pathlib import Path
__all__ = ["User", "Sqlite"]
diff --git a/modules/announcement.py b/modules/announcement.py
index 1d82db8..1c7119e 100644
--- a/modules/announcement.py
+++ b/modules/announcement.py
@@ -1,7 +1,6 @@
-from models.services.scheduler import scheduler
from defs.announcement import get_unread_announcements
-
from misskey_init import misskey_bot_map
+from models.services.scheduler import scheduler
@scheduler.scheduled_job("interval", minutes=15, id="check_announcement")
diff --git a/modules/bind.py b/modules/bind.py
index 4c43ed7..eb1a4d4 100644
--- a/modules/bind.py
+++ b/modules/bind.py
@@ -1,9 +1,8 @@
from pyrogram import Client, filters
from pyrogram.types import Message
-from models.services.user import UserAction
-
from misskey_init import rerun_misskey_bot
+from models.services.user import UserAction
async def pre_check(message: Message):
diff --git a/modules/search_user.py b/modules/search_user.py
index 24f82b8..6b81cdc 100644
--- a/modules/search_user.py
+++ b/modules/search_user.py
@@ -1,4 +1,5 @@
import contextlib
+
from mipac.errors import (
InternalErrorError,
AlreadyFollowingError,
diff --git a/modules/start.py b/modules/start.py
index b2f7226..d6cf38b 100644
--- a/modules/start.py
+++ b/modules/start.py
@@ -1,22 +1,25 @@
from pyrogram import Client, filters
from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
-from glover import misskey_host, web_domain, misskey_domain
+from defs.check_node import get_host, check_host
+from glover import web_domain
from init import bot
from misskey_init import test_token, rerun_misskey_bot
from models.services.user import UserAction
des = f"""欢迎使用 {bot.me.first_name},这是一个用于在 Telegram 上使用 Misskey 的机器人。按下方教程开始使用:
-1. 点击下方按钮绑定 Misskey 账号
+1. 使用 `/start https://[misskey_domain]` 设置账号所在 Misskey 实例地址(仅支持 https 链接)
-2. 在论坛群组中使用 /bind_timeline 绑定 Timeline 话题,接收时间线更新
+2. 点击 start 之后回复你的按钮绑定所在 Misskey 实例的账号
-3. 在论坛群组中使用 /bind_notice 绑定 Notice 话题,接收通知
+3. 在论坛群组中使用 /bind_timeline 绑定 Timeline 话题,接收时间线更新
+
+4. 在论坛群组中使用 /bind_notice 绑定 Notice 话题,接收通知
至此,你便可以在 Telegram 接收 Misskey 消息,同时你可以私聊我使用 /status 查看 Bot 运行状态
-此 Bot 仅支持绑定 {misskey_host} 的 Misskey 账号!"""
+此 Bot 仅支持 Misskey V13 实例的账号!"""
async def finish_check(message: Message):
@@ -26,8 +29,40 @@ async def finish_check(message: Message):
await message.reply("Token 设置完成,请绑定群组。", quote=True)
-def gen_url():
- return f"https://{web_domain}/gen?host={misskey_domain}&back_host={web_domain}&username={bot.me.username}"
+def gen_url(domain: str):
+ return f"https://{web_domain}/gen?host={domain}&back_host={web_domain}&username={bot.me.username}"
+
+
+async def change_host(message: Message, token_or_host: str):
+ host = get_host(token_or_host)
+ if await check_host(host):
+ await UserAction.change_user_host(message.from_user.id, host)
+ await message.reply(
+ "Host 验证成功,请点击下方按钮绑定账号。",
+ quote=True,
+ reply_markup=InlineKeyboardMarkup(
+ [
+ [
+ InlineKeyboardButton(text="绑定 Misskey 账号", url=gen_url(host)),
+ ]
+ ]
+ ),
+ )
+ else:
+ await message.reply("Host 验证失败,请检查 Host 是否正在运行 Misskey V13", quote=True)
+
+
+async def change_token(message: Message, token_or_host: str):
+ if user := await UserAction.get_user_by_id(message.from_user.id):
+ if user.host:
+ if await test_token(user.host, token_or_host):
+ await UserAction.change_user_token(message.from_user.id, token_or_host)
+ await message.reply(
+ "Token 验证成功,绑定账号完成。\n当你撤销此登录时,你可以重新点击按钮授权。", quote=True
+ )
+ await finish_check(message)
+ else:
+ await message.reply("Token 验证失败,请检查 Token 是否正确", quote=True)
@Client.on_message(filters.incoming & filters.private & filters.command(["start"]))
@@ -36,27 +71,13 @@ async def start_command(_: Client, message: Message):
回应 start
"""
if len(message.command) == 2:
- token = message.command[1]
- if not token:
+ token_or_host = message.command[1]
+ if not token_or_host:
await message.reply(des, quote=True)
return
- if await test_token(token):
- await UserAction.change_user_token(message.from_user.id, token)
- await message.reply(
- "Token 验证成功,绑定账号完成。\n" "当你撤销此登录时,你可以重新点击按钮授权。", quote=True
- )
- await finish_check(message)
- else:
- await message.reply("Token 验证失败,请检查 Token 是否正确", quote=True)
+ if token_or_host.startswith("https://"):
+ await change_host(message, token_or_host)
+ return
+ await change_token(message, token_or_host)
return
- await message.reply(
- des,
- quote=True,
- reply_markup=InlineKeyboardMarkup(
- [
- [
- InlineKeyboardButton(text="绑定 Misskey 账号", url=gen_url()),
- ]
- ]
- ),
- )
+ await message.reply(des, quote=True)
diff --git a/modules/status.py b/modules/status.py
index ce6bf75..7749408 100644
--- a/modules/status.py
+++ b/modules/status.py
@@ -2,7 +2,6 @@ from pyrogram import filters, Client
from pyrogram.types import Message
from glover import admin
-
from misskey_init import get_misskey_bot, rerun_misskey_bot, misskey_bot_map
from models.models.user import TokenStatusEnum
from models.services.user import UserAction
diff --git a/requirements.txt b/requirements.txt
index 2a1fe3a..2b04b82 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,4 +5,4 @@ apscheduler==3.10.1
sqlalchemy==1.4.41
sqlmodel==0.0.8
aiosqlite==0.19.0
-PyYAML==6.0
+PyYAML==6.0.1