Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

wechat_channel.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # encoding:utf-8
  2. """
  3. wechat channel
  4. """
  5. import itchat
  6. import json
  7. from itchat.content import *
  8. from channel.channel import Channel
  9. from concurrent.futures import ThreadPoolExecutor
  10. from common.log import logger
  11. from config import conf
  12. import requests
  13. import io
  14. thead_pool = ThreadPoolExecutor(max_workers=8)
  15. @itchat.msg_register(TEXT)
  16. def handler_single_msg(msg):
  17. WechatChannel().handle(msg)
  18. return None
  19. @itchat.msg_register(TEXT, isGroupChat=True)
  20. def handler_group_msg(msg):
  21. WechatChannel().handle_group(msg)
  22. return None
  23. class WechatChannel(Channel):
  24. def __init__(self):
  25. pass
  26. def startup(self):
  27. # login by scan QRCode
  28. itchat.auto_login(enableCmdQR=2)
  29. # start message listener
  30. itchat.run()
  31. def handle(self, msg):
  32. logger.debug("[WX]receive msg: " + json.dumps(msg, ensure_ascii=False))
  33. from_user_id = msg['FromUserName']
  34. to_user_id = msg['ToUserName'] # 接收人id
  35. other_user_id = msg['User']['UserName'] # 对手方id
  36. content = msg['Text']
  37. match_prefix = self.check_prefix(content, conf().get('single_chat_prefix'))
  38. if from_user_id == other_user_id and match_prefix is not None:
  39. # 好友向自己发送消息
  40. if match_prefix != '':
  41. str_list = content.split(match_prefix, 1)
  42. if len(str_list) == 2:
  43. content = str_list[1].strip()
  44. img_match_prefix = self.check_prefix(content, conf().get('image_create_prefix'))
  45. if img_match_prefix:
  46. content = content.split(img_match_prefix, 1)[1].strip()
  47. thead_pool.submit(self._do_send_img, content, from_user_id)
  48. else:
  49. thead_pool.submit(self._do_send, content, from_user_id)
  50. elif to_user_id == other_user_id and match_prefix:
  51. # 自己给好友发送消息
  52. str_list = content.split(match_prefix, 1)
  53. if len(str_list) == 2:
  54. content = str_list[1].strip()
  55. img_match_prefix = self.check_prefix(content, conf().get('image_create_prefix'))
  56. if img_match_prefix:
  57. content = content.split(img_match_prefix, 1)[1].strip()
  58. thead_pool.submit(self._do_send_img, content, to_user_id)
  59. else:
  60. thead_pool.submit(self._do_send, content, to_user_id)
  61. def handle_group(self, msg):
  62. logger.debug("[WX]receive group msg: " + json.dumps(msg, ensure_ascii=False))
  63. group_name = msg['User'].get('NickName', None)
  64. group_id = msg['User'].get('UserName', None)
  65. if not group_name:
  66. return ""
  67. origin_content = msg['Content']
  68. content = msg['Content']
  69. content_list = content.split(' ', 1)
  70. context_special_list = content.split('\u2005', 1)
  71. if len(context_special_list) == 2:
  72. content = context_special_list[1]
  73. elif len(content_list) == 2:
  74. content = content_list[1]
  75. config = conf()
  76. match_prefix = (msg['IsAt'] and not config.get("group_at_off", False)) or self.check_prefix(origin_content, config.get('group_chat_prefix')) \
  77. or self.check_contain(origin_content, config.get('group_chat_keyword'))
  78. if (group_name in config.get('group_name_white_list') or 'ALL_GROUP' in config.get('group_name_white_list') or self.check_contain(group_name, config.get('group_name_keyword_white_list'))) and match_prefix:
  79. img_match_prefix = self.check_prefix(content, conf().get('image_create_prefix'))
  80. if img_match_prefix:
  81. content = content.split(img_match_prefix, 1)[1].strip()
  82. thead_pool.submit(self._do_send_img, content, group_id)
  83. else:
  84. thead_pool.submit(self._do_send_group, content, msg)
  85. def send(self, msg, receiver):
  86. logger.info('[WX] sendMsg={}, receiver={}'.format(msg, receiver))
  87. itchat.send(msg, toUserName=receiver)
  88. def _do_send(self, query, reply_user_id):
  89. try:
  90. if not query:
  91. return
  92. context = dict()
  93. context['from_user_id'] = reply_user_id
  94. reply_text = super().build_reply_content(query, context)
  95. if reply_text:
  96. self.send(conf().get("single_chat_reply_prefix") + reply_text, reply_user_id)
  97. except Exception as e:
  98. logger.exception(e)
  99. def _do_send_img(self, query, reply_user_id):
  100. try:
  101. if not query:
  102. return
  103. context = dict()
  104. context['type'] = 'IMAGE_CREATE'
  105. img_url = super().build_reply_content(query, context)
  106. if not img_url:
  107. return
  108. # 图片下载
  109. pic_res = requests.get(img_url, stream=True)
  110. image_storage = io.BytesIO()
  111. for block in pic_res.iter_content(1024):
  112. image_storage.write(block)
  113. image_storage.seek(0)
  114. # 图片发送
  115. logger.info('[WX] sendImage, receiver={}'.format(reply_user_id))
  116. itchat.send_image(image_storage, reply_user_id)
  117. except Exception as e:
  118. logger.exception(e)
  119. def _do_send_group(self, query, msg):
  120. if not query:
  121. return
  122. context = dict()
  123. context['from_user_id'] = msg['ActualUserName']
  124. reply_text = super().build_reply_content(query, context)
  125. if reply_text:
  126. reply_text = '@' + msg['ActualNickName'] + ' ' + reply_text.strip()
  127. self.send(conf().get("group_chat_reply_prefix", "") + reply_text, msg['User']['UserName'])
  128. def check_prefix(self, content, prefix_list):
  129. for prefix in prefix_list:
  130. if content.startswith(prefix):
  131. return prefix
  132. return None
  133. def check_contain(self, content, keyword_list):
  134. if not keyword_list:
  135. return None
  136. for ky in keyword_list:
  137. if content.find(ky) != -1:
  138. return True
  139. return None