feat: chat message

This commit is contained in:
xtaodada 2023-01-18 01:11:26 +08:00
parent df73cc1246
commit 9c3b55c3ff
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
8 changed files with 285 additions and 7 deletions

151
defs/chat.py Normal file
View File

@ -0,0 +1,151 @@
from typing import Optional
from mipac import ChatMessage, File
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 scheduler import add_delete_file_job, delete_file
def get_user_link(user: LiteUser) -> str:
if user.host:
return f"https://{user.host}/@{user.username}"
return f"https://{misskey_host}/@{user.username}"
def get_source_link(message: ChatMessage) -> str:
return (
f"https://{misskey_host}/my/messaging/{message.user.username}?cid={message.user.id}"
if not message.group and message.user
else f"https://{misskey_host}/my/messaging/group/{message.group.id}"
)
def gen_button(message: ChatMessage):
author = get_user_link(message.user)
source = get_source_link(message)
first_line = [
InlineKeyboardButton(text="Chat", url=source),
InlineKeyboardButton(text="Author", url=author),
]
return InlineKeyboardMarkup([first_line])
def get_content(message: ChatMessage) -> str:
content = message.text or ""
content = content[:768]
user = f"<a href=\"{get_user_link(message.user)}\">{message.user.nickname}</a>"
if message.group:
group = f"<a href=\"{get_source_link(message)}\">{message.group.name}</a>"
user += f" ( {group} )"
return f"""<b>Misskey Message</b>
{user} <code>{content}</code>"""
async def send_text(cid: int, message: ChatMessage, reply_to_message_id: int):
await bot.send_message(
cid,
get_content(message),
reply_to_message_id=reply_to_message_id,
reply_markup=gen_button(message),
disable_web_page_preview=True,
)
def deprecated_to_text(func):
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except MediaEmpty:
return await send_text(args[0], args[2], args[3])
return wrapper
@deprecated_to_text
async def send_photo(cid: int, url: str, message: ChatMessage, reply_to_message_id: int):
if not url:
return await send_text(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),
)
@deprecated_to_text
async def send_video(cid: int, url: str, message: ChatMessage, reply_to_message_id: int):
if not url:
return await send_text(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),
)
@deprecated_to_text
async def send_audio(cid: int, url: str, message: ChatMessage, reply_to_message_id: int):
if not url:
return await send_text(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),
)
async def fetch_document(file: File) -> Optional[str]:
file_name = f"downloads/{file.name}"
file_url = file.url
if file.size > 10 * 1024 * 1024:
return file_url
if not file_url:
return file_url
req = await request.get(file_url)
if req.status_code != 200:
return file_url
with open(file_name, "wb") as f:
f.write(req.content)
add_delete_file_job(file_name)
return file_name
@deprecated_to_text
async def send_document(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)
await bot.send_document(
cid,
file,
reply_to_message_id=reply_to_message_id,
caption=get_content(message),
reply_markup=gen_button(message),
)
await delete_file(file)
async def send_chat_message(cid: int, message: ChatMessage, topic_id: int):
if not message.file:
return await send_text(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)
elif file_type.startswith("video"):
await send_video(cid, file_url, message, topic_id)
elif file_type.startswith("audio"):
await send_audio(cid, file_url, message, topic_id)
else:
await send_document(cid, message.file, message, topic_id)

View File

@ -41,7 +41,51 @@ class ReadySend:
except Exception as e: except Exception as e:
await msg.edit(f"发送失败:{e}") await msg.edit(f"发送失败:{e}")
else: else:
await msg.edit("发送成功") await msg.delete()
finally:
del ready_send[msg.id]
class ReadySendMessage:
def __init__(
self,
text: str,
group: bool = False,
uid: Optional[str] = None,
file_id: Optional[str] = None,
):
self.text = text
self.user_id = None if group else uid
self.group_id = uid if group else None
self.file_id = file_id
async def confirm(self, msg: Message):
msg = await msg.reply(
"确认发送?",
quote=True,
reply_markup=InlineKeyboardMarkup(
[
[
InlineKeyboardButton(text="发送", callback_data="chat_send"),
InlineKeyboardButton(text="拒绝", callback_data="delete")
]
]
),
)
ready_send[msg.id] = self
async def send(self, msg: Message):
try:
await misskey_bot.core.api.chat.action.send(
text=self.text,
user_id=self.user_id,
group_id=self.group_id,
file_id=self.file_id,
)
except Exception as e:
await msg.edit(f"发送失败:{e}")
else:
await msg.delete()
finally: finally:
del ready_send[msg.id] del ready_send[msg.id]

View File

