2023-07-21 05:52:01 +00:00
|
|
|
import contextlib
|
2022-12-22 14:18:43 +00:00
|
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
from typing import Optional
|
|
|
|
|
2023-07-21 05:52:01 +00:00
|
|
|
import aiofiles as aiofiles
|
2022-12-22 14:18:43 +00:00
|
|
|
from mipac import Note
|
|
|
|
from mipac.models.lite import LiteUser
|
|
|
|
from mipac.types import IDriveFile
|
|
|
|
from pyrogram.enums import ParseMode
|
|
|
|
from pyrogram.errors import MediaEmpty
|
2023-07-03 14:39:52 +00:00
|
|
|
from pyrogram.types import (
|
|
|
|
InlineKeyboardMarkup,
|
|
|
|
InlineKeyboardButton,
|
|
|
|
InputMediaPhoto,
|
|
|
|
InputMediaVideo,
|
|
|
|
InputMediaDocument,
|
|
|
|
InputMediaAudio,
|
|
|
|
)
|
2022-12-22 14:18:43 +00:00
|
|
|
|
2023-07-21 06:40:07 +00:00
|
|
|
from defs.image import webp_to_png
|
2022-12-22 14:18:43 +00:00
|
|
|
from init import bot, request
|
2023-01-27 12:36:41 +00:00
|
|
|
from models.services.scheduler import add_delete_file_job, delete_file
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 14:21:37 +00:00
|
|
|
def get_note_url(host: str, note: Note) -> str:
|
|
|
|
return f"https://{host}/notes/{note.id}"
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 15:35:10 +00:00
|
|
|
def gen_button(host: str, note: Note, author: str, show_second: bool):
|
2023-07-20 14:21:37 +00:00
|
|
|
source = get_note_url(host, note)
|
|
|
|
reply_source = get_note_url(host, note.reply) if note.reply else None
|
2023-01-27 15:20:25 +00:00
|
|
|
renote_id = note.renote_id if note.reply else note.id
|
2022-12-22 14:18:43 +00:00
|
|
|
if reply_source:
|
2022-12-24 08:31:16 +00:00
|
|
|
first_line = [
|
2022-12-22 14:18:43 +00:00
|
|
|
InlineKeyboardButton(text="Source", url=source),
|
|
|
|
InlineKeyboardButton(text="RSource", url=reply_source),
|
2022-12-24 08:31:16 +00:00
|
|
|
InlineKeyboardButton(text="Author", url=author),
|
|
|
|
]
|
2022-12-22 14:18:43 +00:00
|
|
|
else:
|
2022-12-24 08:31:16 +00:00
|
|
|
first_line = [
|
2022-12-22 14:18:43 +00:00
|
|
|
InlineKeyboardButton(text="Source", url=source),
|
2022-12-24 08:31:16 +00:00
|
|
|
InlineKeyboardButton(text="Author", url=author),
|
|
|
|
]
|
|
|
|
second_line = [
|
2023-01-27 15:20:25 +00:00
|
|
|
InlineKeyboardButton(text="🔁", callback_data=f"renote:{renote_id}"),
|
2023-07-05 12:02:42 +00:00
|
|
|
InlineKeyboardButton(text="❤️", callback_data=f"react:{renote_id}:love"),
|
|
|
|
InlineKeyboardButton(text="🌐", callback_data=f"translate:{renote_id}"),
|
2022-12-24 08:31:16 +00:00
|
|
|
]
|
2023-07-20 15:35:10 +00:00
|
|
|
return (
|
|
|
|
InlineKeyboardMarkup([first_line, second_line])
|
|
|
|
if show_second
|
|
|
|
else InlineKeyboardMarkup([first_line])
|
|
|
|
)
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 14:21:37 +00:00
|
|
|
def get_user_link(host: str, user: LiteUser) -> str:
|
2022-12-22 14:18:43 +00:00
|
|
|
if user.host:
|
2023-07-20 14:21:37 +00:00
|
|
|
return f"https://{host}/@{user.username}@{user.host}"
|
|
|
|
return f"https://{host}/@{user.username}"
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 14:21:37 +00:00
|
|
|
def get_user_alink(host: str, user: LiteUser) -> str:
|
|
|
|
return '<a href="{}">{}</a>'.format(
|
|
|
|
get_user_link(host, user), user.nickname or f"@{user.username}"
|
|
|
|
)
|
2023-07-05 11:58:39 +00:00
|
|
|
|
|
|
|
|
2022-12-22 14:18:43 +00:00
|
|
|
def get_post_time(date: datetime) -> str:
|
|
|
|
try:
|
|
|
|
date = date + timedelta(hours=8)
|
|
|
|
return date.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
except Exception:
|
|
|
|
return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
|
|
|
2023-07-20 14:21:37 +00:00
|
|
|
def get_content(host: str, note: Note) -> str:
|
2022-12-22 15:01:53 +00:00
|
|
|
content = note.content or ""
|
|
|
|
action = "发表"
|
|
|
|
origin = ""
|
|
|
|
show_note = note
|
|
|
|
if note.renote:
|
|
|
|
show_note = note.renote
|
|
|
|
action = "转推"
|
|
|
|
content = note.renote.content or content
|
2023-07-03 14:39:52 +00:00
|
|
|
origin = (
|
2023-07-20 14:21:37 +00:00
|
|
|
f"\n{get_user_alink(host, note.renote.author)} "
|
2023-07-03 14:39:52 +00:00
|
|
|
f"发表于 {get_post_time(note.renote.created_at)}"
|
|
|
|
)
|
2022-12-24 08:31:16 +00:00
|
|
|
content = content[:768]
|
2022-12-22 14:18:43 +00:00
|
|
|
return f"""<b>Misskey Timeline Update</b>
|
|
|
|
|
2022-12-22 15:01:53 +00:00
|
|
|
<code>{content}</code>
|
2022-12-22 14:18:43 +00:00
|
|
|
|
2023-07-20 14:21:37 +00:00
|
|
|
{get_user_alink(host, note.author)} {action}于 {get_post_time(note.created_at)}{origin}
|
2023-01-17 08:36:41 +00:00
|
|
|
点赞: {sum(show_note.reactions.values())} | 回复: {show_note.replies_count} | 转发: {show_note.renote_count}"""
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 15:35:10 +00:00
|
|
|
async def send_text(
|
|
|
|
host: str, cid: int, note: Note, reply_to_message_id: int, show_second: bool
|
|
|
|
):
|
2022-12-22 14:18:43 +00:00
|
|
|
await bot.send_message(
|
|
|
|
cid,
|
2023-07-20 14:21:37 +00:00
|
|
|
get_content(host, note),
|
2022-12-24 08:31:16 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2023-07-20 15:35:10 +00:00
|
|
|
reply_markup=gen_button(
|
|
|
|
host, note, get_user_link(host, note.author), show_second
|
|
|
|
),
|
2022-12-22 14:18:43 +00:00
|
|
|
disable_web_page_preview=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def deprecated_to_text(func):
|
|
|
|
async def wrapper(*args, **kwargs):
|
|
|
|
try:
|
|
|
|
return await func(*args, **kwargs)
|
|
|
|
except MediaEmpty:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(args[0], args[1], args[3], args[4], args[5])
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
2023-07-21 05:52:01 +00:00
|
|
|
async def fetch_document(file: IDriveFile) -> Optional[str]:
|
|
|
|
file_name = "downloads/" + file.get("name", "file")
|
|
|
|
file_url = file.get("url", None)
|
|
|
|
if file.get("size", 0) > 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
|
2023-07-21 06:40:07 +00:00
|
|
|
if file_name.lower().endswith(".webp"):
|
|
|
|
file_name = file_name[:-5] + ".jpg"
|
|
|
|
io = webp_to_png(req.content).getvalue()
|
|
|
|
else:
|
|
|
|
io = req.content
|
2023-07-21 05:52:01 +00:00
|
|
|
async with aiofiles.open(file_name, "wb") as f:
|
2023-07-21 06:40:07 +00:00
|
|
|
await f.write(io)
|
2023-07-21 05:52:01 +00:00
|
|
|
add_delete_file_job(file_name)
|
|
|
|
return file_name
|
|
|
|
|
|
|
|
|
2022-12-22 14:18:43 +00:00
|
|
|
@deprecated_to_text
|
2023-07-20 14:21:37 +00:00
|
|
|
async def send_photo(
|
2023-07-20 15:35:10 +00:00
|
|
|
host: str,
|
|
|
|
cid: int,
|
|
|
|
url: str,
|
|
|
|
note: Note,
|
|
|
|
reply_to_message_id: int,
|
|
|
|
show_second: bool,
|
2023-07-20 14:21:37 +00:00
|
|
|
):
|
2022-12-22 14:18:43 +00:00
|
|
|
if not url:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(host, cid, note, reply_to_message_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
await bot.send_photo(
|
|
|
|
cid,
|
|
|
|
url,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2023-07-20 14:21:37 +00:00
|
|
|
caption=get_content(host, note),
|
2023-07-20 15:35:10 +00:00
|
|
|
reply_markup=gen_button(
|
|
|
|
host, note, get_user_link(host, note.author), show_second
|
|
|
|
),
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@deprecated_to_text
|
2023-07-20 14:21:37 +00:00
|
|
|
async def send_video(
|
2023-07-20 15:35:10 +00:00
|
|
|
host: str,
|
|
|
|
cid: int,
|
|
|
|
url: str,
|
|
|
|
note: Note,
|
|
|
|
reply_to_message_id: int,
|
|
|
|
show_second: bool,
|
2023-07-20 14:21:37 +00:00
|
|
|
):
|
2022-12-22 14:18:43 +00:00
|
|
|
if not url:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(host, cid, note, reply_to_message_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
await bot.send_video(
|
|
|
|
cid,
|
|
|
|
url,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2023-07-20 14:21:37 +00:00
|
|
|
caption=get_content(host, note),
|
2023-07-20 15:35:10 +00:00
|
|
|
reply_markup=gen_button(
|
|
|
|
host, note, get_user_link(host, note.author), show_second
|
|
|
|
),
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@deprecated_to_text
|
2023-07-20 14:21:37 +00:00
|
|
|
async def send_audio(
|
2023-07-20 15:35:10 +00:00
|
|
|
host: str,
|
|
|
|
cid: int,
|
|
|
|
url: str,
|
|
|
|
note: Note,
|
|
|
|
reply_to_message_id: int,
|
|
|
|
show_second: bool,
|
2023-07-20 14:21:37 +00:00
|
|
|
):
|
2022-12-22 14:18:43 +00:00
|
|
|
if not url:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(host, cid, note, reply_to_message_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
await bot.send_audio(
|
|
|
|
cid,
|
|
|
|
url,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2023-07-20 14:21:37 +00:00
|
|
|
caption=get_content(host, note),
|
2023-07-20 15:35:10 +00:00
|
|
|
reply_markup=gen_button(
|
|
|
|
host, note, get_user_link(host, note.author), show_second
|
|
|
|
),
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@deprecated_to_text
|
2023-07-03 14:39:52 +00:00
|
|
|
async def send_document(
|
2023-07-20 15:35:10 +00:00
|
|
|
host: str,
|
|
|
|
cid: int,
|
2023-07-21 05:52:01 +00:00
|
|
|
url: str,
|
2023-07-20 15:35:10 +00:00
|
|
|
note: Note,
|
|
|
|
reply_to_message_id: int,
|
|
|
|
show_second: bool,
|
2023-07-03 14:39:52 +00:00
|
|
|
):
|
2023-07-21 05:52:01 +00:00
|
|
|
if not url:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(host, cid, note, reply_to_message_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
await bot.send_document(
|
|
|
|
cid,
|
2023-07-21 05:52:01 +00:00
|
|
|
url,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2023-07-20 14:21:37 +00:00
|
|
|
caption=get_content(host, note),
|
2023-07-20 15:35:10 +00:00
|
|
|
reply_markup=gen_button(
|
|
|
|
host, note, get_user_link(host, note.author), show_second
|
|
|
|
),
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
2023-07-21 05:52:01 +00:00
|
|
|
with contextlib.suppress(Exception):
|
|
|
|
await delete_file(url)
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2022-12-24 08:31:16 +00:00
|
|
|
async def get_media_group(files: list[IDriveFile]) -> list:
|
2022-12-22 14:18:43 +00:00
|
|
|
media_lists = []
|
2022-12-24 08:31:16 +00:00
|
|
|
for file_ in files:
|
|
|
|
file_url = file_.get("url", None)
|
2022-12-22 14:18:43 +00:00
|
|
|
if not file_url:
|
|
|
|
continue
|
2022-12-24 08:31:16 +00:00
|
|
|
file_type = file_.get("type", "")
|
2022-12-22 14:18:43 +00:00
|
|
|
if file_type.startswith("image"):
|
|
|
|
media_lists.append(
|
|
|
|
InputMediaPhoto(
|
|
|
|
file_url,
|
|
|
|
parse_mode=ParseMode.HTML,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
elif file_type.startswith("video"):
|
|
|
|
media_lists.append(
|
|
|
|
InputMediaVideo(
|
|
|
|
file_url,
|
|
|
|
parse_mode=ParseMode.HTML,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
elif file_type.startswith("audio"):
|
|
|
|
media_lists.append(
|
|
|
|
InputMediaAudio(
|
|
|
|
file_url,
|
|
|
|
parse_mode=ParseMode.HTML,
|
|
|
|
)
|
|
|
|
)
|
2022-12-24 08:31:16 +00:00
|
|
|
elif file := await fetch_document(file_):
|
2022-12-22 14:18:43 +00:00
|
|
|
media_lists.append(
|
|
|
|
InputMediaDocument(
|
|
|
|
file,
|
|
|
|
parse_mode=ParseMode.HTML,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return media_lists
|
|
|
|
|
|
|
|
|
2023-07-03 14:39:52 +00:00
|
|
|
async def send_group(
|
2023-07-20 15:35:10 +00:00
|
|
|
host: str,
|
|
|
|
cid: int,
|
|
|
|
files: list[IDriveFile],
|
|
|
|
note: Note,
|
|
|
|
reply_to_message_id: int,
|
|
|
|
show_second: bool,
|
2023-07-03 14:39:52 +00:00
|
|
|
):
|
2022-12-24 08:31:16 +00:00
|
|
|
groups = await get_media_group(files)
|
2022-12-22 14:18:43 +00:00
|
|
|
if len(groups) == 0:
|
2023-07-20 15:35:10 +00:00
|
|
|
return await send_text(host, cid, note, reply_to_message_id, show_second)
|
2022-12-24 08:31:16 +00:00
|
|
|
photo, video, audio, document, msg = [], [], [], [], None
|
2022-12-22 14:18:43 +00:00
|
|
|
for i in groups:
|
|
|
|
if isinstance(i, InputMediaPhoto):
|
|
|
|
photo.append(i)
|
|
|
|
elif isinstance(i, InputMediaVideo):
|
|
|
|
video.append(i)
|
|
|
|
elif isinstance(i, InputMediaAudio):
|
|
|
|
audio.append(i)
|
|
|
|
elif isinstance(i, InputMediaDocument):
|
|
|
|
document.append(i)
|
|
|
|
if video and (audio or document):
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
video,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
if audio:
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
audio,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
elif document:
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
document,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
elif audio and (photo or document):
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
audio,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
if photo:
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
photo,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
elif document:
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
document,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
|
|
|
else:
|
2022-12-24 08:31:16 +00:00
|
|
|
msg = await bot.send_media_group(
|
2022-12-22 14:18:43 +00:00
|
|
|
cid,
|
|
|
|
groups,
|
2023-01-17 03:26:10 +00:00
|
|
|
reply_to_message_id=reply_to_message_id,
|
2022-12-22 14:18:43 +00:00
|
|
|
)
|
2022-12-24 08:31:16 +00:00
|
|
|
if msg and isinstance(msg, list):
|
|
|
|
msg = msg[0]
|
2023-07-20 15:35:10 +00:00
|
|
|
await send_text(host, cid, note, msg.id if msg else None, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
|
|
|
|
|
2023-07-20 15:35:10 +00:00
|
|
|
async def send_update(
|
|
|
|
host: str, cid: int, note: Note, topic_id: Optional[int], show_second: bool
|
|
|
|
):
|
2022-12-22 14:18:43 +00:00
|
|
|
files = list(note.files)
|
|
|
|
if note.reply:
|
|
|
|
files.extend(iter(note.reply.files))
|
2022-12-22 15:01:53 +00:00
|
|
|
if note.renote:
|
|
|
|
files.extend(iter(note.renote.files))
|
|
|
|
files = list({f.get("id"): f for f in files}.values())
|
2022-12-22 14:18:43 +00:00
|
|
|
match len(files):
|
|
|
|
case 0:
|
2023-07-20 15:35:10 +00:00
|
|
|
await send_text(host, cid, note, topic_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
case 1:
|
|
|
|
file = files[0]
|
|
|
|
file_type = file.get("type", "")
|
2023-07-21 05:52:01 +00:00
|
|
|
url = await fetch_document(file)
|
2022-12-22 14:18:43 +00:00
|
|
|
if file_type.startswith("image"):
|
2023-07-21 05:52:01 +00:00
|
|
|
await send_photo(host, cid, url, note, topic_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
elif file_type.startswith("video"):
|
2023-07-21 05:52:01 +00:00
|
|
|
await send_video(host, cid, url, note, topic_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
elif file_type.startswith("audio"):
|
2023-07-21 05:52:01 +00:00
|
|
|
await send_audio(host, cid, url, note, topic_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
else:
|
2023-07-21 05:52:01 +00:00
|
|
|
await send_document(host, cid, url, note, topic_id, show_second)
|
2022-12-22 14:18:43 +00:00
|
|
|
case _:
|
2023-07-20 15:35:10 +00:00
|
|
|
await send_group(host, cid, files, note, topic_id, show_second)
|