add slack

This commit is contained in:
jxxghp
2023-06-11 13:15:24 +08:00
parent 346ad2c259
commit f57e801236
4 changed files with 535 additions and 2 deletions

325
app/modules/slack/slack.py Normal file
View File

@ -0,0 +1,325 @@
import re
from threading import Lock
from typing import List, Optional
import requests
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
from slack_sdk import WebClient
from app.core.config import settings
from app.core.context import MediaInfo, Context
from app.core.metainfo import MetaInfo
from app.log import logger
from app.utils.string import StringUtils
lock = Lock()
class Slack:
_client: WebClient = None
_service: SocketModeHandler = None
_ds_url = f"http://127.0.0.1:{settings.PORT}/api/v1/messages?token={settings.API_TOKEN}"
def __init__(self):
if not settings.SLACK_OAUTH_TOKEN or not settings.SLACK_APP_TOKEN:
return
try:
slack_app = App(token=settings.SLACK_OAUTH_TOKEN,
ssl_check_enabled=False,
url_verification_enabled=False)
except Exception as err:
logger.error(f"Slack初始化失败: {err}")
return
self._client = slack_app.client
# 注册消息响应
@slack_app.event("message")
def slack_message(message):
local_res = requests.post(self._ds_url, json=message, timeout=10)
logger.debug("message: %s processed, response is: %s" % (message, local_res.text))
@slack_app.action(re.compile(r"actionId-\d+"))
def slack_action(ack, body):
ack()
local_res = requests.post(self._ds_url, json=body, timeout=60)
logger.debug("message: %s processed, response is: %s" % (body, local_res.text))
@slack_app.event("app_mention")
def slack_mention(say, body):
say(f"收到,请稍等... <@{body.get('event', {}).get('user')}>")
local_res = requests.post(self._ds_url, json=body, timeout=10)
logger.debug("message: %s processed, response is: %s" % (body, local_res.text))
@slack_app.shortcut(re.compile(r"/*"))
def slack_shortcut(ack, body):
ack()
local_res = requests.post(self._ds_url, json=body, timeout=10)
logger.debug("message: %s processed, response is: %s" % (body, local_res.text))
# 启动服务
try:
self._service = SocketModeHandler(
slack_app,
settings.SLACK_APP_TOKEN
)
self._service.connect()
logger.info("Slack消息接收服务启动")
except Exception as err:
logger.error("Slack消息接收服务启动失败: %s" % str(err))
def stop(self):
if self._service:
try:
self._service.close()
logger.info("Slack消息接收服务已停止")
except Exception as err:
logger.error("Slack消息接收服务停止失败: %s" % str(err))
def send_msg(self, title: str, text: str = "", image: str = "", url: str = "", userid: str = ""):
"""
发送Telegram消息
:param title: 消息标题
:param text: 消息内容
:param image: 消息图片地址
:param url: 点击消息转转的URL
:param userid: 用户ID如有则只发消息给该用户
:user_id: 发送消息的目标用户ID为空则发给管理员
"""
if not self._client:
return False, "消息客户端未就绪"
if not title and not text:
return False, "标题和内容不能同时为空"
try:
if userid:
channel = userid
else:
# 消息广播
channel = self.__find_public_channel()
# 拼装消息内容
block = {
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*{title}*\n{text}"
}
}
# 消息图片
if image:
block['accessory'] = {
"type": "image",
"image_url": f"{image}",
"alt_text": f"{title}"
}
blocks = [block]
# 链接
if image and url:
blocks.append({
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "查看详情",
"emoji": True
},
"value": "click_me_url",
"url": f"{url}",
"action_id": "actionId-url"
}
]
})
# 发送
result = self._client.chat_postMessage(
channel=channel,
blocks=blocks
)
return True, result
except Exception as msg_e:
logger.error(f"Slack消息发送失败: {msg_e}")
return False, str(msg_e)
def send_meidas_msg(self, medias: List[MediaInfo], userid: str = "", title: str = "") -> Optional[bool]:
"""
发送列表类消息
"""
if not self._client:
return False
if not medias:
return False
try:
if userid:
channel = userid
else:
# 消息广播
channel = self.__find_public_channel()
# 消息主体
title_section = {
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*{title}*"
}
}
blocks = [title_section]
# 列表
if medias:
blocks.append({
"type": "divider"
})
index = 1
for media in medias:
if media.get_poster_image():
if media.get_star_string():
text = f"{index}. *<{media.get_detail_url()}|{media.get_title_string()}>*" \
f"\n类型:{media.type.value}" \
f"\n{media.get_star_string()}" \
f"\n{media.get_overview_string(50)}"
else:
text = f"{index}. *<{media.get_detail_url()}|{media.get_title_string()}>*" \
f"\n类型:{media.type.value}" \
f"\n{media.get_overview_string(50)}"
blocks.append(
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": text
},
"accessory": {
"type": "image",
"image_url": f"{media.get_poster_image()}",
"alt_text": f"{media.get_title_string()}"
}
}
)
blocks.append(
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "选择",
"emoji": True
},
"value": f"{index}",
"action_id": f"actionId-{index}"
}
]
}
)
index += 1
# 发送
result = self._client.chat_postMessage(
channel=channel,
blocks=blocks
)
return True if result else False
except Exception as msg_e:
logger.error(f"Slack消息发送失败: {msg_e}")
return False
def send_torrents_msg(self, torrents: List[Context],
userid: str = "", title: str = "") -> Optional[bool]:
"""
发送列表消息
"""
if not self._client:
return None
try:
if userid:
channel = userid
else:
# 消息广播
channel = self.__find_public_channel()
# 消息主体
title_section = {
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*{title}*"
}
}
blocks = [title_section, {
"type": "divider"
}]
# 列表
index = 1
for context in torrents:
torrent = context.torrent_info
site_name = torrent.site_name
meta = MetaInfo(torrent.title, torrent.description)
link = torrent.page_url
title = f"{meta.get_season_episode_string()} " \
f"{meta.get_resource_type_string()} " \
f"{meta.get_resource_team_string()} " \
f"{StringUtils.str_filesize(torrent.size)}"
title = re.sub(r"\s+", " ", title).strip()
free = torrent.get_volume_factor_string()
seeder = f"{torrent.seeders}"
description = torrent.description
text = f"{index}. 【{site_name}】[{title}]({link}) {free} {seeder}\n- {description}"
blocks.append(
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": text
}
}
)
blocks.append(
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "选择",
"emoji": True
},
"value": f"{index}",
"action_id": f"actionId-{index}"
}
]
}
)
index += 1
# 发送
result = self._client.chat_postMessage(
channel=channel,
blocks=blocks
)
return True if result else False
except Exception as msg_e:
logger.error(f"Slack消息发送失败: {msg_e}")
return False
def __find_public_channel(self):
"""
查找公共频道
"""
if not self._client:
return ""
conversation_id = ""
try:
for result in self._client.conversations_list():
if conversation_id:
break
for channel in result["channels"]:
if channel.get("name") == settings.SLACK_CHANNEL or "全体":
conversation_id = channel.get("id")
break
except Exception as e:
logger.error(f"查找Slack公共频道失败: {e}")
return conversation_id