@ -264,7 +264,7 @@ async def send_group(cid: int, files: list[IDriveFile], note: Note, reply_to_mes
await send_text(cid, note, msg.id if msg else None) await send_text(cid, note, msg.id if msg else None)
async def send_update(cid: int, note: Note, topic_id: int = None): async def send_update(cid: int, note: Note, topic_id: int):
files = list(note.files) files = list(note.files)
if note.reply: if note.reply:
files.extend(iter(note.reply.files)) files.extend(iter(note.reply.files))

View File

@ -1,10 +1,11 @@
from mipa.ext import commands from mipa.ext import commands
from mipa.router import Router from mipa.router import Router
from mipac import Note, NotificationFollow, NotificationFollowRequest from mipac import Note, NotificationFollow, NotificationFollowRequest, ChatMessage
from defs.chat import send_chat_message
from defs.misskey import send_update from defs.misskey import send_update
from defs.notice import send_user_followed, send_follow_request, send_follow_request_accept from defs.notice import send_user_followed, send_follow_request, send_follow_request_accept
from glover import admin, topic_group_id, timeline_topic_id from glover import admin, topic_group_id, timeline_topic_id, notice_topic_id
class MisskeyBot(commands.Bot): class MisskeyBot(commands.Bot):
@ -29,5 +30,11 @@ class MisskeyBot(commands.Bot):
async def on_follow_request_accept(self, notice: NotificationFollowRequest): async def on_follow_request_accept(self, notice: NotificationFollowRequest):
await send_follow_request_accept(notice) await send_follow_request_accept(notice)
async def on_chat(self, message: ChatMessage):
await send_chat_message(topic_group_id or admin, message, notice_topic_id)
async def on_chat_unread_message(self, message: ChatMessage):
await message.api.read()
misskey_bot = MisskeyBot() misskey_bot = MisskeyBot()

69
modules/chat.py Normal file
View File

@ -0,0 +1,69 @@
import contextlib
from os import remove
from typing import Tuple
from pyrogram import Client, filters, ContinuePropagation
from pyrogram.types import Message, CallbackQuery
from defs.confirm import ready_send, ReadySendMessage
from glover import admin
from init import notice_filter
from misskey_init import misskey_bot
def get_uid(message: Message) -> Tuple[bool, str]:
group, user, uid = False, None, None
if (
not message.reply_to_message
or not message.reply_to_message.reply_markup
):
raise ContinuePropagation
with contextlib.suppress(IndexError, AttributeError):
url = message.reply_to_message.reply_markup.inline_keyboard[0][0].url
user = url.split("/")[-1]
if "/my/messaging/group/" in url:
group = True
uid = user
else:
uid = user.split("?cid=")[1]
if not user:
raise ContinuePropagation
if not uid:
raise ContinuePropagation
return group, uid
@Client.on_message(filters.incoming & notice_filter & filters.text & filters.user(admin))
async def chat_command(_: Client, message: Message):
group, uid = get_uid(message)
text = message.text.strip()
if text.startswith("@"):
raise ContinuePropagation
need_send = ReadySendMessage(text, group, uid)
await need_send.confirm(message)
@Client.on_message(filters.incoming & notice_filter & filters.photo & filters.user(admin))
async def chat_photo_command(_: Client, message: Message):
group, uid = get_uid(message)
text = message.caption.strip() if message.caption else ""
photo = await message.download()
try:
file_ = await misskey_bot.core.api.drive.file.action.upload_file(photo)
except Exception as e:
return await message.reply(f"上传文件失败:{e}", quote=True)
need_send = ReadySendMessage(text, group, uid, file_.id)
remove(photo)
await need_send.confirm(message)
@Client.on_callback_query(filters.regex("^chat_send$"))
async def chat_send_callback(_: Client, callback_query: CallbackQuery):
"""
发送
"""
if need_send := ready_send.get(callback_query.message.id, None):
await need_send.send(callback_query.message)
return await callback_query.answer("发送成功")
else:
return await callback_query.answer("按钮已过期", show_alert=True)

View File

@ -1,3 +1,4 @@
import contextlib
from mipac.errors import InternalErrorError, AlreadyFollowingError, FolloweeIsYourselfError from mipac.errors import InternalErrorError, AlreadyFollowingError, FolloweeIsYourselfError
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.types import Message, CallbackQuery from pyrogram.types import Message, CallbackQuery
@ -42,6 +43,8 @@ async def follow_user_callback(_: Client, callback_query: CallbackQuery):
关注/取消关注用户 关注/取消关注用户
""" """
user_id = callback_query.matches[0].group(1) user_id = callback_query.matches[0].group(1)
button = callback_query.message.reply_markup
follow = True
try: try:
await misskey_bot.core.api.follow.action.add(user_id) await misskey_bot.core.api.follow.action.add(user_id)
await callback_query.answer("关注成功", show_alert=True) await callback_query.answer("关注成功", show_alert=True)
@ -51,12 +54,16 @@ async def follow_user_callback(_: Client, callback_query: CallbackQuery):
try: try:
await misskey_bot.core.api.follow.action.remove(user_id) await misskey_bot.core.api.follow.action.remove(user_id)
await callback_query.answer("取消关注成功", show_alert=True) await callback_query.answer("取消关注成功", show_alert=True)
follow = False
except Exception as e: except Exception as e:
await callback_query.answer("取消关注失败", show_alert=True) await callback_query.answer("取消关注失败", show_alert=True)
await callback_query.message.reply(f"取消关注失败:{e}", quote=True) await callback_query.message.reply(f"取消关注失败:{e}", quote=True)
return
except FolloweeIsYourselfError: except FolloweeIsYourselfError:
await callback_query.answer("不能关注自己", show_alert=True) await callback_query.answer("不能关注自己", show_alert=True)
except Exception as e: except Exception as e:
await callback_query.answer("关注失败", show_alert=True) await callback_query.answer("关注失败", show_alert=True)
await callback_query.message.reply(f"关注失败:{e}", quote=True) await callback_query.message.reply(f"关注失败:{e}", quote=True)
if button:
with contextlib.suppress(Exception):
button.inline_keyboard[1][0].text = "" if follow else ""
await callback_query.message.edit_reply_markup(button)

2
requirements.git.txt Normal file
View File

@ -0,0 +1,2 @@
git+https://github.com/yupix/MiPA.git
git+https://github.com/yupix/MiPAC.git

View File

@ -1,5 +1,3 @@
git+https://github.com/yupix/MiPA.git
git+https://github.com/yupix/MiPAC.git
Pyrogram==2.0.97 Pyrogram==2.0.97
tgCrypto==1.2.5 tgCrypto==1.2.5
httpx==0.23.3 httpx==0.23.3